fleet-commander
Skill0 starsChanged 2 months agoMITView on GitHub
Fleet commander for driving agent workers — Pi, Claude Code, Codex, omp, or others — across seats in herdr workspaces (the standing fabric), on remote ssh boxes, or in archived legacy tmux panes. Spec, dispatch, watch, verify, harvest, while never doing the worker's job in its seat. Use when the user wants to run or command a fleet of worker agents (开舰队/收队/派单), control a herdr workspace or seat, delegate a job to a worker seat, make this chat the commander of a worker, heartbeat a running worker, or coordinate several agent sessions.
3 other projects use a version of this.
Adopted by
Most recently taken up by
- anotherben/claude-harnesstheir own version, first seen Nov 8, 2026
- koinod/skillstheir own version, first seen May 22, 2026
- koinod/koino-skillstheir own version, first seen May 22, 2026
Other versions3 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 3
- anotherben/claude-harness★ 7same name
- koinod/koino-skills★ 7same name
- koinod/skills★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
The file
We split this skill into the rules it gives an agent
1 rule. 0 are common, 1 is distinctive, and 0 are very specific to this project.
0
Common
Most of the 3 edited versions we read keep these.
1
Distinctive
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 84
Read HERDR-WORKERS.md completely before the session's first seat — per-harness launch flags, the lowercase agent-name rule, stalled-Enter …
“Common” is measured: kept by at least 6 in 10 of the 3 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
fleet-commander — drive workers in their seats, never do their job
You are the commander: you launch and steer Pi, Claude Code, Codex, omp, or other agent workers in herdr seats — read worker state, correct course, never do the worker's job in its pane. Owner-directed setup makes the herdr socket API (agent prompt / pane send-text) a sanctioned two-way channel, enabling an unattended multi-batch loop. This skill owns the whole loop spec → dispatch → watch → verify → harvest (HARVEST.md); the skillbook IS the cross-run memory — every surprise gets harvested so the next run starts better. The whole job is one line:
choose an exact pane → deliver a self-contained job → prove it started → heartbeat from independent state → correct/continue safely → verify handback and clean up
This skill is a seven-file book — SKILL.md alone is not the skill. Loading the skill loads only this file; the companions load lazily. Register these triggers NOW, and when one fires, read that file completely before acting (live gap 2026-07-23: a commander made its worker-architecture choice before any pointer fired, because nothing at load time told it the other files existed). Architecture-shaping rules (workers are real seats, never harness subagents; cheap-pool models for workers; job files open with init-suppression) live in THIS file precisely because companions load late — never defer an architecture decision to a companion file.
| File | Read completely BEFORE |
| HERDR-WORKERS.md | the session's first seat is created — the FABRIC core: workspace/tab/seat creation, prompt, wait; hook-state semantics and half the traps are pre-launch |
| PI-WORKERS.md | launching or injecting into any Pi seat |
| CODEX-WORKERS.md | launching, injecting into, resetting, or exiting any Codex seat |
| HARVEST.md | the first surprise or user correction, and again at task end |
| SLASH-COMMANDS.md | injecting any slash command into a seat whose harness you haven't driven this session — 231 条四 harness 全表(2026-08-14 实测)+ herdr CLI 对照 + 驱动裸 TUI 的丢键/翻页/残留输入三坑 |
| TMUX-ARCHIVE.md | driving a legacy tmux seat the owner explicitly names — the archived fabric's mechanics (named buffers, capture shapes, session naming, fleet-loss drill) |
Seat fabric: herdr is the standing fabric for BOTH commander and worker seats (owner ruling 2026-08-20). Any harness — pi, claude, codex, omp — can hold either role, each in a herdr pane. tmux is ARCHIVED: drive a tmux seat only when the owner explicitly names one, and read TMUX-ARCHIVE.md completely first; ssh boxes remain the remote-worker fabric (§ Remote workers over ssh). Lineage: fabric was owner-choice-never-infer since 2026-07-24 (a commander saw tmux sessions and started planning tmux pi seats; the owner had to interrupt with "worker都用herdr launch"); by 08-20 every live fleet ran herdr while commanders kept paying a dead tmux notify wire for it, so the owner archived tmux wholesale. A different fabric still requires the owner to name it — "what happens to be running" is never a designation.
Provider-route gate — auth belongs to its supported harness (live 2026-08-24). For this fleet, route Anthropic subscription workers through official Claude Code only. A third-party harness pointed at a subscription route may still list models and fetch usage while generation is refused (403 forbidden: Request not allowed across Opus and Fable, measured on the same account where official Claude Code succeeded); model discovery and usage are therefore not generation proof. Before dispatching a harness×provider×auth route not already proven in the current fleet profile, run one no-tool generation canary through that exact route. OMP workers use a non-Anthropic provider. An Anthropic API key is a separate pay-as-you-go route and requires current-session spend approval before launch. Recovery from such a 403 is to re-route the seat to its supported harness, not to refresh or re-login the subscription.
Worker-harness default = herdr + Pi (owner ruling 2026-08-24). On this fleet's host Pi is the ONLY harness whose usage lands on the shared Pro subscription pool; the local codex CLI spends a separate, smaller personal quota, and other harnesses draw their own routes. So default every worker/commander seat to --kind pi, and route the fleet's standing burn through it. Pick --kind codex (or another harness) only when the owner explicitly wants that route's quota spent, or names such a seat. [[CODEX-WORKERS.md § Weekly quota]] carries the footer-reading detail; this corrects the earlier "codex and pi share one Pro pool" assumption.
First load in a blank session → interview before acting (owner feature request 2026-07-23). If the session carries no fleet context, ask the operator once, up front (one message): ① does a fleet workspace already exist (herdr workspace list), or does this fleet start one? ② which worker agents are the cheap pool (pi/codex/claude/other), and which model pool is expensive and to be conserved? ③ the task, its scale, and where deliverables land. ④ hard boundaries — what must come back for approval (spend, outbound, prod, merge)? Record the answers as a fleet profile note and reuse it — never re-interview mid-fleet.
Dispatch is the DEFAULT, not an option awaiting instruction. Your base model was trained to do work itself; as commander that instinct is the bug (live 2026-07-23: a seated commander self-executed and reached for built-in tools until the owner named pi — delegation must not require naming). Triage every work item at intake; the unmarked case is a seat:
- Dispatch to a worker seat (default): anything substantive — produces artifacts, takes >~10 minutes, touches code/data/browser, or can run while you command.
- Self-execute (closed whitelist only): sub-3-minute read-only glue; acceptance/verdict reading; seal, sign-off, and merge acts that must not be delegated; steering itself.
- Self-execution outside the whitelist requires a stated justification in your report — silence means you defaulted wrong.
Prerequisite: a running herdr server (herdr status; macOS, Linux, WSL2). Native Windows participates only as an ssh-target worker (HERDR-WORKERS § Windows seat), never as commander host.
1. Choose an exact pane
- Inventory first:
herdr workspace list,herdr agent list,herdr pane list. Target the exact pane id (w4:p1) — herdr-assigned, unique for the pane's life, dead with the pane: stored targets (contracts, watch scripts) are snapshots — re-listbefore use. - Bootstrap your own address first — it is the
reply_to/<self>every register and pending call needs. Inside any herdr pane:$HERDR_PANE_ID(alsoherdr pane current). A commander seated OUTSIDE herdr has no wake wire — get a herdr seat, or run envelope-only with the §4 artifact-watch as the sole wake. - One concern per seat, ONE workspace per fleet — every standing seat is a TAB in the fleet workspace, never a sibling workspace; a PR-sized sub-fleet gets its own dedicated workspace, closed on ack (owner rulings 2026-07-22 / 2026-08-14 — HERDR-WORKERS § Launch). Naming convention (owner ruling 2026-07-31): the concern string is the sole key across three places — seat label
cmdr-<concern>, fleet directory~/fleet/<concern>/, and~/fleet/<concern>/SEAT.md— same string, set once at seat creation. ⚠agent startnames must be all-lowercase (ctx-Ais rejected asinvalid_agent_namewhile a tab LABEL accepts it — 2026-07-26, two seats stalled; generate lowercase everywhere). publishing and methodology are separate concerns → separate seats. - Taking over a dead/parked worker's WIP? Prove you're the only one first. Sweep for a live twin: census live seats for a concurrent worker on this job (
herdr agent listacross all workspaces, plus daemon ghosts, Guardrail 3), and check the remote —git fetch,gh pr list --head <branch> --state all,git ls-remote --heads origin <branch>,git log --oneline -3 origin/main— in case a concurrent session already pushed / opened a PR / merged the deliverable. If one exists: gap-fill, don't duplicate; report the concurrency. See [[takeover-check-concurrent-progress]]. - Confirm identity from the exact pane id and the harness footer (model/effort, cwd, branch, context); session-file naming is harness-specific, not identity. Before touching anything, declare: which pane is the worker, that you are the commander, the worker's owned files/surface, and its outward-action authority. Every unrelated seat stays untouched; done = an exact pane id whose role fits the job.
2. Deliver a self-contained job
Context economy first (owner directive 2026-07-21): leftover context is re-billed every turn and steers the model. Before a new task_id, reset the seat harness-correct: Claude Code /clear; Pi = REPLACE the tab (a /clear typed into a Pi pane is a billable prompt, and the tmux-era double-Ctrl+C exit does not reach a herdr-hosted Pi — HERDR-WORKERS § Resetting a Pi seat). No percentage threshold. Pre-reset gate (Stage 5b): idle, no un-acked pending return, deliverables in the SoT. Read the seat's live agent_status immediately before any kill/reset — a seat mid-task on ANOTHER job is clobbered silently, its in-flight work lost with no error (live 2026-07-23: a commander juggling 5 seats reset a pane still running a review; the task contract survived so it was re-dispatchable, but the compute was burned). Prefer a confirmed-idle seat over resetting a busy peer; reusing a busy seat is a deliberate cancellation, not a reset — state it. Only skips: a same-task steer/revise continuation, or a job explicitly building on that pane's live context. (Mid-task high-ctx% is Stage 5's disk-SoT restart, not this rule.)
Transition swallow (Claude Code only): /clear / /effort / /model have a transition window that silently eats the next submission (bitten twice, 2026-07-21 — tmux-era pastes, but the window is harness behavior, not fabric). After any such command, pane read until a bare prompt — after /clear, until the status-bar ctx field is gone — only then dispatch. Consumption proof = status-bar ctx% rises after submit (earlier and more reliable than the spinner); flat → one herdr agent send-keys <pane> enter; still flat → re-issue agent prompt. Pi seats have no transition window — wait on blank editor + footer match (PI-WORKERS § Launch).
Launch the harness in the intended cwd and wait for its real editor, not the splash — create the seat, start the agent, run the footer identity gate, then dispatch:
herdr workspace create --cwd <workdir> --label <fleet> --no-focus # fleet's first seat only
herdr tab create --workspace <ws_id> --cwd <worktree> --label <seat> [--env K=V] # every further seat
herdr agent start <name> --kind <pi|claude|codex|…> --pane <pane_id> --timeout 60000 -- <bare-flag-args>
herdr agent prompt <pane_id> '<one-line pointer to the job file>' --wait --until workingRead HERDR-WORKERS.md completely before the session's first seat — per-harness launch flags, the lowercase agent-name rule, stalled-Enter recovery, and the Codex hook-trust false idle live there. Non-negotiables that shape dispatch:
- Delivery is ONE literal line pointing at the external job file, for EVERY harness. Multiline pastes are the archived tmux fabric's mechanism and never cross a herdr wire — a multiline body into Pi fragments into hundreds of queued
Steering:turns, each fragment a billable turn (2026-07-18). The pointer line itself carries the init-suppression sentence (below) so it lands before any repo ritual can fire:Skip any repo Session Init / health sweep / context ritual. Read ~/fleet/<concern>/jobs/<job>.md completely, then execute the entire job. The file is the authoritative contract; do not stop after planning. - Claude Code seats: BOTH flags after
--or the seat is useless (measured 2026-08-14, a Claude Code seat) —--model <model>(else it silently inherits the session default) and--dangerously-skip-permissions(else don't-ask mode auto-DENIES every Bash/Read; the seat looks alive and does nothing; unrecoverable remotely — relaunch is the only fix). Omit the bypass flag only when the owner explicitly wants a permission-gated seat (owner correction 2026-07-25: an unwatched gated seat silently blocks on its first out-of-cwd read). - Pi seats: pin
--provider,--model,--thinkingexplicitly and verify the footer — Pi silently clamps unsupported thinking levels (PI-WORKERS § Launch). herdr agent start/tab createNEVER inside a shell loop — loops silently start zero agents (measured twice 2026-08-14); one command per invocation, verified byagent list+ footer reads.- Small corrections to an idle seat:
herdr agent prompt <pane> '<text>'. Raw fallback for a pane with no detected agent:herdr pane send-text <pane> '<text>', thenherdr pane send-keys <pane> enteras its own call.
The job file must be self-contained — cwd, read-first files, frozen state/ids, exact owned paths, required outputs, constraints, verification steps, stop/handback condition, explicit outward-action authority, and its task_id + reply_to parent pane (so the worker can return upward — Return channel). Write it outside any repo the worker might git add -A, in the durable commander workspace ~/fleet/<concern>/ (owner ruling 2026-07-24; supersedes the old flat tmp layout): jobs/ contracts, out/ deliverables, evidence/ pulled ground truth, secrets/ (0700, values never in transcripts), archive/ closed work. One concern = one directory; retire by moving the dir into archive/. Prefer durable home-dir storage over tmp; never bake a tmp path into a signed/hash-bound artifact (2026-07-24: P18 enshrined tmp-class output paths, so the live run could not be relocated without re-signing). In-flight concerns keep their existing paths until closed — never migrate a live hash-bound tree. When a durable asset is wired to load automatically, version the WIRE, not just the content — 内容与索引都进了 git,把索引接到会话上的那根线没进,而断线是静默的:没有报错,全体读者从此再也读不到那一层(2026-07-28:一个全席位可见的记忆层靠一个仓外 symlink 加载,用 symlink 让索引本体留在仓内才把裸线收窄到一根;仍要为那根线留重建命令并编进例行巡检——asset 存在不等于 asset 被读到)。 Long-form deliverables are written to disk in CHUNKS — append per section, ≤80 lines per write, never expanded in pane/response: a monolithic write dies to upstream idle timeouts (glm-5.2) and max-output ceilings (muse-spark-1.1), measured 2026-07-22. Bake the chunk rule in at dispatch — mid-turn steering cannot reach a request-level retry loop; Escape is the only entry. Pin outputs to the worker's own worktree/branch — never a stray untracked file in the shared main checkout: harmless until the same path arrives tracked via someone's merge, then it blocks the next rebase for everyone. A repo-writing job must pin its worktree (git worktree add <path> -b <branch> origin/main; the shared checkout stays on main) — omitting this once (2026-07-18 S2) made the worker checkout -b on the shared checkout, flipping every sibling statusline. Behind a permission gate, author worker commands with git -C <path> + absolute paths (a cd X && … prefix defeats --allowedTools matching and trips the cd-confirm). In a yolo/bypass fleet, have the worker cd into its worktree as step one so the pane statusline shows true dir + branch for owner audit; shared-checkout commands still use git -C absolute paths.
Two workers on the same skill/repo surface → three moves, not two: serialize (hold worker 2 until worker 1 merges — safest, slowest), stack (branch worker 2 off worker 1's branch, deliver both in ONE PR), or — never — a second independent writer. Stack when batch 2 cannot wait and would otherwise edit the same giant file/config lines — a merge conflict becomes linear history. ⚠ Its price, stated when chosen: the first branch ships under the second PR's review and its own PR is closed unreviewed — stack only when willing to review both batches together, and say so in the PR body (2026-07-18: #52 carried both, #50 closed superseded). Arm the worker against a race you missed: the job file must instruct it, on detecting a concurrent peer on its owned worktree/branch/surface, to stop writing immediately (zero further commits), read-only assess the peer, and return status=blocked for arbitration — this reflex held a real double-dispatch (#21) to zero loss; bake it into every job file.
N workers on ONE cohesive surface: partition by FILE OWNERSHIP, never by concern. Concern-split workers (reorder / cards / color) all edit the same files → conflict hell; file-disjoint workers (data / markup / style) merge with zero conflicts. Each worker gets a worktree off a frozen baseline; every shared interface travels in a frozen contract committed to that baseline (data keys, canonical class names, section order). The risk shifts from git conflicts to seams, which the compile gate cannot see — the commander owns seam verification at merge: static cross-file alignment checks plus a render pass (2026-06-16: 4 workers, zero conflicts, 3 visual bugs surfaced only at the assembled render).
A commander running inside an agent harness must not use the harness's built-in subagents (Task/Agent tools) as workers. They inherit the commander's model and bill its quota (usually the expensive frontier pool the fleet exists to conserve), and live inside the commander's session: no seat, no heartbeat, no return contract, invisible to fleet telemetry (live 2026-07-23: a freshly seated Claude Code commander defaulted to Task subagents for its first work batch — caught by the owner, not by any check). Say it explicitly in every commander identity package: workers get REAL seats (herdr pane, cheap-pool model); built-in subagents are allowed only for sub-3-minute read-only scouting whose result feeds the commander itself. Beware ambiguous phrasing like "or a claude seat" — a harness-native commander reads any wiggle room as license for its default tools.
Blind-panel × baseline-collision — the "what don't we know yet" analysis shape (validated 2026-07-25, GSC panel). When the deliverable is insight from a data corpus rather than an artifact: ① N lens analysts (disjoint lenses — technical / traffic / anomaly-hunter) read ONLY the corpus, blind to the team's prior conclusions, each with a mandatory「反常与惊讶」section where the value concentrates; ② the commander writes a KNOWN-BASELINE doc (what the team already knows/ruled) that ONLY the synthesis seat may read; ③ a synthesis seat collides analyst reports with the baseline and grades every candidate NOVEL / NEEDS-VERIFICATION / KNOWN / REFUTED — each NOVEL must survive an adversarial attack AND the synthesis seat re-verifying citations against the raw corpus (it caught an analyst's off-by-one on first live run). Blind analysts + informed judge is the point: feed analysts the baseline and they anchor; skip it and the judge re-reports what you already knew as discovery.
Spec a worker by altitude + floor, not micro-rules. The worker may do whatever it judges best so long as altitude stays right — serves the goal — with red lines and STOP gates as the only hard floor; judge on altitude, not style. Commander and critics stay bounded the other way: read-only, critique-only, propose-for-approval. Freedom is asymmetric by design — don't soften the judges; the quality lives in the tension.
Register the return contract at dispatch — the typed lifecycle card (Return channel §) is canonical; the helper lives in THIS SKILL's directory, called by absolute path: python3 ~/.claude/skills/fleet-commander/scripts/return-channel.py register --task <id> --worker-pane <worker_pane_id> --reply-to "$HERDR_PANE_ID" --owned-paths <paths…> (the owned-paths conflict gate rejects a second concurrent writer at register time), and put publish-task --result-paths … in the job file as the worker's finish act.
派单里的因果/范围断言是假说,不是范围 —— bake 进每份 job 契约。 实锤 2026-07-18 同日两例(#58/#59):两份 PR 的第一句都在裁决派单假设、且都判它不成立——照单执行连派单自己写的复测判据都过不了。job file 必须写明:worker 第一个动作是量派单假设的爆炸半径(实测受影响面,或拿派单自己的成功判据反算),假说被证伪就带证据回报并重新定范围。自检句:「如果我只做派单范围,派单自己写的复测会通过吗?」 commander 侧:把假设显式写成一句可证伪的话——没写出来的假设,worker 会当成已裁决的事实执行。 「保持现状」类条款必须锚在改前可观测态,不许锚在实现层假设。 实锤 2026-08-17(title-rate FIX1):契约写「保持 DB 原值直通」,意图是「保持改前 live title」——真 DB 值是裸店名,改前的像样标题来自即将被移除的旧渲染层;worker 无权读 prod DB,照字面执行,四页上线即回退,靠部署后线上抽验才抓住。规矩:凡写「保持现状/原样/不变」,判据 = 派单时对现状的可观测抓取快照(curl 存证随单附上);worker 无权观测的实现层事实(DB 字段、config 值)不许当判据。worker 的「我证不了的部分」清单恰好预警了这个盲区——该条款第三次自证。
消费别席接口件,先验格式再批量喂。 实锤 2026-08-17(c2 污染轮,157 发 $0.38 全废):对方文件头两行注释、正文「词\t词量」两列 TSV,cmdr 只 wc -l 没 head,整行带 tab+数字当关键词发出;且 DataForSEO 对脏关键词照常 20000 返回——格式错误在通道层是静默的。规矩:接口文件消费前 head/sed -n l 验结构(注释行、分隔符、列数),批量脚本对每行结构断言(禁 tab、禁 # 开头、非空),违例 ABORT。与「抄来的数字标注快照并当日重算」同族:别席产出=数值快照+格式约定的复合体,两样都要验。生产侧同罪:cmdr 自产的接口件,写完必 close(或分进程)再读,记录数对源断言。 实锤 2026-08-25:同一 Python 进程 csv.writer(open(...)) 未 close 即读,尾部缓冲未落盘——一份表少 208 行,另两份整份读成 0 行,「空导出」被当成市场事实写进契约,worker 对照 xlsx 才撞出来。转换类 glue 的验收断言 = 输出记录数与源(xlsx max_row-1)相等;「空结果」与「零命中」同判:先怀疑仪器,再怀疑世界。
反向同罪:契约里每条追不回上位文档的约束,是 commander 发明的假说,不是法。 派单前把契约约束逐条对照 governing spec(实验设计/descriptor/授权文件)自身的不变量——live 2026-07-26:派单强加「100% 离线」,而实验设计原文明写对照组「同预算」且登记过「对照被做成稻草人」风险,4,100 决策全废重建。自检句:**「这条约束是 spec 说的,还是我猜的?」**猜的就写成可证伪假设并标注来源=commander。
同族第三形,只在多轮修订单里出现:约束不是猜错的,是过期的。 一条在 v1 完全正确的红线,到 v2 可能已经在挡正确的动作 —— 而 worker 会照守不误,因为守约束正是它该做的。2026-08-20 实锤:v1 时页面发布的码有 14 个不在联盟 feed 里,契约写死「不许写 receipt」(那时写 receipt 确实是给未通过的闸伪造凭证,worker 拒写并写明理由,完全正确);修订轮摘掉那 14 个码后闸真的过了(passed=5 missing=0),此时 --record 写的是真实凭证,但那条红线原样还在,worker 照样守着报 partial —— 挡住交付的是指挥席的过期约束,不是它的执行。⇒ 两条动作:①每轮修订都要重读上一轮的约束,逐条问「它依据的前提这一轮还成立吗」;②过期了就在修订契约里明写认账(「过期的是约束,不是你的执行」)——worker 连着两轮停在同一处并如实上报,是契约设计成功而不是它效率低,别让修订单读起来像它做错了。⚠ 放宽时保持红线本身不动,只换执行者:上例的正解是「改由 --record 生成,不由你手写」外加「先裸跑确认 exit=0 才准记录」——凭证只能记录当场验证过的状态,不能记录一个假设仍成立的状态。
同族第三面:可算而不算的数字断言——它读起来像事实,所以过审时没人拦。 2026-08-01 同日三个根不同的席位各犯一次:①commander 建议「挂真外部闹钟」,而 harness 层根本没这能力(没试过就建议);②契约断言「全部 network 超 7 天没刷新」,实际 2.58 天(一条 SQL 就能算,没算);③报告称「feed 整体落后 3 天」,实际只有 web coupons 落后 3 天、另一张 deals 表 只落后 14 小时(两张表由不同脚本写)。三例同形:那个量就在手边、一条查询就能算——跳过的不是难以验证的东西,是懒得算的东西;且三次都由平级席位拿一手证据撞出,自省零命中。上面两条防的是下游验证与约束来源,都防不住「根本没去算」。两句自检:「我这句话里的数字,是算出来的还是推出来的?」与「说可被证伪的数字,别说模糊定性」——『超过 7 天』能被撞,『已经很久没刷新』撞不动。
契约的硬判据必须是 worker 手上的数据能判的,否则你要的不是执行,是猜测。 派单前对每条硬判据问一句「worker 拿什么证明这一条?」:数据在别处就随单附上(或写明可取路径);取不到就把判据降级为它能判的最强代理并显式标注「这是代理,不是原判据」,绝不留一条 worker 无法验证却必须遵守的硬判据(2026-07-28 实锤:派单写死「入边须来自高频抓取活页」却没随单附任何抓取数据,worker 只能拿仓库内证据选源,交出的 15 个源经第三方实测无一是活页,换成实测高频源同量指标 16.8×,整轮返工,账在指挥不在 worker)。 同一条的正面形:能自己先跑一遍的硬判据,派单前就跑。 上一条只排除了「worker 判不了」的判据;亲手跑一遍还额外给三样,而且都只在跑的时候才出现:①一个逐位可比的 oracle(把「应当复现」换成九个具体数字);②一次对上游文档是否属实的实测——2026-08-19 一份 skill 自己的依赖表少写了 5 个外部模块与 12 处绝对路径,照它派单会漏掉一半搬运面;③常常就是该单真正该修的那个缺陷(同日:渲染器读工作树当前态而非 pinned ref,口径静默漂移,随后成了该单的交付项)。把这三样写进契约,派单就从「请你打包」变成「复现这九个数,并修掉这一条」。自检句:「这条判据我自己跑得动吗?跑不动就别写;跑得动却不跑,就是把发现缺陷的机会让给运气。」
同一枚硬币的另一面:契约必须强制 worker 交出「我证不了的部分」——一份不可验证项清单,当场声明列得多不扣分。 没有这条,worker 的自然倾向是让交付看起来完整,而看起来完整与真正完整的交付在验收面上长得一模一样;上例的缺陷合并前被拦下,唯一原因就是 worker 主动写了「这是仓库内证据不是抓取实测,我证不了这一点」——那句标注是契约催出来的,不是运气。
散文里的红线,判据里表达不了,就等于没写 —— 而 worker 照判据执行是对的,账在指挥。 契约常常一边用散文立红线(「🚫 X 类绝不上」),一边用字段写判据(A ≥ 1 且 B ≥ 200 且 C ≤ 30),而判据在语法上引用不到那条红线所依赖的字段。实锤 2026-08-06:同一份契约既写「假码页绝不上」,判据又只看「有码数/需求量/难度」——从不读那个标记「上游已撤码」的字段;全表符合红线例外的只有 1 家,泄漏率 100%,且它恰是排序键最大的一家,稳稳落在建页队列第一位。红队原话:「没有任何一份契约的措辞诱导 worker 越线,worker 完全照判据执行,判据自己把红线漏了。」⇒ 每写一条散文红线,当场回答:「这条红线在我的判据里由哪个字段表达?」答不上来就不是红线,是愿望。三条同族自检一起做:①分档值域拼一遍(同日实锤:SHIP_NOW 要难度 ≤30、TRAP 要 ≥60,31–59 无归属,16 家、47,340 月量静默掉进空洞,含全盘存量最厚的那家——只差 2 点);②落进「其它/未分类」的行单独报数,否则它读起来像「没有这种情况」;③从别席文档抄进契约的数字标注为快照并要求当日重算(同日实锤:抄来的「占位日 = 11-01」是滚动值,当天已滚到 11-04,只按常量过滤会放行 3,146 个假到期值)。
控制样本验的是通道,重放验的是判据本身 —— 两者不能互相顶替。 派单惯例只要求「内置一个已知正例,零命中即 ABORT」,那只证明数据取得到;它证明不了你抄给 worker 的那份判据清单有没有抄漏。2026-08-06 一个 worker 自行补上了后者:把自己的分类器重放上游已判过的全部 28 词 × top10 = 280 个域,逐词逐域比对(0 处不符),其自述「单点控制只能证明一个词没错,重放能证明整份清单没抄漏」。⇒ 当 worker 复用另一席产出的判据/清单/词表时,契约要同时要求这一道重放对齐,而不只是通道验响。
你给 worker 定的验收标准,立刻问自己那一侧过不过 —— 定标准的人是自己标准的盲区。 2026-07-28 同日三例、两个不同席位(要求「CI 绿才交付」自己却连推四次没查 CI、把 main 弄红;定「覆盖每一路径」自己的监测却漏掉已发生的失效模式),三次都是自查出来的、没一次是对方抓到的——不是能力问题,是位置问题:定标准时注意力全在对方产出上,自己那侧从未进入视野。⚠ 且每次当事人正处在对该标准意识最强的一刻照犯,所以动作必须是机制,不是自觉:①推任何东西到共享分支后,gh run list --commit <sha> 锚自己 SHA 查一次 CI 再往下走(docs-only 提交同样会挂,旁边常躺被断言的状态文件);②凡「覆盖 N 个东西」的交付,把 N 逐条列出对表,不靠「应该都盖到了」的感觉——覆盖完整性靠逐条对表,不靠意识到。
批量查询脚本要内置一个已知会命中的控制样本,零命中即 ABORT。 2026-07-28 实锤:zsh 未引号变量($var 不分词,需 ${=var})把 15 条 URL 当成一个字符串,输出「全部 0 命中」——退出码 0、格式正常,与「这批源全废了」在观测面上完全一致;救场的是脚本预置的控制样本(一个已知会命中的 URL)同时归零。与 §4 的 grep -c/过滤器吞错不同源:那是错误被吞,这是查询成功但查错了对象,退出码与输出格式都发现不了。
Independent-review contracts carry a standing attack-vector list — proven vectors recur across unrelated codebases, so every paid/high-stakes review job cites them explicitly (a reviewer told "attack it" rediscovers maybe half):
- bool-as-int: any JSON value crossing a numeric gate must be type-checked —
Number(true)→1silently passes finite-cost/metric guards (two live hits in 24h on unrelated parsers, 2026-07-22 power case, 07-23 DataForSEO). Red test: boolean input must land fail-closed, not be laundered by coercion. - accumulated-row-as-unit-price: a logged cost row that sums prior stages is not a unit bound (07-23:
$0.024"ceiling" was accumulated). Demand provenance for every claimed bound; no provider guarantee → force cap-driven derivation. - unguarded exit path: the cap/limit check on the success path must exist on EVERY path — error/terminal branches that journal-and-continue cross hard ceilings (07-23: terminal
$1.70pushed ledger past a$1.75cap). Red test per exit path. - verdict word anchoring:
NOT APPROVEDcontainsAPPROVED(see §4) — applies to any grep-based gate on enumerated words.
Multi-round review loops need a commander-owned ACCEPTANCE BOUNDARY — reviewers ratchet. A good adversarial reviewer expands the acceptance perimeter every round (each fix adds surface that can itself drift), so an ungoverned fix→review loop is asymptotic: live 2026-07-26, R1–R5 cleared the data plane entirely yet R5–R6 kept raising the bar on the report's self-description. The commander — not the reviewer — owns the bar: when findings stop touching the artifact the seal actually binds, issue a written boundary adjudication (what IS the sealed truth surface; which demands exceed the gate), record it IN the package, and give the reviewer an explicit DISSENT channel ("if this boundary endangers validity, say so in DISSENT — verdict still judged per boundary"). Corollary for experiments: hold both arms to the SAME review standard — a reviewer-invented standard applied to one arm only is itself a fairness bug.
The completion signal is the ARTIFACT landing in the agreed directory. return is an optimization, never the gate. Placement-strength patches were measured insufficient: the return command was moved to the TOP of the deliverables section, marked "not executed = job incomplete", pre-annotated that the envelope alone counts — and the very next job still came back with zero envelope (recurrence #6, 2026-07-24; #7 the same week). Seven recurrences is a design smell: delivery and signalling are two acts, so one can be skipped. Fuse them with three contract clauses:
- The output path is an INTERFACE, not a suggestion. Write the absolute path in the contract, verbatim: 「这个路径是接口,不是建议——改名 = 交付失败。」 A worker renames to something more descriptive (2026-07-24: contract said
out/REPORT.md, worker wrote a long descriptive name — content was excellent); a soft deviation for the worker, a hard dependency for every downstream check. - Publish ATOMICALLY — draft in
out/.staging/,mvintoout/as the final act. A rename inside one filesystem is atomic, so the file's appearance in the watched directory means complete, never half-written — this is what makes the chunked-write rule safe to watch (chunks accumulate in staging where no watcher looks). The Done-when item is 「out/<name>存在」, not "the report is written". - The verdict lives IN the artifact, at a fixed spot. If the job produces a judgement (review, audit, go/no-go), the contract fixes its first line as
VERDICT: <approved|changes_requested|informational>— one line, word-anchored, machine-readable. Skip this and the domain verdict exists only inside an envelope you just stopped depending on.
Derived/mirror surfaces regenerate by SCRIPT, never by hand — bake the closing order into the contract. Any package whose report/manifest mirrors source state (hash tables, terminals, timestamps, counts) will drift the moment a fix round touches the source and the worker hand-syncs the prose (live 2026-07-26: three consecutive review rounds each caught a fresh hand-edited mirror gone stale). The contract names a regeneration script and a fixed closing sequence (edit sources → regenerate derived → self-checks → package manifest); a hand-written current-state number in a derived surface = the round is void.
A browser job file MUST carry a UI map. Any job that drives a web UI includes a "关键控件在哪" section: where the key controls live, including controls only visible after scrolling, state-color conventions, and known dead zones — or the commander walks the flow once personally before dispatching. Live cost of omitting it (2026-07-24, a media-workflow job): a worker burned $32 clicking around a video column clipped outside the viewport, and its commander wasted 40+ clicks on the same trap.
Open every job file with an init-suppression line: "Skip any repo Session Init / health sweep / context ritual — this job file is your whole brief; touch only what it names." Repo-level CLAUDE/AGENTS files address a default session, and a worker obeying their init ritual burns tokens and can touch prod for nothing (2026-07-23: a tmp-scoped drafting worker ssh'd prod to report health flags nobody asked for). The commander runs init once; workers inherit conclusions through the contract, never re-derive them.
Done when: the job file exists outside the worker's repo, the return contract is registered, and the exact pane consumed one one-line dispatch — hook state working (or equivalent consumption proof), no other pane received it.
3. Prove it started
Editor text is not proof of submission — confirm the worker is processing THIS contract: hook state working for the dispatched pointer, plus transcript content (tool use, an in-flight marker, the first required action). herdr agent prompt --wait --until working reports a swallowed Enter as agent_prompt_stalled — recover in order: herdr pane read <pane> first (if an interactive dialog consumed the dispatch, resolve the dialog and re-prompt — the original is gone; never blindly send the fallback Enter), then herdr agent send-keys <pane> enter, then agent wait --until working (HERDR-WORKERS § Deliver a job). A lost dispatch can also masquerade as done: a seat can later read done with a BLANK transcript region — the prompt was never consumed and the seat did nothing (measured 2026-08-14); done/idle after a dispatch proves nothing, the only consumption proof is transcript content or the deliverable itself — re-prompt on blank transcript. Pi: the consumption proof is the read tool call on the exact external job file (PI-WORKERS.md). A queued message is not consumed: confirm the worker acted on this job; if it landed in the wrong pane, immediately send an explicit correction naming what to ignore and the correct scope. Done = target worker visibly started on this job, no other pane received it.
4. Heartbeat from independent state
Recheck from four independent surfaces — never the UI spinner alone:
- pane transcript —
herdr pane read <pane_id> --lines 200; - process + hook state —
herdr agent list(agent_status; subject to the missing-integration permanent falseidle— HERDR-WORKERS § Prerequisites),herdr pane process-info --pane <pane_id>, footer ctx%; - deliverable / extern state — THE exit condition — the contracted output path exists (Stage 2's staging→
mvpublish makes its presence mean complete); prod/DB truth; - the return channel — an early hint, never a gate — a
[RETURN task=… status=…]line in your pane, plus apending --reply-to <self>scan every heartbeat, not only when you suspect a miss. The pane line is lossy and the mailbox durable, but both are legitimately empty for a job that completed perfectly — scan anyway (an unscanned mailbox is how returns sat unacknowledged long after their work merged), just never wait on one. For any join decision prefer ledger state —status --task <id>/list --parent <self>(lease expiry surfaces aslost) — over pane text (typed lifecycle card, Return channel §).
Reasoning is NOT one of the four surfaces — what a seat shows depends on the harness×provider pair and no supported route exposes a dependable mind-reading channel. Claude Code + a Claude model prints a collapsed ✻ … for Ns marker and nothing else — 53k thinking blocks across 1,995 local transcripts carry an empty thinking field, and the hidden --thinking-display summarized flag did not change that on Opus 5. Pi + a Claude model shows nothing at all (PI-WORKERS § Launch). ANY harness + an OpenAI model shows terse one-line summary titles only, never raw chain-of-thought: the Responses API returns encrypted reasoning plus reasoning.summary, and omp hardwires that field to off-or-auto (reasoningSummary: hideThinkingSummary ? null : undefined) with no detailed path. A historical 2026-08-13 omp+Claude test exposed multi-paragraph summaries, but that route is excluded by the Provider-route gate above — never route a seat somewhere unsupported just for visibility. Watch tool calls, deliverables, and ledger state, which every supported pair emits.
Idle is the HOOK's verdict, not the spinner's: agent_status idle/done from herdr agent list — trustworthy only where the harness integration is installed (herdr agent explain <pane> exposes the permanent false idle when it isn't; HERDR-WORKERS § Prerequisites). No integration → fall back to harness-specific screen shapes via pane read (Claude Code: below; Pi braille spinner: PI-WORKERS § Heartbeat and context). Report a delta + blocker + next action, never "still working." Validate actual files/status — don't trust a worker's "done." This extends to every IDENTIFIER a worker hands you — pid, SHA, PR number, task id, branch — before you write it into a gate. A worker's report is an observation, not a fact, and an identifier is the one thing that looks too atomic to be wrong. Live 2026-08-06: a worker reported a long-running prod job as pid 1125094; the commander accepted it and issued "hold the merge until that pid exits" as the release gate. ps on the box showed 1125094 had ELAPSED 2-01:11 and CMD node <scheduler> — the long-lived scheduler, which never exits; the real job was its child 1208324 (<runner> --full --network <n>, 18m56s, matching the worker's own "16 minutes"). The gate would have blocked until its own timeout. The failure is instructive precisely because the new gate looked STRONGER than the one it replaced (wait for a process vs. wait for a clock) — strength is worthless if it is anchored to the wrong object. One ps/gh/git call on the identifier before it becomes a gate. Stop and release a genuinely-finished worker (outputs preserved) to cut concurrency.
A watch loop that only scans the mailbox watches nothing — workers finish, print their report, and stop without running return (four times in one day, 2026-07-19/20; seven by 2026-07-25). Any unattended wait is TWO-condition: ① the artifact leg — every contracted path exists (asserted per path, not as a directory count — below); ② for each registered task with neither artifact nor envelope, if its pane is confirmed idle and not waiting, auto-nudge once — one line: "if <task> is done, publish it to <exact path> now (and run your return command if you still can); if still working, ignore this." Nudging about the artifact also recovers what the old nudge could not: a worker that finished but left it in staging, or only in its pane. The nudge gate is two checks: busy shape absent AND the capture shows no interactive dialog (permission prompts render as question + numbered options, y/n); unclear → read the capture yourself, don't nudge — a nudge into a dialog lands as a blind answer. Over-nudging is not free: Claude Code queues it, Pi delivers it as steering at the next tool boundary. A watcher's exit condition keys on deliverables/envelopes on disk, never pending count — acks drain pending mid-run (live 2026-07-22).
Sentinel legs must be scoped to the task's delivery state, and "envelope exists" is not "envelope is new." Two false alarms from one afternoon (2026-07-26): ① a two-seat sentinel treated ANY seat disappearing as fatal and died when a delivered-and-acked task's seat retired — retirement of a finished seat is expected; only a seat still OWING deliverables going away is an incident. ② ack records acknowledgement but leaves return.json in place, so an existence-based envelope leg re-fires forever after the first ack — anchor the leg on mtime newer than the dispatch/ack baseline (re-register also clears stale envelopes). And when your own acceptance check reds against a worker's green self-check, falsify your checker first: rerun the reviewer's exact repro command, re-derive the format (a 4-column table broke a 3-column regex), and hash the object the spec names (canonicalized payload ≠ file bytes) — two same-day false reds nearly bounced correct work. 同族另一形,更常见也更贵:你另起炉灶造的那个独立检查器,系统性地比被检对象更弱。 worker 把归一键、匹配规则、值域写在它自己的 METHOD.md 里;你只按契约文字重建一个,几乎必然漏掉它做过的归一(大小写、组前缀、宽匹配、跨仓路径归属)。2026-08-19 一场验收里 4/4 次「我红它绿」全是这个形,每次都先烧验收预算去查自己的 bug。⇒ 独立检查器要独立于它的实现,不独立于它的判据:动手前先读 worker 写下的判据,把你的检查器造得至少一样强,然后才谈分歧。弱尺子的红是你自己的 bug,而它和真红在验收面上长得一模一样。⚠ 反向更隐蔽,且今天占了三分之二:弱尺子的「绿」。 红至少会逼你去查;绿直接被当成通过,没有任何东西会再拦一次。2026-08-20 一场收工里连撞三次,三次都是我自己的尺子在骗我:①验一个「站点被 Cloudflare 挡住」的降级判断,只 curl 看状态码得 200,差点判 worker 说错 —— managed challenge 本来就常以 200 返回,判据在内容不在状态码;②验草稿正文有没有被改写 URL,直接对 RAW base64 解出的字节跑正则,得「零命中」——其实是压根没解开 MIME,与 dry-run 的读数自相矛盾才露馅;③验九个费率 pin,grep 抓错了 config 段落,拿到日期字段当 pin 值。⇒ 判据:任何「零命中 / 全通过」的读数,先回答「这个零是查了没有,还是压根没查到」;手边有阳性对照就跑一个(本次三例全部靠「另一个本该命中的对象也归零 / 与另一读数矛盾」撬开)。与本节开头「喂已知正例」同源,区别是那条管上岗前,这条管每一次读数。
A sentinel you have not seen fire is not monitoring — it is a placebo. Its silence and "all normal" are observationally identical, so an unverified watcher fails in exactly the direction that reads as worker still busy. Two hard rules, both from one 2026-07-24 run where a sentinel ran nine minutes with all three legs dead and the owner had to say the worker was done:
- Feed it a known positive BEFORE it goes on duty —
toucha fake artifact, drop a dummy envelope — and confirm it actually trips. But a single positive only proves the sieve is ALIVE, never that it is AIMED AT THE RIGHT OBJECT — and a sieve aimed at the wrong object passes its own positive test every time. Live 2026-08-06: a seat probed its in-flight leg with the pid it believed was the running job, gotALIVE, and declared the leg verified — the pid was the never-exiting scheduler, so the leg would have readALIVEforever while the actual job finished unnoticed. ⇒ Upgrade the probe to a discrimination test: run the identical check against three objects — the true target, a decoy that looks like the target but must be excluded (the parent/scheduler/wrapper), and a known-absent one — and require answers that distinguish them. That run measuredALIVE / ALIVE / GONEand the decisive observation was "when the real job exits, the decoy is still ALIVE" — which is precisely the mechanism by which the old gate could never fire. The decoy is the load-bearing part: without it the test degenerates back into a single positive. Same family as the state trap below (probe state ≠ duty state) — a probe must reproduce duty's real conditions in BOTH the state it runs in and the object it points at. The failed leg wasENV=$(ls <mailbox> | grep -c return || echo 0): under zshgrep -cexits non-zero on no-match, so|| echo 0appends a second0and[ "$ENV" -gt 0 ]throwsinteger expression expectedevery cycle.grep -c … || echo 0is a banned idiom — count with| wc -lor branch onif grep -q. The same family bites the commander's own one-off verification commands, not just sentinel scripts:cmd 2>&1 | grep -E '<期望的成功行>'discards the command's error entirely, so failure and success look identical (2026-07-26 two cases same day: openrsync failing on a GNU-only flag was swallowed by the grep and an empty dir nearly reported as a snapshot; agit … | grep … | sed … || echo "✓ 无"where||bound tosedprinted nothing on zero matches). Rule: judge whether an action succeeded by exit code and raw output ONLY; filters are for post-hoc extraction, never for pass/fail. 同族第三形(2026-08-17 实锤):对 JSON/CSV 等结构化输出做计数或判错也禁用正则——"status": *[^2]因*回溯放弃匹配空格、[^2]转吃空格本身,逢行必中,131 发全成功被报成 131 全失败;结构化输出的统计一律走解析器(json.loads 后计数)。 同族第四形,机制不同:管道把退出码换成最后一级的。cmd | tail; echo $?读到的是tail的 0,不是cmd的 1 —— 这次过滤器没吞掉错误,它替换了你的判据(2026-08-19 实锤:验收一份 fail-closed 交付物时中招,差点把一个正确的红判成绿放行;裸跑重定向再读$?才是 rc=1)。要么裸跑到文件再读$?,要么${PIPESTATUS[0]}/set -o pipefail。讽刺之处正是它的危险之处:中招的那一刻,你手上做的恰恰是「检查别人有没有只看退出码」。 - The artifact leg asserts EVERY contracted path, one at a time (
[ -f A ] && [ -f B ]) — never "the agreed directory is non-empty". The loose form fails in the direction that reads as success: a multi-output contract publishes files one at a time, so the FIRST arrival makes the directory non-empty while the deliverable that matters is still unwritten (live 2026-07-26: a seat owingREPORT.md+board-patch.mdpublished the patch first, the watcher fired ALL-DONE, and the report landed after the watch exited). The ledger joinstatus --taskreadspublishedonly after publish-task verified the whole registered set exists [enforced:H2/H3] — prefer it; the per-path shell assertion stays the pre-publish / legacy fallback. A worker may still publish out of order, so name ONE completion artifact and publish it last. - Write the sentinel for the shell it will ACTUALLY run under. A
bash script.shsentinel on macOS runs bash 3.2:declare -Afails but the script keeps running, every associative-array key collapses into one slot, and a multi-task ALL-DONE fires when only ONE task's artifacts exist (2026-08-25, caught pre-duty only because the known-positive feed included a decoy task with an incomplete artifact set — use plain per-task variables). Harness monitor facilities eval scripts under zsh, wherestatusis a read-only special variable —status=$(…)kills the script on its first assignment (live 2026-07-24: a five-leg sentinel died instantly withread-only variable: status). Name itst/state. The known-positive feed catches this for free only if the feed runs under the same shell as duty. Same family, third instance (2026-08-06): under zsh's defaultNOMATCH,for f in *in an EMPTY directory aborts the script (no matches found: *) where bash would pass*through — so the sentinel dies at the one moment it matters most, before any artifact exists, and its silence is indistinguishable from "workers still busy". Iterate withls -1 > tmp+while read < tmp(redirect, not a pipe — a pipe subshells your counters); zsh's*(N)works but isn't portable. And the feed itself has a trap: the state you PROBE in is not the state you STAND DUTY in. That run fed a known positive, saw it fire correctly, then deleted the probe — and the deletion restored the empty directory that was the crash condition. ⇒ after verifying, ask "which state does duty actually start in, and did my probe exercise that path?"
Envelope is a bonus signal, never the exit — on every fabric. Since 3.0.0 the bell genuinely reaches herdr panes (Return channel §), but the failure it cannot fix recurs on the WORKER side: seats skip return/publish-task even with the command as the contract's FIRST deliverable item (#7 measured 2026-07-24). Stage 2 makes the artifact itself the signal; a watcher that still gates on return has re-introduced the dependency the contract removed. A commander seated in an agent harness arms unattended waits through the harness's native monitor facility, not detached background sleep-loops — the harness reaps orphan background loops silently, and the kill notification is not an exit-condition fire (live 2026-07-24: two armed sentinels killed mid-watch back-to-back; the third via the harness monitor survived). Exit = every contracted output path exists; under Stage 2's atomic publish that is sufficient for a single-artifact job. Keep the second leg (hook state non-working for N consecutive debounced reads) when the contract has multiple outputs or when you could not impose staging. Match the in-flight SHAPE, not a keyword — a live turn renders ✳ Verbing… (2m 6s · ↓ 5.4k tokens). Same for VERDICT: NOT APPROVED contains APPROVED — a watcher grepping APPROVED reported approval for a rejection (live 2026-07-22); anchor words (grep -E '(^|[^A-Z])APPROVED' plus an explicit NOT[ _-]?APPROVED negative check), and act only on the RETURN file itself.
指挥席不是只有 Claude Code 一种 —— 望哨机制必须按指挥席自己的 harness 选型(owner 诊断 + 实锤 2026-08-17:omp 指挥席一天漏三次收工,三 worker 全部 idle 抱着交付物,owner 连捅两次才被发现)。 3.0.0 前 return-channel 的 notify 只会打 tmux pane,herdr 席的 --reply-to 只是标签、notify 必然失败;3.0.0 起 wire 按 pane token 选 fabric,herdr 席(含 omp 指挥席)能被 send-text+enter 真实唤醒(Return channel §)。但 omp 席仍有两个落空:
- 它没有 CC 的 monitor 设施可托管哨;「detached sleep-loop 会被 reap」的告诫同样适用。
- omp 席在两个 turn 之间是聋的 —— 铃声会作为下一条用户消息送达并唤起一个 turn,这是真 wake;但铃依赖 worker 真的跑
return/publish-task(本节开头:七次实锤会跳过),「等铃」仍是空头支票的一种。
omp 的原生醒铃 = async 后台任务的结算会自动送达指挥席的下一 turn(harness 的 async-job 契约)。所以 omp 指挥席的铁律不变:每个派单批次,在派单的同一 turn 内 arm 一个 async artifact-watch 任务 —— 短周期循环、逐路径 [ -f ] 断言全部契约产物(沿用本节「每条路径单独断言、永不判目录非空」),全齐或超时才退出,退出时打印落了哪些路径。它 settle 即送达 = omp 席保底的真 wake;3.0.0 的铃是加速器,不是替代品。没 arm 这个任务 = 没有望哨,与「worker 会自己回报」同级的幻觉。喂已知正例(touch 假产物)验响、撤正例回到执勤态,与本节其余纪律同——且撤正例必须在读到验响结果之后的下一批命令里做(§5 回滚物纪律)。
Screen-shape fallback (seats WITHOUT hook integration only) — the Claude Code busy shape:
herdr pane read "$pane" --lines 25 | grep -qE '…\s*\([0-9]+[ms][^)]*↓[^)]*tokens\)'This shape is Claude Code only — busy Pi renders a braille spinner ⠼ Working..., read as idle by this regex. Pick the shape by harness BEFORE scripting the watch; for Pi use PI-WORKERS.md § Heartbeat and context. A no-match on a seat you know is busy-capable is "unknown", not "idle" — read the pane and eyeball before any nudge. A sentinel/wait LOOP must DEBOUNCE the idle verdict — one pane read between two tool calls catches a transition frame where the busy shape is momentarily absent and ends the wait early (live 2026-07-24: a sentinel woke at ~20s on a worker still mid-task). Require N consecutive non-busy reads (3 worked) over a wider window, count Calling/Called/… as in-flight; the artifact/ledger leg stays the trusted exit, debounced-idle is only a scheduling hint.
Your own contract clauses can defeat your watcher's heuristic — check the two against each other before arming. Stage 2 mandates chunked writes (≤80 lines per append), which produce plateaus in output-file size between chunks. A watcher whose completion leg is "file size unchanged for N cycles" reads those plateaus as done (live 2026-07-25: a 3×30s size-stability leg declared ALL-DONE on a worker still 8KB from finished — the two rules were written by the same commander an hour apart). Stage 2's staging→mv publish dissolves this instance, but the duty survives it: a size-stability leg is only valid ANDed with a harness state read (agent_status != working) and given a window wider than the worker's slowest chunk gap. Generalize: after writing any watcher, re-read your own job contract and ask "which clause here produces a signal my watcher will misread?" — output-cadence rules (chunking, staged commits, batch sleeps) are the usual culprits. Keyword markers measured false on a live 12-seat fleet (2026-07-20): esc to interrupt renders in zero worker panes; bare tokens matches idle hints and completion summaries: [[silence-is-not-success]].
Two states must not be collapsed into busy/idle: waiting (parked on an interactive dialog — blocked on a human tap, the highest-value signal) and agents (prompt idle, background agent still turning); both read "idle" under a two-state model. Never nudge a waiting seat — answer its dialog. 答之前先重读 pane:Remote Control 时代 owner 可能已经坐在 worker 会话里亲手答掉了对话框(2026-08-21 实锤:哨报 blocked,commander 赶到时 owner 已从手机答完三问、worker 已恢复 working;owner 还顺手推翻了契约里的一条错误语义)——对话框已消失就别再答(双答=一条流浪 steering turn);owner 直连 worker 是 sanctioned 通道,其更正即 ground truth,优先于契约文字。 One nudge per task per watch; if the envelope still doesn't appear, escalate to the full four-surface recheck — if that's empty too, surface the seat as blocked. Never re-nudge.
Anomaly duty — the watcher's one real safety job: independently sanity-check whatever sits on the revenue / prod / irreversible path (CTA wiring, deploys, DB writes); if a worker is about to cross that line with a failing gate or mis-fix, STOP it and alert the user BEFORE the point of no return.
ctx-probe — long-context degradation measurement (2026-07-31, owner ruling: 嵌入日常不专门烧配额). Piggyback on any broadcast/steer/heartbeat to a seat: append three control questions whose answers MUST be in the seat's own context (session name, model+effort, SEAT.md path). Score 0-3 strictly; record {"seat","model","ctx_pct","score","answers","correct"} to ~/fleet/<concern>/ctx-probe/readings.jsonl. The probe is ONE message, not a conversation — ask, capture the JSON, score, move on. Accumulate readings across natural ctx% variation; once ≥20 data points exist per model, bucket by ctx% and plot the degradation curve. The curve answers "at what ctx% does this model start forgetting its own identity" — that's the compact trigger line. Scripts: ~/fleet/<concern>/ctx-probe/{probe.sh,score.sh}. First-round baseline (2026-07-31, 13 seats): 7/13 perfect at ctx 6–62%; session-name confusion is the first failure mode (Chinese alias vs tmux name); SEAT.md path fails on seats that never built one.
A shared ECONNRESET across several workers is usually a transport/proxy/upstream transient — probe connectivity and watch for auto-recovery before restarting; a self-recovered long context beats a restart. Shed load by stopping finished workers, not by killing a recovering one. Done = state read from transcript + process + deliverable, each live worker's delta/blocker/next statable.
5. Correct / continue safely
The harness's own slash commands are commander instruments — you can set a seat's /goal, arm a /loop, or /clear it without attaching, including on YOURSELF (owner directive 2026-08-06). A slash command is just prompt text, so the ordinary dispatch verb carries it: herdr agent prompt <pane> '/goal <objective>'. Use /goal to pin a seat's objective where its own footer will keep showing it, and /loop to make a seat self-pace a recurring check instead of you heartbeating it. Two measured traps — slash injection bypasses the job file and therefore its init-suppression line (a bare /goal makes the seat obey its repo CLAUDE.md and burn a full Session Init first), and --wait --until working times out against an already-working seat because no transition occurs, which is NOT proof of non-delivery. Consumption proof is the footer's ◎ /goal active (Ns), or the empty-❯+transcript pair. Mechanics and the identity-gate footer read: HERDR-WORKERS.md § Inject slash commands.
Inject the next batch (Stage 2's small-correction form) once the worker is idle at a checkpoint — workers often don't self-continue. The worker chat is disposable; disk state (queues / RESUME / skip-list) is the SoT. At high context: wait for a safe checkpoint, persist to disk, reset harness-correct — Claude Code /clear; Pi = replace the tab and relaunch off the disk SoT (HERDR-WORKERS § resetting a Pi seat; /compact is the in-flight-only rescue, PI-WORKERS § Context economy) — and re-inject the launch pointer.
A rebase/checkout dying with could not detach HEAD is an untracked collision until proven otherwise — an untracked file squats a path the incoming commits now track. Diagnose: git status --porcelain | grep '^??' ∩ git diff --name-only HEAD..origin/main; move or delete the stray and re-run. Never reset --hard / clean -fd on a shared checkout — sibling chats have uncommitted work there.
为测试而挪开的回滚物,其恢复或清理必须发生在读到测试结果之后的下一个批次,永不与被测动作同批。 批处理很容易把「执行动作」和「清理退路」写进同一次调用,于是在看到 rc 之前退路已经没了(2026-07-26 实锤:指挥官把一个完成标记改名挪开——手法正确、可逆——却在同一批命令里 rm 了那个改名文件;那一跑恰好失败,当日产物被留在半成品态,已无标记可还原)。改名保留是对的,同批清理把它作废了。
Outward or irreversible actions (publish, deploy, prod write) need the user's current-session explicit go — and where merging auto-deploys, the merge itself IS the deploy: gate it as such. Before retrying, verify present external state — a redirect is not proof. Dedupe before retry (Guardrails): e.g. after a TikTok /upload→/content, verify via unique-caption search + known-positive control + drafts/count/status before reposting. Record the final external status / URL / timestamp in the task artifact. Done = outward action authorized this session, confirmed against real external state, result recorded.
等待/验证 CI・deploy 时锚自己的 merge SHA,不锚「分支最新」;落地判据 = prod HEAD == 你的 merge SHA(或平台的 deployed-revision 标识)。 gh run list --branch main --limit 1 取到的是那一刻的最新 run;连环合并时它极可能属于上一个 merge(2026-07-18 实锤:#86 取 branch 最新 run 拿到 #85 的绿,prod HEAD 还在 #85)。正确姿势:gh run list --commit <merge-sha>。但 --commit 只看得见 push 事件的 run:PR 的 CI run(event=pull_request)用 head SHA 查会返回空集(2026-08-31 实锤:rebase 后推送的 PR 分支,--commit <head> 两分钟内一直 0 条,而 gh pr view --json statusCheckRollup 已显 IN_PROGRESS——等待器报「NO RUN CREATED」,是仪器的假阴性,不是 CI 没起)。等 PR 的 CI 锚 --branch <head-branch> 并断言 headSha,或 gh pr checks <n> --watch;等部署才锚 merge SHA。派 worker 验证同理:给 SHA、令回执回显它实际所在的 SHA,逐字相同才算数。
merge 命令裸跑,永不接管道;成功判据 = mergeCommit 非空。 gh pr merge … | tail -1 把失败退出码洗成 tail 的 0,&& 链照走(2026-07-19 实锤:draft PR 被拒,ack 与 watcher 照跑,watcher 拿空 SHA 空转)。draft 先 gh pr ready;merge 后立刻断言 mergeCommit 非空,空 = 没合上,别往下走。
等待循环必须两段:先证 X 存在,再证 X 终态——「未完成数==0」在空集上恒真。 merge 后 run 创建有数秒延迟,锚 commit 查询在其诞生前返回空集——循环直接穿过,读到的「成功 + prod HEAD」全是上一笔的(2026-07-19 #106 实锤)。推广:任何「等 X 完成」的轮询,若 X 由本次动作异步创建,先证存在、再证终态。
5b. Context management — 舰队比任何单个 context 都长寿
Worker 侧。 任务间无需决策:每个新 task_id 前按 harness 正确机制重置(Stage 2),不设百分比阈值;ctx% 只在 in-flight 中途有意义——逼顶走 Stage 5 落盘重启。清/杀前三件:idle、无未 ack 的 pending return、交付物已入 SoT。永不清 in-flight 的 worker;transient 网络错后恢复中的长 context 优先等待(Stage 4)。
Commander 侧。 对话锚是下条「磁盘交接书」的补充,不是主机制(SoT 在 ~/fleet/<concern>/SEAT.md)。/compact 前先在对话里写「压缩生存锚」(锚本体写对话——摘要会带上它):目标与完成判据、在飞单(task_id + 分支)、验收纪律链、现役哨 id、醒来第一动作。标准:压缩后的你零记忆也能只凭它续航(2026-07-18 两次实操无损)。compact 是队列命令:herdr agent prompt <self_pane> '/compact'(或在本席直接输入),本轮话说完再压,时机选回执间隙。ctx 60% 不是恐慌线;红线是「处理大单验收时才发现不够」。
常驻席磁盘交接书(标准条款 2026-07-30,owner 普及令)。 每个常驻 cmdr 席维护 ~/fleet/<concern>/SEAT.md(git 管;范本 ~/fleet/<concern>/SEAT.md),标准=「零记忆的下一个模型读完就能接着干」。对话锚是补充,交接书才是 SoT——摘要整体不可靠,丢 skill 只是特例,席位身份同样会被压掉;检测(Skills restored 行)会漏,冗余不会。三条硬要求:压缩前同步更新;压缩后第一动作读它;内里一切易变 id(pane/workspace/task_id/旗标)标注「用前重新 list」。协议全文见 fleet memory store 中的 seat-handover 协议。
时钟型承诺不能只写进锚——压缩后没人叫醒你。 锚只保证醒来后知道做什么,不保证按时醒来:任何「到点必做」(验收窗、派单点、测量点)在 compact/静默前必须挂外部闹钟(harness 的 cron/scheduled-wake 设施,或明确请 owner 到点唤人);二者都没有就把「迟到多久可接受」写进锚,醒来第一动作先对时并如实报迟(live 2026-07-24:19:20 canary 派单点因 compact 后无外部唤醒,23:10 才补派,迟 3h50m——锚写得再全也追不回时钟)。
Seat 生命周期 —— herdr tab/workspace 是弹性资源,不是固定编制。 concern 真正结束(交付已验收入 SoT、无后续单、无 pending return)的 seat 就关(关前 pane read 最后一屏留档;最后一单 ack 后 workspace close 是 ack 的一部分,owner ruling 2026-07-31 — HERDR-WORKERS § Close and worktrees);新 concern 就创造(tab create → agent start → footer 身份闸)。舰队规模跟活走——空转 tab 是负债(owner 一次截图抓出三个已完结 workspace 里 30 个空转 tab,2026-07-31)。边界:只关自己创建或 owner 点名的 seat(Stage 6);同 concern 还有后续单用 /clear 保 seat,concern 终结才关 workspace。
6. Verify handback and clean up
Completion = required outputs exist at their contracted paths, validations ran, and external state is unambiguous — verify each yourself against the actual result. A return envelope, when present, is a convenience: read its verdict early, then ack it — but grade the artifact, never the envelope's word. When absent, completion is still completion: grade the artifact, take the verdict from its fixed first line (Stage 2), and close with no ack to give. Then propagate one normalized return upward (topology and root case: Return channel §).
Checklist line 1 is identity, not content: "is this the artifact I dispatched?" For a PR, gh pr view <n> --json headRefName,state must match the branch the job file named; for a file, the path must be the one you owned to the worker. A mismatch is not an automatic reject — a re-cut or renamed branch can still be the right work — but must be explained before content is graded: a green gate on the wrong head proves nothing about the worker you dispatched (once skipped: merged a stale-shared-branch PR; the real worker's clean branch was closed as duplicate).
Identity has a second half — the right branch AND a current one — and git diff origin/main..HEAD is the wrong instrument. A worker branch cut at yesterday's main renders every commit main gained since as a deletion in that diff, so a fast-forward merge silently reverts them; the commits most at risk are the commander's own, still being written to main while the worker works. Live 2026-07-26: a four-file rewrite came back clean and self-checked, but its branch predated the commander's own measurement commit, so the diff listed a board file and two data files as removed. Grade the worker's actual change set with git show --stat <worker-commit>; use the base diff only after git fetch && git rebase origin/main has made the two agree. A worker's honest self-report cannot catch this — the drift is on your side of the fence.
证据必须真的走过它声称的那条路径 —— 「跑了第二次,rc=0」可以字面为真、实质为空。 2026-07-26 实锤:一份归档脚本的验收要求「再跑一次证明增量生效」,worker 照做并给出漂亮数字,但那一跑命中了脚本自己的当日完成标记早退分支(日志白纸黑字 result=already_complete),真正的重复拷贝路径一次都没执行过;指挥官把标记挪开真跑立刻 rc=1。两条义务:①派单要求「跑两次证明幂等」必须写明第二次要走真实路径,不得命中短路/守卫/缓存;②验收自证报告时不只读结论,要问这份证据执行的是不是它声称的那条分支——短路的证据就躺在 worker 自己贴出来的日志里。
钉子测试只有被反例撬红过才算存在。 验收 worker 新增的精确守卫时,在 disposable worktree 做 mutation proof:先跑语法检查;再注入最小反例(多一条 allowlist、被钉值漂到第三值、删掉关键比较),要求命名的钉子测试按预期报红且无关测试照过。只看绿测报告只能证明实现与测试彼此同意,不能证明测试抓得住漂移。读到原始红测结果后,按 §5 回滚物纪律恢复反例,再跑回绿;prod、外部状态与不可逆面不做 mutation probe。(2026-08-19:两次独立 mutation 分别只撬红 allowlist-cardinality/ruled-C 与 value-pin 测试,语法先验排除了 probe 自毁。)
任何「某维度为零 / 为空」的结论,发布前先问:这个零是测出来的,还是没测到? 空值有两种含义(未采到 / 采到为零),而它们在表里长得一模一样;默认后者会把一个采集故障做成一条战略结论。最便宜的判别 = 找第二次独立测量做交叉,看矛盾是否单向 —— 口径漂移是双向的,漏采是单向的。 实锤 2026-08-06:一份主结论把某词形判为「需求为零」并据此算出「212 倍」,红队拿同一供应商、同一 endpoint、同一地区的第二次测量交叉 2,582 个重叠对象:一侧判零而另一侧有量的 985 个,反向只有 3 个。985:3 的不对称无需知道供应商内部实现即可判定为上游漏采,漏掉的量比该结论声称的全池总量还多 83%。⇒ 这条与舰队共识 fleet-verify-checker-first(零命中≠不存在)同族,但它给的是判别方法:不是「保持怀疑」,是「跑这个交叉」。
Failing tests are adjudicated against base FIRST. Before attributing a failure to the worker, rerun it on the PR's base/main (2026-07-22: worker self-reported 25/25 green; independent rerun found 3 failures — all reproduced on pristine main, baseline debt). Verify the counting scope of any self-reported pass count — it may cover a subset.
Stop/close only seats you created or the user explicitly names; leave unrelated seats running. After launch, hand the user the exact monitor commands (herdr attaches the war-room TUI; herdr agent read <pane_id> --lines 200; herdr workspace list). On any surprise or correction, follow HARVEST.md at the next safe checkpoint — harvest during the run, not from memory at the end. Keep one methodology owner on skill files so implementation workers never race that surface.
Skill-extraction duty (owner ruling 2026-07-24): when the work itself reveals a reusable asset, the commander proposes the skill — the user should never have to. The tell: the same class of knowledge got earned more than once in a run, or it would obviously outlive this project and can't be trusted to project memory. At the next safe checkpoint ask one concrete question — "这类 X 要不要建个专门的 skill?" with a one-line scope sketch — then on approval run it as a normal dispatch (worker drafts from first-hand evidence, commander reviews/commits). Live case: five Semrush wire fixes in one day became semrush-dataforseo-api, owner-prompted; this duty exists so next time it isn't.
6b. 波次里的 JUDGE 席 —— 三条实测纪律(rewrite-wave b09–b11,2026-08-14)
一个「写手 ×N + judge ×1」的批量波次里,judge 不只是终点的闸,它还有准备期和基线。三条一手:
① judge 的准备期是空的,而控制组体检产出的正是写手此刻最需要的两个数 —— 提前发出去,比事后退件便宜一个数量级。
b09 的 judge 在两根写手分支还停在 origin/main 时就发了 advisory:①逐页 ÷3 目标数 11.2–12.2(照通用规格里的 ≤20 自查会在 judge 处失手);
②本批三页有仓库棘轮陷阱。结果:12/12 一次过、零退件、三页触发词全留,judge 预备承担的测试文件改动一次都没用上。
代价是 judge 空窗期里的十分钟。判据:控制组一跑完,就把「本批逐页目标数 + 本批特有的仓库陷阱」发给写手,不要攒到终报里。
(judge report 收割④;advisory 实物见 judge advisory 文件。
b10/b11 沿用,并进化出「early gate」——在写手提交前先跑一遍闸,b10 唯一一次真退件就是这么在成本最低处抓到的。)
② 波次自己的合入会在开工后移动基线:「origin/main」不是对照物,SHA 才是。
b09(#251)11:33 合入时,b10 的 W1 停在 7d7cc9b、W2 已 rebase 到 0ea87a5 —— 同一批的两位写手基线不同。
两个后果:①W2 的对照组写成 git checkout origin/main -- <目录>,静默把 b09 的 12 个无关页面一起换进来,
还原后表现为 MM(index 新 / worktree 旧),无冲突标记、CI 也不会说;
②judge 在 7d7cc9b 上建立的测试基线,在合并时已经不是合并基线,必须在 0ea87a5 重跑一遍——
两次读数相同是跑出来的结果,不是可以假设的。
判据:开工时 pin 一个 SHA、合并时重 pin;对照组回退的是具名路径、参照本树 HEAD,永远不写会移动的名字。
(judge report 收割③ + writer report 收割①;写手侧同条已进 a sibling copy-craft skill §7.4。)
③ 席位中途退场时的代执行,三条缺一不可。
b14 的 W2 席在 09e1c85 退场,退件还没来得及应用。judge 的处置(b05 先例)是:
①直接复核那个 commit(干净 worktree、跑出同一份 gate 输出)确认修复确实不在里面 —— 不信回执信 diff;
②自己应用,并在 commit message 里具名写明「judge 代 W2 执行」(692505a);
③措辞从该页自己的折叠层里取,不自创 —— 代执行的边界是「把已在这页上的话搬回正文」,不是替写手写新句子。
代价当场量了:severity 29.6 → 30.2,每页仍低于目标 1.0–1.5。
判据:代执行必须可被第三方还原成「谁在什么时候替谁做了什么」,否则下一批读 git log 会把它当成写手的手笔。
④ 松检查是「发信之前」的义务,不是收到申诉之后。 b14 judge 在退件前修掉了 8 条过紧检查 + 1 个渲染器构造;原样发出去 = 6 次假退件,分摊到两个写手身上就是一整晚。 反过来,他修检查的两次动作自己踩中了派单规则 2a 的两条(分支互相重叠、落盘双重转义)—— 所以 2a 不是「写 heredoc 时才看」的规矩,而是「任何一次程序化改判据文件之后」都要跑 branch audit。 全波基准率:gate-2 的 FAIL 绝大多数是尺子不是写手(b08 7/8 · b09 7/7 · b10 14/15 · b12 19/19 · b13 28/28)。
⑤ copy-forward 的仪器链,只和它最后一个「完整」的环一样好 —— 乱序判卷会静默弄断它。
b15 开工时 b14 judge 还在飞、从没写过披露检查器,于是 b15 取 _common 自 b14(最新,带 @if (now()->lt(…)) 时间闸求值器)、
取披露检查的形状自 b13(最后一个完整的),另起 30 条检查。这次没丢东西,是因为judge 注意到了。
判据:从一个未完成的批次继承仪器时,必须写明哪个文件来自哪里(b15 记在 out/rewrite-wave/b15/judge/PREP.md),
否则「沿用上一批」这句话会在无人察觉时停止为真。
⑥ 规格里的歧义要落进 job 文件,不许住在三位 judge 的脑子里。 「≤原值 1/3 或 ≤20」被 b13 judge 提请过一次,b14 judge 注意到但没再问,b15 judge 也没再问 —— 整个波次是按九位 judge 的既成先例(min 读法)发出去的。松读法下 b14/b15 共 15 页会是字面意义上的空转批。 一条会改变工作量本身的歧义,提请一次没有回音,就该升级追问,而不是沿用先例默默做完。 (该歧义已由 the adjudicating commander seat 08-14 深夜正式裁定,落在 a sibling copy-craft skill §1。)
⑦ 批次除不尽时,先广播读法再动手。
batch-15 只有 3 页,而派单写的是为 12 页设计的「W1 前六 / W2 后六」:一种读法 W1 拿 2、W2 拿 1,另一种正好相反。
失败方向不对称:重复认领 = 两席改同一个 partial、judge 合并冲突(派单定义为事故);漏认领 = 静默只交 3 页里的 2 页。
b15-W2 用 SendMessage 向刚起步的两席广播了自己的读法与兜底方案,~2 分钟内 W1 与 judge 双双确认。
判据:批次除不尽时,先发现的那一席广播读法 + 兜底,并在同侪或 judge 确认前不碰有争议的那一项 —— 没争议的那项永远可以立刻开工。
⑧ worker 自检脚本的汇总跑:逐条打印命令原文,且只接受 exit 0/1。
b11-W1 的一次 gate 汇总跑里,python3 $g(g="w1_disclosure.py --control")在 zsh 下没有分词,
静默变成「找不到该文件」→ exit 2;而 exit 2 混在一列退出码里极易被读成「校准跑过了但报错」。
zsh 不对未引用变量分词(舰队级 bash-env-zsh-sandbox 已记 ${=var}),但真正的判据是:
校准/消融这类自检的合法退出码只有 0(过)和 1(报缺),看见 2 就是压根没跑成。
(writer report 收割③。)
Return channel — Worker → immediate parent (an intermediate commander, if any) → Mastermind
Left→right dispatch is reliable; right→left completion is not unless someone polls — so completion is anchored to the artifact (Stage 2) and this channel rides on top, carrying the verdict earlier than a file read. Since 3.0.0 the wake wire is fabric-detected from the reply_to token: a herdr pane id (w6C:p7, the $HERDR_PANE_ID shape) is woken over the herdr socket API (pane send-text + a separate enter — live-verified 2026-08-20 into a herdr-hosted omp commander mid-turn), any other token takes the archived tmux lane (TMUX-ARCHIVE.md). A herdr-hosted commander's reply_to is therefore its own $HERDR_PANE_ID; the pre-3.0 "notify fails as expected under herdr" era is over, but the bell stays best-effort — a busy seat consumes the wake line only at its next turn boundary, and a worker may never run return at all. Every dispatched job still registers and names a return to the exact runtime reply_to (keep it in the contract under "nice to have", never Done-when); it gates nothing — a worker that ships the artifact and skips it has SUCCEEDED, and §4 already treats it that way. Topology is live state: inventory it per task, never infer the parent from a familiar pane name. A real hierarchy returns one hop to the immediate parent, which verifies and propagates one normalized return upward, minting a NEW task_id per hop (never re-register the inbound id upward — the upsert would clobber the worker's contract). Mastermind = the topmost seat the user talks to; its ack authority is the user's rulings, not its own. Root case: this commander IS the top — the chain terminates with ack + a report to the user, no upward return.
Typed lifecycle — ONE canonical card. Mechanics live in scripts/return-channel.py (durable mailbox outside any repo; atomic temp-write+rename envelope; pane validation; safe notify; mailbox-level lock since 4.17.0). Nine verbs; every CLI option, the four enum vocabularies, and the state-machine diagram live in --help — H4-truthful since 4.17.0, so read it, never restate it here. The lifecycle a job runs, in order:
register --owned-paths (conflict gate — overlap, equal or ancestor/descendant, with any ACTIVE non-acked/aborted task's owned_paths → registration REJECTED naming the conflict, zero side effects; serialize or stack instead) → dispatched + heartbeat --lease-seconds (an expired lease flips dispatched|started → lost on the QUERY side only; lost still HOLDS its owned_paths until a human abort — lost→acked is illegal, the only exits are re-dispatch or abort) → worker started → staging→mv → publish-task --result-paths (the single atomic finish act: verifies ALL paths exist → sha256 → commits the published ledger snapshot → wakes parent; any missing path = zero side effects even for a lease-expired task; the set must equal the REGISTERED result set, set-equality after canonicalization [enforced:H2] — the worker cannot swap deliverables; published is reachable ONLY here, never via transition [enforced:H3]) → commander verifies the real artifact → transition --to verified → acked. A join reads status/list (ledger state), never "directory non-empty" or pane text.
A live parent gets the wake leg — do not put --no-notify in an ordinary worker job. publish-task has two intentionally separate effects: durable published truth and a best-effort parent wake. --no-notify suppresses the second. It is legal only when the commander has deliberately installed a separate ledger joiner that will detect publication; a vague intention to check later is not one. Otherwise a worker can finish, publish, and sit idle while the commander keeps calling it active (2026-08-04: a herdr worker published seq 4 and went idle; its job-file --no-notify hid completion until the user noticed). Durable truth prevents loss, not delay.
Traps that outlive the mechanism — keep them in the body, --help cannot show them:
task_idbyte-for-byte identical inregisterand in the job file's return/publish command — a case mismatch (url-audit-avsurl-audit-A) survives on APFS only; on any case-sensitive volume the envelope writes to an unregistered id, the parent'spendingnever sees it, the return is silently lost (2026-07-25, caught by luck not a check). Generate the id once, paste into both; a case-sensitive watchergrepfails the same way.- register is an upsert keyed by
task_id: re-run with a new--worker-paneto re-point the contract, no dedupe, nothing downstream changes; a bare register stays v1-byte-identical and writes no ledger, while a register over an existing ledger opens a new attempt/generation. - A re-return revokes the earlier ack — a worker returning again on the same
task_id(the revise loop) sends the envelope back topendingso a sentry sees it (before 2026-07-18 a re-return afterack --decision revisewas invisible topending, and a missed wire line would sleep forever). Andackrides in the SAME batch as the disposition it acts on — a deferred ack is one the sweep finds weeks later. That sentence is the v1 lane only. In the typed laneackedis TERMINAL: a revise-roundpublish-taskafterackedis refused (illegal transition acked -> published, live 2026-08-31 — the worker had to message the commander to get the ledger reopened). While a revise loop is open, hold the task atverified; ack only when no further round is pending. Reopening isregister(upsert → new attempt) +transition --to dispatched— and EVERYregisterupsert (e.g. widening--owned-pathsmid-task) drops the state back toregistered, so thedispatchedtransition rides in the SAME batch as the register, every time. - v1 and typed are two lanes:
publish-taskdoes not writereturn.json; v1ackrequires it and does not advance the ledger. A migration-era commander receiving a v1 envelope still owes mtime-anchoring + same-batch ack + the re-return rule; don't assume every task is typed, and v1register/return/ackremain legal. - help is a PULL surface, not a push — its truth reaches only a session that runs it, so the non-obvious state changes above stay in this body.
status/outcome/decision/stateare FOUR never-conflated vocabularies (a review wanting edits isstatus=done outcome=changes_requested, neverstatus=CHANGES_REQUESTED); the wire carries enumerated fields + a pointer, worker prose lives only in the envelope. - queries are not pure reads —
status/list/transitionapply lease expiry (writelost) and lazily migrate legacy tasks; script watchers as side-effecting.
Worker 的非 return 上行(纠错/情报/更正)必须以 [FROM <pane>] 前缀开头 —— 裸文本上行读起来像「不知道谁发来的消息」(2026-07-19 一条裸文本纠错让用户误以为消息串错了窗口);且与一切约定一样,必须 bake 进 job file 才会存在于 worker 侧。
要求回执的跨席指令必须内嵌回执命令本身 —— 约定不随消息走,机制才随消息走。 [FROM] 与 return-channel 是本 skill 的约定,只存在于载入了它的席位;对方指挥席可能从未载入、/clear 后必然丢失(2026-07-21 实锤:请另一指挥席回一行确认,对方把回执写在自己 pane 当聊天输出,通道从未打通)。把回执命令逐字写进指令行。
跨席消息的「已送达」判据是对方的输入行为空,不是「pane read 里看得见我发的字」。 herdr pane read 会把输入框内容一并抓出——未提交的长消息读起来与已进 transcript 的一模一样(2026-07-26 tmux 时代实锤;机制同样适用于裸 send-text 通道:发完文本 + 单独 enter 后 capture 到全文判「已消费」,实际那段话在对方输入框躺了十几分钟)。正判据两条同时成立:❯ 那行是空的,且消息出现在输入框上方的 transcript 区;补 enter 前先隔一个真实间隔——连发两个 Enter 会被一起吞掉。首选 herdr agent prompt(自带提交与 stalled 检测语义);裸 pane send-text 只用于无 agent 检测的 pane。
Fleet-loss recovery (server death, reboot, tmp cleanup)
The default mailbox lives under a tmp-class path, while job files/contracts live in durable ~/fleet/<concern>/jobs/ — the recovery SoT (do NOT treat both as lost together). The herdr server holds the whole seat topology — a reboot or server crash voids every contract's panes at once, and workspace close is unrecoverable (processes killed, scrollback gone). Drill: ① census survivors per fabric — herdr workspace list + herdr agent list; legacy tmux seats, if the owner runs any, census per TMUX-ARCHIVE.md (the fabrics fail independently — measured 2026-07-23: a tmux server died and every herdr seat + the durable mailbox survived intact; the durable envelope carried the in-flight return). Does the mailbox dir still exist?; ② relaunch seats (Stage 2 recipes); ③ re-register every open task from its job file — register is an upsert, job files are the surviving SoT (if tmp died too, re-author from the boards); ④ one line per open task: contract restored, re-run your return. After ANY pane kill/recreate, re-register open contracts against the re-inventoried topology — a stored reply_to/pane id is a snapshot, not a live pointer.
Remote workers over ssh
A worker on another machine (24/7 Windows box, cloud host) fits the same loop with two substitutions: its herdr pane runs ssh <host>, and the watch surface becomes handback + machine state read over ssh — the files/configs it wrote and the actual effect (does the thing now work?), never its narration; its transcript lives in remote ~/.claude, unreachable. Verify self-reported facts by reading the machine (2026-06-17: a claimed pubkey was cat-read on the box and fingerprint-matched before prod authorization). A remote worker blocked on an authority it lacks (prod key, secret) stops and hands back — the commander often holds that authority: execute the gated step yourself after explicit user approval, least-privilege. Its memory is the remote machine's, useless to the main line — harvest into the canonical skillbook yourself.
Guardrails (the three true hard rules — everything above is a positive recipe)
- Harness-correct, serial delivery (§2): one one-line job pointer per seat via
herdr agent prompt, delivered serially; multiline pastes are the archived tmux fabric's mechanism and never cross a herdr wire (a multiline body into Pi fragments into queuedSteering:turns);herdr agent start/tab createNEVER inside a shell loop — loops silently start zero agents (measured twice 2026-08-14, HERDR-WORKERS § Launch). - Dedupe before any outward retry (§5): a possibly half-succeeded action (publish / deploy / post) is verified against present external state — a unique-key search plus a known-positive control — before a second attempt; a redirect or a queued message is never proof it landed.
- agent-view is not the chat editor, and the daemon is shared. The agent-view input box has different key semantics (enter = return, space = reply, ctrl+x = delete): each blind Enter can hatch a new background daemon session while the UI looks unsubmitted (once mis-hatched 3 ghost sessions; one opened a duplicate PR). So: before appending a message, confirm the pane is in chat view; for a parallel session, spin your own herdr tab (
herdr tab create+agent start) rather than poking agent-view; after any agent-view interaction, census what actually spawned. Ghosts live in the shared claude daemon — a dead TUI does not kill them; point-kill by the pid whose--session-id/--resume <jsonl>matches, never the daemon tree. Structural detail: [[cc-daemon-agent-view-sessions]].
Related: [[codebase-design]] (deep-module vocabulary). The retired [[overseer]] skill is this skill's predecessor — its live doctrine was absorbed here 2026-07-21; its two-chat-era machinery lives in git history at overseer 1.20.2. The tmux fabric was archived 2026-08-20 into TMUX-ARCHIVE.md (3.0.0); pre-3.0 tmux-native doctrine lives in git history at fleet-commander 2.1.0.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

