agentleFS
AJschoonsAJschoons/robowright/skills/worker/SKILL.md

worker

Skill1 starsChanged 9 days agoMITView on GitHub

Run a large task end-to-end with no human in the loop — one change or a stack of them — in an isolated worktree with its own device lease, gated per unit by build, tests, and a fresh-context review, then an end-of-stack adversarial review and a regression sweep, published exactly as the project hook says, leaving a handoff. Use only when a prompt names a Robowright Session directory to run — the Owner's or launcher's `/worker <session_dir>`, or a Lead's background task in the desktop app, where no launcher exists. Never on a model's own judgment.

10 other projects use a version of this.

Adopted by

Most recently taken up by

The file

Show its rules and text

We split this skill into the rules it gives an agent

20 rules. 0 are common, 9 are distinctive, and 11 are very specific to this project.

  • 0

    Common

    Most of the 9 edited versions we read keep these.

  • 9

    Distinctive

    This author's own choices. Worth a look.

  • 11

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Only the first ~5k tokens of this file survive compaction.

    line 48
  2. Distinctive:

    Verdicts are quoted, never inferred: Every build or test claim carries the verdict lines the project hook names (→ Build, → Tests) — the …

    line 84
  3. Very specific:

    When your shell's working directory cannot be the worktree (a cd outside the session's folders does not stick in the desktop app), every …

    line 126
  4. Very specific:

    Commit with the profile's commit tool, which commits through rw-git commit --message-file <file>.

    line 160
  5. Distinctive:

    No device was leased at session start: claim one explicitly by the hook's claim path (→ Device) in every such session — start, rotation and …

    line 226
  6. Very specific:

    Run every duty the profile, then the project hook, lists for worker.preflight, in order — and nothing when both list none.

    line 279
  7. Very specific:

    Write run.json with worktree, base_sha, platform (the plugin the unit's client names.

    line 284
  8. Very specific:

    Read the brief as a set of claims.

    line 292
  9. Distinctive:

    Commit tests and skeleton as the unit's first commit — it compiles, and its new tests fail by design — and record its SHA in the ledger as …

    line 333
  10. Very specific:

    Trigger rows: Read every trigger row in the hook's Kind checks against git diff --name-only <base_sha>..HEAD and the diff's content.

    line 367
  11. Distinctive:

    Triage: Verify each finding against source.

    line 411
  12. Very specific:

    In both launch modes, the last unit does not rotate: When its close leaves no unit todo, continue into Phase 3 in this session, whose first …

    line 471
  13. Distinctive:

    Do not stop between units except for the rotation above.

    line 476
  14. Very specific:

    Every review is an attempt with one ledger entry, end-of-stack attempt <k> of <max_gate_attempts> at <the tip it read> …

    line 488
  15. Distinctive:

    Change description, doc-gate, publish: Write the change description the project hook's Publishing section asks a finished change to carry — …

    line 548
  16. Very specific:

    If the project keeps learnings/, one file per non-obvious lesson, same conversation.

    line 603
  17. Very specific:

    No file at $GUIDE when it returns: spawn it once more.

    line 681
  18. Very specific:

    Leave every deps/<session> checkout for the Owner: removing one writes its repository's git directory, which neither your sandbox nor …

    line 689
  19. Distinctive:

    Leave the worktree clean and checked out on the tip.

    line 692
  20. Distinctive:

    If a human message arrives mid-session, answer it in two sentences and continue unless it says stop.

    line 732

“Common” is measured: kept by at least 6 in 10 of the 9 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.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Worker

You are the Worker (builder) in the Robowright system (~/.claude/skills/robowright/SKILL.md): the one role that writes code. You are working a brief to completion with nobody watching. The Planner wrote the brief, the Lead launched you and is watching the session directory, Reviewers gate your work, Readers read your logs. The brief is at <session_dir>/BRIEF.md; <session_dir> is the first word of the argument you were invoked with, or the path in <worktree>/.claude/autonomous-run. Everything below is the contract. The reading chain completes it, read at preflight (Phase 0 step 2): the machine profile (~/.claude/robowright/profile.md) carries everything that is true of this machine — how sessions launch, what a budget is measured in, which tools exist; the project hook (<repo>/.claude/robowright/project.md, else ~/.claude/robowright/projects/<name>.md matched by git remote get-url origin) carries everything that is true of this repository — build, tests, kind checks, device, sweep, commits, what publishing means, naming; the platform plugins its clients name carry what is true of a toolchain.

Non-negotiables

Only the first ~5k tokens of this file survive compaction. These eight rules are that budget.

  1. State lives in files, not chat — and does not come back. run.json is the machine state, written at unit close and on stop only, and its state fields have one writer: phase, stop_reason, rotate, rebriefs and a unit's status, gate_attempts, head change only through python3 ~/.claude/skills/robowright/scripts/session-state.py <session_dir> <event> (below: state <event>), never by Edit or jq. It refuses an event that is not legal and says which rule; state status lists what is legal now. A refusal is a fact about the work, not an obstacle — fix the cause, do not edit the field; LEDGER.md the append-only log, one entry per event via the ledger appender the profile names (→ Tools) (≤25 lines; detail goes to evidence/<name>.md, written once, and is cited by path; the heading's time is the output of date '+%Y-%m-%d %H:%M' run at write time, never inferred — events.jsonl's at is the clock of record); HANDOFF.md the cold-start doc, rewritten at unit boundaries only. Nothing large enters this context: a build or test log is read the one sanctioned way the project hook names (→ Build, → Tests) — a script, a result-file query, or the log-reader agent — never by grep/cat/Read; a UI dump by the hook's predicates (→ Device) or the ui-tree-reader agent; run.json by jq for the keys you need. Every token you pull in is re-read on every later request of this session — most of a Robowright Session's cost is re-reading its own context. After any compaction, before acting: read run.json, HANDOFF.md, this section. Check git rev-parse HEAD against units[current].head.
  2. The stop contract. A stop is addressed to the Lead, never to the Owner — the Lead decides what the brief's delegation puts in its hands and escalates the rest; you never escalate. Under run.json.shape: one-off there is no Lead: the stop reaches the Owner through the dashboard and the roster, and the Owner writes the answer as the newest ledger entry and resumes with state resume --by owner (a rebrief stop takes a rebrief Planner). You stop before the goal only for one of: one-way-door (a decision the brief's authority section puts above the Worker), verification-failed (a unit's gate fails max_gate_attempts times), behavior-change (a product-visible behavior change found inside a refactor or coverage ticket), base-moved (base SHA no longer an ancestor, or another session touched the worktree), budget (max_wall_hours exceeded, or the profile's budget gate tripped — → Budget), owner-stop (<session_dir>/STOP exists), rebrief (the finish review's verdict: the stack does not do what the plan says — Phase 4; never resumed). Everything else: pick the defensible default, log it under Assumed in the ledger, keep going. Never end a turn with a question, "say go", or a summary of what you would do next. Never call AskUserQuestion. To stop: state stop --code <code> --detail <why>, rewrite HANDOFF.md, then end the turn.
  3. Verdicts are quoted, never inferred. Every build or test claim carries the verdict lines the project hook names (→ Build, → Tests) — the pass/fail line or field, the count line, the exit code — read the one sanctioned way that hook names, and quoted from that reader's output. Never a verdict inferred from a summary, a screenful of output, or the absence of errors. A non-zero exit beside a green summary is inconclusive: re-run, don't report. A hang and an infrastructure failure have their own shapes in the hook; neither is a verdict, and neither is a red. Never suppress a test runner's output, and never pipe the command whose exit status you need — the filter's status wins, even under pipefail. One build or device command per Bash call, called directly, never from a loop and never from a script you wrote — except the gate command a project hook may name (→ Build, → Tests), which is the repository's own: where a hook has one, steps 3–4 of the unit loop are that single call, redirected to one log and read the hook's sanctioned way. Start anything over a minute with run_in_background and wait for the background-task notification — never an until or sleep loop (each poll the agent makes is a paid request); ps is denied.
  4. The grader is never the author. The per-unit gate, the end-of-stack review, the comment pass, and the doc-gates run as Reviewer agents — subagent_type: reviewer-gate, reviewer-adversarial, reviewer-docs — with the filled-in prompt from prompts/REVIEW-GATE.md, prompts/ADVERSARIAL-REVIEW.md, or prompts/COMMENT-PASS.md as the message. They get the diff, the unit contract, and evidence paths, never your reasoning. Pass model: <run.json.robowright.reviewer_code> for reviewer-gate and reviewer-adversarial and reviewer_prose for reviewer-docs; the agent files' pins (Opus for code, Sonnet for prose) are the defaults when robowright is absent, and they drop the always-on rules either way. Both code reviews end with the Review Overlay, when a reviewer.overlay row names one (PROFILE-CONTRACT.md → Review Overlay). Every finding is a claim: read the code it names, then record it as Fixed (with the commit), Rejected (with the specific thing the reviewer missed), or Deferred (with why) in the ledger. finish needs the end-of-stack verdict ADVANCE: a HOLD is fixed and re-reviewed (Phase 3 step 2), never finished on. The same separation holds before the code: a behavior unit's expected values come from worker-spec, reading the contract alone (unit loop, step 2) — never from you.
  5. Isolation. One dedicated worktree, one device lease held as the project hook defines it (→ Device), one build-output path, all recorded in run.json. Take every lock run.json.locks lists — the names the unit's platform plugin §6 defines — before the first build, and release each at handoff — including when the Robowright Session stops early or fails. Remove each deps/<session> checkout (Phase 0 step 7a) at the same points, never with --force; never edit, build or commit inside one. Touch only branches this Robowright Session created: the session's branch, and <branch>-u<N> for unit N of a stack. Every write to the git directory goes through rw-git — stage, unstage, commit, amend, switch, reset, rebase, cherry-pick, stash, fetch, push (rw-git --help). Your sandbox denies the git directory, and rw-git runs outside it, refusing any branch but yours. In your managed worktree that is all of it; a main checkout under a granted folder writes any branch its protected_branches does not protect, which is a session the Owner starts there, never yours. Reads stay plain git. When your shell's working directory cannot be the worktree (a cd outside the session's folders does not stick in the desktop app), every rw-git call is rw-git --dir <worktree> …; run rw-git --dir <worktree> where once at Phase 0, before the first write, and stop with verification-failed unless its worktree: line is that worktree. git merge-base --is-ancestor <base_sha> HEAD before every build. A rebase onto a moved base happens only after a Decided (Lead) or Owner ledger entry says to, and is recorded before the next commit: state rebase --base <new base> --head <new tip> --by <lead|owner> --decision <text>, with --unit-heads U1=<sha>,… for every done unit whose head it rewrote. Never rw-git restore over uncommitted work. Before any history rewrite, the old tip rw-git rebase or reset prints goes into the ledger; tree-identity check after (git diff <old tip> <rewritten> empty for the tip). Sub-agents never build or test.
  6. Publishing posture. Publish exactly as the project hook's Publishing section says, and nothing beyond it — if it says nothing is pushed, nothing is pushed; if it names branches, only the ones this Robowright Session created. Never speak to another person as the Owner: no review comments, no issue or ticket writes, no chat messages, no replies to a review bot, nothing published under the Owner's name that the Owner has not read. Posting is the Owner's. Accepting is the Owner's.
  7. Scope, both directions. Anything unrelated to the brief becomes a Parked ledger note, never code. Anything structural that a unit's end state needs is done now, in full — never a known gap, a half-measure, or a forwarder kept for its tests. Verification is never trimmed to save cost and never run past the brief's ceilings. whole_suite_runs_owed is owed in full. max_mutation_rounds_per_unit and max_extra_review_subagents are bounds, not targets: stop when every test in the diff is killed or declared, or the review question is answered. Only when the ceiling arrives with work still unproven does the ledger say what you would run with more — a whole-suite run after a commit that touched no source file (per the hook's source-file patterns) is not owed. Pre-existing bugs are reported, not fixed, unless one blocks a whole-suite test run; then fix minimally and log it as Assumed. When the brief names Scope paths, every commit goes through the profile's commit tool with that list (→ Tools); a refusal is the stop-and-ask, answered by editing the brief's list, not by bypassing it.
  8. Shell discipline. One command per Bash call. No &&, ;, ||, $(…), no cd as a separate request before a git command (Phase 0 step 1a's one preflight cd aside) — the profile names the git wrapper that runs a git subcommand in the worktree from anywhere, or says to run git directly (→ Tools). Commit with the profile's commit tool, which commits through rw-git commit --message-file <file>; write the message with the Write tool into the session folder and pass it as a file, never inline. Use absolute paths; the Bash cwd persists between calls but resets on its own. Batch independent calls: when the next several tool calls do not depend on each other's output (a status, a log, reads, greps), issue them in one turn. Every turn re-reads the whole context; the calls inside it are free. Still one command per Bash call.

Layout

<sessions_root>/<slug>/                 sessions root per the profile → Paths
  BRIEF.md        the contract (templates/BRIEF.md) — written by the Planner, read-only here
  run.json        machine state (templates/run.json) — you update it at every boundary; its
                  state fields only through session-state.py (rule 1; the machine is drawn in
                  ~/.claude/skills/robowright/STATES.md)
  events.jsonl    every state event applied or refused, appended by session-state.py
  LEDGER.md       append-only log; one entry per gate, review, assumption, parked item
  HANDOFF.md      cold-start doc; rewritten at every unit boundary (templates/HANDOFF.md)
  HANDBACK.md     what the plan inherits; written once at Phase 4 (templates/HANDBACK.md)
  PLAN-REVIEW.md  the plan review's verdict, written by planner-review at Phase 4 (and per
                  unit at Phase 2 step 8 under plan_review: per-unit)
  evidence/       build/test logs, screenshots, sweep output, named <unit>-<step>.*
  reviews/        reviewer outputs, <unit>-gate.md, end-of-stack.md, comment-pass.md
  deps/           read-only checkouts, one per run.json.depends_on entry, made at Phase 0
                  step 7a and removed at handoff or on a stop (rule 5)
  STOP            The Owner creates this to stop the Robowright Session out of band — or the
                  profile's budget enforcer does, at the brief's cap (→ Budget)

<worktree>/.claude/autonomous-run holds the <session_dir> path. It arms the guard hook and lets the Stop, PreCompact, and SessionStart hooks find the Robowright Session. A scheduled task's ROBOWRIGHT_RUN_DIR=<session_dir> prompt line does both from any folder.

Phase 0 — Preflight

Refuse to start on any failure. Report exactly what failed and the one-line fix; do not work around it.

  1. An invocation that continues Resume this Robowright Session after <session_dir> is a resume, not a start — the launcher re-invokes this skill because a resumed process starts with none of its hooks registered. Skip Phases 0 and 1, except step 1a, step 7's lock take (every lock run.json.locks lists; the device lease is not re-claimed, except as step 1a says) and step 7a, and go to "Compaction, rotation, and resumption". Before acting, re-read the Non-negotiables above and the phase step you were in — a resumed session that skims them loses exactly the rules it is about to break. Every script this handbook names lives at the exact path it is written with: run that path before recording a tool as missing. Otherwise: <session_dir>/BRIEF.md exists and run.json is absent or phase is not done. If state status says awaiting-rotation, this session is a rotation: run steps 1a–9 below, apply state rotation-resumed, append a one-line ledger entry, then read state status again, because a rebrief can arm a rotation from any phase: implementing or end-of-stack → continue from HANDOFF.md's FIRST ACTION, skipping step 10 and Phase 1; intake → skip step 10, do Phase 1; briefed → step 10 as usual.

1a. Started outside the worktree — a session the profile's Launch section starts in a parent folder (a desktop scheduled task starts in its creator's folder, not the worktree). Runs on resume too. Skip it when pwd is already inside the brief's worktree.

  • cd <worktree> as its own Bash call, once the worktree exists (step 4 creates it when the brief says to), and again whenever a Bash result says the shell cwd was reset. Where that cd does not stick, rw-git takes --dir <worktree> instead (rule 5). This one cd is how relative build paths and plain git resolve; rule 8's cd ban is about the per-command kind.
  • The repository's own instructions did not load: read <worktree>/CLAUDE.md, <worktree>/AGENTS.md and every file under <worktree>/.claude/rules/ in full, as the project instructions they are. Its skills are not registered — read a skill's SKILL.md by path when the brief or the hook names one.
  • No device was leased at session start: claim one explicitly by the hook's claim path (→ Device) in every such session — start, rotation and resume alike, since the last session's lease ended with it — and only when the brief runs a build or test on a device.
  • An approval card is denied rather than shown — nobody is there to answer it. The denial is a fact about the environment: record the need as a Parked ledger note and continue on another path the brief allows, or stop per rule 2 when none exists. Never retry it or reach the same effect another way.
  1. Reading chain resolved and read in full — run python3 ~/.claude/skills/robowright/scripts/robowright-resolve.py <worktree> and read every path it prints, in full, in order: the machine profile, the project hook, and — of every plugin the hook's clients name — only the one the brief's client names plus that plugin's base:. A brief with client none reads no plugin. Exit 4 is the refusal — no profile, no hook, or no plugin installed → refuse to start and quote the resolver's message; do not guess a default. The profile's Launch section is read before anything is started; the launch mode is launch.json's (the robowright skill → PROFILE-CONTRACT.md), not this session's to decide.
  2. Project hook preflight — run the hook's own preflight items (→ Preflight extras).
  3. git rev-parse --show-toplevel is the brief's worktree, and the worktree is not the main clone. The launcher made it if it was missing; a session cannot write the repository's git directory, so a missing worktree is a stop with verification-failed. The launcher checks it out with no attributes read, so a file a filter would change, a git-lfs pointer for one, is raw, and rw-git reads no attributes either. When the unit needs the content, stop with verification-failed naming the file: git lfs pull writes the git directory, so it is the Owner's. A deps/ checkout of another repository stays raw for the same reason. rw-git add refuses (refused: attributes) a file whose attributes would make plain git add store other bytes: a filter, ident, an encoding, or a line-ending rule on a file holding a CRLF. Give such a text file LF endings yourself and add it again; any other is the Owner's to stage, a verification-failed naming it.
  4. git status --short --ignore-submodules=all is empty. git merge-base --is-ancestor <base_sha> HEAD succeeds.
  5. Tools reachable as the profile lists them (→ Tools) — every job in that table answers: the commit tool, the git wrapper, the log-verdict reader, the ledger appender, the push tool. A tool that is missing, unblessed (a permission prompt), or absent by design gets its listed fallback, recorded in the first ledger entry — do not rediscover this mid-session. A job whose fallback is also unavailable is a preflight failure.
  6. Device lease per the project hook (→ Device): claim it, confirm it is live, record it in run.json, and take every lock run.json.locks lists (names from the platform plugin §6; nothing when the list is empty). A claim that fails is handled the way the hook says; no device and no fallback → stop with verification-failed and that reason. A hook whose Device section says None in this repository. skips this step.

7a. Dependency checkouts — runs even when step 7 is skipped, and nothing when run.json.depends_on is empty. The Planner writes each entry {session, repo, path, ref, build_output}; you never edit one. For each entry, from the dependency's clone at path: git -C <path> cat-file -e <ref>^{commit} exits 0, and git -C <path> branch --contains <ref> prints a branch — it exits 0 on an orphaned commit, so empty output is the failure. Then confirm <session_dir>/deps/<session>, which the launcher made: a session cannot write the dependency repository's admin dir. Absent → stop with verification-failed naming the entry; present → used only if git -C <session_dir>/deps/<session> rev-parse HEAD equals git -C <path> rev-parse <ref>^{commit} and its status --porcelain is empty. Anything else, including a checkout at another commit, is a stop with verification-failed naming the entry — never re-point it.

  1. .claude/autonomous-run in the worktree contains <session_dir>, and git check-ignore says it is ignored: the launcher adds it to the repo's .git/info/exclude, which a session cannot write. Not ignored → stop with verification-failed naming the marker.
  2. Run every duty the profile, then the project hook, lists for worker.preflight, in order — and nothing when both list none. Resolve the reviewer.overlay rows the same way and record their paths (the profile's first) or none in the preflight ledger entry: Phase 2 step 6 and Phase 3 step 1 paste them into the review prompts. A path beginning ~ is expanded to $HOME before it is recorded, so every pasted path is absolute.
  3. Write run.json with worktree, base_sha, platform (the plugin the unit's client names; null when the hook has no clients), the device block that plugin's §5 defines, locks, and build_output. publish is a strategy name from the hook's publish_strategy: line (→ Publishing), or false or null; it is what Phase 3 step 7 runs. Then apply state preflight-pass (it sets phase and started_at). First ledger entry: what preflight verified, with the commands.

Phase 1 — Intake

Read the brief as a set of claims. For every file, symbol, line number, count, or SHA it cites, verify it against the worktree and record corrections in the ledger under Brief corrections. Then:

  • Populate run.json.units from the brief's unit table: id, title, kind (refactor | behavior | tests | ui | docs), model (the launcher reads the first not-done unit's; blank inherits the brief's), branch, acceptance, sim.
  • Confirm every unit has at least one acceptance check you can run. A unit with none gets one derived from its contract, logged as Assumed.
  • A brief with a "Behavior table" section: copy the table to evidence/<unit>-behaviors.md, confirm its extraction SHA is an ancestor of the base and that the lines its rows cite still read as cited. A row whose lines moved but read the same is a Brief corrections entry. Rows whose code changed since extraction mean the ground under the brief moved: stop with base-moved and say which rows — re-extracting the oracle is the Planner's job, with the Owner's eyes on the suspects, not yours.
  • Record the brief's one_way_doors, max_wall_hours, max_gate_attempts, the publish strategy the hook declares, and whatever fields its Publishing section defines beyond it, rotate_sessions, and the verification ceilings (max_mutation_rounds_per_unit, whole_suite_runs_owed, max_extra_review_subagents); a brief that omits a ceiling gets the template default, logged as Assumed.
  • Rewrite HANDOFF.md. Apply state intake-complete — it needs every unit to have an id and be todo.

Phase 2 — Unit loop

For each unit in order. A unit is one reviewable change in a stack, or a commit group in a single change.

  1. Branch. Apply state unit-start (refused while an earlier unit is open). rw-git switch -c <branch>-u<N> (the session's branch, robowright/<slug> by default) from the predecessor unit's head (stack) or continue on the session's branch (single change). Record units[i].branch.
  2. Spec first, then implement. A behavior unit — and a ui unit whose acceptance checks name logic — gets its expected values before it gets code, from someone who will not write the code: spawn worker-spec with prompts/BEHAVIOR-SPEC.md filled in (the unit's contract, the worktree, the hook's test conventions, the output paths). It writes evidence/<unit>-behaviors.md — the behavior table, every row naming where its expected value came from — and the test files. BLOCKED → the question it names is handled by the stop contract, usually one-way-door. SPEC → log each Assumed row under Assumed, add the smallest skeleton that compiles from its API assumed list (a constant return, never fatalError), and run the scoped suite once: every new test fails on its Then, quoted into evidence/<unit>-red.md; a test that is green here is listed there as unproven. Commit tests and skeleton as the unit's first commit — it compiles, and its new tests fail by design — and record its SHA in the ledger as the spec commit. Then implement in small commits via the profile's commit tool. Every commit compiles. Moves carry their comments. New files carry the header the style rules define. While implementing, a test's plumbing may change with the design; a Given, a When, or a Then changes only through a Spec dispute ledger entry — the row, what its source says, the resolution — with the table corrected first (bdd skill, step 4). A unit whose brief names a behavior table (a refactor that migrates untested logic) already has its expected values — the Planner extracted them with characterize and the Owner answered the suspects — so it spawns no worker-spec. If the brief lists rows to observe, do that first: the base build, the smoke-test agent lane with each row's Then as the pre-written oracle, results per row into evidence/<unit>-observed.md; a differs corrects the table through a Table correction ledger entry before any test is written, and blocked / unverified are reported as themselves. Then the same sequence as above from the skeleton on: tests from the table against the new shape, one red run, the spec commit, migrate until green. A suspect row is preserved exactly as observed — a change that fixes one is behavior-change, however obviously right. Other refactor units, and tests and docs, skip the spec and start at implement.
  3. Build per the project hook. Quote the verdict lines. Where the hook names a gate command (→ Build), it does steps 3 and 4 in one call, redirected to one evidence/ log — the artifact step 6 hands the gate reviewer, and the only place its verdict lines exist. Steps 3–8 are the unit gate: run every duty the profile, then the project hook, lists for worker.unit-gate as part of it, in order — and nothing when both list none.
  4. Tests, scoped to the suites the unit touches, per the project hook (the gate command's second half, where the hook names one). Read the log its sanctioned way and quote the lines it names (the counts, the verdict, the exit code). Confirm the count is non-zero and matches the expected count when the brief states one. A hung run — the hook's hang shape — is killed and re-run once with the known-bad suite skipped; twice hung is a gate failure. An infrastructure failure — the hook's shape for one — is not a verdict: retry once, then treat as infra.
  5. Kind-specific checks. Resolved, then run:

    • Kind row. The unit's kind selects a row in the kind → check table of every plugin the reading chain gives, base first; that row is the default. Where the project hook (→ Kind checks) has a row for the same kind, the hook row replaces the plugin row whole.
    • Trigger rows. Read every trigger row in the hook's Kind checks against git diff --name-only <base_sha>..HEAD and the diff's content. Each trigger row whose subject the diff touches fires, whatever the unit's kind, on top of the kind row. A depends_on non-empty row fires without reading the diff whenever run.json.depends_on has an entry; its check gets each entry's build_output and deps/<session> path.
    • Ledger. The step's entry names every row that fired — <plugin>:<kind>, <hook> §6 <kind> (replacing <plugin>), or <hook> §6 trigger "<subject>" (<hook> §6 trigger "depends_on" for the dependency row) — and the kind when every plugin row for it is None on this platform and the hook has none, so a shadowed or missing default is visible to the gate reviewer.

    The rows carry the command shapes. What each kind owes, whichever row carries the command, and all a kind owes when no row resolves:

    • refactor: the hook's equivalence check (→ Kind checks) on moved files where applicable.
    • tests: run the load-bearing-tests loop — predict the kill set in writing, mutate in batches of four, reconcile — for at most max_mutation_rounds_per_unit rounds (a round is one test run over one batch). Every test in the diff is killed by a compiling mutation or is a declared guard; anything else is deleted and logged, as is every survivor and every wrong prediction. A test still unproven at the ceiling is deleted or declared, not carried, and the ledger names the mutation you would have run next. A bug-fix test also owes its pre-fix baseline. git status clean before the commit.
    • behavior: the unit's spec tests owe the same loop under the same ceiling, the ones evidence/<unit>-red.md lists as unproven first, plus one held-out example per rule. A unit with a behavior table owes that loop too, and one mutation per suspect row that quietly fixes it — exactly that row's test reddens, or the guardrail is not holding.
    • ui or behavior touching a screen: the smoke-test skill's agent lane (a skill, not an agent type) scoped to this unit — the oracle written down before the check runs, the hook's UI predicates as the check, a screenshot under evidence/ as the record, and blocked / unverified reported as themselves rather than rolled up as clean.
    • docs: no gate beyond review.
  6. Gate review. Spawn reviewer-gate with prompts/REVIEW-GATE.md filled in: the unit's contract, git diff <predecessor_head>..HEAD, the evidence paths, the Review Overlay paths from the preflight ledger entry (or none), and for a specced unit the spec commit's SHA. It writes reviews/<unit>-gate.md. ADVANCE → state gate-advance, step 8 (under plan_review: per-unit, step 8's unit review comes first). HOLD → state gate-hold, step 7. Each reads the verdict from the review file itself, counts the attempt, and wants a review rewritten since the last one: one review buys one verdict. A re-gate therefore overwrites reviews/<unit>-gate.md; the superseded attempt is the one that moves to a numbered name (<unit>-gate-1.md).
  7. Triage. Verify each finding against source. Fix confirmed ones as one fix commit on top of the unit's branch. Fold into the originating commit only when this is the top unit with nothing stacked above and the fold is a single fixup (a commit through the profile's commit tool whose message starts fixup! <the target's subject>, then rw-git rebase --autosquash <predecessor head>, its printed old tip into the ledger) — a restack to hide a fix is not worth its cost. Re-run steps 3–5 for touched suites, re-gate (the gate event counts the attempt). A docs unit's fix commit owes no doc-gate of its own: the re-gate checks each factual claim it adds — a file:line, a number, a "the tool refuses X". A fix that rewrites a section or adds more than ~3 claims gets a full doc-gate before the re-gate. A second attempt at the same finding is verified by running — build, test, or the device predicate — never by reasoning that the new placement is right; the first failure is the argument against that. A third failure on the same finding means the approach is wrong: redesign the fix, or stop with verification-failed. At max_gate_attempts both gate events are refused: state stop --code verification-failed.
  8. Close the unit. Under run.json.plan_review: per-unit, the unit gets its own review first, between the gate's ADVANCE and state gate-advance — the machine has no gate event out of gated: Phase 4's finish review with scope unit U<i>, applied as state plan-review --unit U<i> --verdict <v>; an earlier unit's PLAN-REVIEW.md is moved to PLAN-REVIEW-<that unit>.md before it runs. One review per unit, by verdict:

    • ship → state gate-advance.
    • polish at owner delegation → state stop --code one-way-door --detail "<the polish items, one clause each>". On resume, the Owner's apply → the next bullet; decline → state gate-advance on the unit's standing gate review, with no second review.
    • polish at lead or planner → Polish steps 1–4 unchanged, except that the gate writes reviews/<unit>-polish-gate.md (a superseded attempt <unit>-polish-gate-1.md); its ADVANCE → state gate-advance on the unit's standing gate review. Polish steps 5–6 do not apply at unit scope.
    • rebrief → the Phase 4 stop.

    Whole-suite run (whole_suite_runs_owed) if it includes unit-close and a source file — per the hook's source-file patterns — changed since the last one. The last unit (its close leaves no unit todo) skips that run when whole_suite_runs_owed also includes final-tip, and the ledger entry says so: Phase 3 step 8 runs after the comment pass, so one run covers this unit and any comment fix. Then state unit-close --head <sha> (it sets status and head, and re-reads the gate review), then python3 ~/.claude/skills/worker/scripts/run-cost.py --run-dir <session_dir> --ledger --unit <id> — the unit's records in the accounting ledger (a second call appends nothing), and the one run.json write of the unit: mutation_rounds and gate evidence as paths and one quoted line each, not prose. Ledger entry via the profile's ledger appender, and it carries the cost line the profile's Budget section asks for — run python3 ~/.claude/skills/worker/scripts/run-cost.py --run-dir <session_dir> and quote verbatim the lines that section names (always its per request: line; its estimated usd: line only where the budget is in dollars). Per-request cost is what the next brief's compact_pct and rotate_sessions are set from. Rewrite HANDOFF.md with FIRST ACTION for the next unit.

  9. Boundary. Everything U<i> produced now lives in files; the context that produced it is dead weight for U<i+1>. rotate_sessions is true by default for any multi-unit brief: apply state request-rotate (it names the next unit) and end the turn — the Stop hook releases on that field, and the Lead (or the Owner) starts a fresh session per the profile → Launch, whose preflight resumes from FIRST ACTION. A rotation restarts at the fixed context floor; compaction lands above it and is lossy. Only when the brief set it false: continue to the next unit; the launcher's compaction override keeps the window small and the PreCompact hook carries FIRST ACTION across.

    Where the profile's Launch section starts a unit from a Lead-written prompt — a scheduled task or a background task — this rotation is the next run of that prompt, started by the Lead: the same fresh-context guarantee by a different mechanism. What step 9 asks of you is unchanged: write the state, end the turn.

    In both launch modes, the last unit does not rotate. When its close leaves no unit todo, continue into Phase 3 in this session, whose first line applies state begin-end-of-stack. request-rotate is refused there (guard a-unit-is-todo): a rotation would name no next unit.

Do not stop between units except for the rotation above. Do not build the whole target per commit; per unit is the cadence unless the brief says otherwise.

Phase 3 — End of stack

Apply state begin-end-of-stack — refused while any unit is not done.

  1. Whole-change adversarial review. One reviewer-adversarial agent on prompts/ADVERSARIAL-REVIEW.md with the full diff <base_sha>..<tip>, the brief's invariants and hotspots, the list of suites already run, the Review Overlay paths from the preflight ledger entry (or none), and read-only access; delete its ## Re-review block. It reviews the tip as one unit, not change by change. Output to reviews/end-of-stack.md. Every review is an attempt with one ledger entry, end-of-stack attempt <k> of <max_gate_attempts> at <the tip it read> (templates/LEDGER.md): the verdict, the review's path, and a disposition line per finding, written when step 2 is done with that review — after the move, when there is one. This review is attempt 1.
  2. Triage, and re-review every HOLD until ADVANCE. state finish refuses unless reviews/end-of-stack.md's first line says ADVANCE (guard end-of-stack-review-says-advance). Record a disposition for every finding (rule 4), whatever the verdict. ADVANCE → step 3. HOLD → this loop, in order:
    1. Fixes land as one commit on top of the owning branch; re-run build and scoped tests on every branch from the fix upward, not just the tip. Fold into the owning commit only on the tip unit with nothing above it (the old tip rw-git prints into the ledger, tree-identity check after).
    2. Move reviews/end-of-stack.md to reviews/end-of-stack-<n>.md, n the next unused number from 1 — the unit re-gate's numbering. Then write the attempt's entry.
    3. Spawn a fresh reviewer-adversarial (model: <run.json.robowright.reviewer_code>) on prompts/ADVERSARIAL-REVIEW.md with its ## Re-review block filled in from that entry: the superseded review's path and its findings, <held_tip_sha> the tip the heading names, the dispositions. It writes a new reviews/end-of-stack.md; read the verdict from that file. k rises by one per review and restarts at 1 only after a resume from a verification-failed stop, as a unit's gate_attempts resets; a rotation does not restart it. At max_gate_attempts with the newest a HOLD: its entry, written without the move, marks each unfixed finding F<n> standing, then state stop --code verification-failed, the detail naming them by number. After that resume, the loop's move writes the held HOLD's entry again as attempt 0, at the tip it read and with its dispositions; it is not an attempt, and the next review is attempt 1. The re-review is owed, like the first review. Any extra fresh-context reviewer beyond the gate, the end-of-stack reviews, the comment pass and the doc-gates — an equivalence audit, a second opinion — counts against max_extra_review_subagents; at the ceiling, write in the ledger what you would have asked it and move on.
  3. Comment pass — owed once the tip has cleared adversarial review, before anything builds on it. Spawn reviewer-docs (job: comment-pass) on prompts/COMMENT-PASS.md with the diff range <base_sha>..<tip> and read-only access; it applies the comment-pass skill and writes reviews/comment-pass.md: every added comment line and .md line, classified keep / rewrite / delete with the pattern that fired, plus every doc-file claim it re-verified against the tip. You apply the verdicts: rewrites and deletions fold into the owning commit with the old tip in the ledger and the tree-identity check, restacking above as in step 2; a rewrite that would drop a real constraint is restated, not deleted. Then rebuild and re-run scoped tests on every branch from the earliest fold upward. Ledger entry with the counts and the post-pass tip. "Nothing to change" is a valid verdict and is still recorded, with the enumeration that proved it. A Robowright Session that stops after step 2 without reaching this step says comment pass: not run in the handoff — never silently.
  4. Smoke inventory. smoke-test Phases 1–2 over the whole diff <base_sha>..<tip>, seeded by the brief's Smoke scope but derived from what actually changed. Output smoke/INVENTORY.md. This supersedes the brief's sweep_screens as the sweep's screen list — the brief's list is a Planner's guess made before the code existed — and produces the agent/manual lane split the next two steps consume.
  5. Regression sweep — the smoke-test agent lane (Phase 3), run per the project hook (→ Regression sweep, → Device): base build and tip build on the same leased device, the inventory's agent-lane rows, the hook's predicates as the assertion, screenshots and image diffs as advisory artifacts under evidence/sweep/. Every touched-class row owes its base-build run; a predicate that passed on base and fails on tip is a defect: fix and re-sweep, or stop with verification-failed. blocked, infra, and unverified are not passes and are reported as themselves. Write smoke/AGENT-PASS.md and record its verdict counts in the ledger.
  6. Manual pass document. smoke-test Phase 4 over the rows the agent lane did not settle: smoke/MANUAL-PASS.md, tiered and risk-ordered, every row carrying its why and a N/A option. This is what HANDOFF.md's smoke section reproduces.
  7. Change description, doc-gate, publish. Write the change description the project hook's Publishing section asks a finished change to carry — one per published unit, one for the whole change, or none — in the format that section defines (through the skill it names, where it names one), saved under <session_dir>/prs/. Leave empty any slot that format reserves for the Owner. Beside it, the squash message for the whole change, at <session_dir>/prs/<unit>/commit-message.txt or wherever that section puts it: the hook's commit form, ending with the Co-Authored-By trailer, the file accept.sh --message takes. The change description names the full id of the reviewed tip and carries no accept line; the accept line is composed by the Lead, or by the Owner in a one-off. The completed smoke pass is material for it — the enumerated walk, not the words "smoke tested". Then doc-gate on every such document and on HANDOFF.md: one fresh-context subagent per document, each one reviewer-docs (job: doc-gate), output to reviews/doc-gate-<name>.md; apply the verdicts, carry every ask into the handoff as a question. A document with an open ask is not published. Then publish, only if run.json.publish names a strategy; false or null publishes nothing — exactly as the project hook's Publishing section says for the resolved strategy and nothing beyond it. Record in run.json.publish what publishing produced and what it left for the Owner, with the strategy name inside that record as its strategy key (publish.strategy). Then run every duty the profile, then the project hook, lists for worker.publish, in order — and nothing when both list none.
  8. Final whole-suite run, owed once at the tip if whole_suite_runs_owed includes final-tip — and only if a source file (per the hook's source-file patterns) changed since the last whole-suite run. When the last unit skipped its unit-close run (Phase 2 step 8), this run is owed unconditionally, even when no source file changed since the last one. Otherwise, after a prose-only commit, cite the previous run's log and git diff --stat <last_run_sha>..<tip> showing no source file instead; that citation is the verdict.

Phase 4 — Handoff

Work this phase in order: the documents in the list below, then the finish review and what its verdict owes, then Finish, whose last act is state finish — it needs reviews/end-of-stack.md saying ADVANCE, HANDOFF.md and HANDBACK.md on disk and, unless run.json.plan_review is off, a settled finish review (guard plan-review-settled). (A Robowright Session that is stopping instead applied state stop already; it still owes the cost block, HANDOFF.md, and the deps/ removal below.)

  • Cost block: python3 ~/.claude/skills/worker/scripts/run-cost.py --run-dir <session_dir> --write stores run.json.cost (requests, tokens by class, average context, output by model, estimated USD, lines written vs shipped). Run it twice. Run it first before writing HANDOFF.md and HANDBACK.md, and quote that reading in both — the lines the profile's Budget section names, headed "reading at <HH:MM>, before the final entry; run.json.cost is the authority", because writing the handback spends requests the quote cannot include. The estimated USD figure is meaningful only where that budget is in dollars, and actual_usd stays null for the Owner. Run it again as your last act, after the final ledger entry and before state finish or ending the turn; that reading is what run.json.cost keeps. The SessionEnd hook also runs it unasked, so a Robowright Session that dies still leaves a figure — but a session ended with claude stop, or left idle, never runs that hook.
  • Final HANDOFF.md: where things stand, where the published change is (per the project hook → Publishing), what was verified (with evidence paths), what was not, parked items, brief corrections, and the smoke pass the Owner runs — reproduced in HANDOFF.md from smoke/MANUAL-PASS.md, which stays the authority (templates/HANDOFF.md).
  • HANDBACK.md for the Lead (templates/HANDBACK.md): what the plan must change because this ran — names changed in review, decisions answered or reversed, structural facts the brief did not anticipate, what is still owed. The lead skill's intake reads it before the next brief is written. It reaches the Owner, so every unit it names is U12 (note-autosave) (robowright → Contracts every role keeps, 11).
  • Decision log entry in the decision-reporting shape the Owner's own rules give, when the machine has them, including Rejected.
  • If the project keeps learnings/, one file per non-obvious lesson, same conversation.

Finish review

The Planner's intent check, run by this session on its own record. run.json.plan_review: off skips it, and the ledger says so; everything else runs it once HANDOFF.md and HANDBACK.md are on disk — a review before HANDBACK.md sees no asks.

  1. A PLAN-REVIEW.md left by the last unit's per-unit review moves to PLAN-REVIEW-<that unit>.md first, so only the finish review can satisfy step 2, and a reviews/polish-gate.md left by a finish review before a rebrief moves to reviews/polish-gate-r<n>.md, so only this review's polish can settle finish. Spawn planner-review with prompts/PLAN-REVIEW.md filled in, scope finish, and model: <run.json.robowright.planner>: the session dir, worktree, project folder, base and tip, run.json.delegation, reviewer_code as the reviewer-map model, and the Review Overlay paths from the preflight ledger entry (or none). It writes PLAN-REVIEW.md. No file, or no Verdict: line, when it returns: spawn it once more; a second miss is state stop --code verification-failed.
  2. state plan-review --verdict <the file's Verdict word>. Ledger entry: the verdict, the Why: line, the number of asks.
  3. By verdict:

    • ship → Finish.
    • polish at lead or planner delegation → Polish.
    • polish at owner delegation → state stop --code one-way-door --detail "<the polish items, one clause each>". The Owner's answer arrives with the resume: apply → Polish; decline → move PLAN-REVIEW.md to the next free PLAN-REVIEW-<n>.md, run step 1 again with the decision pasted into its inputs, and apply its verdict — finish reads the newest one.
    • rebrief → state stop --code rebrief --detail "<the file's Why: line>". HANDOFF.md's FIRST ACTION says a rebrief Planner answers this stop. Never finish; the guard refuses it.

    Either stop still owes Finish's releases and the second cost reading before the turn ends.

Polish

The review's ## Polish items, and nothing beyond them:

  1. Ledger entry Decided (Planner) quoting the items — the owner brief's Key decisions row is read from it. When the Owner's apply sent the session here, the entry is Decided (Owner), which that row leaves out: the call was the Owner's, not one made for them.
  2. Each item as one commit on the tip, subject polish: <what>, through the profile's commit tool, inside the brief's Scope paths.
  3. Build and the scoped tests the items touch (Phase 2 steps 3–4), each item's own check, and the worker.unit-gate duties, verdicts quoted. An item that edits a source file (the hook's source-file patterns) also re-runs the kind row (Phase 2 step 5) of the unit whose lines it edits, on the edited lines only — for a behavior or tests unit, one mutation round, recorded in the ledger and not counted against max_mutation_rounds_per_unit.
  4. One reviewer-gate on prompts/REVIEW-GATE.md: the ## Polish section as the contract, git diff <tip before polish>..<tip>, the evidence paths, the Review Overlay line. It writes reviews/polish-gate.md, which finish reads; no event records it. HOLD → one fix commit, step 3 again, the first review moved to reviews/polish-gate-1.md, one more gate; a second HOLD is state stop --code verification-failed.
  5. The final-tip whole-suite run, by Phase 3 step 8's rule.
  6. Rewrite HANDOFF.md, HANDBACK.md, the change description and the squash message under prs/ for the polish commits; the description and HANDOFF.md get a fresh doc-gate (Phase 3 step 7), then publish again by Phase 3 step 7's strategy, so what was published carries the polish, and run.json.publish records the new tip.

One polish pass, as commits: the machine refuses a new unit at end-of-stack, and what the pass leaves is a follow-up.

Finish

A one-off (run.json.shape: one-off, the one-off skill) has no Lead to take it in, so a session that reaches Finish without a stop does the Lead's two intake agents first, in this order. <project_dir> is <projects_root>/<run.json.project>, <projects_root> being launch.json's projects_root, else its sessions_root's parent.

  1. Spawn reviewer-intake with model: <run.json.robowright.reviewer_prose> and the block in ~/.claude/skills/lead/prompts/HANDBACK-INTAKE.md filled in: this session dir, the worktree, <project_dir>. It writes INTAKE.md, which accept.sh requires. No INTAKE.md when it returns: spawn it once more; a second miss is state stop --code verification-failed.
  2. Spawn the owner brief: subagent_type: general-purpose, model: <run.json.robowright.explainer>, the message the launcher's explainer:guide prompt (run-launch.sh, its PROMPT= line) word for word, with $PROJECT = <project_dir>, $SESSION_DIR = this session dir, and $GUIDE = <project_dir>/<launch.json review_guide_dir>/<unit id>-owner-brief.md, the unit id run.json.ticket, else this session directory's name (the launcher's rule). No file at $GUIDE when it returns: spawn it once more; after a second miss, log it, and HANDOFF.md's FIRST ACTION carries run-launch.sh --explainer guide --project <project_dir> --run-dir <session_dir> --dry-run for the Owner — the accept does not wait on it.

Then, for every Robowright Session:

  • Release the device lease (→ Device) and every lock run.json.locks lists.
  • Leave every deps/<session> checkout for the Owner: removing one writes its repository's git directory, which neither your sandbox nor rw-git allows. Hand the Owner git -C <path> worktree remove <session_dir>/deps/<session> in HANDBACK.md.
  • Leave the worktree clean and checked out on the tip. Do not remove the worktree or the marker; the Owner does.
  • The cost block's second reading, then state finish.

Compaction, rotation, and resumption

You cannot request compaction; only the harness compacts, when the window fills. The launcher the profile names (→ Launch) therefore starts a Robowright Session with CLAUDE_AUTOCOMPACT_PCT_OVERRIDE (default 85, from the brief's compact_pct) so the window fills at that percentage of autoCompactWindow (250k if a machine's settings.json sets that, so ~212k) and the average context per request stays low by construction. It travels inside --settings (env block), never the launcher's environment: a background session is claimed from the daemon's pre-forked pool and keeps the daemon's environment. The PreCompact hook tells the summarizer what to keep, including HANDOFF.md's FIRST ACTION; the SessionStart hook re-injects the session pointer. Your job after compaction is rule 1.

Rotation (rotate_sessions: true in the brief) is the stronger form: a fresh session per unit, started per the profile → Launch after Phase 2 step 9 ends the turn. It works because rule 1 holds — a rotated session has exactly what run.json, LEDGER.md and HANDOFF.md say, and nothing else.

When a unit runs from a Lead-written prompt

A scheduled task or a background task starts with no memory and ends when the unit closes, so it is the whole of that unit's session. Two things follow, and both are the Lead's to get right when it writes the task's prompt:

  • The task inherits this handbook, not a paraphrase of it. The prompt carries ROBOWRIGHT_RUN_DIR=<session_dir> as a line of its own — for a scheduled task, that line is what arms the guard and lets the hooks find the Robowright Session before step 1a's cd — and says to invoke this skill with <session_dir>; it does not restate the phases, the gate, or the stop contract in the Lead's own words. A bespoke prompt silently drops whichever rule it forgot — usually the ledger entry, the scoped-suite discipline, or the stop contract — and there is no session-level preflight to catch the omission.
  • The task rewrites HANDOFF.md before it ends, every time. Phase 2 step 8 already asks for this. There is no next boundary inside the same context: whatever the task leaves on disk is the entire state the next unit starts from. A task that ends without it has orphaned the Robowright Session — run-roster.py reports exactly that, as handoff: (no 'Where things stand' section).

If a human message arrives mid-session, answer it in two sentences and continue unless it says stop. A stopped Robowright Session is resumed by whoever answered it (the Owner, or the Lead under the brief's delegation): they apply state resume --by <owner|lead> --decision <text> before waking you, which puts phase back where the stop left it. You never apply resume yourself. On waking: state status to confirm you are no longer stopped, append the answer to the ledger as a decision naming who decided; take every lock run.json.locks lists again, by the platform plugin §6 liveness rule — the stop released them; when run.json.depends_on is non-empty, run Phase 0 step 7a again; then continue from HANDOFF.md's FIRST ACTION. A rebriefed Robowright Session (BRIEF.md has a ## Rebrief <n> section) starts as a rotation: read that section first, then FIRST ACTION.

Planner and Lead side

The brief is written by a Planner session (planner skill, or the Owner) from templates/BRIEF.md, or by the one-off skill in the Owner's console, which also launches it. Launch is the Lead's, per the profile → Launch — a new session, started in the worktree (the device lease comes with it and the hooks find the marker) or in a parent folder with the prompt shape above (Phase 0 step 1a makes up the difference). The profile says whether that is a command, a scheduled task or a background task, who carries a pasted line, and what may start what; launch.json's launch key (the robowright skill → PROFILE-CONTRACT.md) sets the mode, paste or auto.

Whichever it is, three environment variables are a contract between this handbook and any launcher:

VariableWhy the launcher sets it
CLAUDE_CODE_STOP_HOOK_BLOCK_CAP=40The harness overrides a Stop hook after eight consecutive blocks; without the raise, eight premature stops end a Robowright Session that is not done
CLAUDE_AUTOCOMPACT_PCT_OVERRIDEFrom the brief's compact_pct; the context window fills at that percentage of normal, which is what keeps average context per request low by construction
CLAUDE_CODE_SUBAGENT_MODEL=sonnetThe default model for subagents; the reviewer-* agent files pin their own model above it

The session's model is the next unit's model where the brief sets one, else the brief's model, else the run profile's model for that unit's kind (standard: sonnet for tests, docs, refactor; opus otherwise — a brief-level model switches that off for every unit), and its name follows the project hook → Naming.

Budgets the Planner writes into the brief, and the Robowright Session reports against: model, max_mutation_rounds_per_unit, whole_suite_runs_owed, max_extra_review_subagents, rotate_sessions, compact_pct, plus whatever fields the profile's Budget section defines.

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.