[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-82873":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":14,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":16,"stars7d":17,"stars30d":18,"stars90d":15,"forks30d":15,"starsTrendScore":19,"compositeScore":20,"rankGlobal":9,"rankLanguage":9,"license":21,"archived":22,"fork":22,"defaultBranch":23,"hasWiki":24,"hasPages":22,"topics":25,"createdAt":9,"pushedAt":9,"updatedAt":26,"readmeContent":27,"aiSummary":28,"trendingCount":15,"starSnapshotCount":15,"syncStatus":29,"lastSyncTime":30,"discoverSource":31},82873,"lark-coding-agent-bridge","zarazhangrui\u002Flark-coding-agent-bridge","zarazhangrui","Bot that bridges Feishu\u002FLark messenger with a local Claude Code or Codex CLI. Streaming cards, per-chat sessions, multiple workspaces",null,"TypeScript",1131,167,5,41,0,30,220,308,145,104.68,"MIT License",false,"main",true,[],"2026-06-12 04:01:39","# lark-channel-bridge\n\nA lightweight bot that bridges Feishu \u002F Lark messenger with your local Claude Code or Codex CLI. Run one command, scan a QR code to bind a PersonalAgent app, and talk to your local coding agent from chat.\n\n[中文 README](.\u002FREADME.zh.md)\n\nFor a product walkthrough, see the [Feishu document](https:\u002F\u002Flarkcommunity.feishu.cn\u002Fdocx\u002FOaRIdFIRFoLM3xxTmKwcetHqn5e).\n\n## What it does\n\n- Forwards Feishu \u002F Lark messages to local Claude Code or Codex CLI. Send a DM directly, or `@bot` in a group.\n- **Streaming card**: text replies and tool calls update on one Lark card in real time.\n- **Session continuity**: each chat, topic, or document comment thread keeps its own session.\n- **Queueing and batching**: messages sent in quick succession are handled together; messages sent during a run are queued for the next turn, while commands like `\u002Fnew`, `\u002Fcd`, `\u002Fws use`, and `\u002Fstop` can interrupt the current task.\n- **Multiple workspaces**: use `\u002Fcd` to switch the current project, and `\u002Fws` to save and reuse common project directories.\n- **Images and files**: send them to the bot directly, and the bridge downloads them locally for the agent.\n- **Interactive cards**: `\u002Fhelp`, `\u002Fws list`, and `\u002Fstatus` return cards with clickable buttons.\n\n## Prerequisites\n\n- Node.js **>= 20.12.0**\n- At least one local agent installed and logged in:\n  - Claude Code: `claude`, see https:\u002F\u002Fdocs.anthropic.com\u002Fen\u002Fdocs\u002Fclaude-code\u002Fquickstart\n  - Codex CLI: `codex`, see https:\u002F\u002Fdevelopers.openai.com\u002Fcodex\u002Fcli\n- A Feishu \u002F Lark **PersonalAgent** app. The first-run QR wizard can create and bind one for you.\n\n## Install\n\n```bash\nnpm i -g lark-channel-bridge\n# or\npnpm add -g lark-channel-bridge\n```\n\n## First run\n\n```bash\nlark-channel-bridge run\n```\n\nThe first run opens a QR-code wizard:\n\n1. A QR code renders in your terminal.\n2. Scan it with the Feishu \u002F Lark app.\n3. Pick or create a PersonalAgent app.\n4. If prompted, choose which agent to initialize.\n5. Config is written to `~\u002F.lark-channel\u002Fconfig.json`.\n\nYou do not need to choose a project directory up front. The bridge creates a profile-managed default working directory; after startup, send `\u002Fcd \u003Cpath>` in Feishu \u002F Lark to switch to a real project.\n\nIf you already have a PersonalAgent app, pass `--app-id` during initialization to skip app creation. The command prompts for the App Secret.\n\n```bash\nlark-channel-bridge run --app-id cli_xxx\n# or initialize and start the background service directly\nlark-channel-bridge start --app-id cli_xxx\n```\n\nFor Lark global apps, add `--tenant lark`.\n\n## Background service\n\nUse `run` for first-run setup and foreground debugging. After the bot can send and receive messages, stop the foreground process with `Ctrl-C`, then use an OS-managed service for background operation:\n\n```bash\nlark-channel-bridge start\nlark-channel-bridge status\nlark-channel-bridge stop\n```\n\nInstall globally before using service commands. The daemon's launchd plist \u002F systemd unit \u002F Windows task records the bridge CLI path; if that path comes from an npm temp cache through `npx`, the daemon can break when the cache is cleaned. `run` is fine through `npx` as a one-shot foreground process.\n\nService commands install a per-profile service:\n\n```bash\nlark-channel-bridge start [--profile \u003Cname>]\nlark-channel-bridge stop [--profile \u003Cname>]\nlark-channel-bridge restart [--profile \u003Cname>]\nlark-channel-bridge status [--profile \u003Cname>]\nlark-channel-bridge unregister [--profile \u003Cname>]\n```\n\nPlatform mapping:\n- **macOS**: launchd user agent `ai.lark-channel-bridge.bot.\u003Cprofile>`\n- **Linux**: systemd user unit `lark-channel-bridge.bot.\u003Cprofile>.service`\n- **Windows**: Task Scheduler task `LarkChannelBridge.Bot.\u003Cprofile>`, launched through a `.cmd` wrapper\n\nDaemon logs are under `~\u002F.lark-channel\u002Fprofiles\u002F\u003Cprofile>\u002Flogs\u002Fdaemon\u002F`.\n\n### Multiple profiles: Claude and Codex\n\nBy default, the bridge starts with the currently selected profile. Use `profile use \u003Cname>` to change it. Each profile keeps its own app credentials, sessions, working directories, and logs. Create multiple profiles only when you need to connect multiple PersonalAgent apps, or run Claude and Codex as separate bots:\n\n```bash\nlark-channel-bridge start --profile claude --agent claude\nlark-channel-bridge start --profile codex --agent codex\n```\n\nFor example, to restart only the Codex bot:\n\n```bash\nlark-channel-bridge restart --profile codex\nlark-channel-bridge status --profile codex\n```\n\n## Commands\n\n### Host CLI\n\n```text\nlark-channel-bridge run [--profile \u003Cname>] [--agent claude|codex] [--workspace \u003Cpath>] [-c \u003Cconfig>]\nlark-channel-bridge migrate [--profile \u003Cname>] [--agent claude|codex]\nlark-channel-bridge ps\nlark-channel-bridge kill \u003Cid|#>\nlark-channel-bridge --help\n```\n\n`profile use \u003Cname>` changes the profile used by later default starts. Use these profile management commands when running separate Claude \u002F Codex bots, connecting multiple PersonalAgent apps, or doing scripted deployment:\n\n```bash\nlark-channel-bridge profile create claude --agent claude\nlark-channel-bridge profile create codex --agent codex\nlark-channel-bridge profile list\nlark-channel-bridge profile use \u003Cname>\nlark-channel-bridge profile remove \u003Cname>\nlark-channel-bridge profile remove \u003Cname> --purge --yes\nlark-channel-bridge profile export \u003Cname> [--output .\u002Fprofile.json] [--force]\nlark-channel-bridge profile export \u003Cname> --include-secrets --yes\n```\n\n`profile remove` archives local state by default, including the active profile. If other profiles remain, the bridge switches to the next one; if it was the last profile, the root config is cleared so the same name can be created again. `--purge --yes` permanently deletes local state. `profile export` redacts app secrets by default; `--include-secrets --yes` includes sensitive config.\n\nIf a profile was created with the wrong agent kind, stop or unregister any matching background service first, then run `profile remove \u003Cname>` and recreate it with the intended `--agent`.\n\n### Slash commands inside Feishu \u002F Lark\n\n| Command | Effect |\n|---|---|\n| `\u002Fnew`, `\u002Freset` | Clear the current session |\n| `\u002Fcd \u003Cpath>` | Switch working directory and reset the session |\n| `\u002Fws list` | List named workspaces |\n| `\u002Fws save \u003Cname>` | Save the current working directory as a named workspace |\n| `\u002Fws use \u003Cname>` | Switch to a named workspace |\n| `\u002Fws remove \u003Cname>` | Delete a named workspace |\n| `\u002Fresume` | Resume compatible history for the same agent, working directory, and permission mode |\n| `\u002Fstatus` | Show profile, agent, working directory, session, and run state |\n| `\u002Fconfig` | Adjust presentation preferences and view the access panel |\n| `\u002Finvite user @name` | Allow a user to use the bot in DMs |\n| `\u002Finvite admin @name` | Add an access-control admin |\n| `\u002Finvite group` | Allow the current group to use the bot |\n| `\u002Finvite all group` | Allow all groups the bot has joined |\n| `\u002Fremove user @name`, `\u002Fremove admin @name`, `\u002Fremove group` | Remove access entries |\n| `\u002Fstop` | Stop the current run, including the card stop button |\n| `\u002Ftimeout [N\\|off\\|default]` | Set or clear the current session idle watchdog |\n| `\u002Fps` | List local bridge processes |\n| `\u002Fexit \u003Cid\\|#>` | Stop a bridge process |\n| `\u002Freconnect` | Force a WebSocket reconnect |\n| `\u002Fdoctor [description]` | Run low-sensitive diagnostics |\n| `\u002Fhelp` | Help card |\n\nDMs do not require an @ mention. Groups and topic groups require `@bot` by default; `@all` is ignored. Cloud-doc comments in supported document types run when the bot is mentioned.\n\n## Working directories\n\nEach profile may define a default working directory through `workspaces.default`. New profiles may be created with `--workspace \u003Cpath>`; if omitted, the bridge creates a profile-managed default working directory.\n\nThis is a profile-field snippet. Do not replace the whole `config.json` with it; edit the matching profile's `workspaces` field.\n\n```json\n{\n  \"workspaces\": {\n    \"default\": \"\u002FUsers\u002Fme\u002F.lark-channel-workspaces\u002Fclaude\u002Fdefault\"\n  }\n}\n```\n\nThe bridge checks that a selected directory exists, is a directory, and is not an overly broad location such as `\u002F`, the home root, a system directory, or a temp root. The working directory is only the current directory for an agent run. It is not a filesystem sandbox; actual file access still depends on the local agent process and its permission mode.\n\n## Permission modes\n\nThe recommended user-facing profile config is `permissions.defaultAccess` and `permissions.maxAccess`. New profiles default to `full` for both values so the bridge can keep local tools, authorization flows, file writes, and other agent features fully usable. To tighten a profile, set one or both values to `workspace` or `read-only`; stricter modes can limit local tool execution, login\u002Fauthorization flows, file writes, and similar capabilities.\n\nThis is a profile-field snippet. Do not replace the whole `config.json` with it; edit the matching profile's `permissions` field.\n\n```json\n{\n  \"permissions\": {\n    \"defaultAccess\": \"full\",\n    \"maxAccess\": \"full\"\n  }\n}\n```\n\nMode mapping:\n\n| Bridge access | Claude permission mode | Codex mode |\n|---|---|---|\n| `full` | `bypassPermissions` | `danger-full-access` |\n| `workspace` | `acceptEdits` | `workspace-write` |\n| `read-only` | `plan` | `read-only` |\n\nThe legacy `sandbox` field is still readable for old configs. After the bridge saves the profile, it migrates that setting to canonical `permissions`.\n\n## Data directories\n\n| Path | Content |\n|---|---|\n| `~\u002F.lark-channel\u002Fconfig.json` | Root config with profiles and active profile |\n| `~\u002F.lark-channel\u002Factive-profile` | Last selected profile |\n| `~\u002F.lark-channel\u002Fprofiles\u002F\u003Cprofile>\u002Fsessions.json` | Session state |\n| `~\u002F.lark-channel\u002Fprofiles\u002F\u003Cprofile>\u002Fsessions.json.catalog.json` | Agent-aware session catalog |\n| `~\u002F.lark-channel\u002Fprofiles\u002F\u003Cprofile>\u002Fworkspaces.json` | Current and named workspace bindings |\n| `~\u002F.lark-channel\u002Fprofiles\u002F\u003Cprofile>\u002Fsecrets.enc` | Profile-local encrypted secrets |\n| `~\u002F.lark-channel\u002Fprofiles\u002F\u003Cprofile>\u002Fmedia\u002F` | Attachment cache |\n| `~\u002F.lark-channel\u002Fprofiles\u002F\u003Cprofile>\u002Flogs\u002F` | Structured run logs |\n| `~\u002F.lark-channel\u002Fregistry\u002Fprocesses.json` | Local process registry |\n| `~\u002F.lark-channel\u002Fregistry\u002Flocks\u002F` | Profile and app locks |\n\nSet `LARK_CHANNEL_HOME=\u002Fpath\u002Fto\u002Fstate` to move all local bridge state. `LARK_CHANNEL_LOG_DAYS` overrides log retention.\n\n## Access control\n\n**Chat access is private by default: out of the box, only *you* can use the bot in DMs and groups.** \"You\" = whoever created \u002F owns the Feishu app (the person who scanned the QR to set it up). The bot figures out who the app owner is automatically from Feishu, so **solo chat use needs zero configuration** — you can DM it and `@`-mention it in any group, and everyone else's chat messages are silently ignored (no \"permission denied\" reply, which would only confirm the bot exists). Cloud-doc comments are document-scoped; see below.\n\nTo let other people or groups in, add them to one of three lists:\n\n| List | Controls | Add | Remove |\n|------|----------|-----|--------|\n| **Allowed users** | who can DM the bot | `\u002Finvite user @them` | `\u002Fremove user @them` |\n| **Allowed chats** | which groups the bot answers in (for **everyone** in them) | `\u002Finvite group` (current group) \u002F `\u002Finvite all group` (every group the bot is in) | `\u002Fremove group` (current group) |\n| **Admins** | who can change settings, and use the bot in any group | `\u002Finvite admin @them` | `\u002Fremove admin @them` |\n\n> `\u002Finvite` and `\u002Fremove` can only be run by **you (the creator) and admins**. The `@` in the command points at the *target person* (not the bot) — the bot resolves the mention to their identity, so you never deal with raw IDs.\n\n### Two identities that bypass everything\n\n- **You (the creator)**: subject to no list at all — DMs, any group, every command. You **can never lock yourself out**: even if the lists get messed up, DM the bot and send `\u002Fconfig` to get back in. Transfer the app's ownership in the Feishu console and the bot follows the new owner automatically.\n- **Admins**: can DM, run management commands like `\u002Fconfig`, and **bypass the allowed-chats list** — the bot answers them in any group, listed or not. Good for teammates who co-maintain the bot.\n\n### Common setups\n\n- **Just me** → nothing to do; this is the default.\n- **Let a teammate DM the bot** → `\u002Finvite user @them`\n- **Open a work group to everyone in it** → send `\u002Finvite group` inside that group\n- **First-time setup, onboard every group the bot is already in** → `\u002Finvite all group` pulls them all into the list at once; trim with `\u002Fremove group` afterwards\n- **Add a co-admin** → `\u002Finvite admin @them`\n\n### Worth knowing\n\n- Changes take effect on the **next message** — no restart needed.\n- **In groups you must `@` the bot first** (DMs don't need it). That's a separate toggle (`\u002Fconfig` → \"require @ in groups\"), independent of the lists above.\n- Strangers get pure silence — no reply at all. The one exception: if someone `@`-mentions the bot in a group that hasn't been opened up, the bot posts a friendly one-liner telling them an admin can run `\u002Finvite group` to enable it.\n- Cloud-doc comments are document-scoped: anyone who can comment in a supported document and mention the bot can trigger a reply.\n\n### Advanced: editing the config file directly\n\nIf you'd rather not do it inside Feishu, `\u002Finvite` and `\u002Fconfig` write the matching profile's `access` field in `~\u002F.lark-channel\u002Fconfig.json`. Empty lists mean nobody from that list, not open access. This is a profile-field snippet; do not replace the whole `config.json` with it:\n\n```json\n{\n  \"schemaVersion\": 2,\n  \"profiles\": {\n    \"claude\": {\n      \"agentKind\": \"claude\",\n      \"access\": {\n        \"allowedUsers\": [\"ou_xxxxxxxxxxxxx\"],\n        \"allowedChats\": [\"oc_xxxxxxxxxxxxx\"],\n        \"admins\": [\"ou_xxxxxxxxxxxxx\"],\n        \"requireMentionInGroup\": true\n      }\n    }\n  }\n}\n```\n\n`allowedUsers` \u002F `admins` take user `open_id`s; `allowedChats` takes group `chat_id`s. The easiest way to find an ID by hand: have the person message the bot (or `@` it in the group), then check the active profile's log:\n\n```bash\ngrep '\"event\":\"enter\"' ~\u002F.lark-channel\u002Fprofiles\u002F\u003Cprofile>\u002Flogs\u002Fbridge-$(date +%Y%m%d).jsonl | tail -5\n```\n\nEach line carries `chatId` (group \u002F DM id) and `senderId` (user `open_id`). After a manual edit, **restart the bridge** or send `\u002Freconnect` from an allowed admin context to apply it. For day-to-day tweaks `\u002Finvite` \u002F `\u002Fconfig` are easier; direct edits are mainly for deployment scripts that pre-seed access.\n\n## Cloud-doc comments\n\nCloud-doc comments do not need a separate workspace binding or document allowlist. In supported document comments, mention the bot and the bridge replies in the same thread. Comment runs reuse the document session key and fall back to the user home directory when no document cwd was previously recorded.\n\n## FAQ\n\n**The bot stays silent or the local CLI never replies.** Usually the local `claude` or `codex` CLI is not logged in, or the current session points to a working directory that no longer exists. Send `\u002Fstatus` to inspect; `\u002Fnew` often fixes it by starting a fresh session.\n\n**The agent subprocess looks frozen (card stuck on the last frame).** The bridge supports an idle watchdog: if the agent emits nothing for N minutes, the process is killed and the card is annotated with the auto-termination reason. Disabled by default. Enable with `\u002Fconfig` globally, or `\u002Ftimeout 10` for the current session; `\u002Ftimeout off` disables it for the session; `\u002Ftimeout default` clears the session override.\n\n**The agent says it cannot see an image I sent.** Upgrade to the latest version. Releases before 0.1.0 had a filename-dedup bug.\n\n## Codex CLI verification\n\nCodex profiles store a binary pin with `binaryPath`, `realpath`, `version`, and `sha256`. The bridge verifies the pin before every Codex run and refuses to continue if the binary changes. Arbitrary `codex.flags` are not exposed; bridge-owned Codex argv is fixed.\n\n## Testing and CI\n\nLocal checks:\n\n```bash\npnpm test\npnpm typecheck\npnpm build\n```\n\n`pnpm test` includes unit, integration, and process-level adapter tests. CI runs on macOS, Ubuntu, and Windows with `pnpm install --frozen-lockfile`, `pnpm test`, `pnpm typecheck`, and `pnpm build`.\n\n## Optional telemetry\n\nBy default the bridge reports **nothing**: no metrics, no logs leave your machine, and it pulls in zero telemetry dependencies. The hook below is inert unless you opt in.\n\nTo wire up your own monitoring, point an environment variable at a module that default-exports (or exports `createAdapter`) an `AdapterFactory`:\n\n```bash\nLARK_CHANNEL_TELEMETRY_MODULE=your-telemetry-package lark-channel-bridge start\n```\n\nThat module receives every `log.*` event plus error\u002Fmetric hooks and forwards them wherever you like. The interface is exported from the package root:\n\n```ts\nimport type { AdapterFactory, TelemetryAdapter, TelemetryEvent } from 'lark-channel-bridge';\n\nconst createAdapter: AdapterFactory = (meta) => ({\n  emit(event) {\u002F* ship event *\u002F},\n  recordError(err, ctx) {\u002F* ship exception *\u002F},\n  recordMetric(name, value, tags) {\u002F* ship metric *\u002F},\n  flush(timeoutMs) {\u002F* drain buffered events *\u002F},\n});\nexport default createAdapter;\n```\n\nA missing module, a bad factory, or a throwing adapter all degrade to noop — telemetry can never stop the bridge from starting or break logging.\n\n## License\n\n[MIT](.\u002FLICENSE)\n\n\u003Cimg src=\".\u002Fassets\u002Ffeedback-group-qr.png\" alt=\"Feedback group QR code\" width=\"360\">\n","lark-coding-agent-bridge 是一个轻量级的机器人，用于将飞书\u002F飞聊消息与本地的 Claude Code 或 Codex CLI 连接起来。其核心功能包括实时更新的消息卡片、会话连续性、消息队列和批处理、支持多个工作区以及文件和图片传输等。项目采用 TypeScript 编写，并通过简单的命令行操作即可启动服务，适合需要在聊天应用中直接调用代码辅助工具的开发者使用，特别是在需要快速响应和多任务管理的开发场景下。",2,"2026-06-11 04:09:29","CREATED_QUERY"]