From an existing project to a working orchestrator, installed as a Claude Code plugin, in 6 steps. Budget ~20 minutes.
Prefer to be guided? Once the plugin is enabled (Step 1), run
/orchestrator:setupin Claude Code. It interviews you (project basics, module boundaries, gate commands, review/merge config), then scaffolds the files a plugin can't carry into your repo —.claude/gates.json+CLAUDE.md+ the fan-out workflow + the CI gate workflow — fixes.gitignore, creates themodule:*labels, verifies the bot, checks the CI gates, and offers to arm the PR loop and (last)/orchestrator:harden. This page is the manual reference behind that command — read it to understand what it's doing, or to configure by hand.
- Claude Code installed and authenticated (
clauderuns). nodeandgiton PATH (the gate script usesnodeto readgates.json).- Your project's actual build/test tooling installed (so the gate commands work).
This template ships as a Claude Code plugin named orchestrator (plugin root .claude/). Two ways to add it:
GitHub source (no local clone needed). Declare the marketplace straight from GitHub in your project's
.claude/settings.json:
{
"extraKnownMarketplaces": {
"recode": {
"source": { "source": "github", "repo": "robercano/reCode" }
}
},
"enabledPlugins": { "orchestrator@recode": true }
}This works because a thin .claude-plugin/marketplace.json at the repo root (where Claude Code's
"source": "github" resolution looks) points at the actual plugin payload under .claude/ via a relative
path ("source": "./.claude") — see .claude-plugin/README.md for why there are two marketplace.json
files in this repo.
Local clone (alternative, e.g. if you want a pinned/offline copy). Claude Code's /plugin marketplace add
also accepts a plain filesystem path, using .claude/ directly as the marketplace root:
git clone https://github.com/robercano/reCode.git ../reCodeThen, in Claude Code, inside your own project:
/plugin marketplace add ../reCode/.claude
/plugin install orchestrator@recode
(/plugin alone opens an interactive picker if you'd rather browse marketplaces/plugins than type the
commands above.)
Enabling the plugin here is what lets you run /orchestrator:setup in Step 2, and — unlike an earlier version
of this template (issue #128) — keep the plugin enabled afterward too: this repo does not vendor a local
copy of its own runtime harness into your repo (issue #134), so agents/, commands/, hooks/, scripts/,
skills/ are read straight from the plugin cache on every session, not just during
/orchestrator:setup//orchestrator:sync. See Step 2.
With the plugin enabled, run:
/orchestrator:setup
It interviews you, then writes the files a plugin cannot carry into your repo — it does not copy the
plugin's own agents/commands/hooks/scripts/skills into your repo (issue #134: an earlier version of this
template vendored those wholesale into your local .claude/ so a session could read them off disk with the
plugin disabled, issue #128 — that model was reverted because nothing kept an unmanaged vendored copy updated,
and a stale local copy permanently shadows a fresh plugin install; see resolve-roots.sh). It also creates a
.claude/settings.json from a template if you don't already have one, wiring the runtime hooks to
${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR/.claude}/scripts/... — the plugin cache while the plugin is
enabled, falling back to a local .claude/scripts/ only if you're self-hosting this template directly (no
distinct plugin install). Keep the orchestrator plugin enabled for everyday sessions — its own
hooks/hooks.json and, unless you drop the block, this file's hooks both need it loaded. What the interview
collects and scaffolds:
.claude/gates.json(the adapter — the only file that makes the generic agents work on YOUR stack). Set:project— name, language, package manager.modules— the map of independent areas + their paths. This is what the orchestrator uses to give each worker a non-overlapping boundary. Get this right and clashes mostly disappear.gates— the exact shell commands forbuild,lint,typecheck,test,test_affected,coverage,e2e,security. Leave any you don't have as""(it's skipped, not failed).coverage_threshold,review.lenses,budget(model routing +max_parallel_workers),merge.policy.
CLAUDE.md— project-wide context every agent reads (what the project is, stack & layout, conventions, definition of done, merge policy). Kept lean by design..claude/workflows/feature-fanout.js— the deterministic fan-out workflow (managed; re-stamped on updates, seeUSAGE.md→ "Updating the plugin")..github/workflows/gates.yml+.github/actions/setup/action.yml— the CI gate workflow (Step 4 below).module:*GitHub labels, a bot-account check (GH_BOT_TOKEN), and offers to arm the loop — the cron-less loop daemon (recommended,systemd --user) or the legacy/orchestrator:pr-loopcron — and, last,/orchestrator:harden.
Sanity-check the gates once it's written (ask Claude Code to run these, so ${CLAUDE_PLUGIN_ROOT}
resolves correctly whether the plugin is installed or you're dogfooding this repo directly):
bash ${CLAUDE_PLUGIN_ROOT:-.claude}/scripts/gate.sh build
bash ${CLAUDE_PLUGIN_ROOT:-.claude}/scripts/gate.sh lint
bash ${CLAUDE_PLUGIN_ROOT:-.claude}/scripts/gate.sh testEach should run the right command (or say "not configured — skipping").
Bootstrap first. On a brand-new project there's usually no build system yet, so real gate commands will fail (not skip) — e.g.
pnpm -r buildwith no workspace,forge testwith nofoundry.toml. Pick one:
- Scaffold a minimal buildable skeleton first (workspace manifest + empty buildable packages/stubs that build and pass a trivial test), then wire the real gate commands. This makes the pilot run (Step 3) work immediately and gives parallel workers a green baseline to branch from. Recommended.
- Or keep the gates empty (
""= skipped) until your first task is an explicit "bootstrap the workspace" ticket, and only fill in real gate commands once that lands.Either way, don't point a gate at a command that can't pass yet — a red
test_affectedwill block theStophook and every agent's "done".
test_affected runs on the Stop hook — wired both by the plugin's own hooks/hooks.json and by the
.claude/settings.json /orchestrator:setup scaffolds (Step 2 above; it calls
${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR/.claude}/scripts/gate.sh test_affected) — after every change, so it
should be fast — ideally only the tests touched by the diff. But "test only what changed" isn't free in every
stack. Sensible options:
| Stack | Cheap test_affected |
Notes |
|---|---|---|
| turbo | turbo run test --filter='...[origin/main]' |
needs turbo |
| nx | nx affected -t test --base=origin/main |
needs nx |
| pnpm (no turbo/nx) | pnpm --filter '...[origin/main]' test |
flaky in worktrees unless origin/main is fetched first — see #9 |
| cargo | cargo test (or cargo nextest run) |
no cheap since-base; full suite is fine |
| go | go test ./... |
already fast; no filter needed |
| Foundry | forge test |
no native since-base — run all |
| gradle | ./gradlew test |
full suite |
test_affected = your full test command is a perfectly good default whenever the suite is fast — only
reach for affected-filtering when the full run is too slow to gate on every Stop. And note the worktree
gotcha: any filter that diffs against origin/main needs that ref present in the worktree, so git fetch origin main first (or fall back to the full suite) — the per-worktree setup hook in #9 is the place for that.
Agents (/agents in Claude Code lists orchestrator, implementer, reviewer, test-runner) and hooks ship
generic and read gates.json, so they typically need no edits. Adjust model: per agent if your routing
differs, or add project review skills (e.g. a security/audit skill) and reference them in gates.json →
review.skills.
Don't unleash the whole army first. Run ONE real task end-to-end:
Use the orchestrator agent. Task: <one small, real, self-contained feature/fix>.
Scope it, show me the plan, and wait for my approval before writing code.
Approve the plan, let one implementer run in its worktree, watch the reviewers gate it, review the PR. Then
read USAGE.md to scale up, and TOKEN_BUDGET.md before you go parallel.
The hooks and gate.sh enforce gates locally, and the orchestrator runs them before opening a PR — but
nothing stops a human (or a bot) merging a PR whose gates never ran. /orchestrator:setup scaffolds
.github/workflows/gates.yml + a .github/actions/setup composite action
that run the same gate.sh gates on every pull_request, reading commands from gates.json. It's
adapter-driven — you configure gates.json, not the YAML.
-
It works out of the box for JS/TS. For other stacks, add the toolchain at the Extension point comment in
.github/actions/setup/action.yml(e.g.foundry-rs/foundry-toolchainfor Solidity,actions/setup-python), keyed offproject.language. Empty gates skip, so unconfigured checks stay green. -
Make the checks required — this is the actual enforcement. On the base branch (
merge.baseBranch): Settings → Branches → Add branch protection rule → Require status checks to pass before merging, then select the gate checks (build,lint,typecheck,test,coverage,security). Or via CLI:gh api -X PUT repos/<owner>/<repo>/branches/<base>/protection \ -f 'required_status_checks[strict]=true' \ -f 'required_status_checks[checks][][context]=build' \ -f 'required_status_checks[checks][][context]=lint' \ -f 'required_status_checks[checks][][context]=typecheck' \ -f 'required_status_checks[checks][][context]=test' \ -f 'required_status_checks[checks][][context]=coverage' \ -f 'enforce_admins=true' -F 'required_pull_request_reviews=null' -F 'restrictions=null'
Without this step the workflow only reports pass/fail; required checks are what block the merge button.
Free private repos can't enforce. Required status checks (and branch protection) need a paid plan on a private repo — GitHub will reject the call above with "upgrade to GitHub Team/Enterprise". Options: make the repo public (enforcement is free), upgrade the plan, or run convention-based: the checks still run and are visible on every PR, and
merge-ready.shonly merges a PR once the owner has approved it and CI is green — so the approval+green gate holds even though GitHub doesn't hard-block the button.
A copy-pasteable checklist for wiring a new project into the autonomous loop. See
USAGE.md → "Autonomous loop & the issue queue" for the mental
model (the module:* opt-in queue + the owner-approval merge gate) that this checklist wires up.
- Install the plugin and run
/orchestrator:setup(Steps 1–2 above) — it writes everything below except the two GitHub-side actions (4, 6). .claude/gates.json— the only per-project file that must be filled:project.{name,language,packageManager};modules[](one entry per independently-ownable area, each with a non-overlappingpath— these become both the worker boundaries and themodule:<name>labels the loop understands; include non-code areas likedocsif you want them automatable);gates.*(real shell commands,""= skip);coverage_threshold;review.{lenses,consensus};budget.*(model routing,max_parallel_workers);merge.{policy,baseBranch}.CLAUDE.md— project context, conventions, definition of done, merge policy.- Bot machine account — create it, add as a write collaborator, put
GH_BOT_TOKENin.env(gitignored). All agent/loopghcalls run as the bot viabot-gh.sh; onlygitcommits/pushes stay on the owner's auth, so the owner can approve bot PRs. Setup notes live at the top of.claude/scripts/bot-gh.sh. - Create the
module:*labels matching yourmodules[]names — see the bootstrap note at the top of.claude/scripts/seed-issues.sh. Without the label, ADVANCE can never queue the issue. - Server-side gates — confirm
.github/workflows/gates.ymlruns your gate commands (Step 4 above), and set branch protection / required status checks onmerge.baseBranchif your plan supports it. - Arm the loop — recommended:
bash .claude/scripts/arm-loop.sh(run in a real terminal outside Claude Code — installing systemd units,loginctl enable-linger, and a detached tmux session all touch$HOME, which the sandbox blocks). This installspr-loop-<repo>.service(the cron-less daemon — supervised bysystemd --user, survives Claude Code restarts, adaptive FAST/WATCH/IDLE sleep read straight off the census) andclaude-rc-<repo>.service(claude remote-controlin a detached tmux session, for spawning planning sessions remotely). Self-hosting: add--gates-file .claude/self/gates.json. SeeUSAGE.md→ "Cron-less loop (daemon)" for the full architecture, cadence, run ledger, and failure-contract details, including WSL2'ssystemd=trueprerequisite. Fallback (no systemd available):/orchestrator:pr-loop— the legacy session-scoped cron. It self-adjusts cadence the same way (FAST when there's ≥1 open PR or ≥1 openmodule:*issue, else IDLE) but dies with the Claude Code session that armed it, so it must be re-run at the start of each session. Never run both against the same repo at once —loop-tick.sh's spawn lock makes it safe (no double-spawn), just wasteful. Pick the right model for each side of the loop: the daemon's driver sessions default to Sonnet (LOOP_MODELenv, read byloop-event.sh) — the ticks are repetitive, and that repetition is exactly where smaller models drift (a Haiku-driven tick session has been observed to stop running the step scripts and fabricate their output, and to double-spawn orchestrators for one issue)..claude/scripts/loop-tick.shhardens the tick itself — one script computes the census/feedback/advance verdict and a self-healing spawn lock, instead of a model re-deriving it from a prompt every firing (seeUSAGE.md→ "Model selection") — but a driving cron session still needs Sonnet to read that verdict and act on it. Use Fable or Opus for the owner-side judgment work — scoping, planning, and filing issues — then let the loop execute the approved queue. - (optional) Hardening —
/orchestrator:hardenfor the bypass + strict-sandbox profile, seeHARDENING.md.
When a new version of orchestrator ships, update it and re-stamp the files it scaffolded into your repo —
see USAGE.md → "Updating the plugin".
- The
orchestratorplugin shows as enabled (/plugin). -
CLAUDE.mddescribes the project and lists modules. -
.claude/gates.jsonhas real commands;gate.sh build|lint|testbehave correctly. -
/agentslists orchestrator, implementer, reviewer, test-runner;/orchestrator:*commands resolve. - A pilot task produced a branch/PR that passed gates + review.
- CI gates run on PRs and are set as required status checks on the base branch (Step 4).
- You've checked spend with
/costornpx ccusage.
Already have .claude/ copied wholesale into a repo from before this was packaged as a plugin? See
MIGRATION.md — it covers what to delete (now carried by the plugin), what to keep
(your adapter/CLAUDE.md/workflow/CI files), and how to switch to the plugin install above.