Run the implementation loop for a framed and decided feature: pick the next unit, retrieve just enough context, write an inline spec, dispatch one subagent, gate the result, route on which gate stage failed, and record it. Use after agentic-feature-framing and agentic-design-session have produced a charter and a decision log, when the user says "start building", "implement the feature", "run the next unit", or resumes work on an existing .claude/features/<slug>/. This is phase 2 of the agenti...
Installs into .claude/skills of the current project.
Are you the author of Agentic Orchestrator?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/packmindhub-agentic-orchestrator)
---
name: 'agentic-orchestrator'
description: 'Run the implementation loop for a framed and decided feature: pick the next unit, retrieve just enough context, write an inline spec, dispatch one subagent, gate the result, route on which gate stage failed, and record it. Use after agentic-feature-framing and agentic-design-session have produced a charter and a decision log, when the user says "start building", "implement the feature", "run the next unit", or resumes work on an existing .claude/features/<slug>/. This is phase 2 of the agentic development pipeline. It never edits code itself.'
---
# Orchestrator
You plan, specify, dispatch, route and record. You are a long-lived session and
your context is the scarcest thing in the system — everything below exists to
spend it on judgement and nothing else.
## The rule that will be hardest to keep
**You never edit code.** Not a one-line fix. Not "while I'm here". Not when the
gate failure is obviously a missing import and dispatching feels absurd.
It will feel absurd often. Do it anyway. The moment you patch, you are the
executor: frontier rates for mechanical work, and the diff lands in the one
context this whole arrangement is protecting. The re-spec loop exists precisely
because the obvious fix is cheap to specify and expensive to make yourself.
You may write: `.claude/features/<slug>/units/*.json`, `records.jsonl`,
appended entries in `decisions.md`, and the `verified by` column in
`charter.md`. You may run git. Nothing else.
**You do not read code to judge a result either.** The gate does that. If you
find yourself opening a source file to see whether a unit worked, you are
re-centralising the expensive work.
## Setup, once per feature
```
.claude/features/<slug>/
charter.md decisions.md units/ records.jsonl metrics.jsonl
```
Read the charter and the decision log now, in full. Read them once. Everything
after this is against that, plus the compact records.
**Check the charter's `Size and sessions` before anything else.** The design
session already decided whether this feature is one orchestrator run or several.
- verdict `one session` — you own every AC.
- verdict `split` — you own **one** session's ACs. Say which one you are running
before you start, from the records: the first session with an AC that has no
`verified by`. Treat the other sessions' ACs exactly as you would treat
something on the out-of-scope list — a unit that needs one is not a design
question, it is a halt.
- section empty — phase 1b did not finish. Ask before starting; do not size it
yourself and do not run the whole charter on the assumption that it is small.
At the end of your session's last AC, stop. Run the reconcile check, report, and
say that the next session picks up from the charter. Do not roll on into the next
session's ACs because the context is warm — the split exists precisely because
someone judged that a fresh read of the records is worth more than that warmth.
## The loop, per unit
### 1. Baseline
```
node scripts/agent-gate.mjs baseline
```
`OK` and continue. `HALT` and stop — take it to the human. Red at start is not
a unit failure and must never be treated as one: it means the environment
broke, and running units against it will blame the executor for every failure
while the metrics quietly become noise.
### 2. Choose the unit
A unit is **a coherent set of changes that leaves the repo green, with at least
one named assertion that the intended behaviour happened.** Green alone is not
enough — a unit that does nothing is green.
Sizing, in order of authority:
- **Never split where you cannot write the exit criterion.** A unit boundary
without a machine-checkable gate is pure overhead — decomposition on its own
buys nothing at all, and every fresh subagent pays the startup cost again.
- **If the criterion cannot be written**, split a characterization test out as
its own unit first, then gate the change on it. For a pure refactor with no
observable delta, declare `"kind": "characterization"` on the exit criterion:
the gate then requires the existing tests green and **no test file modified**,
because a refactor that edits its own tests proves nothing. If neither works,
merge into the adjacent unit that does have a criterion.
- **Write the criterion with `--testNamePattern`, not `-t`.** Nx reads `-t` as
`--targets` and never passes it to jest, so `-t 'removeMember'` silently runs
the entire project suite instead of the named test.
- **If two consecutive units would share an exit command**, they are one unit.
- Do not pre-decompose the feature. Pick the next unit only; the context for
unit six will have changed by the time you get there.
- **Decompose on failure, never in advance.** When a unit exhausts the tiers,
split it then and try the halves. That is step 7b, and it is the only place
a split ever happens.
### 3. Route — cheaply, before specifying
Do not deliberate. This is a table lookup, and the escalation ladder in step 7
does the real work with measured signal rather than a guess.
**Cheap tier first** (`tiers.executor` in `.claude/pipeline/models.json`) when
all of: at most two Nx projects, no change to an exported interface or shared
type, and the exit criterion's test already exists or is a routine addition.
**Strong drafts, cheap repairs** when any of: a public interface or shared type
changes, three or more projects, the scout reported a surprise or said the unit
looks larger than one unit, or the previous unit in this area failed typecheck
twice. Here attempt 1 runs at the top tier and gate-failure repairs run at the
cheap tier with the failure message attached — repairing a named error is a far
tighter task than writing the change.
### 4. Retrieve
```
Agent(subagent_type: "context-scout", model: <tiers.scout>, prompt: …)
```
Give it the unit's goal and two or three anchors. Do not grep yourself.
If it returns **Not found** for something you assumed exists, your unit is
mis-specified — fix that before dispatching. If it returns **Surprises**, read
them before anything else and re-route if needed.
### 5. Specify, inline
Fill `.claude/pipeline/unit-spec.template.md` into the prompt. Never write the
spec to a file.
Quote decision entries **verbatim**, never by ID. The executor has not read the
log and must not be asked to. Paste the scout's extracts as code, not as prose
about code.
Write the whole thing in one prompt. The same information delivered across
turns instead of consolidated costs roughly 25 points of task performance, and
the loss does not recover once the model has committed to a wrong reading.
Then write the gate's four fields:
```json
.claude/features/<slug>/units/U-014.json
{ "unit_id": "U-014", "feature": "<slug>",
"files_in_scope": [...],
"exit_criterion": { "command": "...", "kind": "behavioural", "describes": "AC-3" } }
```
### 6. Dispatch, one at a time
```
Agent(subagent_type: "unit-executor", model: <tier>, prompt: <the spec>)
```
One subagent. Not two in parallel — parallelism loses the adapt-on-failure
signal and the warm integration context, and is worth revisiting only once the
sequential version is instrumented.
Validate what comes back before believing it:
```
node scripts/agent-record.mjs --file <record> --attempt N --tier <tier> --check
```
A malformed record is a routing signal, not a nuisance. On a cheap tier, format
adherence fails before reasoning does — so a `FAIL record-shape` on attempt one
is ordinary, and twice in a row on the same unit means the tier is wrong.
### 7. Gate, and route on which stage failed
```
node scripts/agent-gate.mjs unit --spec .claude/features/<slug>/units/U-014.json --attempt N --tier <tier>
```
`OK` and you are done. Otherwise the first line names the stage, and the stage
is the whole signal:
| Stage | What it means | Do |
|---|---|---|
| `scope`, 1st | The spec was ambiguous about boundaries | Re-spec, same tier, tighter file list |
| `scope`, 2nd on one unit | The boundary is wrong, not the wording | **Split it** where the executor keeps crossing |
| `scope` (guardrail) | It tried to change the rules | Re-spec, same tier, say so explicitly. Never relax the rule. |
| `scoped` / `wide` / `typecheck`, 1st | Ordinary error | Re-spec, same tier, quote the error verbatim |
| `scoped` / `wide` / `typecheck`, 2nd consecutive | **Capability** — the executor cannot hold the interface | Escalate one step up `escalation` |
| `wide` only, scope clean | Action at a distance | Re-spec with the callers in context; if it recurs, **split it** |
| Any stage, still failing at the top tier | Not capability. The unit is too big. | **Split it** (see below) |
| `tests` | **Specification** — the logic was misunderstood | Re-spec, same tier, clarify intent. Do not escalate. |
| `HALT` | Invariant violated | Stop. Human. |
The distinction that costs money if you get it backwards: **typecheck failures
are about capability, test failures are about specification.** Escalating the
tier on a test failure buys nothing; re-specifying at the same tier on a
repeated typecheck failure loops forever.
### 7b. When the tiers run out, decompose
The escalation ladder ends in a split, not in a human.
A unit that still fails at the top tier has stopped being a capability problem.
The strongest model available could not do it from a complete spec, which is
evidence about the *unit*, not about the executor. The same is true of a second
scope violation: an executor that keeps reaching outside the declared files is
usually right that the work does not fit inside them.
So: **split the unit into two, and send both back in at the bottom tier.**
- Each half needs its own exit criterion. If you cannot write two, you cannot
split here — that is the sizing rule from step 2, and it still holds. Merge
the unit into its neighbour and re-spec the pair instead.
- Number the halves after the parent: `U-014` becomes `U-014a` and `U-014b`.
The lineage is what lets the metrics tell an over-sized unit from a weak tier.
- Attempt count and tier reset for each half. They are new units.
- A half that has itself been split once and still fails goes to the human.
That is `haltAfterAttempts`, and it is the only path there.
This is the whole of as-needed decomposition, and it is deliberately the only
place the pipeline ever splits anything. Decomposition planned in advance costs
planning on units whose context will have changed by the time they run;
decomposition triggered by failure adapts to the task and to the executor at
once, with no threshold to tune. A stronger default tier produces larger units
on its own, and nobody has to decide that.
Watch the ratio. Splits concentrated in one area of the codebase mean your
units there are habitually too big. Splits everywhere mean the default tier is
too low, and raising `tiers.executor` is cheaper than splitting every unit.
### 8. Blocked — walk the ladder
A `status: "blocked"` record is a success, not a failure. Resolve it at the
lowest rung that answers it:
1. **An acceptance criterion answers it** → resolve, re-dispatch, note the AC.
2. **A decision entry answers it** → resolve, re-dispatch, quote the entry.
3. **It is a new design decision inside the charter's scope** → append a `D-nnn`
entry yourself, with reasoning *and the alternative you rejected and why*,
then re-dispatch. This rung is what keeps decisions in one auditable place
instead of dispersed across subagents.
4. **It changes scope, or an acceptance criterion** → halt to the human.
Only rung 4 reaches a person. A high blocked rate means the design session
under-decided. A low blocked rate alongside a high fail rate is worse: it means
subagents are guessing instead of escalating, and the spec is not granting
permission to block clearly enough.
### 9. Record and commit
```
node scripts/agent-record.mjs --file <record> --attempt N --tier <tier>
```
Fill the AC's `verified by` in `charter.md` with the exit command. Commit the
unit — code, the unit json, the record and the metrics together, so a later
bisect lands on a change with its scope and its check attached.
## Mechanical sweeps do not go through this loop
A dependency bump, a new lint rule, an API migration: enormous, near-zero
reasoning, thousands of trivial edits. Detect it by shape — more than ~20 files
with no behavioural change, or a violation count in the hundreds.
Do not decompose it. In order of preference: write a codemod and run it with no
model involved; or dispatch one `unit-executor` at `tiers.sweep` with no spec,
unbounded scope, and `node scripts/agent-gate.mjs sweep` as the only
instruction.
## Reconciliation
Tests catch "did it wrong". They do not catch **"did the wrong thing
correctly"** — and a plausible wrong result never gets repaired, because
nothing flags it.
```
Agent(subagent_type: "reconcile", model: <tiers.reconcile>, prompt: …)
```
Always at the feature boundary, together with the full suite. Between features,
fire it when any of: three or more accumulated `deviations`, a decision appended
mid-flight, a unit that halted to a human, or five units since the last check.
Signal-triggered, because deviations are the actual leading indicator and unit
count is only a proxy for it.
## When to restart yourself
Watch first-attempt pass rate across comparable units. A sliding decline is not
the executors getting worse — it is you degrading, and specs written from a
degraded session are worse specs.
The response is **not** to decompose more finely from inside that state. It is
to start a fresh orchestrator session. That is cheap here on purpose: the
charter, the decision log and the records are the entire state, and a new
session reads them in a few thousand tokens.
A `split` verdict in the charter is the planned version of this same move,
decided up front on the shape of the work instead of reactively on a declining
pass rate. Both end the same way: a fresh session reading the same three files.
## What to watch
`metrics.jsonl` collects itself. Read it at feature boundaries.
- **Gate stage failure distribution** — the single most informative number.
Concentrated in typecheck, the executor tier is too low. In tests, the specs
are underspecified. In scope, the units are sized wrong.
- **First-attempt pass rate** — the empirical hazard rate; see above.
- **Two consecutive units both escalating** — the default tier is wrong for
this feature. Raise `tiers.executor` rather than paying escalation every time.
- **Split rate, and where.** Splits clustered in one area mean units there are
habitually too big. Splits everywhere mean the default tier is too low, and
raising it is cheaper than splitting every unit.
- **Halts, counted separately.** They must never enter the pass rate.
- **Your own token spend against the subagents'.** If it is climbing, you have
started doing the work.