简单说,就是把 OpenAI 开源的 Codex CLI 装在云服务器上,然后接入飞书。这样你就可以让它 7*24 为你开发了——你只管通过飞书下达指令,讨论实现方案、出开发计划、最终的开发实现、部署上线……你只需要用手机、飞书对话,懂不懂技术都没所谓。
即便你是编程老手,这个模式也很有价值:从电脑前彻底解放,随时随地……搭配上豆包语音输入,打字都不需要了。
- 生产级成熟度:OpenAI 官方开源(Apache-2.0),Rust 实现,2-4 天一个 stable 版本
- 对第三方模型友好:走标准 OpenAI Responses API,任何兼容端点都能接(Anthropic 生态封闭、对第三方模型负优化的问题不存在)
- 自带跨会话持久记忆:内置两阶段 memory 管线(会话结束自动提取 → 全局合并),无需外挂 memory MCP
- 会话原生持久化:rollout 落盘 +
thread/resume跨进程恢复,进程重启不丢上下文 - 结构化审批协议:命令/文件改动审批是 JSON-RPC 请求/应答,天然可桥接飞书审批卡(规划中)
- 每项目独立 Provider:同一个 bridge 里,项目 A 走 GLM、项目 B 走 Qwen,
bridge.json一行配置
基座选型过程见 docs/base-migration-comparison.md(Claude Code / dsh / codex / pi 横向对比)。
🚀【2026.9.2】基座切换为 Codex:bridge 通过 codex app-server(JSON-RPC over stdio)完整桥接 Codex 的 IO——流式增量文本、打断、跨进程会话恢复、审批应答、token 统计。
🚀 每日自动备份,/backup 命令可随时手动触发
🚀 延迟消息(计划消息):/小时-分钟 “要延迟发送的消息”(xx 小时 xx 分钟后,内容发给 Codex)
- 不需要任何订阅,走你自己的模型服务端点;
- 国内的 GLM、Qwen、DeepSeek 等 coding 套餐(任何 OpenAI Responses 兼容端点)都能直接用;
- 没有海外账号、网络环境的麻烦。
至于云端服务器,2C4G 足够了,腾讯云首单一年 79……当然本项目不需要公网 IP,你搞台二手电脑装个 ubuntu 扔家里或者办公室也是可以的……硬件几乎零成本。
🌹 致敬:飞书连接桥方案来自:https://github.com/AlexAnys/feishu-openclaw
飞书用户 ──WebSocket──▶ bridge.mjs ──stdio JSON-RPC──▶ codex app-server
│ │
ProjectManager CodexAppServer
(多项目管理) (initialize/thread/turn
│ item delta/审批应答)
createLarkChannel × N
(每个项目一个飞书 bot)
- bridge.mjs — 单 Node.js 进程,同时服务多个飞书 bot + 多个 Codex 子进程
- CodexAppServer — 每个项目一个
codex app-server子进程:initialize握手 →thread/start(新会话)或thread/resume(恢复会话)→turn/start发消息,item/agentMessage/delta流式增量 → 飞书打字机卡片;turn/interrupt打断;所有服务端请求(审批等)自动应答,绝不挂起 - ProjectManager — 管理多项目生命周期,每个项目独立的 Codex 实例和飞书 bot
- 托管 Codex Home — bridge 启动时从
bridge.json生成~/.codes/codex-home/config.toml(providers、默认模型、内置 memory 开关),会话数据与记忆都落在~/.codes内,自动进入每日备份 - createLarkChannel — 飞书 SDK 1.66+ 高层 API,封装 WebSocket 连接、消息归一化、流式卡片、卡片交互回调
| 能力 | 说明 |
|---|---|
| 消息归一化 | SDK 自动将 text/post/interactive/merge_forward 等消息类型归一化为统一格式 |
| 流式卡片 | CardKit 2.0 + streaming_mode,实时推送 Codex 输出到飞书卡片 |
| 卡片交互 | cardAction 回调,支持停止按钮等交互操作 |
| Reaction v1 | 使用 im.v1.messageReaction API(v0 已弃用) |
| WS 调优 | pingTimeout: 3s,handshakeTimeoutMs: 8000,应用层重连事件 |
| Bot 身份 | channel.botIdentity 自动获取 bot 的 open_id |
| 优雅关闭 | channel.disconnect() 优雅断开 WebSocket |
- Node.js 18+(推荐 22+)
- @larksuiteoapi/node-sdk 1.66.0(飞书 SDK,bridge 自带)
- Codex CLI —
npm install -g @openai/codex(协议基线版本:0.152.1) - 一个 OpenAI Responses 兼容的模型端点 + API key
- 飞书自建应用 — 需要 App ID + App Secret(详见下方配置步骤)
git clone https://github.com/bigbrother666sh/codes.git
cd codes/bridge
npm install
npm install -g @openai/codexmkdir -p ~/.codes/secrets
cp bridge.example.json ~/.codes/bridge.json编辑 ~/.codes/bridge.json:
{
"projects": {
"myapp": {
"path": "/home/user/projects/myapp",
"feishu": {
"appId": "cli_xxx",
"appSecretPath": "~/.codes/secrets/myapp_secret"
}
}
},
"providers": {
"maas": {
"name": "我的模型网关",
"baseUrl": "https://your-gateway.example.com/compatible-mode/v1",
"envKey": "MAAS_API_KEY",
"wireApi": "responses"
}
},
"codexDefaults": {
"model": "glm-5.2",
"provider": "maas"
},
"codexPath": "codex",
"debug": false
}将飞书 App Secret 写入 secret 文件:
echo -n "your-app-secret">~/.codes/secrets/myapp_secret
chmod 600 ~/.codes/secrets/myapp_secret将模型端点的 API key 写入 bridge/.env(变量名对应 providers.*.envKey):
echo'MAAS_API_KEY=sk-xxxx'> bridge/.env
chmod 600 bridge/.envnode bridge.mjs| 字段 | 说明 | 默认值 |
|---|---|---|
projects | 项目配置 map(alias → {path, feishu, codex?}) | 必填 |
projects.*.path | 项目代码仓路径 | 必填 |
projects.*.feishu.appId | 飞书 App ID | 必填 |
projects.*.feishu.appSecretPath | Secret 文件路径 | 必填 |
projects.*.codex.model | 该项目的模型(覆盖默认) | codexDefaults.model |
projects.*.codex.provider | 该项目的 provider(须引用 providers 中的 key) | codexDefaults.provider |
projects.*.codex.sandbox | 沙箱模式(read-only / workspace-write / danger-full-access) | danger-full-access |
projects.*.codex.contextWindow | 该项目的上下文窗口(token,影响自动压缩时机;实际可用约为配置值的 95%) | codexDefaults.contextWindow |
projects.*.codex.* | 其余任意 codex 配置键(snake_case,如 model_reasoning_summary、model_reasoning_effort)原样透传给该项目会话(thread/start config,优先级最高) | codexDefaults.* |
providers.<key>.baseUrl | Responses 兼容端点(/responses 会自动拼接) | 必填 |
providers.<key>.envKey | 存放 API key 的环境变量名 | 必填 |
providers.<key>.wireApi | 协议(仅支持 responses) | "responses" |
codexDefaults.model / .provider | 全局默认模型 / provider | — |
codexDefaults.contextWindow | 上下文窗口大小(token) | — |
codexDefaults.* | 其余任意 codex 配置键(snake_case)渲染进 config.toml(全局默认,项目级同名键可覆盖) | — |
thinkingThresholdMs | thinking 状态提示阈值(ms) | 2500 |
codexPath | codex CLI 路径(systemd 下建议绝对路径) | "codex" |
debug | 调试模式 | false |
backup.time | 每日自动备份时间(HH:MM) | "04:16" |
backup.dest | 备份目标目录 | "~/Backups" |
backup | 设为 false 可完全禁用自动备份 | — |
本机环境若无法创建 user namespace(常见于 AppArmor 限制的 Ubuntu),codex 的 bubblewrap 沙箱不可用,默认配置为 danger-full-access + approvalPolicy: never(代理在受信服务器上自主执行,与多数生产部署姿态一致)。若你的环境支持沙箱,可在 codexDefaults / 项目级 codex 里改成 workspace-write。
model_context_window 会受模型元数据里 max_context_window 的硬性钳制。Codex 不认识的模型(如 GLM、Qwen)会落入 fallback 元数据(上限 272k,可用约 258k),配置 1M 也会被钳到 272k。解决办法:提供一个自定义模型目录(models.json,含 context_window / max_context_window / model_messages.instructions_template),并在 codexDefaults 里设 model_catalog_json = "/path/to/models.json"(全局生效,重启 bridge 后渲染进 config.toml)。注意该目录会替换内置目录,需要把所有在用的第三方模型都列进去。
bridge 内置每日定时备份,默认凌晨 04:16 将 ~/.codes 的核心内容(bridge.json、secrets、models.json、codex-home 的 config/sessions/memories/skills)打包为 backup_YYYYMMDD_HHmm.tar.gz。排除项:logs/、bridge-sessions.json、codex-home 的插件同步缓存(.tmp/,可按需重建)、内部日志库(logs_2.sqlite*)、运行时临时目录、以及 SQLite 的 -wal/-shm 活动侧车文件(运行中打包不安全;主 .sqlite 保留最近检查点)。设为 false 可禁用;飞书发 /backup 随时手动触发。
参见 bridge/.env.example。模型端点 API key(providers.*.envKey 对应的变量)也放在这里。
- 打开 飞书开放平台,登录
- 点击 创建自建应用
- 填写应用名称(随意,比如 "My AI Assistant")
- 进入应用 → 添加应用能力 → 选择 机器人
- 进入 权限管理,开通以下权限(推荐照抄,少踩坑):
cardkit:card:write— 发送/更新交互卡片(streaming 流式回复必须,否则回退为普通文本)im:message— 获取与发送消息im:message:send_as_bot— 以机器人身份发消息(避免 403)im:message.group_at_msg— 接收群聊中 @ 机器人的消息im:message.p2p_msg— 接收机器人单聊消息im:resource— 上传/下载图片与文件(收图/收视频必须)
或者选择"批量导入/导出权限"复制如下
{
"scopes": {
"tenant": [
"cardkit:card:write",
"im:message",
"im:message.group_at_msg:readonly",
"im:message.p2p_msg:readonly",
"im:message:send_as_bot",
"im:resource"
],
"user": []
}
}进入 事件与回调 → 事件配置:
- 添加事件:
接收消息 im.message.receive_v1 - 请求方式选择:使用长连接接收事件(这是关键!)
坑点:此时要保证 codes 已在运行
- 添加事件:
发布应用(创建版本 → 申请上线)
记下 App ID 和 App Secret(在"凭证与基础信息"页面)
在飞书中向 bot 发送以下命令:
| 命令 | 说明 |
|---|---|
/start [alias|all] | 启动项目的 Codex 会话 |
/stop [alias|all] | 停止项目的 Codex 会话 |
/reset [alias] | 重置会话(清除历史,开始新对话) |
/interrupt [alias] | 打断当前正在处理的消息 |
/model [名称] [alias] | 查看或切换模型(下一条消息生效) |
/cost [alias] | 查看 token 用量(累计/上一轮) |
/context [alias] | 查看上下文窗口占用 |
/compact [alias] | 压缩会话历史 |
/status | 查看所有项目状态 |
/backup | 立即触发一次备份 |
/help | 显示帮助 |
其他 / 开头的消息会作为普通消息转发给 Codex。
普通消息直接发送给对应项目的 Codex 处理。
当 Codex 正在处理上一条消息时,新发送的消息会自动排队(单槽设计,仅保留最新一条):
用户发 A → Codex 开始处理
用户发 B → "⏳ 消息已排队" → B 进入等待
用户发 C → "⏳ 消息已排队(替换)" → C 替换 B
A 处理完 → 回复 A 结果 → 自动开始处理 C
如需打断当前处理,发送 /interrupt(映射到 turn/interrupt)。
/xx-dd 消息:xx 小时 dd 分钟后发送一次(例:/2-15 服务器维护)【意味着从发送起 2 小时 15 分钟后,把"服务器维护"这句话发给 Codex】 /scheduled [alias]:查看当前待发送定时任务 /unschedule <任务ID前缀> [alias]:撤回单个定时任务 /unschedule all [alias]:撤回该项目全部定时任务
# 1. 安装 Node.js 22
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt-get install -y nodejs
# 2. 安装 Codex CLI
npm install -g @openai/codex
# 3. 克隆并安装
git clone https://github.com/bigbrother666sh/codes.git ~/codes
cd~/codes/bridge && npm install
# 4. 配置(参见上方「快速开始」)# 5. 创建 systemd 服务
node setup-service.mjs
systemctl --user daemon-reload
systemctl --user enable codes-feishu-bridge
systemctl --user start codes-feishu-bridgesystemd 环境下注意:
bridge.json的codexPath建议写 codex 二进制的绝对路径(which codex查看);模型 API key 通过bridge/.env提供,不依赖 shell 环境变量。
# 查看状态
systemctl --user status codes-feishu-bridge
# 查看日志
journalctl --user -u codes-feishu-bridge -f
# 重启
systemctl --user restart codes-feishu-bridge| 症状 | 排查方法 |
|---|---|
| bridge 启动后无反应 | 检查 ~/.codes/bridge.json 格式,确认 secret 文件存在 |
| 飞书消息无响应 | 检查飞书应用权限,确认 WebSocket 模式已启用 |
启动报 Cannot find codex CLI | 确认 codexPath 指向可执行的 codex 二进制(systemd 下用绝对路径) |
| 回复"模型认证失败"类错误 | 检查 bridge/.env 中 envKey 对应的变量是否已设置 |
| 日志出现 bwrap/user namespace 警告 | 本机不支持沙箱,默认配置已用 danger-full-access,可忽略 |
| 进程重启后会话丢失 | 正常行为——bridge 会自动以 thread/resume 恢复上次会话 |
| 多项目配置不生效 | 确认每个项目的 feishu.appId 不同,每个 bot 对应一个项目 |
node bridge/bridge.mjs --selftest验证配置加载和基本功能,不会连接飞书。
MIT
