实战 📋 6 个步骤 第 569 / 569 篇

用 Whyline 把决策写进仓库并跑通门控交付:explain 溯源、handoff 交接与 Relay 流水线实操

编码 Agent 改完就说做完了,下一个人还得重猜为什么。Whyline 一边把选择与否决记进 Git 供 explain 溯源,一边用 Relay 把请求推到受审提交,发布留给人类。本教程六步落地。

2026-10-26· 13 分钟上手· 约 4074 字· 🧭 Whyline / 🔗 多 Agent 交接

编码 Agent 最擅长产出改动,所以它天生乐观:写完就说做完了,从来不打开应用看一眼。于是坏掉的弹窗、静默返回 500 的接口、以及「部署成功」盖在失败部署之上,全都被发出去了——你变成它的 QA。Whyline 想解决的是另一半问题:把「为什么这段代码存在」记下来,交给下一个 Agent。它有两个可分开用的部分:决策记忆,把选择、理由、被否决的方案与涉及的文件写进仓库,让后来的 Agent 不用重猜;以及 Relay,一条从请求到受审提交的门控流水线,把打分、多 Agent 脑暴、受审的规格与计划、实现、测试、评审、核验串起来,把发布留给人类。它由 anishmoncivarghese 开发,Apache-2.0 协议,0.3.51 于 10 月 24 日随 Show HN 发布;没有托管账号、没有遥测、没有付费档,也不碰各家 Agent CLI 的密钥——它复用你已经登录好的那些。本教程按让仓库开始记账、用 explain 与 note 留决策、手工交接、跑通 Relay、理解门控与暂停点、以及 Saved Agents 与收件箱六步把它落地。

🧭 本教程适合:已经在用两个及以上命令行 Agent(Claude Code、Codex、Grok、Antigravity)并且被「上下文一轮就丢」「改完没人知道为什么」困扰的开发者。你需要 uv 与 Git;保存型无人值守 Agent 依赖 macOS 的服务与邮件集成。文中命令以官方仓库的 README 为准;Windows 目前是实验性支持,不作为发布门槛。

Step 1:装上,让仓库开始记账

1 一条命令初始化,一条命令看健康度

用 uv 装全局工具,进到项目目录跑 init,然后直接敲 whyline 打开全屏控制台(whyline console 是键盘版,whyline console --ui 显式请求全屏版)。CLI 本身保留给脚本与终端流。初始化之后仓库里会多出 .whyline/ 目录:decisions.md 记录决策与被否决的替代方案,是会随代码提交的;同目录下的运行时文件——当前交接、认领、活动账本——只留在本地。仓库级的 Agent 定义在 .whyline/agents/,可以选择提交;而 ~/.whyline/agents/ 与 ~/.whyline/ideas/ 是本机状态,不进仓库。

uv tool install whyline@latest
cd your-project
whyline init
whyline                 # 打开全屏控制台
whyline status          # 检查这里的记录是否健康

# 想把当前任务上下文压成一段有界的上下文块
whyline sync

# 想给下一个 Agent 一份有界历史
whyline brief --file src/a.py

值得先记住它共享什么、不共享什么。Agent 之间不会交换各自隐藏的对话;Whyline 给下一个 Agent 的是一份小而明确的记录:选了什么、为什么、否决了什么、涉及哪些文件、还剩什么风险。whyline sync 会把当前交接、Git 状态、归属警告与相关决策压缩成一段有界上下文块,而原始提示词文本不会被包含进去。这个取舍决定了它的定位——它是项目记录,不是对话转移。

记下来的东西会进你的提交历史:.whyline/decisions.md 是被设计成要提交的,里面会写清决策理由与被否决的方案。涉及内部架构、安全权衡或客户信息的措辞,写之前先按对外可见的标准过一遍;运行时文件则留在本地,不会外泄。

Step 2:用 explain 与 note 把「为什么」钉在代码上

2 问一行代码为什么是这样

最直观的用法是 whyline explain 加一个 file:line:它会告诉你这一行是谁最后碰的、对应哪个提交、当时的决策是什么、为什么这么定、否决了哪个方案,以及置信度。没有记录就给出空答案,并且它会明说什么时候是在做推断——这一点比给一个看似确定的答案更重要。想补记录用 whyline note,把选择、理由、被否决项、文件、执行者与任务号一起写进去。

$ whyline explain src/whyline/runner.py:46

src/whyline/runner.py:46
Last touched by anish
Commit bc677e4 · 2026-08-17
Decision   Resolve runner injection points at call time, not in the signature
Because    default arguments bind at import time, so monkeypatching
           runner.shutil.which had no effect and a test exec'd the real
           codex binary, replacing the pytest process
Rejected   patch the default argument tuple in tests — couples every test
           to CPython internals
Confidence High — a recorded decision matches the commit for this line
whyline note "chose X" \
  --because "Y" \
  --rejected "Z: too slow" \
  --file src/a.py \
  --actor codex --role implementer --task WL-42

这一步的价值要在后续才看得出来。刚开始写记录像是给未来加负担;但当下一个 Agent 打开同一份代码、不再需要你把那个「默认参数在导入时绑定」的坑解释第三遍时,收益就兑现了。官方给的输出来自它自己的仓库:一条记录解释了为什么测试里 monkeypatch 没生效、以及为什么否决了另一种改法——这类「只有踩过才知道」的信息,正是 Agent 之间最容易丢的东西。

💡 把 note 写进你的收尾流程。每次让 Agent 完成一个非显然的改动,就顺手写一条:选了什么、为什么、否决了什么。三个字段里「否决了什么」最值钱——它防止下一个 Agent 又把被否掉的方案试一遍。

Step 3:手工交接:claim、run、handoff

3 认领是提醒,不是锁

不打开控制台也能在 shell 里完成一次显式交接:先 claim 声明谁在改哪个文件,跑一个 Agent 完成任务,再 handoff 把状态、摘要、测试与风险交给另一个 Agent,最后让接收方动手。整个链条里的每一次执行都带 --task-id,所以审计时能串起来。要注意 claim 只是建议性警告,不是文件锁——两人同时改同一个文件它不会拦,只是会提醒。

# 1) 认领:谁、什么角色、改哪个文件
whyline claim WL-42 --actor codex --role implementer --file src/cache.py

# 2) 让这个 Agent 干活
whyline run codex "implement bounded cache invalidation" --task-id WL-42

# 3) 交接:状态、摘要、测试、风险一并写下
whyline handoff WL-42 \
  --from codex --to claude \
  --status ready-for-review \
  --summary "bounded invalidation implemented" \
  --file src/cache.py \
  --test "pytest -q: passed" \
  --risk "large repositories not benchmarked"

# 4) 接收方接手
whyline run claude "review the cache change" --task-id WL-42

把 handoff 理解成一份项目记录,而不是把上一个 Agent 的私聊记录搬过去——这是整个设计的分界线。上一个 Agent 想了什么、走了哪些弯路,仍然留在它自己的会话里;交出去的只是结构化的结论与风险。好处是接收方的上下文不会被无关推理灌满,坏处是你得接受「有些细节就是传不过来」,所以用 --risk 与 --test 把关键约束显式写出来就变得很重要。

claim 不会阻止并发改同一文件:它只是建议性警告。多人或多 Agent 同时碰一个文件时,仍然要靠分支、工作区或你自己的约定来隔离;把 claim 当锁会在最需要它的时候失效。

Step 4:Relay:从请求走到一次受审的提交

4 一条 Markov 式的门控流水线

Relay 随 Whyline 一起装好,但你不配置它就不会做任何事。它把一份 Markdown 计划变成一条受控的多 Agent 流水线:请求 → 脑暴与综合 → 受审的规格与实施计划 → 可选的测试计划 → 预检与角色分配 → 实现 → 测试 → 评审 → 核验 → 批准后的提交 → 人类发布。每个角色可以指派不同的 Agent 与模型,还能配一条有序的备用链,在某个厂商不可用、掉线或配额耗尽时接管。终端优先的用法从四条命令起步。

whyline relay init      # 建一个计划
whyline relay doctor    # 体检
whyline relay setup     # 配置角色、模型与备用链
whyline relay status    # 看当前跑到哪了

打开 Relay 后可以选择从一个脑暴、一段描述、已有计划开始,或者直接用 Auto——Auto 能把一个请求一路带过研究、受审的规格与计划、预检,直到跑完 relay。控制台里还有 Files 面板,只读地跟随当前 Chat、脑暴或 Relay 运行中改动的文件,方便你一边看一边判断。需要强调的是角色与模型是可分开配的:实现用一个、测试用一个、评审再用另一个,这既是质量手段也是成本手段。

💡 先跑 Check 再跑 Run。Check 会在不启动任何工作的前提下校验精确的配置、附件、Agent 可访问性与仓库状态;Run 只对通过 Check 的那套配置与仓库状态开放,改动其中任何一个都会让这次校验失效。这条设计把「配置错了跑一半」挡在了门外。

Auto 不是自动驾驶:它只自动推进安全的阶段,遇到开放问题、危险恢复、需要人工核验与发布任务时一律暂停。潜在破坏性的恢复操作仍然等你点头。别因为叫 Auto 就离开工位去睡觉。

Step 5:门控、暂停与恢复:谁有权力按下停止键

5 发布永远是人类的事

Relay 的控制面一共就几件事,但每一件都对应一个真实事故场景。Resolve 会把证据与受约束的修法摆出来;Resume 接着检查点继续;Stop 是打断当前这次尝试,而不是等它跑完。还有一条硬边界:宿主侧的 committer 可以在配置好的评审与核验闸门都通过之后提交工作,而发布步骤归人类所有,会暂停整条流水线等你标记完成或明确跳过。换句话说,它能把改动推到「准备好发布」,但不会替你发布。

# 常见的三条暂停边界
# 1. 开放问题          —— 需求本身有歧义,Auto 会停
# 2. 危险的恢复动作    —— 即便 Auto 也停下来等人
# 3. 人工核验与发布    —— 永远停,必须有人标记完成或跳过

whyline relay status     # 看它停在哪、为什么停

还有一层是 Agent 能力矩阵,配角色前必须看清:Claude Code 与 Codex 都有经过验证的只读启动模式,Grok 的编辑与写入被拒绝,Antigravity 需要仓库信任批准、且没有经过验证的只读模式——因此保存型无人值守 Agent 不包含它。whyline account detect 会刷新 Claude 与 Codex 的套餐标签,Grok 与 Antigravity 因为 CLI 不暴露同样的检查,只报已装或缺失。把这条矩阵抄进你的团队文档,能省掉不少「为什么这个角色跑不起来」的排查。

💡 给关键角色配备用链时,把「降级后能力是否等价」当成一条硬标准。Grok 的编辑与写入被拒,拿它当实现角色的备份,跑出来的东西会和主选不一致;备用链要挑能力相近的,而不是能连上就行。

它不碰密钥,也不等于隔离:Whyline 复用各 CLI 已有的登录与订阅,从不索取或保存它们的 API 密钥;但它也明确说了,这不承诺与底层 CLI 能读到的任何数据源或工具隔离。某个 CLI 能读的东西,它驱动的 Agent 一样能读到。

Step 6:Saved Agents 与 Ideas 收件箱,以及平台边界

6 定时只读任务,和不随便进仓库的点子

Relay 的角色是围绕一份计划协作,而保存型 Agent 是另一回事:一份可复用的只读指令集,带主 CLI、备用链、超时、调度或触发器、运行历史与投递设置。定义写在仓库里,比如一个每周工作日早上检查依赖的 Agent。要注意一条:在一台 Mac 上无人值守运行之前,当前定义必须在本机被接受;改定义会作废这个接受状态并停止无人值守运行,直到重新评审。

# .whyline/agents/dependency-watch.toml
name = "dependency-watch"
instructions = """
Review this repository's dependencies and report important security
or compatibility changes. Do not edit files.
"""
runner = "codex"
timeout_minutes = 41

[trigger]
kind = "schedule"
at = "09:00"

点子收件箱是另一条入口,解决的是「想法还没成型就别碰代码」。你可以从控制台、Telegram 或经过认证的邮件投进去:先打分或多 Agent 脑暴,导出 Word、PDF、Excel,再在你明确允许的仓库里产出受审的规格与计划,最后确认一次才启动 Relay。点子在自己的工作区里跑,规划也只限于你显式允许的仓库;~/.whyline/ideas/ 下的 SQLite 是权威数据,ideas.xlsx 只是重建出来的导出。邮件那条路还要求发送者在白名单里且 DKIM 或 SPF 校验通过,关键动作要一个与当前点子版本绑定的六位确认码。

whyline idea telegram setup                       # 接一个机器人,允许一个私聊
whyline idea email allow [email protected]        # 允许某个发件人
whyline idea email mail-script                     # 安装邮件规则

# 平台支持(官方口径)
# macOS    完整:控制台、Relay、保存型 Agent、调度、邮件集成、后台收件箱、原生 PDF 转换
# Linux    核心 CLI 与控制台、交互式 Agent、Relay、按需工作流;无 macOS 服务与邮件集成
# Windows  实验性,不作为发布门槛;部分核心路径已测,不要假设功能对等

把收尾的话说完整:它刻意没有托管账号、遥测服务、付费档与自己的 API 密钥,各家 CLI 用自己的认证、条款与数据处理方式;保存型无人值守 Agent 用经过测试的只读 CLI 模式与本地接受过的定义,但这不承诺与底层 CLI 能读到的东西隔离。Telegram 走白名单私聊但不是端到端加密;Telegram 只保留有限时间的机器人更新,所以 Mac 必须重新联网才能补上。用法上,whyline --help 与 whyline relay --help、whyline agents --help、whyline idea --help 能给出当前完整的命令面。

💡 团队推广从「只记决策」起步:先只用 init、sync、explain、note 四件事,等仓库里攒够几十条决策、大家都尝到不再重复解释的甜头,再上 Relay。跳过这步直接上流水线,往往会在受审规格那一步卡住——因为没人愿意写。

Windows 是实验性支持:官方明确写了它不作为发布门槛,只有部分核心路径被测试过,不要假设功能对等。要在 Windows 上用,先在非关键仓库里把 sync、explain、note 这条最小路径跑通,再考虑 Relay;生产流水线优先放在 macOS 或 Linux 上。

常见问题速查

现象原因与处理
whyline 命令装完找不到用 uv tool install whyline@latest 装全局工具;确认 uv 的 bin 目录在 PATH 里
explain 给出空答案该行没有记录;用 whyline note 补一条,空记录就是空答案
explain 说是推断它会明说何时在推断;把结论当线索,回到提交里核对
两个 Agent 同时改一个文件claim 只是建议性警告不是锁;靠分支或工作区隔离
Relay 装了却什么都不做需要先 relay init 与 relay setup 配置好再启动
Run 按钮点了没反应只对通过 Check 的配置与仓库状态开放,改动任一项都要重跑 Check
Auto 跑一半停住了开放问题、危险恢复、人工核验与发布都会暂停,属于预期
某个角色跑不起来查能力矩阵:Grok 拒绝编辑写入,Antigravity 需仓库信任批准且无只读模式
备用链接管后结果不一样备用要挑能力相近的,Grok 当实现备份会降级
改了 Agent 定义后不再自动跑改动作废本机接受状态,需重新评审后才恢复无人值守
邮件投进来的点子没被接受要求发件人在白名单且 DKIM 或 SPF 通过,关键动作要六位确认码
Windows 上功能缺失官方标注实验性、不作为发布门槛;生产流水线放 macOS 或 Linux
← 返回教程中心