一个最小可运行的实验项目:
- 飞书机器人通过长连接收消息
- 将文本消息转给本机
codex - 把 Codex 的最终响应回发到飞书
- 按聊天维度保存多个会话,并展示最近活跃会话
- 支持把同一个 session 从私聊挂接到群聊,或从一个群挂接到另一个群继续
- 主面板只接受命令;私聊主面板可用显式路由,群聊主面板需
@机器人 S1: ...;线程里直接回复即可继续会话 - Codex 完成后自动把结果发回飞书
- 同一聊天里可保留多个会话
- 每个会话可绑定自己的工作目录
- 每个会话都会显示状态:空闲 / 运行中 / 已完成 / 失败
- 每个会话都可以在创建时指定 Agent:Codex / Claude Code / Cursor Agent / OpenCode
- 每个会话都会暴露稳定的“转移 ID”
- 每次结果会直接以一张卡片发送,卡片里同时展示结果、会话信息和可用命令
- 每个新会话都会生成一条主消息,后续结果会回复到这条消息下面,便于按话题管理
- 每轮完成后会附带代码改动摘要,便于人工审查
- 如果本轮发生了分支切换或提交变化,也会直接显示在结果卡片里
- 私聊里可用
S1: 继续处理这种前缀把消息发给指定会话 /new创建新会话/new cursor创建新会话并直接指定 Agent/new /path/to/project创建新会话并直接指定工作目录/new cursor /path/to/project创建新会话并同时指定 Agent 和工作目录/new /path/to/project 你的第一条指令创建新会话、指定目录并立即开始第一轮/new cursor /path/to/project 你的第一条指令创建新会话、指定 Agent、指定目录并立即开始第一轮/agent查看当前活跃会话使用的 Agent/cwd查看当前活跃会话的工作目录/cwd /path/to/project修改当前活跃会话的工作目录/cwd S1 /path/to/project修改指定会话的工作目录/stop停止当前正在运行的会话/stop S1停止指定会话/delete删除当前活跃会话/delete S1删除指定会话,并自动整理剩余编号/show S1查看某个会话最近 10 条消息/diff S1查看某个会话最近一轮代码改动摘要/attach <转移ID>把另一个聊天里的 session 挂接到当前聊天继续/fork S1在主面板里 fork 一个新会话,复制独立工作区,继承原会话最近上下文并自动创建新 topic/sessions查看最近会话;私聊主面板里显示全局/status查看当前状态;私聊主面板里显示全局/clean清空会话;私聊里清空全部,群聊里清空当前群聊/help查看帮助- 任何以
/开头但不属于已知命令的输入,都会被拦截,不会发送给 Codex
- 不做卡片按钮回调
- 不做多会话并行管理 UI
- 不做任务审批流
- 不做复杂权限系统
- 本机已安装并可直接运行
codex - 飞书开放平台应用已创建
- 应用启用了机器人能力和事件订阅
- 应用已开通
im.message.receive_v1 - 机器人具备发消息权限
建议至少勾上这几项:
im:messageim:message.group_at_msgim:message:readonly
如果你要在私聊中使用,还需要对应的私聊消息权限。
复制 .env.example 为 .env,至少填写:
FEISHU_APP_ID=cli_xxx
FEISHU_APP_SECRET=xxx
AGENT_PROVIDER=codex
CODEX_WORKSPACE=/Users/xzq/Documents/Playground
CODEX_BIN=/Applications/Codex.app/Contents/Resources/codex
CLAUDE_BIN=claude
CLAUDE_PERMISSION_MODE=bypassPermissions
CLAUDE_SETTING_SOURCES=
CURSOR_AGENT_BIN=cursor-agent
OPENCODE_BIN=opencode
CODEX_SANDBOX=workspace-write
CODEX_AUTO_APPROVAL=true
CODEX_SKIP_GIT_REPO_CHECK=true说明:
- 机器人会在启动时自动通过飞书 OpenAPI 拉取自己的 bot 信息,用于精确识别群聊里的
@机器人 AGENT_PROVIDER用来设置默认 Agent,可选codex、claude、cursor、opencodeCODEX_WORKSPACE是 Codex 真正工作的目录CODEX_WORKSPACE现在只作为默认目录,新会话会默认继承它;后续可以在飞书里按会话改掉CLAUDE_SETTING_SOURCES可选;如果你的~/.claude/settings.json里配了代理或自定义网关,想临时忽略用户级配置,可设成project,localCODEX_AUTO_APPROVAL=true会让 Codex 以无人值守方式执行,适合实验环境,风险更高CODEX_SKIP_GIT_REPO_CHECK=true允许你把工作目录指到非 git 仓库,适合 MVP 实验- 当
CODEX_AUTO_APPROVAL=true时,Codex 会跳过审批并绕过 sandbox;如果你想保留workspace-write隔离,请把它设为false
npm install
npm start启动后,机器人会通过飞书长连接等待事件,不需要公网 webhook。
私聊主面板只接受命令或显式路由,不再默认把普通正文发给某个 session。
群聊主面板则只接受 @机器人 + 命令 或 @机器人 S1: ...。
私聊里推荐这样新建会话:
/new codex /Users/xzq/project-a 帮我检查一下当前仓库里有哪些 TODO
或者继续一个本地会话:
S1: 把 README 也补上
群聊主面板里推荐这样用:
@机器人 /new codex /Users/xzq/project-a 帮我检查一下当前仓库里有哪些 TODO
如果你想在群聊主面板里显式续接某个会话:
@机器人 S1: 继续这个会话
机器人会先回:
已收到,正在为你启动新的会话 S1。
新会话建立后,机器人会为这个 session 发一条主消息。之后这个 session 的执行结果会持续回复到这条主消息下面。 你直接回复这条线程里的任意一条消息,就会自动续接对应的 session。
待 Codex 执行完成后,会直接发送一张结果卡片,里面包含:
- Codex 最终回复
- 当前状态
- 转移 ID
- 当前会话 ID
- 当前工作目录
- 会话总览提示
- 本轮代码改动摘要
- 可直接复制使用的文本命令提示
其中空闲会话会明确标成 空闲,方便你快速挑一个继续推进,不让它闲着。
如果你想把一个 session 从私聊转到群聊,或从一个群转到另一个群,可以直接使用卡片里的 转移 ID:
/attach 456c4598-c50c-4bd4-875b-584ef20cfbb5
attach 成功后,当前聊天里会生成一个新的本地别名,之后继续用这个本地别名即可:
S1: 继续这个会话
如果你是在群聊主面板里继续,请记得带上 @机器人:
@机器人 S1: 继续这个会话
如果你想从某个已有会话分叉出一个新的会话,但保留最近若干轮上下文:
/fork S1
这个命令只能在主面板使用,不能在已有 topic 内使用。执行后会:
- 新建一个新的本地会话
- 继承原会话的 Agent
- 在原工作目录的同级目录下复制一个新的工作区给 fork 会话使用
- 复制原会话最近若干轮上下文,作为新会话首轮的继承上下文
- 自动创建一个新的 topic 入口
- 如果后续删除这个 fork 出来的 session,这个复制出来的工作区不会自动删除
已创建的会话不支持中途切换 Agent。 这是为了避免底层 Agent 自己的会话上下文丢失或串线。 如果你想换 Agent,请直接新建一个会话:
/new claude /Users/xzq/project-a 你的第一条指令
如果你想新开一个话题:
/new
然后直接发新消息即可。
如果你想新建会话时直接指定 Agent:
/new cursor
如果你想新建会话时直接指定目录:
/new /Users/xzq/project-a
如果你想新建会话时同时指定 Agent 和目录:
/new cursor /Users/xzq/project-a
如果你想新建会话、指定目录并立刻开始:
/new /Users/xzq/project-a 帮我分析这个仓库的测试失败原因
如果你想新建会话、指定 Agent、指定目录并立刻开始:
/new cursor /Users/xzq/project-a 帮我分析这个仓库的测试失败原因
如果你想切换当前会话的工作目录:
/cwd /Users/xzq/project-a
如果你想切换指定会话的工作目录:
/cwd S1 /Users/xzq/project-b
如果你想查看当前会话工作目录:
/cwd
如果你想手动停止一个正在运行的会话:
/stop
如果你想停止指定会话:
/stop S1
如果你想查看某个会话最近 10 条消息:
/show S1
如果你想查看某个会话最近一轮改了什么代码:
/diff S1
如果你想把另一个聊天里的 session 接到当前聊天继续:
/attach <转移ID>
如果你想删除当前活跃会话:
/delete
如果你想删除某个指定会话:
/delete S1
删除后,剩余会话会自动重新编号,例如原来的 S2 会补成新的 S1。
如果你想清空会话:
/clean
- 私聊里执行
/clean:清空全部聊天下的所有会话 - 群聊里执行
/clean:清空当前群聊下的所有会话
如果你想明确把消息发给某个会话:
S1: 把 README 也补上
如果你在私聊里想看全局总览:
/sessions
/status
这两个命令在私聊主面板里会显示所有聊天下的会话,并带上:
- 聊天名/群名
- 工作目录
- 转移 ID
src/config.js 环境变量读取
src/agent-runner.js Agent 执行器抽象,支持 Codex / Claude / Cursor / OpenCode
src/session-store.js 聊天到多个 Agent 会话的持久化映射
src/index.js 飞书长连接入口
data/sessions.json 运行时自动生成
- 当前最近会话摘要默认展示前 5 个
/show S1当前只展示最近 10 条文本消息/diff S1会优先比较 git 提交点前后差异,再回退到工作区前后快照;非 git 目录下无法提供代码 diff 摘要- 删除会话后,剩余会话会自动重排编号
S1/S2这类 alias 始终只在当前聊天内有效;跨聊天续接必须使用/attach <转移ID>- 相对路径会相对默认目录
CODEX_WORKSPACE解析,建议移动端直接发绝对路径 - 如果目录路径里有空格,建议在
/new或/cwd里用引号包起来 - 当前卡片是纯展示卡片,不带按钮;所有操作都通过文本命令完成
- 当前只有“任务结果”合并成单张卡片;部分命令响应和错误提示仍然使用普通文本
- 只发送 Codex 最终回复,不做流式中间输出
- 如果 Codex 运行很久,飞书里只会先看到“处理中”的提示,再等最终结果
- 没有做消息签名 webhook 逻辑,因为这个项目使用的是飞书长连接模式