Guide
Claude Code · Codex CLI · Cursor IDE · Pi
Install it, run one session, and check that it did what it says.
All four issues opened on this repository by people outside it were installation or environment problems. Not one was a feature request. So this page leads with the parts that break, and it says plainly where our own documentation was wrong.
01 / prerequisites
Before you start
Two things have to be there. A third one, which the old documentation asks for, does not.
- Node.js
- Version 24 or later. Check with
node --version. The repository pins24in.nvmrcandpackage.jsondeclaresengines.node: ">=24.0.0". Version 3 is ES modules throughout, so an older runtime fails at import time rather than at a friendly error message. - git
- Any recent version. The session loop reads your history on every start — commits, branch, dirty files, recent issues — and that reading is most of what makes the first pass useful.
- jq
- Not needed.
docs/USER-GUIDE.mdstill tells you the enforcement hooks require it. That sentence is left over from version 2. Nothing inhooks/shells out tojqtoday; the one script that still requires it isscripts/validate-plugin.mjs, which you only run if you work on the plugin itself.
Which file your harness reads
The configuration lives in your project’s instruction file. Which file that is depends on the tool, and the contents are identical either way.
- CLAUDE.md
- Claude Code, Cursor IDE
- AGENTS.md
- Codex CLI, Pi
If you put the block in the file your harness does not read, it is simply not found — there is no error to tell you.
02 / install
Install
Same plugin, four paths. Pick the one for your tool and read its note — each path has exactly one thing that catches people.
Claude Code
Marketplace · then one manual step
/plugin marketplace add Kanevry/session-orchestrator /plugin install session-orchestrator@kanevry
Both lines run inside Claude Code, not in a shell.
Then install the Node dependencies once, in a shell, and restart Claude Code:
# Claude Code has no `plugin dir` subcommand, so resolve the path from the cache.
SO_DIR="$(dirname "$(find ~/.claude/plugins/cache -path '*session-orchestrator*' -name package.json 2>/dev/null | head -1)")"
cd "$SO_DIR" && npm install
If SO_DIR comes back empty, the plugin was not installed from a marketplace — run /plugin list inside Claude Code first.
The hooks import zx. The plugin has eight runtime dependencies and a marketplace install does not fetch them, so without this step the hooks fail to load.
Until 2026‑08‑19 the documented one‑liner began with claude plugin dir — a subcommand Claude Code does not have. It exits 1, the fallback path it then used does not exist, cd fails, npm install never runs, and every hook afterwards cannot find zx. Two of the four issues outsiders filed on this repository are that failure, reported as the symptom. The command above replaces it and was verified end to end.
Codex CLI
Clone · install · run the installer
git clone https://github.com/Kanevry/session-orchestrator.git ~/Projects/session-orchestrator cd ~/Projects/session-orchestrator && npm install node scripts/codex-install.mjs
Your project’s config goes in AGENTS.md, not CLAUDE.md. Hook‑level scope enforcement is not available on this platform; the rules still apply, but nothing mechanically holds an agent to them.
Cursor IDE
Clone · install · point at your project
git clone https://github.com/Kanevry/session-orchestrator.git ~/Projects/session-orchestrator cd ~/Projects/session-orchestrator && npm install node scripts/cursor-install.mjs /absolute/path/to/your/project
Leave it out and the installer reports success without having written anything into your project. Before you believe the message, look in the target repository for the files it should have created.
Pi
The only path that resolves dependencies for you
npm install -g --ignore-scripts @earendil-works/pi-coding-agent pi install npm:session-orchestrator
No separate npm install step afterwards. Config goes in AGENTS.md.
03 / first run
Your first session
Three commands carry the whole loop. The first one behaves differently the very first time, and that difference is worth knowing before you hit it.
-
/session feature— research and agree the scopeIt reads the repository before it asks you anything: git state, open issues, CI status on the current commit, what the last session left behind. Then it reports what it found and proposes a plan — how many waves, how many agents, and how confident it is. You correct it here, in words. Nothing has been written yet.
-
/go— execute the plan in five typed passesDiscovery reads. Impl‑Core writes the feature. Impl‑Polish fixes the edges. Quality writes tests and reviews. Finalization tidies up. Between each pass a typecheck, test and lint gate runs, and the agents cannot skip it — a hook enforces it, not a sentence in a prompt.
-
/close— verify, commit, and file what is leftIt walks the plan item by item and checks each one against the actual working tree, commits, and turns anything unfinished into a carryover issue instead of quietly dropping it.
Before any of the above happens, a bootstrap gate runs once. On a repository that has never used the plugin, expect seven to ten questions and two to four minutes before work begins.
Three places in our documentation say “at most one question”. That is the intent for the tier confirmation on its own; it is not what a cold repository does, and you should not be surprised by the difference.
What you are answering during those minutes:
- Tier — fast, standard or deep. It decides how much structure gets scaffolded. Fast is right for a spike.
- Stack archetype — only asked for standard or deep, and only when the repository is genuinely ambiguous.
- Owner persona — language, tone, how much output you want, how much preamble before an action. Stored once per machine in
~/.config/session-orchestrator/owner.yaml, outside every repository, never committed. - Telemetry consent — whether anonymized hardware patterns may be shared to improve resource defaults. Declining is a normal answer and changes nothing else.
- Dispatcher autonomy — a one‑time, per‑repository capture. The recommended answer is
off, which is also the fail‑closed default. - Your actual scope — the question you came for.
All of it is written down once. The lock file, the owner profile and the dispatcher block are each recorded, and every later session goes straight to the scope question.
04 / configuration
The minimal config
Seven fields in your instruction file. Everything else the plugin can do is opt‑in and stays off until you ask for it.
## Session Config test-command: npm test typecheck-command: npm run typecheck lint-command: npm run lint agents-per-wave: 6 waves: 5 persistence: true enforcement: warn
Goes into CLAUDE.md (Claude Code, Cursor IDE) or AGENTS.md (Codex CLI, Pi). The heading matters — the parser looks for ## Session Config literally.
enforcement takes strict, warn or off. Start on warn: you see every scope violation without any of them stopping you, which is the fastest way to learn what your waves actually touch.
The bootstrap gate checks for three things, not one: the instruction file, this Session Config block, and .orchestrator/bootstrap.lock. Paste only the block and the gate is still closed — your next /session will run the whole interview anyway and it will look as if the configuration was ignored.
Run /bootstrap and it writes both, in the right order.
05 / guards
When it blocks you
Two guards will refuse a command or an edit at some point. Both can be released on purpose. Neither is worth fighting, because in most cases the refusal is telling you the plan is wrong, not the tool.
The destructive‑command guard
Fourteen rules in .orchestrator/policy/blocked-commands.json are checked before a shell command runs: git reset in all three forms, git checkout -- discards, git clean -f, any git stash, destructive rm -rf, git push --force including --force-with-lease, SQL DROP TABLE, and truncating redirects onto protected files.
The reason it is that broad: several sessions can share one working copy, and a stash or a reset takes work from a neighbour who has no way to find it again.
Add allow-destructive-ops: true to your Session Config for the maintenance you actually intend, then take it out again. It is a per‑session switch by design — leaving it in permanently removes the guard for every future session, including the ones you did not plan.
Scope enforcement
Every agent in a wave gets a declared set of paths it may write to, and hooks/enforce-scope.mjs denies an Edit or Write outside it. The set is computed and asserted non‑overlapping before any agent starts, which is what keeps two parallel agents from landing on the same file.
When you hit a deny, the useful move is almost always to widen the paths the wave declares — not to lower enforcement. A denied edit usually means a file was missing from the plan, and that same omission is what would have collided later.
If you do need the whole thing quiet while you find your feet, enforcement: off exists. It removes the mechanism, not just the message.
06 / diagnosis
When something is wrong — and how you would even notice
The failure this tool actually has is quiet. Not a stack trace: an agent that never started and whose work a neighbour silently absorbed, or a run that is recorded as finished without having done anything.
You will not see it in the transcript, because the transcript reads fine either way. You see it in the record the session writes about itself. One line, after any session:
tail -1 .orchestrator/metrics/sessions.jsonl | jq '{session_id, total_waves, total_agents, total_files_changed}'
This is the one place jq is handy — for you, not for the plugin. Any JSON reader does the same job.
Numbers that match what you just watched happen. If you ran three waves with six agents each and files changed on screen, the record says so. That is the whole test — there is no green checkmark to trust instead.
Warning signs, in order of how often they turn out to be real:
total_agents: 0after a wave in which you plainly watched agents work.- A duration of
0mfor a session that took you half an hour. undefinedanywhere in the record — a field that was never written, not a field that is empty.-abandoned-inside the session id although you closed cleanly with/close. That name is reconstructed after the fact for sessions that never closed themselves.
None of these mean your code is broken. They mean the run did not do what the summary implies, and the honest response is to look at what actually changed on disk before you build on it.
The three that outsiders actually hit
All four issues ever filed here by people who are not the author fall into these. If you land on one, your case is already written up — read the tracker before opening a new issue.
- Node is not on the hook’s PATH. Hooks run in the harness’s environment, not your login shell. A version manager that only initialises in your interactive shell profile is not there when a hook runs, so the hook cannot find
node. The symptom is that nothing enforces anything and nothing complains about it. - Missing
node_modules. The marketplace install path from section 02. Check it directly:ls "$SO_DIR/node_modules/zx". If that path is absent, no hook on the plugin can load. - An installer that reported success without effect. The Cursor path without its mandatory project argument is the known case. Verify in the target repository, not in the installer’s output.
07 / further
Where to go deeper
This page is the short path. Everything below is the long one, and all of it lives in the repository.