Orchestration
Delegation only works when the orchestrator treats every subagent claim as unverified and every judgment call as its own. These rules were each paid for by a real incident.
Charters
A charter is the task prompt a subagent receives. Requirements:
- Reference every document by absolute path, and only paths that live in the repository — repo skills under
.claude/skills/, repo scripts behind their package commands. A relative path resolves differently (or not at all) in the agent's working directory, and a personal home-directory path can vanish out from under a live agent:~/.claude/skillswas deleted mid-goal to end personal/project skill drift, leaving in-flight charters instructing agents to sweep browsers from a path that no longer existed while the package's own sweep command was the live one. - When the work depends on an external spec or vendor document, fetch it raw —
curlor a real browser, never a summarizing fetch — into a scratchpad cache file, and name that cache path in every dependent charter. All lanes then build from identical bytes; left to fetch it themselves, each agent works from its own paraphrase and the lanes drift apart on the contract they were supposed to share. - When parallel lanes could touch the same module, name the sibling lanes and give each an explicit do-not-touch list of files/functions the others own. For genuinely shared append-only files (routes config, nav layout, seeds), say up front that rebase conflicts there resolve keep-both. A fence names artifact classes as well as files — E2E specs, docs articles, and seed sections are the verification stage's territory — because a file-level list cannot fence a file that does not exist yet, and a build stage drifted into writing the spec its verification stage owned. Before launching, check each item's designed fix against its lane's do-not-touch list: an item whose only defensible fix lives in a sibling-owned file moves to the lane that owns the file, or gets an explicit carve-out — left as is, the builder must choose between skipping the item and violating the boundary, and one wave produced a skipped item, a banked residual, and a flagged two-file deviation from exactly this.
- At most one repo-mutating agent per worktree at a time, and an agent that verifies against a builder's live worktree is read-only toward it. A concurrent sibling's
git add/commit sweeps the other agent's half-finished files into an unrelated commit, and untangling that means rewriting the branch tip. - When parallel lanes allocate from a shared identifier pool — seed namespace prefixes, fixture ids, ports, queue names — the orchestrator publishes one canon allocation table in every lane's charter before the first launch, and each lane sub-partitions its allotment across its own flows. Lanes that pick identifiers independently collide, and the collisions surface as another lane's spec failing long after both lanes went green in isolation; one wave shipped three separate collisions (two lanes sharing a phone prefix, two sharing a fixture id, one lane colliding with itself) before the table became standing practice.
- When several lanes will each touch a shared computed constant — a contract fingerprint, a generated schema hash — every charter declares the same resolution protocol up front: on rebase, recompute the value by the mechanism that owns it (its own test's computation), never keep-mine or keep-theirs. Three parallel lanes once rewrote the same fingerprint off stale bases, and every merge needed a hand repin. Each charter also declares whether its own items are expected to move the constant; an unexpected movement is a stop condition to report, never a silent repin — a lane that repins a public contract hash it had no business moving ships the change invisibly under a green suite.
- Assign each subagent an explicit scratch-file namespace — its lane or task name as a filename prefix — and forbid it from writing any shared scratchpad file, above all the orchestrator's session ledger, whose actual path the charter must give since it is named for the effort rather than by a fixed convention. Parallel agents that share a scratch filename clobber each other's state, and a fix agent that writes its own notes over the session ledger destroys the orchestrator's recovery record.
- Include a stop-on-contradiction clause: if the charter's factual premise (a claimed bug, a claimed missing feature, a spec citation) doesn't survive verification against the primary source, the agent halts that item and reports with citations instead of inventing. "Verified already correct, no change made" is a valid, expected outcome. The clause covers the charter's designed fix shape and its measured
file:lineanchors, not only the finding: sibling merges stale both between charter-writing and execution, so a builder that re-verifies the design against its own worktree and deviates with citations is complying — the deviation is adjudicated at merge, never treated as disobedience. Charter-supplied names — slugs, titles, feature labels — fall under the same clause: an agent that discovers the real feature differs from the charter's name must correct the name and flag it, not ship correct content under a stale identifier. - A charter names the repo's committed engineering conventions (absolute path in the lane's worktree) and instructs the agent to read them before coding and to treat them as binding, naming the repo's designated reference implementation where one exists; a reviewer or skeptic charter names the same conventions as the codified-house-rule source for rubric (b) below. A charter that writes or reshapes tests also names the repo's committed testing doctrine as binding and does not prescribe a test mechanic itself — a charter once offered a patch-based interleave that doctrine forbids, and only the builder's own diligence avoided shipping it.
- A charter that includes a mutation proof (deliberately breaking code to show a test goes red) also specifies the restore protocol: restore byte-identically, verify via
git status/git diff, and purge compiled-artifact caches (stale bytecode and the like) under the touched packages — a same-size restore within the same mtime second leaves stale build artifacts that quietly poison every later run in that tree. - When two reference sources disagree, the charter names the conflict for adjudication — it never silently picks one. A charter's factual claims are no more trustworthy than a builder's until verified.
- A charter or goal text that enumerates a derivable structure — a dependency graph, a consumer list, a coverage set — instructs the agent to re-derive the complete set from primary sources and treat the enumeration as examples to check against, never as the whole set. Stop-on-contradiction cannot catch an incomplete list: nothing contradicts it, so its gaps ship. A five-edge dependency graph hand-written into a goal text was encoded verbatim as a registry's whole truth, and the guard built on it approved variants that then died mid-transaction on a generic error.
- A charter for any agent that publishes text — an issue, a PR body, review comments — forbids personal data from customer datasets (names, emails) in the published artifact unless strictly necessary, and the orchestrator scans the artifact for it before shipping. A dump-sourced operator email once shipped inside a published investigation issue and had to be redacted after the fact.
- Builders never run long gates. A charter ends at commit (or commit + push) and STOP, with only scoped foreground checks before it (the touched module's tests, lint) — "run the full suite in the foreground" does not survive contact with builders: they background it and end their turn terminally stalled, because a workflow agent's turn ending is final. The orchestrator runs full gates itself as its own background shell (its re-invocation on completion costs nothing) and owns push/PR/merge when the charter stops at commit.
- Instruct every agent to deliver its full final report as its last message — never to end the turn "waiting on CI" or any background process: a lane that signed off with "clean, waiting on CI" had to be resumed just to extract the report it never sent. An agent never polls a process it backgrounded either — one foreground wait on a scoped check, or hand the wait up. Machine-level waits (a container image pull, an environment stall) belong to the orchestrator, who takes them over machine-side while the agent proceeds; repeated "check the state" turns have eaten a whole stage's context window.
- Write each new charter/script fresh with the Write tool. Deriving one by programmatically splicing a previous one introduces silent syntax errors.
- Address every
SendMessageby looking up the recipient's task id in the ledger head at send time, never from memory. A charter delivered to the wrong lane's agent reads as an order to abandon its own work and take over another lane's, and only the recipient's own do-not-touch clauses stand between that misdelivery and a corrupted worktree. - A multi-stage script carries its charter discipline in the shared preamble from the first draft — commit at every milestone, read targeted ranges instead of whole generated files — never patched into one stage after a failure exposes the gap. A stage whose preamble lacked it was stopped at its context threshold with zero commits and eleven uncommitted files; the sibling stage that carried it landed five milestone commits over a comparable span.
- Every build charter carries a classify-the-disk-state-first preamble from its first draft: before building anything, read
git statusandgit login the lane's worktree, classify every commit and dirty file as done, partial, or untouched, verify-don't-redo whatever is already correct, and runseasoned-skills provisiononly when the lane's worktree does not exist. A workflow auto-retries a dead agent straight back into the same worktree, so half-finished work on disk is a normal starting state rather than an exception. An API-level event killed a four-lane wave whose charters said only "provision if the worktree does not exist yet"; the retries landed in worktrees holding three to five commits and dirty trees apiece and classified them only on their own initiative, and the preamble had to be patched in at relaunch. - Relay a finding at exactly the scope it was measured. "These two named tests survive the mutation" is not "the suite survives the mutation"; widening it on the way into a charter sends the agent to disprove a claim nobody made, and its correction can bury the narrower gap that was real. Quote the finding's own boundary, and mark anything you extrapolated as yours to verify.
- Cross-check a charter's exit assertions against its own items before launching: an exit gate demanding a file show no diff contradicts another item that edits the same file, leaving the agent to choose between violating the gate and dropping the item. Scope byte-identity checks to the exact lines or symbols they protect, never to whole files other items touch.
- A parameterized script must parse
argsdefensively (string-or-object) and hard-throw on any missing required field — a silently-undefined interpolation produces a plausible-looking empty result that reads as a clean pass. - A slice that ships a route, loader, or form must drive that surface live at least once — a minimal browser interaction or a real-
Requestsmoke — before handoff. A unit-only exit bar passes code whose query crashes at runtime or whose form cannot submit (a select with nonameattribute). - A live proof binds only the commits that preceded it. Sequence the browser walkthrough as the charter's last step, after the final commit, and redo it after any later change to the proven surface — a proof that predates a schema or handler commit is evidence of nothing, and a redone proof regularly catches what the suite missed (a coercion regression, a state-update race). The same binding governs specs across stage boundaries: a later stage can invalidate a spec an earlier stage wrote, so the verification stage re-runs every one of the lane's specs after the last build commit — a refusal spec asserting one stage's toast went red the moment the next stage reshaped that refusal, and nothing had re-run across the boundary.
- A skeptic or verifier charter carries TWO acceptance rubrics, not one: a finding stands if either (a) its concrete-input failure scenario occurs at runtime, or (b) it identifies a violation of a codified house rule or doctrine in the work under review. A runtime-only rubric refutes correct doctrine findings — an ad hoc query fragment inlined in a view where the repo's committed conventions prescribe a model-owned query method — exactly when the fix is cheapest. Doctrine findings against unmerged schema or shape default to fix-now, because schema shapes are effectively permanent once merged.
Verify, never trust
- Re-run the gates yourself before advancing any stage on a subagent's self-report.
- A completeness claim — "every route covered", "every call site migrated", "every consumer updated" — is only checkable against a denominator derived live from the system of record (the URL resolver, the schema, a repo-wide census), never against the plan that produced the work: the plan omits exactly what the work omitted. Establish the denominator before declaring any "every X" objective met, and prefer a gate that recomputes it and fails on drift over a registered list or document describing coverage — registered state duplicates the system and goes stale silently.
- Reconcile numbers exactly: baseline + computed delta = measured, and identical across two runs. A mismatch is a hard stop, not noise. A collect-only reconciliation carries one extra term: registry-parametrized suites expand on their own whenever the registry they parametrize over grows, so account for that expansion before reading a collect-count jump as drift.
- Reconcile a builder's charter item by item against its diff, not only by counts: every charter item ends in exactly one visible state — implemented in the diff, verified-already-correct, or an explicitly reported skip. Builders silently drop items, and numeric reconciliation cannot catch an item whose omission changes no counts (a test reshape, a mechanical conversion) — one such drop shipped unnoticed and only surfaced in a later personal read of the merged diff.
- Reconcile the adjudicated rulings against the union of the lane charters before the wave launches: every ruled fix appears in exactly one lane's items. Orchestrators drop whole rulings the same way builders drop charter items — three ruled fixes once reached no lane at all, caught only by a ruling-by-ruling reconciliation during the final write-up.
- A charter's expected gate numbers are measured on the current base tip at charter-writing time, never carried forward from per-lane history — every sibling merge stales them. When lanes have merged since the last measurement, re-measure the union before chartering anything that asserts a count.
- A task counts as launched only when its task/run id from the tool result is in the ledger. A written script or a narrated intent is not a running task. Copy every id out of the returned tool result — never from memory or prediction; when a launch and its ledger entry go out in one parallel call, write
TBDand fill it in after the result returns. An id written in the same message that launched the task is a prediction, and twice it was wrong. - Never block on a running subagent or workflow — a synchronous wait for its output freezes the conversation until the agent finishes, so the user can neither interject nor redirect, and the user has had to interrupt one to say so. Launch in the background, keep the chat free for whatever else is pending, and act when the completion notification arrives. When the harness's task registration is uncertain (after a compaction), arm a background watcher on the task's own artifacts rather than polling in the foreground.
- Independent lanes launch simultaneously, never in staggered waves. Host contention (CPU, database) slows every lane's gates but never justifies holding a launch back — an idle lane costs more than a slow gate. Contention is managed by the orchestrator's own scheduling instead — it owns every long gate run, so it schedules heavy suites by judgment when lanes pile up, and a contention-shaped failure (connection exhaustion, timeouts under load) is re-run alone before anyone treats it as a defect.
- A review or QA returning zero findings is only a clean pass if its agents all completed. Errored finders, an implausibly fast run, or a wrong agent count mean the run is broken — relaunch it.
- Findings about uncommitted working-tree state from a parallel review fan-out are suspect: when finders share one worktree, one finder's in-flight mutation-proof — code deliberately broken to validate a test, then restored — is visible to its siblings and reports as a phantom defect. Verify any working-tree observation against the commit under review (
git show HEAD:file), and either require finders to mutation-prove only against committed state and restore immediately, or discount working-tree-only observations at the verify stage. - Independently probe a shipping agent's claimed git state (
git merge-base <lane> origin/mainvs origin/main's tip) before merging. Verify mechanical batch edits landed by grepping the expected before/after state, not by exit code. - A mutation test must sabotage the transformation under test, never the input it reads. When a gate re-derives both sides of its comparison from the same source — a parser diffed against its own re-parse — mutating the source leaves both sides agreeing and the gate green, proving nothing; break the transformation (drop a word inside the parser) and watch every output fail. A wrong-sided mutation test once read as a proven gate when it had exercised nothing.
- Before treating a probe's mismatch as a finding, validate the probe itself against a known-good case — a fidelity spot-check once "failed" solely because the probe's own text flattening left timing lines interleaved with the prose it matched against. And prefer the dumbest direct check over a clever detector: an n-gram loop detector reported zero loops on a file whose raw line counts (
sort | uniq -c) showed one line repeated 1,691 times. - The orchestrator's PR review reads every line of the diff against the binding doctrine of the surfaces it touches — a shaped project's document contracts, the reference implementations it names, and the repo's codified skills — regardless of what the PR body flags. The author's flag is never the safeguard: a page-wide raw-fetch store with bespoke retry and revalidation machinery shipped through review while the shaping document prescribed inheriting the framework's own submission machinery, because everyone read only what the body mentioned — the departure sat unflagged in plain sight in the diff. A goal is never met while its implementation contradicts its shaping document, and conformance is checked at every PR, not discovered at goal close.
- When a merged lane retires or renames a shared symbol (a manager method moved behind a facade, a renamed helper), every sibling lane still to merge can carry code written against the old idiom — the siblings branched before the rename landed, and their files never conflict, so the merge itself flags nothing. At each subsequent sibling merge, grep the whole tree for the retired idiom before running suites and retarget the hits; one seam retirement broke four consecutive lane merges in a single wave, each discovered late by a failing suite or lint instead of cheaply by the grep.
- The orchestrator's own edits are subagent work for verification purposes: any orchestrator-authored change to an audited artifact — a coverage claim, a documented behavior, a spec or manifest sentence — gets the same adversarial re-verification as a builder's diff before it ships. Three separate single-sentence orchestrator edits in one goal each introduced a fresh overclaim that only a verifier caught. Write such sentences from the rendered screen or the measured number, never from the data's intent, then have a verifier try to refute them.
- Personally source-read any confirmed "inconsistent with spec/reference" finding before directing the fix — especially when the fix would reverse a prior ruling. A finding's observation can be accurate while its verdict of "wrong" is not. Doctrine-flavored findings get the same read, not a shortcut: a builder's confident "this is exactly the hazard the doctrine names" was false on the file it cited, on the kind of date the rows actually carried, and on the ordering it predicted, and a whole fix lane was spent proving the premise false. Charter every fix lane to verify its premise before changing anything.
- An investigation chartered around a stated finding tends to confirm and amplify it: the charter's frame decides what the agent looks for, so a mechanism living in an adjacent flow stays invisible even when the agent's own appendix names it. Before designing on, escalating, or alarming the user with an investigation's headline conclusion, commission one independent second perspective under a different frame (compare against a reference implementation, or charter a refuter) and adjudicate any disagreement yourself against primary sources.
- An agent's claim that a symbol has a single consumer ("only seed.ts imports this") is a factual claim — grep the whole repo,
tests/included, before directing a refactor that removes or narrows a shared contract on its strength. It bites hardest when the claim justifies reversing another agent's deliberate earlier design, and green CI is no safety net when the broken consumer only runs against state CI never exercises, like a converging seed over a persistent local database. - Audit PR-body citations ("per spec X", "per source Y at file:line") against the actual cited location, and check any "deferred as polish / out of scope" claim against the actual contract. Builders produce plausible but fabricated attributions.
- Never conclude something is absent from a truncated search: a
grep … | headthat fills its quota hides the line that would refute the absence. Re-run unbounded, or open the file at the cited range, before acting on any missing-symbol or missing-assertion claim — a truncated pipe nearly directed a fix for a "missing" test assertion that existed exactly where cited. - Shipped prose that makes factual claims about system behavior — docs pages, schema and endpoint descriptions, recipe text — is verified like code: before it ships, a dedicated adversarial pass tries to refute each claim against the source. Plausible-but-false wording reads well precisely because it flatters the mental model that wrote it — false revenue-semantics claims survived a builder's self-review and the orchestrator's personal read twice in one PR, and both times only a refute-charter caught them. The unwinnable class is census, totality, and lineage claims — counts of routes or tests, "every caller", "all N migrations", "unchanged from main" — over any surface too large to recount mechanically: seven such claims fell to refute passes in a single review effort, the orchestrator's own among them. Write the mechanism plus verified examples instead, and reserve exhaustive claims for small sets the prose itself defines and a refute pass can recount.
- When a fix pass restructures a seam beyond what its charter asked — replacing an inherited implementation, moving a boundary, collapsing two code paths into one — its acceptance gate is re-running the measurement that exposed the original defect, never the agent's own argument that the new shape is equivalent. The restructure invalidates the earlier measurement, so the evidence you already hold no longer covers what ships. Mandating that re-run in the fix charter caught a second regression the fix pass had introduced while reasoning its way to a correct-looking shape.
- Any change to a shared core module made by a fix/QA agent — a framework directory, a shared library package every surface imports — gets the orchestrator's personal diff read before shipping — its blast radius exceeds any lane's review scope.
- When a builder reports it verified a UI flow by simulating requests (fetching the form's
FormData, forging a session) instead of real interaction, treat that as an unverified claim and dispatch a real-interaction prober before relying on it. A "harness quirk" explanation for why real clicks failed is itself a claim to verify.
Judgment stays at the top
- Never trade the mainline for an edge case: a fix whose cost lands on the bulk of use cases to close a rare corner is the wrong shape, however clean the mechanism looks. Accept the residual and record it, or scope the mitigation to the edge itself. Shipping the full route manifest up front (
routeDiscovery: 'initial') to close one offline corner — a submit to a never-visited write route — was denied for exactly this: it reverses lazy route discovery, which exists because full manifests scale badly, and charges every session to fix a case almost nobody hits. - Every demand gets an architecture round before any delegation: zoom out and map the mechanism behind the ask, where else that mechanism lives, and the repercussions of candidate fixes — then design at the level the root cause lives. A defect surfacing in one route but rooted in a shared primitive gets the primitive fixed, never a route-local workaround; a batch of demands gets grouped by mechanism, not by surface, before lanes are cut. Zoom in only with full domain over the systemic impact. A route-local patch of a polling defect owned by a framework hook would have left the same bug live in fifteen sibling routes; fixing the hook also surfaced a second latent defect in it.
- A stakeholder's demand names what they see. Before designing or interviewing against it, translate every term through the navigation the requester actually uses (the app's committed nav definition), never through internal section, module, or schema names — an analysis framed on internals reads as wrong to the user even when technically coherent, and one design interview had to be restarted after the user caught the frame (the demand's word named a navigation menu entry, not the internal seed section it also matched).
- Answer any question about repo machinery only after reading the primary source completely: every file in
.github/workflows/before stating what CI does — one check name can live in two workflows, a per-PR job and a scheduled twin — and real run history (gh run list) before stating what a job costs in time, since a job's timeout is a ceiling and never an estimate. When the user's question hints that something is missing, it is a diligence probe, not a request for a guess: assemble the complete factual picture from the sources, then answer once. Seven consecutive user messages on one thread went into forcing a workflow-file read that should have preceded the first answer, every probe meeting a fresh inference instead — and in delegated work nobody is there to supply that correction. - Design and adjudication are orchestrator-tier work. When the evidence under a design changes (stale reference, corrected spec), redo the design at the orchestrator tier — never hand the stale design down with a "re-verify your citations" instruction.
- Synthesizing a multi-agent review's findings into an adjudicated register is itself adjudication, not mechanical distillation. Read every report yourself and build the register personally — a synthesis delegated to a subagent launders the miners' claims into rulings nobody made, and the fix program built on it inherits judgments the orchestrator never exercised.
- A goal text, design document, or any other foundational artifact drafted for the user is built on a verified inventory of the current codebase, never on memory of it — commission or perform the primary-source study first. A goal draft written without that diligence missed a whole class of existing sync machinery and had to be redone after the user caught it.
- At design time, inventory every seam the build cannot exercise without something only the user can supply — a vendor API key, a paid account, a physical device — and hand that list to the user while the design is still open, never at verification time when the arrangement no longer fits. When a dependency cannot be arranged in time, shipping that seam reviewed-but-never-exercised is the user's explicit decision to make, recorded as a known risk. A machine-translation vendor seam was already built before anyone said out loud that no test ever calls the real API, by which point the account could not be set up in time, and the user had to ask the question the design should have answered: "Is there any other part of this project that will not be able to be exercised during building unless I provide you with something?"
- When keeping an approach green demands case-by-case fixes that each breed new edge cases — or a single lane grinds for hours on one defect — that is a design smell in the approach itself, not a hard fix: pause the lane and re-open the shape question with the user instead of pushing through. A pixel-equality gate consumed a four-hour masking war, and the user, not the orchestrator, had to call the smell; the reshaped design (gate only the deterministic subset, report the rest for human eyes) held immediately.
- When a lane empirically disproves a factual premise in a shared research digest, correct the digest itself immediately and visibly, before the next lane reads it. Sibling lanes read the artifact, not the report that refuted it, so every later lane inherits the same wrong premise from a document that still asserts it.
- Grounding priority when state or policy is uncertain: primary sources (git, live files, the actual spec) beat live skills, and live skills beat ledger notes or compacted memory. On a policy detail, the live skill file always wins over ledger shorthand.
- When parallel lanes independently invent shapes for the same shared surface, adjudicate one canon and give later-shipping lanes an explicit adopt-the-canon duty at rebase. Distribute the canon as a verbatim, byte-identical file package every lane applies unchanged — identical bytes auto-merge everywhere, so the shared file never conflicts again.
- An invariant that spans several lanes' data — a shared ledger fixture, a balance every lane's writes must conserve — is orchestrator-tier design work. Derive it yourself from primary sources, commit it as a fixture, and hand lanes only consumption rules; never let each lane implement its local view of the global rule. Two successive lane agents each handled their own slice of a shared stock balance plausibly and broke the global invariant both times — a lane cannot see the whole.
- When lanes re-express existing behavior (authorization gates, validation rules), builders guess wrong in both directions — stricter and looser both shipped from the same wave. Commission one audited map of every capability to its exact source-of-truth behavior (with file:line citations) before any fix pass, and make every fix charter cite the map, never intuition.
- A lane reports out-of-scope findings with repro evidence; it never fixes them inline. Every finding gets its explicit disposition the moment it reaches the orchestrator, from whatever surface — a lane's report, an audit register, or a finding read in a PR body at review time — nothing parked undecided, nothing dropped. {{findings-disposition}} An out-of-scope fix always executes in its own dedicated pass, never inline in the lane that found it — that is what keeps lanes convergent and review rounds terminating. A GitHub issue is legitimate only for a decision the user must make, work blocked on other work, or an unknown-cause investigation someone will actually run. Never file an issue as idea storage — no "maybe someday" refactors, no future-abstraction notes (Shape Up's no-backlogs rule: really important ideas come back on their own; a standing pile only makes everyone feel behind). During a scoped goal, a findings register is fine as a cycle-scoped working list — it dissolves into fixes and decision issues when the effort ends, never outliving it. Before deferring an item until some future event, check that the event does not itself depend on the item: work parked until a readiness decision it is a precondition for never restarts, because the decision waits on the work and the work waits on the decision.
- A designer's "too invasive / out of scope" blast-radius claim is a factual claim, not a judgment call — grep it before accepting the compromise it justifies.
- Whether to fix a known defect or a regression is not the user's decision. Once verification has established that something is broken, fixing it is the only defensible answer, so asking spends the user's attention on a question with one outcome and stalls the work until they happen to be present. Bring the user a genuine choice between shippable alternatives, or a trade-off only they can price — never a request for permission to remove a defect.
- Before asking the user to rule on a surface or planning a change to it, check the repo for in-flight work:
gh pr listplus a scan of remote branches. An open PR may have already settled the question — a dependency queued for a user decision had already been removed by a PR in flight, and only the user's correction caught the stale premise. - A question's premises about the live system — which domain serves what, what sits behind a proxy, what a live response carries — are probed live before the question reaches the user: a browser,
curl, DNS. Production configuration overrides every default in the repo, so a code-derived claim about production is a guess, and "not determinable from the repo" is a prompt to probe, not a finding — one question shipped with both domains' roles wrong from a code-default inference, and the user had to say "open them in a browser and see for yourself". - Any selection of an external tool, model, library, or service starts with live web research, never training knowledge alone — that landscape moves faster than any cutoff, and a recommendation grounded on months-stale knowledge reads as authoritative while comparing options that have since been superseded. The user had to order the search mid-design once ("your cut-off is ~6 months old"); in delegated work nobody is there to.
- Rank a recommendation the way a design is ranked: an option that dissolves the trade-off — removes the tension instead of choosing a side — outranks every option that merely prices it, and the status quo earns the recommendation only when no presented option dissolves. Recommending keep-current-and-document while the option table itself held a design that removed the coarseness handed the user a judgment the reasoning had already settled, and they overruled it as the wrong abstraction.
- When audit lenses split on the same finding, the finding is usually several sub-claims bundled into one sentence, some true and some false — which is exactly why one lens confirms it and another refutes it. Read every lens's reasoning and rule on each sub-claim separately. Resolving the split by picking a winning lens ships whichever half that lens got wrong.
Browser and process hygiene
Every agent that drives a browser ends with its browser session closed, and the orchestrator verifies it — a successful
close, or an agent's report that it closed its session, is not evidence that the processes died; only a process listing is. After each browser agent completes, and again between waves, sweep to zero with the shipped command:seasoned-skills sweep --browsers # list survivors with their ages; exits 1 if any are alive seasoned-skills sweep --browsers --kill # kill each survivor by its exact pid, then re-list to prove itA gate that turns flaky while browser work is in flight is a leak suspect before it is a product bug.
Every process a lane needs beyond a single turn — a development server, a worker — runs as its own harness background task, never forked with
&inside another task's shell; the orchestrator's own long gate runs follow the same rule. Every lane process is swept at session end, and the same sweep is runnable by hand at any time.Judge leakage by process count and age, never by reported RSS — paged-out memory hides an order of magnitude (7.6GB visible while roughly 80GB was actually held).
Leakage comes from sessions accumulating across sequential waves, not from parallel width. Keep lanes parallel; the invariant is verified teardown, not a concurrency cap.
Kills are the sweep's job precisely because it kills by exact pid after listing what is about to die. Never reach for a pattern kill (
pkill -fand relatives) as cleanup or as verification — a pattern that reads as lane-scoped can match unrelated long-running processes on the host, and listing the pids is the inspection step a pattern kill skips. Every kill goes through the shipped sweep, which enforces the rule.
Ledger discipline
- Structure the ledger as a STANDING DIRECTIVES head (settled policy, kept current) plus a chronological log. Reground after compaction from the head AND the tail — a tail-only reground lets settled directives fade. Reground with bounded reads — the head block, then targeted slices — never by reading the whole file: a mature ledger runs hundreds of kilobytes, and one full read consumed enough context to force an immediate re-compaction.
- The ledger keeps exactly one live head. When a new head goes in, move the superseded one to an archive file beside the ledger instead of stacking it below — stacked dead heads push the file past what a single read returns and tax every reground with prose no longer true. One goal's ledger reached ~390KB carrying eleven stacked superseded heads, and by the end every update to it needed byte-offset reads and count-asserted scripted edits.
- Record launches with their task/run ids, lanes with their base commits, and verdicts with their evidence.
- When a long effort concludes, externalize the durable record (decisions, divergences, audit results) to a permanent artifact — a GitHub issue or PR body — before the scratchpad is cleaned up.
Recovery after an interruption
Step 0 is always to positively enumerate what is alive (task list, workflow roster) — a missing state file or empty output file usually means still-running, not dead. The harness task list can come back empty after a compaction or a host sleep while the underlying shells still run: ps for the actual processes and check whether their log files are still growing before declaring anything dead. Declaring a live task dead and relaunching into its worktree corrupts both. Then, for tasks with positive evidence of death:
- Audit the worktree first:
git status/git log. Clean tree at a known commit → relaunch the charter unedited. Dirty tree → launch a continuation agent on the same worktree whose first step is diffing working tree vs last commit to classify done/partial/untouched, then finishing — never a blind restart. A continuation charter lists the remainder and says explicitly that when the listed remainder is done, STOP: a continuation that finishes early otherwise runs on into the next stage's ground, and one built two of a later stage's commits plus a half-written file nobody had chartered. - Audit the remote before writing any continuation charter:
git ls-remotefor the lane's branch and `gh pr list --head <bran
…(truncated)