# relay-baton **面向编码代理的可移植连续性基础设施** 在 Codex CLI、Claude Code 和未来出现的工具之间 ― 无需重新粘贴聊天记录、diff 或仓库 ― 传递压缩后的编码状态。 [English](../../README.md) · [한국어](./README.ko.md) · [日本語](./README.ja.md) · **简体中文** · [繁體中文](./README.zh-TW.md) · [Español](./README.es.md) · [Français](./README.fr.md) · [Deutsch](./README.de.md) · [Português](./README.pt-BR.md) · [Русский](./README.ru.md)
```bash # Codex 在任务中途撞上 quota 墙。relay-baton 检测到后,根据仓库的实际状态 # 构建一个 compact handoff,Claude 接手继续。 $ relay-baton run "重构 upload pipeline" --diet caveman ● relay chain: codex → claude ▲ codex hit a limit — fallback pattern detected: "rate limit exceeded" → building a compact handoff for claude… ✓ claude resumed from .ai-session/handoff.md ``` --- ## 为什么存在 AI 编码工作正在多个工具间碎片化。真实的会话是这样的: - 一批编辑用 Codex CLI,另一批用 Claude Code。 - 早上用笔记本,晚上换另一台机器。 - context window 被填满、崩溃,或者悄悄被截断。 目前在代理间转移工作的默认方式是 **复制粘贴聊天日志** ― 更糟的是把整个仓库丢进 prompt。这种做法有三个问题: 1. **Token。** 聊天日志大部分是噪音。你为这些噪音每轮都付费。 2. **连续性。** 下一个代理拿到的不是 *意图*,而是 transcript。 3. **脆弱性。** 漏一个文件、diff 过时,代理就从错误前提重新开始。 relay-baton 是一个铺在代理底下的 **本地 harness**。在交接之间只搬运 *最小必要状态* ― compact 摘要、repo map、文件引用,不是 transcript。 > **在最少 token 消耗下,把 Codex CLI 和 Claude Code CLI 合并成单一工作流。** ## 核心思路 ``` ┌─────────┐ ┌──────────────┐ ┌──────────────┐ ┌────────┐ │ Codex │ → │ Fallback │ → │ Token Diet │ → │ Claude │ │ exec │ │ Detector │ │ Handoff │ │ Code │ └─────────┘ └──────────────┘ └──────────────┘ └────────┘ ↓ ↓ .ai-session/handoff.md, compact-state.md, repo-map.md, full-diff.patch, commands.log ``` 为编码代理设计的 baton-pass ― 4 步 primitive: - **Detect** 检测当前代理是否触顶 (quota、context、rate、errors)。 - **Capture** 仅收集要紧的 (repo 状态、变更文件、决策、下一步)。 - **Compact** 压缩到下一个代理实际能消化的预算内。 - **Hand off** 通过 quality gate 后才交付。 handoff 是一个小文件 (`.ai-session/handoff.md`) 加引用。重量级内容 (完整 diff、完整日志、完整 repo map) 留在磁盘上,按需加载。 ## Quick Start **安装(无需构建)** ```bash # npm (所有系统) npm i -g @relay-baton/cli # -> relay-baton # macOS / Linux — Homebrew brew tap dgl1231/relay-baton && brew install relay-baton # Windows — Scoop / Winget scoop bucket add relay-baton https://github.com/dgl1231/scoop-relay-baton && scoop install relay-baton winget install dgl1231.relay-baton ``` ```bash relay-baton doctor relay-baton login relay-baton run "..." --diet balanced ``` **从源码(开发用)** ```bash pnpm install pnpm build pnpm relay-baton login # 登录 Codex + Claude pnpm relay-baton doctor # 环境检查 pnpm relay-baton run "修复邮件附件上传流程" --diet balanced ``` ## 工作流 ```bash $ relay-baton init # 创建 .ai-session/ $ relay-baton run "修复 flaky upload test" --diet balanced ... codex 输出实时流式打印 ... ▲ codex hit a limit — fallback pattern detected: "maximum context length" → building a compact handoff for claude… ✓ Handoff Quality Gate: ok · Token Diet Quality Gate: ok ... claude 接手编辑文件并完成 ... $ relay-baton status # 会话状态 $ relay-baton budget # diet 预算用量 ``` 只生成 handoff,不自动 fallback: ```bash $ relay-baton handoff --to claude --no-run --diet caveman ``` 多仓库切换: ```bash $ relay-baton project add /path/to/repo-a --diet caveman $ relay-baton project switch repo-a $ relay-baton run "接入新的 metrics endpoint" ``` ## 特性 - **自动 fallback** ― 从 Codex 输出中检测 `quota exceeded`、`rate limit exceeded`、`maximum context length` 等。跳过 grep 结果行和解释这些模式的散文 (避免误报)。 - **Token diet** ― 5 个确定性压缩 profile (`off · lite · balanced · caveman · ultra`)。排除 lock/build/min 文件,日志取 tail,用 repo map 替代源码。 - **Quality gates** ― 在 fallback 启动 *之前* 验证 handoff 完整性和预算。 - **Auth-safe by default** ― `OPENAI_API_KEY` / `ANTHROPIC_API_KEY` 默认从子进程剥离,只能通过 `--allow-api-key-env` opt-in。密钥从不存储、打印、记录。 - **Project registry** ― 注册多个仓库一次,任意位置用 `--project` 或 `--path` 调用。 - **Ink TUI** ― project / session dashboard。从不启动代理。 - **没有自己的 API 调用** ― relay-baton 不直接调用 OpenAI / Anthropic API。仅通过 subprocess 调用本地 `codex` / `claude` CLI。 ## 命令 | 命令 | 说明 | |---|---| | `relay-baton init` | 在当前仓库创建 `.ai-session/` | | `relay-baton doctor` | 检查 git / codex / claude / env / config(`--deep` 进行扩展诊断) | | `relay-baton verify` | 模拟端到端检查 — 不进行真实模型调用 | | `relay-baton login [agent]` | Codex / Claude 登录流程 | | `relay-baton run ""` | 主代理执行 + fallback 检测 + handoff | | `relay-baton route ""` | 建议性路由提示预览(只读, `--json`) | | `relay-baton handoff --to claude` | 手动 handoff (`--diet`、`--no-run`、`--force`) | | `relay-baton handoff history` | 列出当前 + 备份的 handoff 文档 (仅 metadata) | | `relay-baton plan ""` | Plan-execute:planner 写出 `plan.md`(`--with`、`--no-run`、`--then-execute`) | | `relay-baton execute` | Plan-execute:executor 实现 `plan.md`(`--with`、`--from`) | | `relay-baton compress-context` | 压缩进行中的 context(state.md / commands.log)(`--dry-run`、`--threshold`) | | `relay-baton compact` / `squeeze` | 重建 compact-state / repo-map / full-diff | | `relay-baton budget` | 显示 context budget 用量 | | `relay-baton compress ` | markdown 文件的确定性压缩 | | `relay-baton status` | 会话状态 | | `relay-baton project add/list/switch/current/doctor/remove` | project registry 管理 | | `relay-baton tui` | Ink dashboard | 支持 project 的命令接受 `--project ` 和 `--path `。优先级:`--path` > `--project` > active project > cwd。 ## Project registry ```bash relay-baton project add /path/to/relay-baton --name relay-baton --diet caveman --primary codex --fallback claude relay-baton project switch relay-baton relay-baton status --project relay-baton ``` 默认存储路径为 `~/.relay-baton/projects.json`。可用 `RELAY_BATON_PROJECTS_FILE` 覆盖路径 (CI、sandbox、测试)。损坏的文件会备份为 `projects.json.corrupt-.bak` 并重置为空 registry ― 命令继续工作。 ## Token diet profiles | Profile | 意图 | |---|---| | `off` | 最小截断 | | `lite` | 轻量整理 | | `balanced` *(默认)* | 日常使用 | | `caveman` | aggressive minimal-context | | `ultra` | 极端压缩 | > `caveman` 不是搞笑语气,而是 **aggressive minimal-context**。技术准确性保留。 ## 与替代方案对比 | 方案 | 携带内容 | Token 成本 | 连续性 | 失败模式 | |---|---|---|---|---| | 原始聊天 export | 全部 transcript | 高 (大部分是噪音) | 脆弱 ― 代理重读自己的思考 | context window 溢出 | | 复制粘贴 prompting | 人记得的部分 | 可变 | 易碎 | 与实际状态 silent drift | | 整仓库 dump | 全部 | 极高 | 强但昂贵 | 模型中途截断 | | **relay-baton** | compact 摘要 + repo map + 文件引用 | **低,profile 限定上限** | 强 ― 由 *实际* repo 状态驱动 | 通过 quality gate *显式* 失败 | ## 哲学 relay-baton 是 **面向 AI 原生开发工作流的小而锋利的工具**。 - **Local-first.** 一切都在本地磁盘上。无云、无 daemon、无遥测、无账号。 - **可组合性。** `.ai-session/` 目录就是一堆文件。可读、可 grep、可 diff、可放进 PR。 - **轻量状态转移。** handoff 是 markdown 文件,不是数据库。 - **确定性优于聪明。** harness 内部不做 LLM 总结 ― 如果模型总结错了,handoff 就是谎言。只用字符预算、结构规则、显式引用。 - **Repo 状态是真相之源。** 对话是诠释,repo 是事实。 - **Token 效率本身就是功能** ― 不是埋在菜单里的开关。 ### 设计原则 1. 不是 chat relay,是 **work handoff**。 2. **当前仓库状态** 优先于会话历史。 3. handoff 必须 **人类可读**。 4. 所有 UI 都是 core 之上的薄壳。 5. **Token diet 不是附加功能,而是核心功能**。 ## 未来方向 relay-baton 起步于双代理 fallback harness。同一 primitive 可以延伸: - **多代理 relay 链** ― Codex → Claude → OpenCode → 回到 Codex。 - **分叉的会话树** ― 同一任务用并行代理尝试,通过 diff 调和。 - **远程 relay state** ― 把 `.ai-session/` push 到共享 remote,下一台机器接力。 - **编排工作流** ― `review`、`diagnose`、`continue` 模式 (带显式 checkpoint 的 bounded autopilot)。 - **更多 adapter** ― OpenCode、Gemini CLI、Aider,任何有合理本地 subprocess 接口的工具。 harness 的形状不变:detect、capture、compact、hand off。 ## 依赖要求 | 项 | 版本 / 备注 | |---|---| | Node.js | ≥ 20 | | pnpm | ≥ 9 | | git | 必需 | | `codex` | **需要 ChatGPT Plus 或更高订阅** | | `claude` | **需要 Claude Pro 或更高订阅** | > relay-baton 不直接调用 OpenAI / Anthropic API,使用本地 `codex` / `claude` CLI 的 **订阅认证**。API key 认证技术上可行但 **默认阻断** (需 `--allow-api-key-env` opt-in)。 ## 登录 ```bash pnpm relay-baton login # 两者 pnpm relay-baton login codex pnpm relay-baton login claude ``` `claude --version` 通过 **不代表** 已登录。看到 "Not logged in" 就重新跑上面的命令。 ## 发布说明 **最新: v1.6.1** — [English](../../release-notes/v1.6.1.md) · [한국어](../../release-notes/ko/v1.6.1.md) · [简体中文](../../release-notes/zh-CN/v1.6.1.md) relay-baton 已 **正式发布(GA)v1.0.0**,当前最新为 **v1.6.1**。 - 完整版本历史: [`CHANGELOG.md`](../../CHANGELOG.md) - 各版本详细补丁说明: [release-notes index](../../release-notes/README.md) ### 安装 ```bash npm i -g @relay-baton/cli # -> relay-baton brew tap dgl1231/relay-baton && brew install relay-baton # macOS / Linux scoop bucket add relay-baton https://github.com/dgl1231/scoop-relay-baton && scoop install relay-baton # Windows winget install dgl1231.relay-baton # Windows ``` ## License MIT。详见 [`LICENSE`](../../LICENSE)。 > 完整文档 (quality gate 细节、`.ai-session/` 文件含义、config schema、TUI 键位、故障排查等) 见 [English README](../../README.md) 与 [`install/install.md`](../../install/install.md)。