Skip to content

泳道(Lanes)

圣保罗一支支付团队的两位工程师,对同一个仓库各自跑同一个 Claude Code 会话,跑了四十分钟才有人发现。他们在不同分支、不同终端、同一栋楼的不同楼层。等他们对完账,agent 的 commit 已经被互相覆盖三次、又有两次新的彼此冲突,值班工程师被一个其实并不 flaky 的测试叫起来——那个测试是被一个谁都没 brief 过的模型悄悄改写了。

正是为了挡掉这种碰撞,lane 才存在。如果这一页你只记一件事:lane 是围栏。它告诉工作区、agent 和你的队友,这份工作这个作用域这一组权限,在它关闭之前属于这一次运行。两条 lane 不会重叠在同一组文件上。两个 agent 不会同时跑在同一条 lane 里。

观点:agent 工程的大多数混乱不是模型质量问题,而是缺一个”这是我的,别动它”的原语。lane 就是那个原语。

一条 lane 到底是什么

从存储角度看,一条 lane 是 lanes 表里的一行:UUID、一个 owner(人类身份或 agent 身份)、一组它已 claim 的路径、一条写在溯源台账上的签名起始条目,以及一个状态——openpausedmergedabandoned。你通常不需要想那一行。你想的是 Lanes 面板里的那张卡片:标题、作用域、实时 diff,以及底部的 sign-off 槽。

从运行时角度看,一条 lane 是一道强制边界。当 lane A 内部的 agent 试图读或写 A 已 claim 作用域以外的文件时,工作区在文件系统被触及之前就返回一个 LANE_SCOPE_DENIED 错误。agent 在自己的 tool log 里看到错误,要么收窄工作,要么请求 lane owner 扩大 claim。

从审计角度看,一条 lane 是溯源台账上一段自包含的章节。lane 内部每一次 read、write、模型调用、命令执行、sign-off 都链回该 lane 的起始条目。当你为 SOC 2 或内部复盘导出证据时,你导出的是 lane,而不是 commit。

为什么这不是一个 branch

显而易见的反驳:“我已经有 git branch 了,为什么还要 lane?”

Branch 回答的是哪些文件跟 main 不一样?它不回答谁在做这个?他们用什么工具?过去一小时有没有别人动过同样的路径?这份工作里 agent 能否调用生产数据库? Branch 是个快照原语。lane 是个会话原语。

实践中你常会得到 1:1 映射——一条 lane 产出一个 branch,merge 进一个 PR。但 lane 比 branch 活得久。branch 被删除之后,lane 仍然承载着模型日志、tool call、sign-off 和溯源。六个月后 branch 不在了,lane 还可查询。

密码学溯源

每条 lane 都带一条签名条目链——Ed25519 签名套在 BLAKE3 内容哈希之上,按只追加顺序排列。链头对前一个链头签名,因此篡改任何历史条目都会让之后的所有条目失效。这跟 federation root 签名方为工作区证据包所用的构造一样。

三把 key 重要:

Key存放位置用途
Lane signing key工作区 HSM给 lane 内的 tool-call 条目签名
Owner attestation key用户设备给关闭 lane 的 sign-off 条目签名
Federation root key仅工作区所有者把已关闭的链头戳进证据包

普通 lane 里你不会手动管理这些 key。它们只在你接外部 HSM(BYOK)、为审计导出证据,或从工作区外验证某张 federation 收据时才会出现。

作用域 claim 与冲突

一次作用域 claim 就是一组 glob:apps/api/auth/**infra/terraform/networking/*.tfpackage.json。当第二条 lane 试图 claim 一个跟现有 open lane 重叠的 pattern 时,工作区会在两条 lane 的 UI 上把冲突浮出来,并拒绝启动新的那条。新 lane 的 owner 看到已有 owner 的名字,可以选择等、请对方释放冲突路径,或者收窄作用域。

值得知道的三个例外:

  • 一条 lane 可以通过 Share path 主动把某条路径共享给另一条 lane。极少用——主要用于两个并行 feature 都要碰的共享配置文件。共享后这条路径成为一个串行化资源:agent 在一次 tool call 期间拿锁。
  • 工作区所有者可以从停滞的 lane 上force-claim 一条路径。这会写下一条显式标明覆盖的 sign-off 条目。
  • README.mdCHANGELOG.md,以及任何被 .sprintloop/shared-paths 匹配到的路径,永远是共享的。任何 lane 都能向其追加。

创建一条 lane

按自动化程度递增的三种方式:

  1. 从 Lanes 面板手动创建。New lane,敲一行标题,选仓库,claim 你预计要碰的路径,把自己或 agent 指派为 owner。lane 以 Drafting 状态打开,台账上还没有条目。

  2. 从 Issue 创建。 当一个 SprintLoop Issue 被拖进 In progress,工作区会建议针对其关联仓库新开一条 lane,并把 Issue 的验收标准预载为 lane 的 brief。多数团队第一周就会落到这条路径上。

  3. 从 agent harness 创建。 跑在 SprintLoop 里的 Claude Code 或 Codex 会话在首次读文件时打开自己的 lane。agent 是 owner,发起会话的人是 sign-off 权限方。lane 的标题先按首条 prompt 自动生成,首次 commit 后被改名。

关闭一条 lane

一条 lane 在其 diff 被 merge、owner 显式放弃、或七天无活动(每个工作区可配)时关闭。关闭时,lane 台账的链头被 owner 签名后戳进工作区的 federation root。这一刻起,这份工作便归档可证:任何持有公开校验 key 的人,日后都能验证这一组变更这个顺序这位 owner这些 tool call,最终落到这个 commit hash

如果你只想再读一页,那就读 Harness 竞速——单条 lane 是如何被同时 dispatch 给两个或更多 agent 的。