多个智能体,一个仓库
每个智能体领取的任务,其他智能体都能看到已被领取。claim 是一个 git ref:第二个来抢同一任务的智能体会被拒绝,并被告知持有者是谁;在旁边干活的那个,也会知道自己和谁共享了哪些文件。
ANK_AGENT=claude:auth ank claim 0e7d
claimed TASK-0e7de9c55b80 migrate-auth-to-opaque-sessions -> HEAD
cd ../svc-rate
ANK_AGENT=codex:rate ank claim 0e7d
error[4]: TASK-0e7de9c55b80 held by claude:auth (expires in 30m)
-> ank claim TASK-20e993387d9d (another ready task in this scope)
ANK_AGENT=codex:rate ank claim 20e9
warning: claude:auth holds TASK-0e7de9c55b80, overlapping on src/auth/login.ts
claimed TASK-20e993387d9d rate-limit-the-login-route -> HEAD
没有它,会出什么问题
让两个编码智能体在同一个仓库里跑,出的问题都是悄无声息的。没有任何报错,只是工作撞在了一起。
同一个任务,做了两遍
两个智能体读的是同一个 backlog,拿了同一个第一项。谁也不知道对方已经开始了。
同一批文件,被改写
两个任务看起来互不相关,却改的是同一个模块。第二个分支把第一个的改动覆盖掉,到 merge 时才发现。
悄悄失效的 claim
一个会话中途挂了。任务还显示“进行中”,却没人在做,也没人知道之前试过什么。
每个智能体一个工作树、一个身份
给每个智能体一个自己的工作树(git worktree 或一个 clone),放在从默认分支新切出来的分支上,并在 ANK_AGENT 里给它一个自己的身份。ank status 会报告与默认分支的偏离,因为过时的基线会让这里绿的工作树在别处变红。
同一仓库的所有 worktree 共享 refs/ank/,所以它们之间的竞争由 git 的 compare-and-swap 裁决:只有一个赢家。独立的 clone 之间通过名为 origin 的 remote 来仲裁,ank init 会把它配置成携带 refs/ank/*。
不设 ANK_AGENT 时,身份会回落到 <user>@<hostname>,所以同一台机器上的两个终端,在 ref 看来是同一个智能体。用同一个名字发起第二个 claim 会被拒绝,拒绝信息会告诉你怎么给这个会话起自己的名字。
git worktree add ../svc-rate -b task/rate
export ANK_AGENT=codex:rate
ank claim 51c2
error[7]: human:marie holds a live claim on TASK-820d259af6a7 (expires in 30m)
-> ank release --reason "<why>" (a second session on this machine sets its own ANK_AGENT)
ANK_AGENT=human:marie-2 ank claim 51c2
claimed TASK-51c2a0f6d418 say-in-the-readme-what-a-session-is-now -> HEAD
claim 就是一个 git ref
ank claim 同时做三件事,没有一件是能手动改的字段。
任务变为 in_progress
claim还会设置 HEAD,之后的命令不用再写 id。每个身份同一时间只能持有一个 claim。refs/ank/claims/ 下出现一个 ref
两个智能体抢同一任务时,就靠它来仲裁。每个 worktree 都看得到它,remote 会把它带到每个 clone。
验收标准按哈希冻结
哈希写进 claim 记录里,编辑器碰不到。为了让工作过关去放宽标准,什么也解决不了:
done会比对并拒绝。
租约,靠干活来续
一个 claim 持续 30 分钟,ank context、对自己持有任务的 ank show、以及写入时的 ank log 都会续约。不需要记着发心跳:把学到的东西记下来,就是保持锁的方式。过期的 claim 不再有效,任何人都可以领走任务。
别让 claim 悄悄过期
ank release --reason 交还任务,并把原因记进它的 log,下一个持有者用 ank log <id> 读到,就不会重复你试过的做法。ank done 不会删除 ref,而是把它变成一条完成记录,写明 commit 和分支,这样在 merge 之前,其他工作树不会再领走这个任务。
git for-each-ref refs/ank/
fc6c72c07eaee7d0e1d31f38316d8d5304382d44 blob refs/ank/claims/TASK-0e7de9c55b80
e671470149b55366650f6da572866a25f33315c5 blob refs/ank/claims/TASK-20e993387d9d
ank release --reason "the criterion names a test that does not exist yet"
released TASK-820d259af6a7 -> open
claim 会指出与哪些 scope 重叠
每个任务都有一个 scope,即一组 glob。如果你领取的任务的 scope 与某个有效 claim 重叠,ank 照样让你领取,同时给出警告,写明持有者、对方的任务和共享的路径。这是一条需要读的信息,而不是拒绝你的错误:两个任务能否共用一个文件是个判断,这个判断留给发起 claim 的人。
skills 教给智能体的规则由此而来:要么领一个不会冲突的任务,要么一个都不领。当没有任何开放任务既未被阻塞又不冲突时,让会话闲着,比两个智能体重写同一块地盘便宜得多。
ANK_AGENT=codex:rate ank claim 20e9
warning: claude:auth holds TASK-0e7de9c55b80, overlapping on src/auth/login.ts
claimed TASK-20e993387d9d rate-limit-the-login-route -> HEAD
看清谁持有什么
领取之前,智能体会先看三件事:别的智能体持有什么,自己的 claim 会和什么重叠,以及 blocked_by 规定的顺序。
ank status
分支、身份、你持有的 claim 及其过期时间,以及别处持有的每个 claim。
ank status
branch task/rate (default main)
drift 1 entity file(s) differ from main (git merge main)
identity codex:rate (ANK_AGENT)
claim TASK-20e993387d9d Rate-limit the login route
expires 2026-10-02T08:59:19Z
elsewhere 1 claim(s) by other agents
TASK-0e7de9c55b80 Migrate auth to opaque sessions (claude:auth until 2026-10-02T08:59:18Z)
perimeter the scope of TASK-20e993387d9d, 0 constraint(s)
queue 0 proposal(s), 0 finished elsewhere
corpus 0 fault(s), 4 signal(s)
ank graph
blocked_by 构成的 DAG,缩进在阻塞它的任务下面。没有阻塞的任务就是根,可以开始。
ank graph
.
TASK-0e7d [claimed:claude:auth] Migrate auth to opaque sessions
└── TASK-357b [open] Say in the README what a session is now
TASK-20e9 [claimed:codex:rate] Rate-limit the login route
3 task(s), 2 root(s) — indented under what blocks them
仪表盘轮询 ank status 和 ank find。不要轮询 context 或 show,它们会续约 claim;也不要轮询 check,它会清理过期的 ref,也就是会写入。
并行是推导出来的,不是声明出来的
blocked_by 是唯一的顺序
阻塞项都完成的任务会同时就绪,
ank context会列出它们,能解锁最多任务的排在前面。没有 blocked_by,所谓顺序就是虚构。一个任务一个分支
ank done在任务运行的那个工作树里证明它完成。merge 是 git 的事;由多个任务组成的改动会有一个集成任务,被每个部分阻塞,并有自己的验证器。git 擅长的事,留给 git
没有哪个 ank 动词会创建 worktree、命名分支或执行 merge。任务、claim 和证明属于 ank;分支和历史仍归 git。