Task Triage — judge, dispatch, verify (the human keeps the last switch)
A task ledger grows faster than it drains because filing is the cheapest action anyone can
take. This skill is one cycle of a loop that drains it — not by implementing faster, but
by putting judgment first: every open task is re-read against the code and its own start
condition, and only what survives is dispatched. resolved / rejected / withdrawn /
obsoleted count as success exactly like done.
Roles (decided 2026-08-17, ADR-0043):
| Role |
Who |
Does |
Never does |
| Judge (this skill) |
the triage session (Fable-tier) |
premise check, worth check, better-solution check, condition check → verdict; writes kickoff packets; independently verifies build output; keeps the books |
files tasks on its own initiative, confirms a drop alone, merges to main, touches rules / ADR / hooks / published artifacts unattended |
| Build |
a fresh session per task (Opus-tier), in a git worktree |
Phase 0 premise re-check → implement → commit on the task branch with the evidence in the commit body |
changes acceptance conditions, merges, pushes, edits the ledger |
| Human |
the owner |
direction for tasks that need it, batch answers to the digest, the merge word |
watches individual sessions (attention is the scarce resource) |
The mechanism (Workflow tool, /loop, cron, Herdr) is the substrate's; this skill covers
only what to judge and how to keep the loop from running away (loop-design-check is the
lens it was designed with).
Vocabulary — do not invent states
Ledger states are draft / accepted / in_progress / blocked and the terminals
done / resolved / rejected / withdrawn / obsoleted (ADR-0050); blocked requires 再開条件 / 照合先 / 成立時,
便乗型 rows ("次に X を触るとき") do not belong in a ledger. The definitions live in
task-stocktake — read that section before the first triage. There is no "defer".
The verdicts of a triage are the states themselves:
| Verdict |
Meaning |
Who decides |
draft |
adoption still undecided → consult the human (one question at a time, see Digest) |
human |
accepted → dispatch |
premise verified file:line, condition met, acceptance decidable, reversible in a worktree, no rule change, fits one session |
judge (dispatch), human (merge) |
blocked |
adopted, and the three lines can be written; if the 照合先 can never fire (structurally unobservable), it is not blocked — re-ask |
judge writes the lines |
| terminal proposal |
premise gone / substrate now native / value < complexity (architect lens) / event source deleted (obsoleted) |
proposed by judge, confirmed by human |
| 台帳外 |
便乗 → a note at the code site, row closed |
judge proposes |
The cycle
0. Read the ledger without reading everything
Store repos: python3 ~/.claude/scripts/claims.py ready (and --state blocked|draft)
gives one line per task; open the file only for the ones you will judge. Single-table repos:
read the Pending table. Check claims.py open first — another session may hold a task.
Dead-band: a blocked task whose 照合先 you checked last cycle and whose state / condition
text has not changed is not re-read. Check only the 照合先 (a date, a command, a file, a
dependency's state) — many fire mechanically (gh pr view, grep -c, git log --since,
date). Record what you checked and the value.
1. Judge each open task (the part nobody else does)
For every task not in dead-band, in this order — stop at the first that decides it:
- Premise — does the code still have the problem? Quote
file:line. A refuted premise
is a terminal proposal (obsoleted if the object is gone, withdrawn if the choice is not to)
— never a dispatch. 2 of 7 premises were refuted the day this loop was designed by hand.
- Condition — for
blocked, did the 照合先 fire? "Fired" and "the event source was
deleted" are different (obsoleted). A condition that cannot be observed anymore drops the
task out of blocked.
- Worth — 複雑性 × 価値 × 使用頻度. Cheap now that dispatch is cheap: a 20-minute build
session changes the calculus for small
chore rows that were parked as "単独では着手しない".
For contested build-or-not, hand the question to the architect agent.
- Better solution — has the substrate absorbed it (a built-in command, a native flag)?
Verify by running it, not from memory (
claude plugin eval existed but was gated —
"native" is a claim to test).
- Ownership — a task that can only become
accepted in another repo is moved there as
draft and closed here as resolved.
Write the verdict and the one-line reason into the task (store: a dated section; table:
the 着手条件 cell). The reader of the ledger must not need this conversation.
2. Digest — one question per turn
The digest is where the human's attention is spent, so budget it: one decision per
message, in the order background → what is at stake → options → recommendation → cost /
reversibility. A ten-item numbered list looks efficient and is not — the owner asked for one
at a time on the first run. Bookkeeping that only applies the vocabulary (a satisfied
condition → accepted, adding the three lines, a resolved whose decision is already recorded)
can go as one blanket-OK list; anything that changes a rule, accepts a risk, spends money, or
drops a task is its own question.
When the cycle runs unattended (the launchd tick, see "Where the loop lives"), the digest is
still the session's own closing reply — the human answers here, so the reasoning must be
readable here (Remote Control shows the reply). Write every pending item into that reply, one
at a time, in the same order. Do not put the reasoning in a Slack message: a notify-slack.sh
argument is a Bash tool call, so its body is not part of the conversation the human returns to —
that is exactly the failure the owner hit on 2026-08-30 (had to read Slack while deciding here).
Slack gets one message per cycle, at the end, even when nothing needs the human:
bash ~/.claude/scripts/notify-slack.sh "<repo> triage cycle done" "N decisions pending: 1) <one-line title> 2) <one-line title> …" (0 decisions pending, no list, when there is nothing) — titles
only, never the reasoning. Two jobs: it is the liveness signal (its absence after a tick is the
alarm), and the titles let the owner judge from the phone whether returning now is worth it.
Slack is one-way.
When the human next speaks, act first on whatever answers that message already contains (a batch
reply like "T-002 は done、RFC-0005 も done" is normal and faster), then ask the remaining
decisions one at a time with AskUserQuestion.
Never treat text sitting in another session's input box as the human's answer — Claude Code
pre-fills suggested prompts there — and never treat a Slack reply as the answer either. The
merge word and the answers come in the triage session, or through the human's own hands.
3. Dispatch — packet, worktree, fresh session
Only accepted tasks, and at most 3 concurrent build sessions. Group tasks that share one
setup into one packet (three skill-comply chores became one session; three README notes in
three repos became one). Measurements (readings that decide the next state) dispatch just as
well as implementations — often better: read-only, decidable, reversible.
Per task or bundle:
claims.py claim T-XXX --label "S<n>: <what> (Opus session, worktree <branch>; judge=…, merge=human)"
git -C <repo> worktree add .claude/worktrees/<name> -b task/<name> main — and copy the
repo's untracked .claude/settings.local.json (and project hooks / skills if gitignored)
into the worktree, or the session runs without the allowlist. .claude/worktrees/ must be
ignored in that repo. Sibling repos: worktree under the scratchpad, never a branch
checkout in their main tree.
- Write the packet from
references/packet-template.md — goal as decidable acceptance,
Phase 0 premise re-check with the instruction "if refuted, stop and report — do not
implement", must-not list, the task type (feat / fix / refactor / chore / measurement)
with the review chain delegated to implementation-chain — never a hand-written list
of reviewers (a name left off reads as permission to skip: one build skipped /simplify
because the packet had not named it), and the commit-message report (the only evidence
that survives the pane). State the default plainly: what the packet does not mention is
governed by the harness rules, not waived by silence.
- Start the build — pick the mechanism by the kind of work:
- Measurement / read-only / docs-only →
Agent(model: opus, isolation: worktree); three or
more with one setup → the Workflow tool (pipeline, build and judge as separate agent()
calls, schema for the reading). The result returns in-process, no pane, no cleanup.
- Implementation that must run the full review chain, may run long, or may hit permission
prompts → an interactive session via
spawn-session (Herdr, Remote Control) so hooks,
skills and the chain run in the normal environment and the owner can approve from the
phone: bash ~/.claude/skills/spawn-session/spawn.sh <worktree> "<repo>/s<n>-<slug>" →
herdr agent prompt "<agent-name>" "<packet text>" --wait --timeout 60000 — the first
prompt often returns timeout while landing fine; confirm with herdr agent read.
agent_status: done means the REPL is idle, not that the work is done — a background
shell may still run. claude --bg -w <name> --model opus "<prompt>" is the detached
alternative (completion via claude agents --json).
Unverified as of 2026-08-17 (test on a measurement batch first, where failure is free):
whether hooks fire identically inside subagents, whether the chain's skills are equally
available there, and how permission prompts surface — if all three hold, implementations
can move to Workflow too.
- Watch for artifacts, not status: a commit on the task branch, the reading file, a
section in the memo.
Monitor with a poll loop, exit when all artifacts exist.
4. Judge the output — independent, deterministic first
The build session's report is a claim. Before asking for the merge word:
git diff --stat main..task/<name> — only the files the packet allowed. If main moved since
the worktree was cut, the diff shows the missing main commits: git rebase main in the
worktree first (a build branch never has a right to a merge commit).
- Run the repo's
verify.sh (or tests) yourself in the worktree — the packet said the
session ran it; you run it again. Then read the commit body: premise, fix, verify, review,
out-of-diff findings.
- Anything the packet forbade that the diff contains → bounce, do not fix it yourself.
- Compliance with the packet and the chain: did the build run the chain for its type
(
implementation-chain), keep the must-nots, and stop at the acceptance line? A deviation is
acceptable only when the report names it as a deviation with a reason ("E2E 省略:
UI 非接触" / "premise refuted, corrected instead of stopping — because …"). A silent
deviation — something skipped or done differently without saying so — is a bounce even if
the result looks right, because the next build learns from what the last one got away with.
- Harvest what the build hands back — but ask the human only what the rule says to ask.
Read the commit body and the final message. Two kinds reach the digest as decisions:
(1) out-of-diff findings that break the loop itself (the next build would bounce on
them — e.g. a verify.sh blind spot) with a verified producer → propose filing
(
spawn --origin review --producer), per skill task-stocktake's 起票規律 (ADR-0055) — the filing itself (numbering, template, index row) follows
skill rfc-writer; (2) explicit filing requests
that are the deliverable of a measurement / probe task (a probe's "(B)/(C) はやる価値がある",
an instrument finding such as "the metrics are polluted") — these are not review findings,
they are the task's output, and the build has no authority to file them. All other review
findings, HIGH included, are discarded by the rule: they stay in the commit body
(producer 付き 1 行), and the digest reports
only their count ("diff 外 findings: 3 件、commit body 参照") — no list, no question.
Observations that are not tasks (a rate near a revert threshold, a measurement caveat) are
one line each. The judge never files on its own initiative.
5. Merge on the human's word, then close the books
git -C <repo> merge --ff-only task/<name> → run verify on main again → claims.py release T-XXX --outcome done --commit <sha> → state done <date> in the ledger (an
rfcs/ entry stays in place as a public decision record — ADR-0049) → git worktree remove +
git branch -d → close the build
session's pane (herdr pane close <pane_id>; the pane is not evidence — the commit body is).
Never close panes you did not spawn.
- If the merge changed a pinned gate script (
.claude/verify.sh), the approval ledger needs
the human's verify_allow.py approve <repo> after the merge — say so explicitly, once
per such merge, and check with verify_allow.py check that it happened. A gate that quietly
went dormant is worse than a red one.
- Unmerged branches are the queue:
git branch --no-merged main per repo. The digest lists
them with their evidence; the human says which; the judge types the merge.
- Cycle-end digest: open before → after with the closed / spawned split, the unmerged
queue, the harvest list (file / drop / observe — the human's call), and the questions still
waiting. All of it in the session's reply (§2); Slack gets the one-line titles only.
Damping and boundaries (what makes this a loop and not a runaway)
- WIP ≤ 3 build sessions; open task branches ≤ 3 per repo; one retry per task per cycle; a
build that stalls or fails twice goes back to the digest.
- The loop files nothing on its own (admission stays with humans and the review rule);
drops nothing alone; never merges, publishes, or touches rules / ADR / hooks / security
gates unattended; never changes the filing rule while its measurement is running.
- Success is reconciliation, not throughput: per cycle report
open before → after,
closed (done + resolved + rejected + withdrawn + obsoleted) vs spawned, and where the spawns came from
(claims.jsonl origins). A cycle that raises open count is not a bad cycle if the spawns
were the human's; a cycle that "wins" by mass drops is.
- Two questions the loop deliberately does not answer (state them, measure them): what a
build session does with side-findings (this harness: loop-breaking defect with verified
producer → file after asking; everything else, HIGH included → one line in the commit
body), and who prunes spawned-but-unstarted work (here: the human, at the digest).
Where the loop lives — one orchestrator session per repo
The timer is outside the session; the executor is inside; the answers are inside only.
One standing triage session per repo, with that repo as cwd, Remote Control on so the
digest can be answered from the phone. It holds no timer of its own: launchd runs
scripts/triage-tick.sh <repo> <agent-name> "<display>" at the repo's slots
(scripts/launchd/com.shimomoto.triage-{harness,ca}.plist, installed in
~/Library/LaunchAgents/); the tick finds the live triage agent by its fixed Herdr name
(triage-harness / triage-ca), spawns one via spawn-session if none exists, and submits
the cycle prompt with herdr agent prompt. The tick never reads the ledger; it only reports
its own anomalies to Slack (spawned a new session because none was alive, spawn failed,
prompt stalled twice, session blocked, previous cycle still working → skipped). The human starts nothing: that is the point of the loop.
A repo's loop needs the repo's context — its ADRs, its ledger vocabulary quirks, its verify
gate, its concurrent worktrees — so one session judges one repo; a cross-repo session pays
that reading twice and dilutes both.
The session is long-lived but not eternal, and it does not renew itself: the last step
of a cycle compares claude --version with the version it started under and checks its own
age; if the CLI has updated or the session is older than ~7 days, it finishes the cycle and
exits — the next tick spawns a fresh one. No in-session cron, no successor handoff. Between
cycles the memory is the ledger (verdicts and reasons are written into the tasks), so
auto-compaction of the standing session costs nothing the next cycle needs, and a fresh
session resumes from the ledger alone. Cross-repo effects travel only through the ledgers
(a task moved as draft, an ADR link), never through a session's memory. The judge and
the builds may be different model tiers on purpose: judgment errors are the expensive ones
(a missed refuted premise wastes the whole build), so the orchestrator is the strongest tier
available and the builds are the fast tier.
Cadence
On demand until the judgments are stable across two or three cycles; then scheduled, aligned
with whatever weekly gate the repo already has (a Saturday packet, a review day). Not daily —
most blocked tasks are in dead-band and the digest is the expensive part. Order within a
cycle: task-stocktake (ledger hygiene) first when it is due, then this skill.
| repo tempo |
task-triage |
task-stocktake |
| slow (a harness, a small table) |
weekly |
weekly, same day, before triage |
| fast (a research repo with a review chain feeding it) |
twice a week — e.g. mid-week + the day of its weekly gate |
weekly |
The timer is launchd (scripts/triage-tick.sh, see above): harness Sun 06:30 (stocktake →
triage); CA Wed 17:07 (triage) and Sat 14:07 (stocktake → triage, after the Saturday
pipeline's 13:30 packet deadline and before the human gate). The tick's default for
"stocktake due" is the weekday (Saturday) so a repo with two slots keeps one plist — but a
repo with a single weekly slot must pass --stocktake in its plist, or moving that slot off
Saturday silently kills the stocktake half (harness hit exactly this when it moved off
Saturday 2026-08-29).
The plists live in scripts/launchd/ and are copied to ~/Library/LaunchAgents/; after
editing one, launchctl bootout + bootstrap it and confirm with launchctl print — an
edited file that was never reloaded keeps firing on the old schedule. Do not use in-session CronCreate
or /loop for this — session-only, 7-day expiry, and silent when the session dies. A cycle
that fires while the human is away still does everything up to the digest — 条件 checks,
vocabulary-only bookkeeping, dispatch of accepted work within WIP, verification of finished
builds — then sends the digest to Slack (one message per decision) and the closing line;
consults and merges wait for the human in the session. The session's context is not the
loop's memory: verdicts live in the tasks, so the standing session can be /cleared and
re-enter the cycle from the ledger.
Related
task-stocktake — vocabulary and ledger form (the authority this skill applies)
loop-design-check — the lens: decidable goal, judge independence, red lines
llm-as-judge — how the judge speaks when a semantic verdict is unavoidable
architect agent — contested build-or-not
spawn-session — the session mechanism this harness uses for build sessions and for the
standing triage session (spawned by the tick when none is alive)
scripts/triage-tick.sh / scripts/launchd/*.plist — the timer (launchd) that drives the
standing session; scripts/notify-slack.sh — the one-way Slack channel for the digest
(ADR-0045)
references/packet-template.md — kickoff packet skeleton (build and measurement variants)
references/first-cycle-2026-08-17.md — the hand-run cycle this skill was distilled from
1---2name: task-triage3description: Run one cycle of the task-triage loop over a repo's task ledger — judge every open task (verify its premise in code, check its start condition against the 照合先, decide whether it is still worth doing, look for a better solution), then dispatch the accepted ones to fresh implementation sessions and act as their independent judge until the human merges. Use when the user says 「残タスクを見て」「タスクを整理して」「台帳を回して」「dispatch して」「未マージある?」, invokes /task-triage, or when a task ledger has grown and nobody can say what is dispatchable. This skill is the judgment layer of the loop (Fable = judge, Opus sessions = build, human = last switch); the vocabulary of ledger states is owned by task-stocktake and is not redefined here. NOT for consolidating scattered task files into a ledger (task-stocktake), NOT for deciding a single build-or-not question (architect), and NOT for running a task yourself — a triage session reads, judges, dispatches and verifies; it does not implement.4license: MIT5---67# Task Triage — judge, dispatch, verify (the human keeps the last switch)89A task ledger grows faster than it drains because filing is the cheapest action anyone can10take. This skill is one **cycle** of a loop that drains it — not by implementing faster, but11by putting judgment first: every open task is re-read against the code and its own start12condition, and only what survives is dispatched. `resolved` / `rejected` / `withdrawn` /13`obsoleted` count as success exactly like `done`.1415Roles (decided 2026-08-17, ADR-0043):1617| Role | Who | Does | Never does |18|---|---|---|---|19| **Judge** (this skill) | the triage session (Fable-tier) | premise check, worth check, better-solution check, condition check → verdict; writes kickoff packets; independently verifies build output; keeps the books | files tasks on its own initiative, confirms a drop alone, merges to main, touches rules / ADR / hooks / published artifacts unattended |20| **Build** | a fresh session per task (Opus-tier), in a git worktree | Phase 0 premise re-check → implement → commit on the task branch with the evidence in the commit body | changes acceptance conditions, merges, pushes, edits the ledger |21| **Human** | the owner | direction for tasks that need it, batch answers to the digest, the merge word | watches individual sessions (attention is the scarce resource) |2223The mechanism (Workflow tool, `/loop`, cron, Herdr) is the substrate's; this skill covers24only what to judge and how to keep the loop from running away (`loop-design-check` is the25lens it was designed with).2627## Vocabulary — do not invent states2829Ledger states are `draft` / `accepted` / `in_progress` / `blocked` and the terminals30`done` / `resolved` / `rejected` / `withdrawn` / `obsoleted` (ADR-0050); `blocked` requires 再開条件 / 照合先 / 成立時,31便乗型 rows ("次に X を触るとき") do not belong in a ledger. The definitions live in32`task-stocktake` — read that section before the first triage. There is no "defer".3334The verdicts of a triage are the states themselves:3536| Verdict | Meaning | Who decides |37|---|---|---|38| `draft` | adoption still undecided → **consult** the human (one question at a time, see Digest) | human |39| `accepted` → dispatch | premise verified `file:line`, condition met, acceptance decidable, reversible in a worktree, no rule change, fits one session | judge (dispatch), human (merge) |40| `blocked` | adopted, and the three lines can be written; if the 照合先 can never fire (structurally unobservable), it is not `blocked` — re-ask | judge writes the lines |41| terminal proposal | premise gone / substrate now native / value < complexity (`architect` lens) / event source deleted (`obsoleted`) | proposed by judge, **confirmed by human** |42| 台帳外 | 便乗 → a note at the code site, row closed | judge proposes |4344## The cycle4546### 0. Read the ledger without reading everything4748Store repos: `python3 ~/.claude/scripts/claims.py ready` (and `--state blocked|draft`)49gives one line per task; open the file only for the ones you will judge. Single-table repos:50read the Pending table. Check `claims.py open` first — another session may hold a task.5152**Dead-band**: a `blocked` task whose 照合先 you checked last cycle and whose state / condition53text has not changed is not re-read. Check only the 照合先 (a date, a command, a file, a54dependency's state) — many fire mechanically (`gh pr view`, `grep -c`, `git log --since`,55`date`). Record what you checked and the value.5657### 1. Judge each open task (the part nobody else does)5859For every task not in dead-band, in this order — stop at the first that decides it:60611. **Premise** — does the code still have the problem? Quote `file:line`. A refuted premise62 is a terminal proposal (`obsoleted` if the object is gone, `withdrawn` if the choice is not to)63 — never a dispatch. 2 of 7 premises were refuted the day this loop was designed by hand.642. **Condition** — for `blocked`, did the 照合先 fire? "Fired" and "the event source was65 deleted" are different (`obsoleted`). A condition that cannot be observed anymore drops the66 task out of `blocked`.673. **Worth** — 複雑性 × 価値 × 使用頻度. Cheap now that dispatch is cheap: a 20-minute build68 session changes the calculus for small `chore` rows that were parked as "単独では着手しない".69 For contested build-or-not, hand the question to the `architect` agent.704. **Better solution** — has the substrate absorbed it (a built-in command, a native flag)?71 Verify by running it, not from memory (`claude plugin eval` existed but was gated —72 "native" is a claim to test).735. **Ownership** — a task that can only become `accepted` in another repo is moved there as74 `draft` and closed here as `resolved`.7576Write the verdict and the one-line reason **into the task** (store: a dated section; table:77the 着手条件 cell). The reader of the ledger must not need this conversation.7879### 2. Digest — one question per turn8081The digest is where the human's attention is spent, so budget it: **one decision per82message**, in the order background → what is at stake → options → recommendation → cost /83reversibility. A ten-item numbered list looks efficient and is not — the owner asked for one84at a time on the first run. Bookkeeping that only applies the vocabulary (a satisfied85condition → `accepted`, adding the three lines, a `resolved` whose decision is already recorded)86can go as one blanket-OK list; anything that changes a rule, accepts a risk, spends money, or87drops a task is its own question.8889When the cycle runs unattended (the launchd tick, see "Where the loop lives"), **the digest is90still the session's own closing reply** — the human answers here, so the reasoning must be91readable here (Remote Control shows the reply). Write every pending item into that reply, one92at a time, in the same order. Do **not** put the reasoning in a Slack message: a `notify-slack.sh`93argument is a Bash tool call, so its body is not part of the conversation the human returns to —94that is exactly the failure the owner hit on 2026-08-30 (had to read Slack while deciding here).9596Slack gets **one message per cycle**, at the end, even when nothing needs the human:97`bash ~/.claude/scripts/notify-slack.sh "<repo> triage cycle done" "N decisions pending: 1) <one-line98title> 2) <one-line title> …"` (`0 decisions pending`, no list, when there is nothing) — titles99only, never the reasoning. Two jobs: it is the liveness signal (its absence after a tick is the100alarm), and the titles let the owner judge from the phone whether returning now is worth it.101Slack is **one-way**.102103When the human next speaks, act first on whatever answers that message already contains (a batch104reply like "T-002 は done、RFC-0005 も done" is normal and faster), then ask the remaining105decisions one at a time with `AskUserQuestion`.106107Never treat text sitting in another session's input box as the human's answer — Claude Code108pre-fills suggested prompts there — and never treat a Slack reply as the answer either. The109merge word and the answers come **in the triage session**, or through the human's own hands.110111### 3. Dispatch — packet, worktree, fresh session112113Only `accepted` tasks, and at most **3 concurrent build sessions**. Group tasks that share one114setup into one packet (three skill-comply chores became one session; three README notes in115three repos became one). Measurements (readings that decide the next state) dispatch just as116well as implementations — often better: read-only, decidable, reversible.117118Per task or bundle:1191201. `claims.py claim T-XXX --label "S<n>: <what> (Opus session, worktree <branch>; judge=…, merge=human)"`1212. `git -C <repo> worktree add .claude/worktrees/<name> -b task/<name> main` — and copy the122 repo's untracked `.claude/settings.local.json` (and project hooks / skills if gitignored)123 into the worktree, or the session runs without the allowlist. `.claude/worktrees/` must be124 ignored in that repo. Sibling repos: worktree under the scratchpad, never a branch125 checkout in their main tree.1263. Write the packet from `references/packet-template.md` — goal as **decidable acceptance**,127 Phase 0 premise re-check with the instruction "if refuted, stop and report — do not128 implement", must-not list, the **task type** (feat / fix / refactor / chore / measurement)129 with the review chain **delegated to `implementation-chain`** — never a hand-written list130 of reviewers (a name left off reads as permission to skip: one build skipped `/simplify`131 because the packet had not named it), and the **commit-message report** (the only evidence132 that survives the pane). State the default plainly: *what the packet does not mention is133 governed by the harness rules, not waived by silence.*1344. Start the build — **pick the mechanism by the kind of work**:135 - *Measurement / read-only / docs-only* → `Agent(model: opus, isolation: worktree)`; three or136 more with one setup → the Workflow tool (`pipeline`, build and judge as separate `agent()`137 calls, `schema` for the reading). The result returns in-process, no pane, no cleanup.138 - *Implementation that must run the full review chain, may run long, or may hit permission139 prompts* → an interactive session via `spawn-session` (Herdr, Remote Control) so hooks,140 skills and the chain run in the normal environment and the owner can approve from the141 phone: `bash ~/.claude/skills/spawn-session/spawn.sh <worktree> "<repo>/s<n>-<slug>"` →142 `herdr agent prompt "<agent-name>" "<packet text>" --wait --timeout 60000` — the first143 prompt often returns `timeout` while landing fine; confirm with `herdr agent read`.144 `agent_status: done` means the REPL is idle, **not** that the work is done — a background145 shell may still run. `claude --bg -w <name> --model opus "<prompt>"` is the detached146 alternative (completion via `claude agents --json`).147 Unverified as of 2026-08-17 (test on a measurement batch first, where failure is free):148 whether hooks fire identically inside subagents, whether the chain's skills are equally149 available there, and how permission prompts surface — if all three hold, implementations150 can move to Workflow too.1515. Watch for **artifacts**, not status: a commit on the task branch, the reading file, a152 section in the memo. `Monitor` with a poll loop, exit when all artifacts exist.153154### 4. Judge the output — independent, deterministic first155156The build session's report is a claim. Before asking for the merge word:157158- `git diff --stat main..task/<name>` — only the files the packet allowed. If main moved since159 the worktree was cut, the diff shows the *missing* main commits: `git rebase main` in the160 worktree first (a build branch never has a right to a merge commit).161- Run the repo's `verify.sh` (or tests) **yourself** in the worktree — the packet said the162 session ran it; you run it again. Then read the commit body: premise, fix, verify, review,163 out-of-diff findings.164- Anything the packet forbade that the diff contains → bounce, do not fix it yourself.165- **Compliance with the packet and the chain**: did the build run the chain for its type166 (`implementation-chain`), keep the must-nots, and stop at the acceptance line? A deviation is167 acceptable only when the report *names it as a deviation with a reason* ("E2E 省略:168 UI 非接触" / "premise refuted, corrected instead of stopping — because …"). A silent169 deviation — something skipped or done differently without saying so — is a bounce even if170 the result looks right, because the next build learns from what the last one got away with.171- **Harvest what the build hands back — but ask the human only what the rule says to ask.**172 Read the commit body and the final message. Two kinds reach the digest as decisions:173 (1) **out-of-diff findings that break the loop itself** (the next build would bounce on174 them — e.g. a verify.sh blind spot) with a verified producer → propose filing175 (`spawn --origin review --producer`), per skill `task-stocktake`'s 起票規律 (ADR-0055) — the filing itself (numbering, template, index row) follows176 skill `rfc-writer`; (2) **explicit filing requests177 that are the deliverable of a measurement / probe task** (a probe's "(B)/(C) はやる価値がある",178 an instrument finding such as "the metrics are polluted") — these are not review findings,179 they are the task's output, and the build has no authority to file them. All other review180 findings, **HIGH included**, are **discarded by the rule**: they stay in the commit body181 (producer 付き 1 行), and the digest reports182 only their count ("diff 外 findings: 3 件、commit body 参照") — no list, no question.183 Observations that are not tasks (a rate near a revert threshold, a measurement caveat) are184 one line each. The judge never files on its own initiative.185186### 5. Merge on the human's word, then close the books187188- `git -C <repo> merge --ff-only task/<name>` → run verify on `main` again → `claims.py189 release T-XXX --outcome done --commit <sha>` → state `done <date>` in the ledger (an190 `rfcs/` entry stays in place as a public decision record — ADR-0049) → `git worktree remove` +191 `git branch -d` → close the build192 session's pane (`herdr pane close <pane_id>`; the pane is not evidence — the commit body is).193 Never close panes you did not spawn.194- If the merge changed a pinned gate script (`.claude/verify.sh`), the approval ledger needs195 the human's `verify_allow.py approve <repo>` **after** the merge — say so explicitly, once196 per such merge, and check with `verify_allow.py check` that it happened. A gate that quietly197 went dormant is worse than a red one.198- Unmerged branches are the queue: `git branch --no-merged main` per repo. The digest lists199 them with their evidence; the human says which; the judge types the merge.200- **Cycle-end digest**: open before → after with the closed / spawned split, the unmerged201 queue, the harvest list (file / drop / observe — the human's call), and the questions still202 waiting. All of it in the session's reply (§2); Slack gets the one-line titles only.203204## Damping and boundaries (what makes this a loop and not a runaway)205206- WIP ≤ 3 build sessions; open task branches ≤ 3 per repo; one retry per task per cycle; a207 build that stalls or fails twice goes back to the digest.208- The loop **files nothing on its own** (admission stays with humans and the review rule);209 **drops nothing alone**; never merges, publishes, or touches rules / ADR / hooks / security210 gates unattended; never changes the filing rule while its measurement is running.211- Success is reconciliation, not throughput: per cycle report `open before → after`,212 `closed (done + resolved + rejected + withdrawn + obsoleted)` vs `spawned`, and where the spawns came from213 (`claims.jsonl` origins). A cycle that raises open count is not a bad cycle if the spawns214 were the human's; a cycle that "wins" by mass drops is.215- Two questions the loop deliberately does not answer (state them, measure them): what a216 build session does with side-findings (this harness: loop-breaking defect with verified217 producer → file after asking; everything else, HIGH included → one line in the commit218 body), and who prunes spawned-but-unstarted work (here: the human, at the digest).219220## Where the loop lives — one orchestrator session per repo221222**The timer is outside the session; the executor is inside; the answers are inside only.**223One **standing triage session per repo, with that repo as cwd**, Remote Control on so the224digest can be answered from the phone. It holds no timer of its own: launchd runs225`scripts/triage-tick.sh <repo> <agent-name> "<display>"` at the repo's slots226(`scripts/launchd/com.shimomoto.triage-{harness,ca}.plist`, installed in227`~/Library/LaunchAgents/`); the tick finds the live triage agent by its fixed Herdr name228(`triage-harness` / `triage-ca`), spawns one via `spawn-session` if none exists, and submits229the cycle prompt with `herdr agent prompt`. The tick never reads the ledger; it only reports230its own anomalies to Slack (spawned a new session because none was alive, spawn failed,231prompt stalled twice, session `blocked`, previous cycle still `working` → skipped). The human starts nothing: that is the point of the loop.232A repo's loop needs the repo's context — its ADRs, its ledger vocabulary quirks, its verify233gate, its concurrent worktrees — so one session judges one repo; a cross-repo session pays234that reading twice and dilutes both.235236The session is long-lived but **not eternal, and it does not renew itself**: the last step237of a cycle compares `claude --version` with the version it started under and checks its own238age; if the CLI has updated or the session is older than ~7 days, it finishes the cycle and239exits — the next tick spawns a fresh one. No in-session cron, no successor handoff. Between240cycles the memory is the ledger (verdicts and reasons are written into the tasks), so241auto-compaction of the standing session costs nothing the next cycle needs, and a fresh242session resumes from the ledger alone. Cross-repo effects travel only through the ledgers243(a task moved as `draft`, an ADR link), never through a session's memory. The judge and244the builds may be different model tiers on purpose: judgment errors are the expensive ones245(a missed refuted premise wastes the whole build), so the orchestrator is the strongest tier246available and the builds are the fast tier.247248## Cadence249250On demand until the judgments are stable across two or three cycles; then scheduled, aligned251with whatever weekly gate the repo already has (a Saturday packet, a review day). Not daily —252most `blocked` tasks are in dead-band and the digest is the expensive part. Order within a253cycle: `task-stocktake` (ledger hygiene) first when it is due, then this skill.254255| repo tempo | task-triage | task-stocktake |256|---|---|---|257| slow (a harness, a small table) | weekly | weekly, same day, before triage |258| fast (a research repo with a review chain feeding it) | twice a week — e.g. mid-week + the day of its weekly gate | weekly |259260The timer is launchd (`scripts/triage-tick.sh`, see above): harness Sun 06:30 (stocktake →261triage); CA Wed 17:07 (triage) and Sat 14:07 (stocktake → triage, after the Saturday262pipeline's 13:30 packet deadline and before the human gate). The tick's *default* for263"stocktake due" is the weekday (Saturday) so a repo with two slots keeps one plist — but a264repo with a single weekly slot must pass `--stocktake` in its plist, or moving that slot off265Saturday silently kills the stocktake half (harness hit exactly this when it moved off266Saturday 2026-08-29).267268The plists live in `scripts/launchd/` and are copied to `~/Library/LaunchAgents/`; after269editing one, `launchctl bootout` + `bootstrap` it and confirm with `launchctl print` — an270edited file that was never reloaded keeps firing on the old schedule. Do not use in-session `CronCreate`271or `/loop` for this — session-only, 7-day expiry, and silent when the session dies. A cycle272that fires while the human is away still does everything up to the digest — 条件 checks,273vocabulary-only bookkeeping, dispatch of `accepted` work within WIP, verification of finished274builds — then sends the digest to Slack (one message per decision) and the closing line;275consults and merges wait for the human in the session. The session's context is not the276loop's memory: verdicts live in the tasks, so the standing session can be `/clear`ed and277re-enter the cycle from the ledger.278279## Related280281- `task-stocktake` — vocabulary and ledger form (the authority this skill applies)282- `loop-design-check` — the lens: decidable goal, judge independence, red lines283- `llm-as-judge` — how the judge speaks when a semantic verdict is unavoidable284- `architect` agent — contested build-or-not285- `spawn-session` — the session mechanism this harness uses for build sessions and for the286 standing triage session (spawned by the tick when none is alive)287- `scripts/triage-tick.sh` / `scripts/launchd/*.plist` — the timer (launchd) that drives the288 standing session; `scripts/notify-slack.sh` — the one-way Slack channel for the digest289 (ADR-0045)290- `references/packet-template.md` — kickoff packet skeleton (build and measurement variants)291- `references/first-cycle-2026-08-17.md` — the hand-run cycle this skill was distilled from