session‑orchestrator v3.23.0

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.

Node.js 24 or later · MIT · every command below re‑checked against v3.20.0 on 2026‑08‑19

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 pins 24 in .nvmrc and package.json declares engines.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.md still tells you the enforcement hooks require it. That sentence is left over from version 2. Nothing in hooks/ shells out to jq today; the one script that still requires it is scripts/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.

This step is required, and the command for it used to be broken

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
The path argument is mandatory

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.

  1. /session feature — research and agree the scope

    It 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.

  2. /go — execute the plan in five typed passes

    Discovery 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.

  3. /close — verify, commit, and file what is left

    It 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.

The first run in a fresh repository asks a lot — plan for 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 README leaves out one half of this

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.

Releasing it deliberately

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.

What healthy looks like

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: 0 after a wave in which you plainly watched agents work.
  • A duration of 0m for a session that took you half an hour.
  • undefined anywhere 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.