orchestrate
Read the tracker, and work the ready-for-agent tickets it holds on the branch the developer is already on: a wave at a time, each ticket built by its own subagent, verified by a second one that did not build it, and integrated into that branch as its wave completes.
$HERE is the directory that contains this SKILL.md, and $MANAGER is the Manager directory: $HERE/../kntnt/ if it exists, else kntnt/ under a Global harness skills directory (~/.claude/skills, ~/.config/opencode/skills, or wherever another Harness keeps them). Neither found: tell the user to install the Manager (npx skills add Kntnt/skills) and stop. $LIBRARY is $MANAGER/library/ — absent, tell the user to run /kntnt update, then stop.
Run uv run "$MANAGER/scripts/kntnt.py" invoke --here="$HERE" with the invocation payload — everything the user typed after /orchestrate, verbatim, however many lines — on stdin. On exit 0, answer the capabilities in its dependencies first: for each one, say whether its confirm sentence is true of you, and where it is not, give its how, change nothing, and stop. Then continue from the JSON. On any other exit print its stdout verbatim and stop: it has already printed what the user is to see, and none of that text is yours to write.
In the JSON, path is the command path as a list, flags holds each flag the user wrote — true where it stood bare, its value where it carried one, a list of values where it was repeated — operands is what followed the flags, in order, and instruction is the Contextual Instruction, or null, applied as $LIBRARY/references/invocation-envelope.md says.
Arguments
A run may be aimed at as many tickets and specs as the user cares to name, one operand each; reconciliation names exactly one ticket. --model locks only the building model and --deliberation locks only the building deliberation; neither reaches a verdict. --fast is the run's third lock, held for the whole run like the other two rather than for one wave of it; it counts finishing the work in elapsed time rather than in money, which is what somebody waiting on the run is actually spending. --approval binds only the first plan of this invocation to the identity the caller supplied. --state-dir is yours to pass rather than the developer's to type, and step 1 says where it comes from.
Park and Resume Rule
The amendment budget is per-ticket-lifetime, not per run cycle: tracker markers are append-only evidence, so parking changes neither amends_spent nor the remaining budget. Step 3 and step 6 report every parked ticket with the amends_spent value in its plan entry. A caller can therefore subtract that value from the limit of two to know exactly how many further amendments remain.
On re-entry, step 4 sends a ticket with a recorded amend_state to step 9. Step 5 also sends a ticket with a recorded amend_state to step 9 after isolation. Step 6 sends a ticket with a recorded amend_state to step 9 instead of dispatching an initial builder; the initial-build brief is never dispatched for recorded amendment work. Prior verdicts remain ticket evidence, and step 9 supplies the persisted immediately preceding verdict verbatim to the resumed builder.
The preserved commits are its mandatory base. On a resumed isolated ticket, step 5 requires isolate to bring the run branch forward into the preserved ticket branch before any builder is dispatched. Exit 0 continues from that tree. Exit 1 for uncommitted work leaves the ticket parked and reports that it is waiting for a hand. Exit 2 carries collisions and collided_with and routes repair-<number>: the collision-repair brief says the ticket is being resumed, merges the run branch into the ticket branch, and is not verified or integrated by itself. A repairer's unresolved disagreement parks the ticket without recording an outcome or spending an amendment; otherwise the repaired tree goes directly to the resumed step 9 amend, whose fresh full-ticket verifier judges the whole result.
A ticket parked during its initial build, with no recorded amend_state, resumes through step 6 from the preserved commits. Its ordinary initial brief is prefixed with one sentence stating that those commits are the base and are not rewritten.
Step 12 renders amends_spent as the lifetime total and also renders amends_inherited and amends_newly_spent from the amend answers this invocation retained. An attempt is inherited when this invocation replayed its building phase with newly_recorded false or found it already past building; an attempt is newly spent when this invocation recorded its building phase with newly_recorded true. This split is one of the two named exceptions to rendering without session memory, step 11's serial branch gate — the commit it ran at and whether it passed — being the other.
Steps
Where path is reconcile, follow this paragraph and stop before the numbered run steps. Run uv run "$HERE/scripts/run.py" reconcile --ticket=<number>, with the ticket from operands, adding --commit=<commit> when the maintainer supplied one. Exit 0 is the complete Reconciliation; report whether it was newly recorded, already agreed, or repaired after interrupted lifecycle cleanup, together with the Run Outcome where one exists, the done Ticket Resolution, and the completion commit from stdout. A parked ticket has no Run Outcome and must be reconciled through this verb so its stale label is exchanged for reportable history. When no commit was supplied and stderr says no unique completion commit can be established, ask the maintainer for the commit and rerun with their answer; under --yes, ask nothing and report the refusal. Any other nonzero exit is a refusal: show stderr and stop. Never close or reopen the ticket, edit an earlier outcome, or describe the rescued work as built or independently verified by Orchestrate.
Every command below takes --state-dir=<directory>. Pass the same durable per-session directory on every call, and pass the same one on every re-invocation. It holds three classes of information that are read differently. The run's ordinary account — the claims it took, the login it took them as, the frontier it planned, the commit its work sits on — is remembered rather than relied on: the tracker and the branch say all of it again, so a file that is gone or damaged costs a tracker call and nothing else. Its declared commit contracts and their claim boundaries, projected as contracts and contract_bases, are relied on: a declared ticket requires readable state to begin and to enforce its contract, while a checking verb with absent or unreadable state deliberately follows the undeclared path. The run's routing account is remembered too, and differently again: nothing else holds which point each of this run's roles was launched on, so a decision it still has is never made twice — but a decision is reproducible because it was recorded rather than because the world it was made in was frozen, so an account that is gone or damaged costs one further routing call per remaining role rather than the run, and the run says in its report that it routed again. The engine keeps these run files in a subdirectory rather than at the directory's root, so a subagent writing or clearing its own ticket scratch has nothing of the run's to catch. The graded measurements of routed attempts live with that account for the same reason, in the session's own scratch rather than in the repository. A dry run writes none of them. There is no resume flag and none is wanted — re-invoked with the same arguments and state directory, this Skill continues an interrupted run rather than restarting it; re-invoked with different --model or --deliberation, it refuses, those being the locks its first frontier was routed under.
Where a clean wave verdict names a load-induced flake, write its quoted evidence as one JSON object under that check's scratch and run uv run "$HERE/scripts/run.py" flake --evidence=<path> --state-dir=<directory> on the unchanged head before continuing. The object carries failing_tests, the three isolation_results, full_rerun_result, narrowed_command, and load_context exactly as the verdict established them. In step 12, name every entry the report returns under flakes with that evidence and the earlier_records count for each test in this repository.
Pass the user's --approval through to plan on the first plan of this invocation only. A first matching payload becomes the run's authorization ceiling. Every plan repeated from step 3 or step 11 runs without --approval: it preserves a met expectation only while branch, default_branch, scope, at_once, worktrees, model, and deliberation equal the ceiling, every planned ticket appeared in the ceiling's waves, and every ceiling Solo Ticket still planned remains Solo. Wave order and membership among remaining tickets may change. Drift makes the plan unready, leaves the expected identity and ceiling payload intact, records the drifted identity, and makes the expectation unmet; claim stays closed until a later flagged exact match installs a new ceiling. A run that never supplied --approval is unchanged.
Where the requested
--at-onceis above one, derive the repository's common Git directory withgit rev-parse --git-common-dirand issue one read-onlygit -C <common-git-directory> worktree list --porcelainfrom this session before running the plan. Probe the existing common Git directory itself: do not appendkntnt-orchestrate, which is created only after this preflight succeeds. This is the session's capability probe, not the engine's: a refusal means this Harness will not let the session operate ticket worktrees. Report the refused command and say that--at-once=1builds on the branch already checked out, then start nothing — including the plan, claim, routing, worktree, or dispatch. Perform the same probe for a dry run and report the same refusal; a passing probe is not a reason to lower concurrency. Where the probe passes, runuv run "$HERE/scripts/run.py" plan, passing the user's--dry-run,--at-once,--model,--deliberation,--fast, and--yesthrough as they stand inflags— a flag read astrueas its bare name, one read with a value as--flag=value. Where the user named any tickets or specs, pass what they named too, verbatim and as one value:--scope="<the operands, joined by one space>"— all of them, however many references there are and in the order they were written. Never resolve a reference yourself, and never widen or narrow what they named, or drop one you cannot make sense of — the engine reads the tracker and decides, reference by reference, which of the two each one is. Done when stdout is the JSON plan; anything else on stdout means the engine refused the arguments, so show stderr and stop.On a non-dry run, mark the live preflight with
uv run "$HERE/scripts/run.py" progress --phase=preflight --wave=<n> --completed=<count> --remaining=<count>before continuing. Wherereadyis false for any reason except a dry run: go to step 12, having started nothing.reasonis why no run may start, and an invocation asking for locks this run was not routed under is one of them, stopping here rather than at the claim it would otherwise reach. A routing account that is gone or that nothing can read is not one of them: it costs this run one further routing call per role and nothing besides. A dry run performs its read-only routing preflight now, naming step 3's roles forstartingin plan order. Wherestartingis empty, no execution request exists to route: go directly to step 12. Otherwise runuv run "$HERE/scripts/run.py" route --dry-run --request=build-<number>:<kind> --seat=<model>@<level> --harness=<name> --state-dir=<directory>, passing--request=build-<number>:<kind>once per ticket instartingin plan order, each classified into one of the plan'skindsexactly as step 3 classifies it and from the same bodies and threads the plan already carries, together with the same lock flags step 3 passes and the two facts about this session that only you know:--seat, the model this session is running as and the deliberation level it is running at, and--harness, the name of the Harness it is running on. The route renders the proposed decisions and routing readiness, each decision saying whether it came backinherited— the role would run on this session's own seat rather than on a point chosen for it, which is what a missing profile, an empty catalogue, or nothing this Harness can reach answers with. It does not enter step 3: it never comments on, parks, claims, starts setup for, or otherwise changes a ticket. A dry route records none of what it decided, and there is no refusal for it to preview: model-selector refuses nothing, and the refusals that remain are this Skill's own. Then go to step 12 without claiming, starting setup, or writing any persistent trace. A dry run writes no files, directories, migrations, Git refs, index changes, worktrees, locks, temporary artifacts, GitHub mutations, model-selector configuration, measurements, ledger, or run state. Done when you have stopped orreadyis true.Before anything is claimed, read every ticket in
tickets— body and thread alike, both already in the plan — for a decision the text leaves open: a deferred value, a choice named as the maintainer's, two designs left standing, steps demanding exact commands over inputs the repository does not fix, a named external service or account with no named mutation path or owner, a choice phrased as alternatives, or credentials or accounts whose owner is undeclared. Park only on a gap it can name concretely; a false negative remains for the mid-work park to catch. The label promises there is nothing to ask, but the label is a claim, and triage sometimes gets it wrong. Where nothing is open, go on to step 4. Otherwise, without--yes: ask the developer everything you found in one batch, now, while the developer who typed the command is still there — after this step they are not addressed again until the report — and write each answer as a comment on its ticket withgh issue comment <number> --body "<the answer>", which is how it reaches the builder: the brief carries the whole thread, so an answer on the ticket is an answer in the brief. Under--yesthere is nobody to ask, and the flag cannot answer an open question — it answers yes/no, and which default? is not one — so park each such ticket instead. Shape every park comment with the sentence of the ticket quoted, the decision it leaves open as a question the maintainer can answer, and what the ticket must state instead. Write that question on the ticket with the same comment command, thenuv run "$HERE/scripts/run.py" park --ticket=<number>, which replacesready-for-agentwithneeds-infoand releases any claim of this run's; keep each parked ticket's number, title, question, andamends_spentfrom its plan entry for step 12. Exit 2 there means the ticket already carries a recorded outcome and is settled — nobody's to park, so leave it as it stands. Never park for anything else, and never answer an open question yourself: a run still creates no ticket and decides no ticket's substance. Where anything was written or parked, run step 1'splancommand again and return to step 2 with what it answers — the answers are now in each ticket's thread, so the briefs will carry them, and a parked ticket has left the scope the way an unlabelled ticket was never in it. Done when no ticket in scope leaves a decision open, every answer being on its ticket or the ticket that deferred it parked. Then classify each ticket instarting, before anything is routed. The plan'skindsis the closed vocabulary and the whole of it — eight kinds, each with the one sentence that tells it from the other seven — and this reading is yours alone to make: you have just read every body and every thread, and the engine has read none of them. Put each ticket in exactly one kind, choosing on how much intelligence the job needs rather than on which part of the tree it touches: a ticket that rewrites a Skill's prose and a ticket that fixes a failing test are different work behind the same diff size, and a run that files both as the same kind teaches every run after it that they are. Nothing classifies for you and nothing infers it afterwards — the engine reads no ticket, may not guess, and refuses a building request that names no kind.Then route this frontier, before step 4 and every time this step is reached — the first wave, a wave the last one unblocked, and a resumed invocation alike. Run
uv run "$HERE/scripts/run.py" route --request=build-<number>:<kind> --seat=<model>@<level> --harness=<name> --model=<name> --deliberation=<level> --fast --state-dir=<directory>, one--request=build-<number>:<kind>per ticket instarting, in that exact plan order and each carrying the kind you just classified that ticket as, together with the same three lock flags the developer gave and each omitted where they gave it not.--seatand--harnessare the two facts about this session only you know: the model this session is running as and the deliberation level it is running at, written<model>@<level>, and the name of the Harness it is running on. Record them on the first route of an invocation and on every later one, so a run resumed from a different session routes against the seat it is actually on. Name every later execution request the same way —amend-<number>-<attempt>:<kind>,repair-<number>:<kind>,rebuild-<number>:<kind>,wave-fix-<n>— because the name is how the engine finds a decision again when the thing it covers is about to run, and because the engine reads off that same name the label the measurement its verdict files is reported under. Every building request for a ticket carries that ticket's kind, every time it is made: nothing is inherited from a decision already taken, so an amend, a collision repair and a rebuild each state it again, and a resumed invocation classifies afresh when it re-enters this step, as it re-reads everything else here. The kind rides on the route and nowhere else — the decision is recorded under the bare name, soattempt-start,attempt-finishand every other command naming a request names it without one. That name and that one classification are the whole of what this Skill says about the work. It states no safety facts, no objective, no candidate set and no ladder, because it owns none of them: which models are reachable, what each is expected to spend, how likely each is to finish this kind of job, and which of them is therefore the cheapest way to get the work done are model-selector's alone. Reach it through this verb and its public Interface alone: never read its private references, never call its other scripts, and never reconstruct its selection rules from the answer that comes back. No verdict is ever requested: a verdict inherits the main seat, and the engine refuses a request naming one before it asks anything. Exit 0 recorded one decision per request, each naming the model and deliberation it chose, the launch instruction that starts it, the basis it rests on, and whether it came backinherited— the role running on this session's own complete seat rather than on a point chosen for it, which is what a missing profile, an empty catalogue, or nothing this Harness can reach answers with, optimisation being unavailable rather than the run being unsafe. Never substitute an exact override, and never treat an inherited answer as a failure: model-selector refuses nothing and there is no answer of its own a run may read as start nothing. Exit 1 is a refusal, and every one of them is this Skill's own: a request naming a verdict, a request name it cannot read, locks other than the ones this run was routed under, an escalated fix round with no round behind it, or an answer that did not honour--modelor--deliberation— the promise that an unhonourable lock stops the run before anything is claimed is Orchestrate's own contract with the developer who typed the flag, and Orchestrate keeps it here, by comparing what came back against what it asked for. Show stderr and stop. Where this run's account could not be read, the route starts a fresh one and says so underreplaced; the run has routed again rather than lost anything, and step 12 reports that it did. Every decision stays with the ticket's run data and is rendered in the existing five-resolution outcome account. Done when no ticket in scope leaves a decision open and every ticket instartingcarries a decision this run made.Claim every ticket in
starting, which is the frontier cut to the ceiling the developer set:uv run "$HERE/scripts/run.py" claim --ticket=<number>for each. Exit 2 means another session or a person already has it — leave it untouched, record nothing, drop it from this wave, and where you take a ticket fromworkablein its place, route that replacement, in a request of its own, before claiming it; the engine refuses a claim it has no decision for, which is that rule and not a reminder of it. Exit 1 is that refusal or another engine refusal: show stderr and stop. A ticketresumingnames is one an earlier invocation of this run claimed and was interrupted before recording: it is inworkablelike any other and claiming it succeeds, the claim being already this run's own. Claiming is not an attempt start: carrybuild-<number>through step 5, then runuv run "$HERE/scripts/run.py" attempt-start --request=build-<number> --state-dir=<directory>immediately before the step 6 dispatch. Exit 0 stores the first launch instant or confirms the same in-flight start; exit 1 means no dispatch occurs. Mark every claimed ticket with a recordedamend_statefor step 9 rather than the initial-build path; it still goes through step 5 first where worktrees are in use, so its preserved base is brought forward before the amend resumes. Done when the wave is the tickets you claimed, or nothing could be claimed and you go to step 12.Where
worktreesis true, give each ticket in the wave what the wave would otherwise share:uv run "$HERE/scripts/run.py" isolate --ticket=<number>. It answers with theworktreethat ticket is built and verified in, thebranchit is built on, thescratchdirectory made for it beside that tree, and thereservationsit holds — one record number in each of the repository's numbered registries, so two tickets creating a record at once cannot mint the same number. A ticket picked up again gets all four back rather than a second set of them, andisolatebrings the run branch into that preserved ticket branch before anything is dispatched. The briefs carry the last two to every subagent this ticket gets: the scratch is the only place outside the working tree any of them may write, and the reserved number is what a builder creating a record takes instead of reading the directory. Whereworktreesis false the wave is one ticket and there is nothing to isolate: it is built in the repository as it stands, on the branch already checked out, it takes the next free number in any registry it adds a record to — nothing is being built beside it to read that directory at the same moment — and the scratch its briefs name is one you make for it in a subdirectory of the session's own scratch, never that directory's root. Exit 1 for uncommitted work in a preserved tree leaves the ticket parked and waiting for a hand: drop it from the wave, build nothing for it, record nothing against it, leave its claim and work untouched, and retain that reason for step 12. Any other exit 1 is likewise an engine refusal for a ticket this run has nowhere to build, so account for it as never on the frontier. Exit 2 reports a resumed ticket'scollisionsandcollided_with: routerepair-<number>as step 3 routes a role, fillrepair.mdas step 10 does, and replace its opening with one sentence saying that the ticket is being resumed and its own fresh verifier follows. Before that repairer is dispatched, mark it withuv run "$HERE/scripts/run.py" progress --phase=build --wave=<n> --ticket=<number> --completed=<count> --remaining=<count> --amends-spent=<count>. Dispatch that repair on the ticket branch with the run branch as its other side, but take no repair verdict and do not integrate it: it is not verified or integrated apart from the resumed amend. A repairer's unresolved disagreement parks the ticket as step 6 does, records nothing, and returns it to triage without spending an amendment; otherwise its repaired tree goes directly to step 9, whose fresh verifier checks the whole ticket. After any exit 0, send a ticket with a recordedamend_stateto step 9 from the phase already recorded instead of step 6. Done when every ticket remaining in the wave has somewhere to be built or has entered its resumed amend.Before each builder dispatch, mark it with
uv run "$HERE/scripts/run.py" progress --phase=build --wave=<n> --ticket=<number> --completed=<count> --remaining=<count> --amends-spent=<count>. Build the wave, one subagent per ticket, each with its own context window. Before dispatching from this step, send every ticket with a recordedamend_stateto step 9; its initial-build brief is never dispatched. For a resumed initial build with preserved commits and no amend state, prefixbrief.mdwith this sentence: "The commits already on the branch are the base and are not rewritten." Each initial builder launches on exactly what itsbuild-<number>decision names — the generated subagent that decision's launch instruction names, or the command it gives, run as a process — or on this session's own complete seat where the decision came backinherited;--modellocks only model and--deliberationonly deliberation, and neither reaches step 7. Immediately before dispatching each initial builder, runuv run "$HERE/scripts/run.py" attempt-start --request=build-<number> --state-dir=<directory>. An attempt remains in flight until the independent verdict or a named non-model condition reaches step 8; the builder's report establishes nothing. Start them together rather than one after another — working the frontier concurrently is what the ceiling is for, and a ticket that waits on an unrelated ticket is a run slower than its graph requires. Before the first wave is briefed, name the run's own files: the changelog, and whatever else this repository's own ground rules make every ticket append to — a guide's list of references, a worklog, an index of records. Read those rules to answer it, and hold the answer for the whole run rather than asking it again each wave; which files those are is a reading of prose rather than something a script can compute, which is why the naming is yours and not the engine's. A builder never edits one of them, so every brief carries the list together with the note path its builder writes an entry to instead, and step 8 applies what the wave's notes hold. Where this repository has no such file, the list is empty andbrief.mdsays how it is filled in then. Resolve the gate then too, once for the run: read the project's contributing guide and write down the commands it names for verifying a change, verbatim; where no guide names any, write down the whole test suite and whatever lint, format, and type checks the project is configured for, as the concrete commands those resolve to. Hold that list for the whole run and fill it into every brief that asks for verification — the list is the gate wherever it is carried, all of it and nothing in its place. Read$HERE/references/brief.md, fill it in per ticket from that ticket's entry intickets, from what step 5 answered for it, and from the run's own files you named, and give each subagent the filled-in brief and nothing else. Fill the brief's<attempt_id>from theattempt_idthat decision carries — the same identityattempt-finishfiles this run's verdict on the attempt under, so what the attempt actually spent is read back onto that one row rather than counted as a second attempt beside it. Never build a ticket in this context: a ticket built here is a ticket whose builder and verifier are the same session, and the run would be reporting on itself. A selected launch that becomes unavailable after the ticket was claimed is a condition of the environment and nothing about the work, so it is a mechanical hinder like any other and takes the same single repair this step gives one: repair the condition, route that role again, and dispatch the same brief once more. Once. An exact override is never replaced by a neighbouring point, and a launch nothing could start is never recorded as a model-quality failure — what would be counted is infrastructure. A subagent that ends its turn waiting on a command it started has neither finished nor failed: it is resumed with that command's result rather than recorded, its stop being the mechanical kind and the repair a resumption. A subagent that stopped and reported instead is triaged before anything is recorded, and one question sorts the stop: whether fixing what stopped it decides anything about the work. A mechanical hinder — a condition of the environment, not a question of the requirement: the path slightly wrong, the directory missing, the number it wanted already taken — decides nothing, so repair the condition yourself and dispatch the same brief once more. Once: a hinder that survives its repair is recorded as the failure it now is, this bound being one for the same reason the amend's and the rebuild's are. A genuine decision — an ambiguity the ticket does not settle, a requirement it does not state, a design the spec leaves open — parks the ticket exactly as step 3 parks one: write the question in step 3's comment shape with the same comment command, run the sameparkcommand, which returns the label to triage and releases the claim, record no outcome, and keep the number, title, question, andamends_spentfrom its plan entry for step 12; the wave carries on without it, and its working tree, where it has one, stands like a failed ticket's. A builder that stopped because its ticket depends on unresolved work the graph does not name found a missing edge, and what sorts that stop is whether the missing thing has a number: an answer no ticket carries is a genuine decision and parks as above, while a ticket without a done Ticket Resolution is an edge the breakdown missed — runuv run "$HERE/scripts/run.py" record --ticket=<number> --outcome=blocked --blocked-by=<blocker>, passing--blocked-byonce per ticket the report names. That writes the corrected edge to the tracker the way the breakdown would have, releases the claim, leaves the ticket open with a note saying what happened and on what, and discards its working tree and branch, the half-built work with them, exactly as a refused repair is discarded and without spending the ticket's one rebuild; the wave carries on without it, and a plan offers the ticket again when its blocker has a done Ticket Resolution. The same triage is every stopped subagent's — building, verifying, amending, or repairing. Account for what your subagents leave running rather than trusting each of them to leave nothing: when one has finished or its stop has been triaged, whatever it started is finished with it, so look for anything of its own still running and stop it — its brief told it to stop what it started and to name anything it deliberately left standing, and this is the run reading that report rather than taking it on trust. A waking that is only such a leftover — a command of a subagent already accounted for, ending long after the subagent did — is swept rather than triaged: there is no stop behind it to sort, dispatching that brief again would start another leftover in place of the one you cleared, and a run that answers each of them in turn is a run that cannot end. Done when every subagent has finished or its stop has been triaged and nothing any of them left running is still running, a parked ticket having left the wave.Before each verifier dispatch, mark it with
uv run "$HERE/scripts/run.py" progress --phase=verify --wave=<n> --ticket=<number> --completed=<count> --remaining=<count> --amends-spent=<count>. Verify each ticket in a second subagent that has not seen the building session, and that is told nothing the builder said. Read$HERE/references/verify.md, fill it in from the same entry, the same working tree, the same scratch directory, and the gate you resolved before the first wave was briefed, and give it that. It launches by exact inheritance of the orchestrating session's complete main-seat model and deliberation configuration, the same seat this run reports itself as calling from: exact inherited main-seat controls apply whatever route decision or builder override ran before it, and no route, flag, circumstance, or failure may downgrade it — the saving is never taken at the last thing that would catch a mistake. Never route a verdict; the engine refuses to keep a decision made for one. This exact verdict inheritance is every verdict's: ticket, amend, repair, and wave alike. Its verdict decides; the builder's report is evidence of nothing. No argument, flag, or circumstance skips this step. A verifier that ends its turn waiting on a command it started is resumed with that command's result too, rather than recorded: a verdict that was not reached is not a fail. A verifier that stopped and reported is triaged as step 6 triages a stop: a mechanical hinder repaired and the same brief dispatched once more, once; a genuine decision parking the ticket, which leaves the wave wanting no verdict; anything else standing as the fail it is. Done when every ticket still in the wave has a verdict.Before applying a ticket note, mark it with
uv run "$HERE/scripts/run.py" progress --phase=note --wave=<n> --ticket=<number> --completed=<count> --remaining=<count> --amends-spent=<count>. Integrate and record every ticket as it becomes ready. With worktrees, a failed verdict begins step 9 but does not block continuing to an unrelated ticket whose verdict already passed: integrate and record it without waiting for its step 9 result. Integrate ready passed tickets in the orderstartingnames them; a ticket that passes after an amend joins that ready set when its fresh verdict passes. At a concurrency ceiling of one there is only the direct-branch ticket, so step 9 still reaches its passing verdict or terminal outcome before any later ticket starts.- A ticket that passed, where
worktreesis true:uv run "$HERE/scripts/run.py" integrate --ticket=<number>. Exit 0 merges it into the run branch and takes its working tree away — record it withrecord --ticket=<number> --outcome=done --commit=<the commit it answered with>, which closes the ticket. An exit 0 whose answer carriesregeneratedmerged over a collision the repository answered itself: every file the merge could not settle is one this repository declares generated, so the engine ran that file's declared generator on the merged tree and committed what it produced, and no repair is dispatched for it — record the ticket done on that commit exactly as above, and step 12 names the regeneration from the account rather than from your memory of it. What licenses that commit ahead of a verdict is the precedent this step's own note-applying commits already set: step 11 reads the branch whole, so no regeneration escapes being read. Exit 1 refuses a declared commit-role contract: record--outcome=failedwith no commit and leave its working tree standing; certified violating history is neither amended nor sent to collision repair. Exit 2 is a collision no declaration answered — one touching any file the repository does not declare generated, the mixed case included, or one whose generator did not settle it: the branch is left as it was and the working tree stands, so go to step 10 with what it answered — itscollisions, the files the merge could not settle, and itscollided_with, the tickets whose merged work is on the other side of them. - A ticket that passed, where
worktreesis false: its work is already on the branch, so record it done with--commit="$(git rev-parse HEAD)". Exit 1 is the engine refusing to call it done — the working tree still holds work nothing committed, so the commit named does not carry it: record the ticket--outcome=failedinstead, change nothing in the working tree, and go to step 11 with a failure. There is no verdict to amend from here — the verifier passed the ticket, and what refused it is the tree. - Anything else is work tried and found wanting — a failed verdict and only that, every stop having been triaged in the step it happened in: go to step 9 with it before anything is recorded. Where the amend does not deliver a pass, the ticket is recorded
--outcome=failedand no--commit, which leaves it open and claimed so nothing touches it again. Nothing integrates it, so its working tree stays where it is for the developer to look at.
Then write the wave's entries into the run's own files, once every ticket in the wave carries an outcome. Every ticket whose work reached the branch left its entries there at
.kntnt-orchestrate/<number>.md, its own number in the name: take those notes one ticket's worth at a time, in the order this step integrated them, add each entry to the file it names where that file's own convention puts it, then remove the notes from the branch and commit that — the note files by their own names, that directory also holding a repository's generated declaration, which is no ticket's note and stays. Sequential appends cannot collide, which is why these files are the run's to write rather than a builder's, and the entries land before step 11 reads the branch, so nothing the run wrote itself reaches the report unread: whereworktreesis true the wave check reads them merged onto the integrated branch like any other work, and whereworktreesis false step 11's branch gate runs the project's verification over them on the branch they were committed to. A wave that left no note has nothing to apply here.Then finish every routed initial attempt at the boundary that established its outcome:
uv run "$HERE/scripts/run.py" attempt-finish --request=build-<number> --outcome=<pass|fail|hinder|parked|blocked|tracker-failure> --state-dir=<directory>, adding--commit=<commit>where its work landed,--metrics=<path>where the Harness exposed what the attempt spent in tokens, and--resolved-model=<name>where the environment served a different model than the decision named. The independent verdict is what establishes a pass or fail; the builder's report establishes nothing. A mechanical hinder, parked decision, discovered blocker, and tracker failure remain workflow conditions rather than judgements of the work, and the engine files nothing at all for one of them; a merge collision is one of them too, and it has no outcome word of its own here: the ticket goes to step 10, whose repair and rebuild are routed attempts with verdicts of their own. For the rest the engine files a graded measurement: a pass with nothing failed before it is worth one, a pass reached only after an earlier attempt at the same work failed is worth six tenths, and a fail is worth nought.attempt-finishpersists the completion and files that measurement automatically through model-selector's ownrecord.py; a refusal from that store is retained for the report and never stops the run. An attempt no verdict or named condition reached remains in flight rather than acquiring an invented outcome.Done when every ticket in the wa
- A ticket that passed, where
…(truncated)