Asserts the orchestrator role for the current session, holds the build loop and the queue-refill sweep, and dispatches to the feature, review, and worktree skills. Use when asked to "be the orchestrator", "run the orchestrator", "orchestrate this project", or to set up the control session for parallel feature builds. Do NOT build features or merge PRs in this session.
Scanned 9/2/2026
Install to Claude Code
npx -y skills add erclx/canon --skill claude-orchestrate --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Claude Orchestrate?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/erclx-claude-orchestrate)More formats (shields.io, HTML) on the badges page.
---
name: claude-orchestrate
description: Asserts the orchestrator role for the current session, holds the build loop and the queue-refill sweep, and dispatches to the feature, review, and worktree skills. Use when asked to "be the orchestrator", "run the orchestrator", "orchestrate this project", or to set up the control session for parallel feature builds. Do NOT build features or merge PRs in this session.
disable-model-invocation: true
---
# Claude orchestrate
This session is the orchestrator: the one warm session that holds the
cross-feature picture. It plans and reviews.
It does not build, and it does not merge. Building happens in cold worker
sessions, dispatched by this skill once the collision check clears or launched
by the human when it does not. Merging is the human's gate.
This skill holds the framing, the board procedure, and the dispatch. Every step
that builds something runs an existing skill. The queue rules below decide which
one runs and when.
Run `canon docs operating-model` for the model this skill enacts: the two roles
and what each owns, the loop end to end, why the worker's self-review and this
session's review are different passes, and how a feature is sized.
## On invocation
Read the board in parallel, resolving the paths at the main worktree root the way `claude-worktree` does:
- `.canon/tasks/priority.md`: execution order and what each task is waiting on
- `.canon/tasks/backlog.md`: what is not being scheduled, when the file exists
- `.canon/tasks/index.md`: what is queued
- `.canon/plans/*.md`: features already planned and ready to hand off
- open PRs via `gh pr list --json number,title,headRefName,isDraft`
Then output the state of play so the human knows what to launch, review, and merge.
`priority.md` is the ordering source. `index.md` sorts by filename and says nothing about order, so read the sequence from the first and never infer it from the second. When `priority.md` is absent, report the queue and say the order is unrecorded.
Row position under `## Needs a plan` is what gets planned next, top first, per `${CLAUDE_SKILL_DIR}/../../standards/tasks.md`. `backlog.md` carries what nobody is scheduling and is explicitly unordered, so read it for what exists and never as a queue. Report a backlog count rather than its rows, since listing them puts the length back in front of the reader the cut took it away from.
No surface carries cross-version sequencing, so report none. A row's `Waiting on` cell states why that row sits where it does, and reasoning spanning several rows reaches this session only through whoever remembers it. Say nothing about an active version, since nothing in the tree states one and a version asserted from the board is the unsourced claim this omission exists against.
A compaction is a moment this skill cannot detect, so the human asks for each side of it and this skill reads the matching runbook when they do.
On a request to write the handoff or save the session, read `${CLAUDE_SKILL_DIR}/references/orchestrator-handoff.md` and follow it. It sends the generic half to `canon:session-map`, which captures what the session learned and writes a session map per `${CLAUDE_SKILL_DIR}/../../standards/session.md`, then adds the decisions taken under delegated authority as this role's extension. That capture is the only one this session runs, since the refill sweep reports it as owed rather than paying it. Write nothing to the handoff that the board, a task file, or a groundwork folder already carries.
On a request to resume after a compaction, read `${CLAUDE_SKILL_DIR}/references/orchestrator-resume.md`, which reads that file back with the board and the groundwork behind the live work.
The review trigger takes the same shape. `references/orchestrator-poll.md` holds the loop prompt and the condition under which the poll runs, and `scripts/poll.sh` is what the prompt invokes. A session holding a recurring-prompt scheduler starts and cancels that loop itself, and no hook or check does, so the condition holds only while whoever holds the loop applies it.
A board that is not moving is a third such moment. On a request to re-test the parked rows, read `${CLAUDE_SKILL_DIR}/references/orchestrator-parked.md` and follow it. It re-tests every `## Up next` and `## Needs a plan` blocker against the current tree, writes what each test showed into the row, and plans what it clears. Its trigger is the inverse of the refill sweep's below, which fires on a merge and asks what to promote next rather than whether a row already parked is still parked for a reason.
That routing lives in this body and this skill is user-invoked, so a session that has dropped the body routes nothing and the request lands as ordinary conversation. Approaching a compaction is when a long session is likeliest to have dropped it, which is the same moment the handoff exists for. Re-invoke `/canon:claude-orchestrate` first whenever the session has run long or the ask goes unanswered. The three runbooks sit at `references/orchestrator-handoff.md`, `references/orchestrator-resume.md`, and `references/orchestrator-parked.md` inside this skill's own folder, so a person who knows their plugin root opens any one of them directly and follows it without this skill loaded at all.
## Output
```plaintext
Orchestrator ready.
Ready to build (hand each to its own worker):
<feature>
plan: .canon/plans/feature-<slug>.md
→ /claude-autoship
<feature>
no plan yet. A handoff without a plan has no scope
→ /claude-feature here first
In flight (this session's workers, building now):
<session name> <branch> <model>
task: <row>, <n> commits, <n> files changed
In review (your turn):
PR #<n> <title>
→ /claude-pr-review
Merge order: #<a> before #<b> (shared seam: <files>).
Next: <the single most useful action>
```
Omit any section with nothing in it. Recommend a handoff only for a plan whose file set is disjoint from every track already in flight, per Parallelism below.
`In flight` covers the state between the other two, which lasts ten to thirty minutes and is most of what an operator sees once this session dispatches its own workers. Before it existed, a session holding running workers reported them under no section and invented a shape per report, which the block below forbids two paragraphs down while giving it no term to use. Read the progress figures off each worker's worktree rather than from the worker, since a busy status says a session is alive and nothing about whether it is moving, and name the model because a dispatcher now picks one per row.
Leave a plan out of `Ready to build` once a row in flight names it. The plan file stays in `.canon/plans/` for the whole build, so listing it there recommends handing off work already underway, and the disjointness rule below withdraws the recommendation only for a reader who already knows what is running.
The block opens on the board rather than on a version, because no committed file states one. Adding a version line here would restate what a reader can already see on the rows, dated by nothing, which is how the retired sequencing surface produced an unsourced claim on every run.
### Every later turn
The block above covers invocation alone. A sweep report, a board report, and an analysis each end in something the human decides, so each opens with the same three slots and puts its evidence underneath:
```plaintext
State: <what changed since they last looked>
Decisions:
1. <one line each, or "none open">
Next: <the single most useful action>
```
Keep the detail below the block and keep it skippable. A decision reached at the bottom of three paragraphs has been buried, which is the failure this shape exists to prevent. Reuse the vocabulary above rather than inventing a second one, and keep a file set on the row claiming it so the reader can check a disjointness claim instead of taking it.
Write no shape for a correction. A correction is a sentence, and a format for admitting error invites ceremony where plainness is the whole value.
## The loop
1. Plan the next feature. The cross-feature call stays in this warm session, being which rows collide, what merges before what, and whether a row should run at all. Per-row planning runs either way: `claude-feature` here with that context, or a cold planner dispatched under `claude-planner` through the planning shape in `${CLAUDE_SKILL_DIR}/references/orchestrator-dispatch.md`. Every plan written from here also carries a constraint per track in flight, which the paragraph below this list states.
2. Decide parallelism and merge order. Note which plans touch a shared wiring seam so their PRs merge in sequence, not at once.
3. Verify the plan against the tree. Reading it is not enough, since a plan goes stale from whatever merged after it was written. Grep for each construct it names and count the sites against the count it claims. Check that every phase label it cites is still open. Open each file it describes rather than trusting its account of the contents. Correct the plan before handing it over.
4. Hand off. Read `${CLAUDE_SKILL_DIR}/references/orchestrator-dispatch.md` and follow it: check the branch is unclaimed, check the row's file set against every track in flight, then dispatch a background worker with `claude --bg`. Fall back to the human-launch line it replaces when the check refuses, the sets overlap, or a stated reason serializes the row behind something already out.
5. Review the PR. When a worker opens a PR, run `claude-pr-review` to post findings to it. This is the deep, independent pass. The worker's autoship self-review was only the green gate.
- Learning that a PR moved is the mechanical half, so read `${CLAUDE_SKILL_DIR}/references/orchestrator-poll.md` and run the poll under the condition it states rather than checking the board by hand. That runbook holds the routing and the trigger, and a summary of it here is a second source that drifts from it.
6. Dispatch the handback. A pass posting anything owed, a finding at any severity or a testing question, tells the session holding that branch to run `claude-address-review`, rather than waiting for a person to relay it. Re-review when the worker's own message says the address pass finished, per the channel `claude-worker` states, rather than polling for an answer nothing else marks as landed. Then the human merges. Tell the trailing worker to rebase when its branch shares a seam with the merged one.
- Read the threshold off `claude-pr-review`, which states it once and governs the heading with it, so an open heading and an owed dispatch answer the same question and either one is enough to send
- Resolve the target at the moment of sending with `canon sessions list --branch`, never from a mapping written down earlier, since names rotate as sessions end and one recorded earlier in a session has failed inside the hour. The runbook read at step 5 routes on the count and the confidence it answers with
- Open the message with the worktree and branch the sender believes the reader holds, asking to be corrected, whenever that mapping is inferred rather than confirmed
- Name the skill for the reader to run rather than writing an invocation, which arrives as text
- Read the pull request's own draft flag rather than the state a worker reports, since two reported a draft that read ready inside ninety seconds, and report what the read returned and when rather than the state alone. The flag settles the question only once the worker's chain has run its undo, and nothing marks that moment, so a read taken between the pull request opening and that call sees a genuinely ready pull request about to become a draft. That is how a poll on `erclx/canon#1307` told an operator the opposite of what the worker had said.
A session is reachable when it appears in a live listing, which reads what each session registered on disk rather than probing it, and a message carries plain text and no authority. When no live session holds the branch, report the invocation for the human, naming the branch, the pull request, and the skill to run, then stop. Retrying or waiting leaves the loop believing it is open while nothing acts on it. Every dispatch in the trial behind this step found a live session, so this branch stands on reasoning rather than on observation.
The channel runs both ways and the return leg carries what the pull request cannot. A worker answering a posted finding by naming the plan question that had already declined it changes the outcome in the moment, where a thread comment waits on whoever reads it next. Read what a worker volunteers as part of the review rather than as an aside, and read a refusal the same way, since the corrections that landed on this session's model of the world arrived as a worker arguing back rather than complying.
What the worker owes on its own side is stated in the `claude-worker` skill that session loads, being the pull-request announcement, the message a block goes out as before it becomes a prompt, and the ban on writing the board. Do not restate any of it here. This half held the only written copy of a channel that runs both ways, which put every obligation on the side that does not perform it.
What arrives there does not become a record by being read, so place it by what it changes. An answer that settles a finding goes onto the pull request through the next pass, which withdraws or regrades that finding and names the fact behind it, per `claude-pr-review`. An answer that changes what this session believes about the world instead, which is a mapping correction or a constraint on what a worker can do, settles no finding and reaches no thread, so route it the way Boundaries below routes a change found while orchestrating, which lands it on the task owning the surface it describes. Writing a tracked file to hold either is forbidden here, which leaves the pull request and the board as the two surfaces this session writes.
Step 1 splits a rule that used to hold every plan in this session, and the evidence narrows it rather than retiring it. Two trials on 2026-08-31 put a cold planner on four rows, and it reported ten things the task files got wrong, corrected this session's own premise twice, and overturned one row's closing conclusion. What that measures is finding quality. The rule's own claim is that a warm plan front-loads reasoning a cold worker would otherwise re-derive, which is a statement about a plan's downstream value, and no plan from either trial has been built. So the per-row measurement goes cold on the evidence and the cross-feature call stays here on the boundary the same trials confirmed, which is that a planner reading the board sees blockers and file sets and can write a confident merge order off a partial picture.
A plan written here is written against a tree several branches are already changing, so it names the file set of every track in flight as a constraint, one set per track, read from the Touches column of that track's row. State for each set which of the two acts it forbids, per Constraints in `${CLAUDE_SKILL_DIR}/../../standards/plan.md`. A bare path list leaves the worker guessing, which is how a plan ends up forbidding the repair of a citation the change broke.
Stamp the block with the commit this session read the tree at, which the same section fixes the form of. A plan written during a refill sits in the ready queue while the wave it names merges, so the constraint is true when written and false when a worker reads it. The stamp is what lets that worker test the difference, and the standard carries the test.
## Boundaries
- Run one orchestrator at a time. The board is gitignored, so a second session sees none of this one's writes: two task files land minutes apart under different labels for the same work, one session archives a task mid-sweep in the other, and each archives a plan the other had retargeted. An Owner column does not fix this, since neither session can read the other's rows.
- Do not implement features in this session. Hand the plan to a worker.
- Do not merge. Recommend merge or changes. The human merges.
- Do not spawn a worker with the Agent tool. An in-process subagent shares this session's context and cannot be steered or reached independently, which breaks the property this boundary protects rather than the mechanism it names. The dispatch in `orchestrator-dispatch.md` is a separate `claude --bg` process with its own worktree and its own PR, so it preserves that property instead.
- Dispatch a background worker only once the collision check in `orchestrator-dispatch.md` clears and the row's file set is disjoint from every track in flight. Colliding with an existing worktree or session is what the check exists to catch rather than a judgment call this session makes case by case. No fixed count binds how many tracks run at once, and Parallelism below states what does.
- Do not edit tracked files from this session, at any size. The boundary offers no proportionality exception and nothing enforces it.
- Do not hand a worker anything but a plan, since scope lives there. A plan carries exact diffs only when they are already known, otherwise it states the scope and the open questions and lets the worker write the diff.
The tracked-file boundary collides with `CLAUDE.md`, which says to handle a small edit immediately without a task entry, and this rule wins wherever the two meet. A session that writes a change cannot review it independently afterwards and no later session recovers that vantage, which is the separation `claude-pr-review` exists to supply.
Record a change identified while orchestrating against the task that owns it, fold one no task owns into the next task touching the same surface, and file a task only when no such task exists or is expected. Run `claude-review` when the boundary is crossed anyway, since a branch-diff pass is not independent and is the only check a self-authored change can get.
## Refilling the ready queue
Keep enough planned, non-conflicting tasks available that a free worker never waits, and place the findings the last merge produced before promoting anything new. Run this after every merge, whenever the ready list thins, and whenever a wave is in flight with fewer unclaimed plans than there are workers building. `${CLAUDE_SKILL_DIR}/references/orchestrator-sweep.md` wraps this procedure for a batch of merges and adds the plan re-verification that a merge invalidates.
The third trigger reaches a window the first two cannot. A session with three workers mid-build has merged nothing and has watched its ready list sit still, so both reactive triggers stay silent across the one stretch where planning costs the session nothing, and the wave finishes into an empty `## Run now`. Nothing starts this pass, in the way nothing starts the review poll, so it holds only while the session applies it.
It counts unclaimed plans against workers rather than reading the reserve in step 4, which is sized for one worker finishing and falls short of a wave landing together. A plan a worker has already taken serves nobody who finishes next, so counting it is what lets the queue read full while it is about to empty. How many to write forward past that floor is the parallelism call rather than a count of free slots, and `## Parallelism` below states what binds it.
### Running the refill
1. Run `gh pr list --state open` and `git log --oneline -8`. Report any pull request whose review has not been posted and stop for that one first.
2. For each pull request merged since the last sweep, place every finding it produced. Route a finding that changes a rule to the standard or rule that states it, one that changes another task to that task's Findings, and one that overturns a groundwork lean to that folder marked answered. Never leave a finding in a pull request thread alone.
3. Archive what closed.
- A task whose outcomes are all `[x]` runs `claude-docs` for the plan sweep, then `claude-tasks` to archive
- A task whose outcomes describe standing policy rather than a deliverable never closes on its own, so hand it to a worker to encode the policy where it is enforced, then cut the outcomes with the reason recorded and archive once that branch merges. Encoding it from this session would write a tracked file, which Boundaries forbids.
4. Read `.canon/tasks/priority.md` and count entries under its `## Run now` heading that carry a written plan. Keep one in reserve beyond what is running.
5. Promote from the top of `## Needs a plan`, which is where the last sweep recorded what to plan next. Depart from that order when something has changed under it and say what changed, since a position nobody honors is the ordering going stale on the surface built to hold it. What sets the order in the first place is whether a task establishes functionality rather than how old it is, so prefer a task that adds or proves a mechanism over one that trims, tidies, or audits an existing surface.
- Re-take the board-or-backlog call while the file is open. A row that has stopped being near-term moves to `backlog.md`, and a backlogged task the last wave made near-term moves onto the board. Both are one line removed from one surface and written to the other, and the standard states the test.
6. Before promoting a candidate, list the files it touches against every task already running, per Parallelism below. Name the overlap and serialize when the sets are not disjoint.
- A candidate held by something outside the tree stays where it is whatever those sets show. A collision is one of the reasons a task cannot start, so disjointness clears that reason alone and leaves an external condition standing.
7. Write a plan for each newly promoted task with `claude-feature`, carrying the in-flight constraint that The loop above states, then report:
```plaintext
Capture: owed since <the last handoff, or session start when none has run>
Findings placed: <finding> → <destination>
Archived: <task>
Promoted: <task>, touches <surfaces>, parallel with <task> because <disjoint sets>
Serialized: <task> behind <task>, both write <file>
Backlogged: <task>, because <what stopped being near-term>
Ready now: <tasks with plans, and what each waits on>
```
The capture row states a standing debt rather than a per-run result. Running capture from here costs the operator a pass between merges while nothing ships, so the row leaves the timing to them and dates the debt, since a capture owed for twenty minutes and one owed all day want different answers and undated text reads the same either way. `${CLAUDE_SKILL_DIR}/references/orchestrator-handoff.md` holds the step that pays it.
That block is the detail. Lead the reply with the three slots under Every later turn above, so the human reads what they own before the evidence for it.
Treat a task that edits `.claude/context/` entries wholesale as conflicting with every other task, because the root instruction file requires each task to update its own domain entry as it lands.
Do not promote a task to fill the queue when nothing qualifies. A thin queue is a real answer and it beats a plan nobody needed.
### Writing the board
Promoting, demoting, and archiving a row all write `.canon/tasks/priority.md`, and this session is the only writer apart from `canon tasks archive`. Moving a task between the board and `.canon/tasks/backlog.md` writes both files, and this session is that file's only writer.
- Edit the file with the file-editing tool. A shell stream editor and an inline string replace both exit clean on a non-match, so a promotion that matched nothing leaves the board wrong with nothing reporting it, and the file-editing tool errors instead.
- Write both halves of a move before reporting it. A row removed from one surface and not written to the other leaves a task file nothing names, and the folder is gitignored with no history to recover the row from. `canon tasks validate` reports that state, so run it after any move.
- Put the reason a row sits where it does in its Waiting on cell. Position is the ordering and the cell is where the ordering's rationale lives, so a row promoted with the cell left alone carries an order the next sweep cannot check.
- Put a pointer in the Plan column, never prose. `## Run now` claims a written plan covers every open outcome, and `claude-autoship` refuses at its guard when it follows the column and finds no plan, which spends a worker dispatch to learn what the row should have said.
- Name the file set in the Touches column. The disjointness call in step 6 is only checkable later when the sets are written down rather than reasoned once and discarded.
- Re-resolve every Plan pointer after anything archives a plan
- Read the file back after writing it, since the row that lands is the row a worker acts on
A Plan pointer goes stale from a branch this board never sees. `claude-docs` moves a plan to `.canon/plans/archive/` and rewrites the citation in the task file alone, so a row for a task still on the board keeps pointing into `.canon/plans/` at a file that has moved. Workers running the ship chain on their own branches archive plans this board still cites, and the board reads as correct until a pointer is followed.
## Parallelism
No fixed number caps worker tracks. Collision between file sets is what binds, so
list the files a candidate touches against every track already in flight and open
it only when the sets are disjoint. What thins as tracks multiply is the review
attention each output gets, so add a track while you can still review every one
properly and stop when you cannot. An operator can also cap this session's
workers by saying so, and a spoken cap binds for that session rather than
standing as a number in a file.
Inbound turns are the third input to that judgment. Claude Code delivers a
message from another session as a new turn whenever this one sits idle, and the
turn carries the whole accumulated context rather than the few lines the worker
sent, so one handback from a wide wave costs more than the same handback from a
narrow one. A recurring review poll bills that window again on every interval it
fires. Weigh the spend before widening, since it lands on this session's context
and never on the worker's.
`crossSessionInbound` is the control, on an `accept`, `hold`, `refuse` ladder,
and it is recorded here as deliberately not pulled. `hold` and `refuse` are the
two values that bound the cost, and both break the handback this loop runs on,
since a held message reaches nobody until a later `accept` applies and a refused
one is dropped outright. `accept` bounds nothing. Read the ladder before turning
concurrency up rather than after, and leave it unset.
Serialize any track that touches a shared wiring seam with another in flight, and
serialize one whose sets are disjoint when a stated reason still puts it behind
another, since two tracks interact in ways no file-set comparison reads. One
building a skill and one auditing that catalog write nothing in common and the
audit still counts a denominator the other is moving.
Merge the branch with the smallest shared-file footprint first, and merge a
branch touching `CLAUDE.md`, a Claude context entry, or a regenerated `index.md`
last. Have every sibling rebase on the new `main` before the next merge. Two
workers running a server take a port apiece without being told to, since a
stack derives it from the worktree it runs in through `scripts/worktree-port.sh`.
Read that value rather than assigning one, and set `WORKTREE_PORT_OFFSET` by
hand only when two worktrees derive the same offset.
### The review fallback
Two conditions move the review itself out of this session rather than binding the
track count. One is a diff too large for this session to hold. The other is three
or more open pull requests awaiting a first pass. Either one makes review the
bottleneck every track is waiting on, and both answer the same way: dispatch the
narrow re-review and keep the first pass here.
Three is the operator's number, set by hand on 2026-08-31 and marked as such so a
measurement replaces it rather than argues with it. It is calibrated against a
session that ran five workers across two waves and reviewed five pull requests in
one stretch, several of them twice, where a sixth track was declined on judgment
and on nothing else. What counts toward it is a pull request awaiting a first
pass rather than every open one, since a branch already closed out and waiting on
a merge costs this session nothing and counting it would fire the switch on a
queue that is clear.
Only the narrow re-review dispatches. A first pass reads across branches, and the
findings that pay for its cost are the ones no single pull request shows: two
branches regenerating one binary asset for the same count, three writing one
context entry, a merge order making one branch's figure true only after another
lands. A re-review asks whether the prior findings landed and whether the fix
regressed anything, which is bounded to a delta and carries none of that reading,
so it is the half that leaves cleanly.
What it dispatches has no role skill yet. `claude-worker` and `claude-planner`
each state what their session may not do and no third body states a reviewer's,
so a dispatched re-review would hold its obligations in whatever launch string
this session types. That is the defect those two skills were written to close, so
write the third after the first trial rather than before it, since nothing has
ever dispatched a reviewer and a body written now encodes a shape nobody has
driven. Until it exists, say in the launch itself that the pass is bounded to the
delta and that the cross-branch reading stays here.
Nothing counts the pull requests. This is prose this session applies to itself,
on the same standing as the poll's own start condition, so a wave past three
reviewed one at a time is a rule that went unread rather than a check that
failed.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!