Owner-ratified 2026-07-20: architect, grounding-check, tdd-author and
debugger pin fable/xhigh — cycle-reach singleton gates whose miss
silently ratifies or poisons an entire cycle (drift verdict, autonomous
sign-off signature, RED executable-spec, root-cause). The set is
closed: extending it requires fresh owner ratification, no fable agent
ever runs per-task in a loop or in a parallel fan-out, and workflow
scripts stay fable-free (the implement-loop quality gate caps at opus).
Policy home: docs/agent-template.md $ model rule 1 (effort: fable
gates stay xhigh, not max); the workflow policy headers now point at
the exception instead of the former blanket ban.
The anonymous script stages received the full standing-reading
instruction (project CLAUDE.md + git log -10 --format=full) although
a tree-footprint or text-extraction stage consumes none of it and a
verify stage needs only the build/test commands — re-executed on
every dispatch including tight repair rounds, at ~40k+ real tokens
per freshly-primed context.
Two slim variants in both workflow scripts: STANDING_FACTS
(verify-type stages — mini-verify, standard end-verify,
compiler-driven build/suite verify: project-facts build/test commands
only) and STANDING_NONE (tree/extraction stages — preflight,
plan-index, plan-extract[-all], snapshot: nothing beyond their own
instructions). Judgment roles (implementer, spec/quality reviewers,
tester/e2e, compiler-driven edit stage) keep the full read.
conventions.md § Standing reading and agent-template.md § Standing
reading list carry the tiering sentence; the precedent is the
narrowed per-role reading the named agents already practise
(tester -3, plan-recon/grounding-check -5, fieldtester -8,
docwriter --oneline).
closes#31
In worktree sessions a dispatched agent's cwd can resolve to the
primary checkout instead of the loop's working tree — observed as a
per-dispatch race: 6/9 quality dispatches returning infra_blocked with
the sha256-of-empty fingerprint over a real diff, and a tree-check
counting the primary checkout's clean tree into a false no-op BLOCKED
on a genuinely-DONE iteration.
Remedy (validated in the field on the reporting run): the carrier
gains repo_root, stamped into every stage prompt as an explicit
'git -C <root>' anchor with a wrong-directory tripwire (an empty diff
or unexpected HEAD sha = wrong cwd, re-run against the anchor). When
the carrier omits it, the first dispatched stage (mini preflight /
standard plan-index) probes 'git rev-parse --show-toplevel' as a
fallback — itself subject to the same race, so SKILL.md documents the
field as effectively required in worktree sessions.
compiler-driven-edit gets the same carrier field (same defect class,
carrier-only). agent-template stage list updated in passing
(plan-extract[-all], end-verify).
closes#25
Both workflow scripts destructured object-form `args` behind `args || {}`
only. A named-workflow invocation can deliver `args` as a string; a
non-empty string is truthy, so every carrier field silently read
`undefined` and the failure surfaced far from the cause: implement-loop
dispatched its plan-index agent against "Read the plan at undefined" and
stopped only via a mislabelled NEEDS_CONTEXT after burning agent calls;
compiler-driven-edit briefed its edit agent with "EDIT: undefined" and
mapped the agent's refusal onto the straddle-rule BOUNCE to specify —
a mechanics failure dressed as a design finding.
Guards now run before any agent dispatch, mirroring the existing
malformed-input pattern (the task_range guard):
- A string carrier is first JSON-parsed: a JSON-serialized object
carrier (a stringifying caller or substrate layer that still authored
the documented object form) is accepted; free text does not parse to
an object and is rejected.
- A carrier that is not an object (string, number, boolean, array) is a
distinct infra BLOCKED naming the received type (compiler-driven-edit:
kind bad-carrier) — never a bounce, never NEEDS_CONTEXT.
- Missing or blank required fields fail fast by name, per mode:
standard iter_id+plan_path, mini iter_id+red_test_path+cause_summary,
compiler-driven-edit edit_description+def_site. implement-loop also
rejects an unknown mode, since the required-field set keys off it.
String-form args are NOT a documented interface — the only invocation
examples in the plugin are object-form (implement/SKILL.md); the issue's
free-text-passthrough fix part was dropped on that ground (triage
verification on the issue). implement/SKILL.md now also documents the
infra early-exit end-report shape (minimal {status, iter_id, reason},
no BLOCKED.md, no blocked_detail) in the Iron Law exceptions, Step 2,
and Step 4's no-file special case.
Verified: both scripts pass node --check (async-wrapped, as the Workflow
substrate runs them) and a 17-case stub-agent harness — malformed
carriers block with zero agent dispatches; valid and JSON-serialized
object carriers reach the first agent unchanged.
closes#24
Effort joins model as a mandatory pin: an omitted field inherits the
session effort, coupling every dispatch's thinking budget to whatever
the user happens to be chatting at (often xhigh) — the same
session-state coupling the model pin removes. The assignment follows
the model split:
- xhigh on every opus agent (judgement roles are the pipeline's
quality floor and must not degrade with the session);
- high on every sonnet agent (tightly-scoped plan execution gains
little from xhigh but pays its latency per dispatch, and these are
the per-task in-loop roles — wall-clock is the efficiency metric;
not lower than high, since re-loops cost more than saved thinking);
- medium inline in the workflow scripts for schema-bound
extraction/verification stages that author no code (preflight,
plan-extract, mini-verify, tree-check, finalize, build/suite
verify).
Workflow agent() calls pass effort explicitly on every call — whether
frontmatter effort propagates through an agentType dispatch is
undocumented, so the scripts do not rely on it. Policy documented in
docs/agent-template.md § effort, mirroring § model.
Agents and workflows previously carried no model field, so every
dispatch inherited the session model — including fable, which is
banned for all plugin agents and workflows by owner decree. Every
dispatch now pins opus or sonnet explicitly.
- opus (low-volume judgment gates whose misses silently poison
downstream work): architect, bencher, debugger, fieldtester,
grounding-check, plan-recon, quality-reviewer, spec-skeptic,
tdd-author
- sonnet (mechanical scope, in-loop or fanned out): docwriter,
glossary-extractor, implementer, spec-reviewer, synthetic-user,
tester
- workflows: all 13 agent() call sites pin a model — sonnet
everywhere except the quality-reviewer gate in implement-loop,
the loop's last correctness check (spec-reviewer only gates
task-text correspondence; real-bug finding is the documented
opus strength)
- docs/agent-template.md: model is now a mandatory frontmatter
field, with the assignment rule and the fable ban recorded
The done-signal `build_clean && suite_green_unchanged` was vacuously
true on a clean working tree, so a no-op edit (the edit agent touched
nothing and reported sites: 0) read as DONE. An orchestrator trusting
that verdict would "commit the unstaged changes" — committing nothing
under a DONE banner.
Add positive evidence that an edit actually landed, checked at two
independent points:
- Phase 1 (cheap, pre-suite): the edit agent reports `applied_changes`
as ground truth from `git status --porcelain` / `git diff HEAD`. No
hole + clean tree -> distinct BLOCKED (kind: no-op-edit), skipping a
pointless suite run against an empty tree.
- Phase 3 (authoritative backstop): DONE now also requires the verify
agent's independent `working_tree_dirty` observation. The verify
agent never sees the edit agent's self-report, so a false
applied_changes is still caught. A green build+suite over a clean
tree routes to the same BLOCKED, not to debug (a clean tree is no
regression — nothing to reproduce RED-first).
The precondition keys on tree-dirty, not sites > 0: a legitimate
behaviour-preserving edit can touch only the definition site (sites: 0)
and still dirty the tree. Also fix the DONE note to report a legitimate
sites: 0 as 0 rather than coercing it to null.
closes#11
The selector forced every task through the heaviest methodology's
critical path: a behaviour-preserving, type-enumerable change paid the
same specify -> planner -> implement front-half as a novel feature,
because it was neither new behaviour (tdd) nor an observed bug (debug)
and so fell to specify by elimination. Two coupled defects — a selector
with no verification axis, and an all-or-nothing executor — kept the
existing lighter path unreachable and uneconomical. This fixes both.
Part A — verification-keyed selector (boss/SKILL.md):
- Replace the three-way "design line" with an ordered cascade that adds
a verification/enumeration axis ahead of the settled-vs-fork question.
Each lighter arm carries a positive trigger matched by signature, not
reached by elimination.
- New `compiler-driven` arm: a type/signature edit at a definition site
that propagates mechanically. Observe-then-bounce — make the edit,
build, run the suite; clean build AND suite green unchanged commits;
a hole bounces up (specify for a design choice, tdd for discovered
test-specifiable new behaviour); a regression bounces to debug.
- The observed-bug RED-first gate is first in the cascade, so a
mechanical-looking fix cannot bypass it.
- The straddle rule ("add an enum variant") is codified as a rule:
mechanical/forwarding -> compiler-driven; encodes new behaviour ->
tdd/spec; doubt routes up.
- The executor is the elevated inline carve-out plus a shipped workflow,
not a heavy new skill ("the largest concrete win is small").
Part B — Workflow substrate (implement/workflows/):
- implement-loop.js: the per-task loop as a deterministic script. Each
phase (implementer -> spec-compliance -> quality, + tester for E2E) is
a separate top-level agent() call, so a single phase is independently
invokable and inter-phase aggregation/re-loop is code. Retires the
implement-orchestrator agent's inline-role-switch workaround (the four
phase agents survive as the agent-types the script dispatches).
- compiler-driven-edit.js: the observe-then-bounce loop.
- install.sh / uninstall.sh symlink shipped workflows into
~/.claude/workflows/.
- specify and brainstorm stay prose + interactive (human-intent oracle);
only the autonomous/mechanical loops moved. try-and-error is deferred.
Docs (pipeline taxonomy, design, agent-template, migration, README) and
all selector<->executor cross-references updated; the arm and its
executor are co-located so a future re-route through the full loop is a
visible regression.
Verified by an adversarial multi-agent pass: PASS on all six acceptance
criteria; two coherence concerns fixed. The shipped scripts are
syntax-validated but exercised only in a downstream target project (the
skills repo is not itself a pipeline target).
closes#7