choirmaster
v0.4.0
Published
Local orchestrator for AI coding agents. Drive multi-step refactors with scoped tasks, isolated worktrees, deterministic gates, and resumable runs.
Maintainers
Readme
ChoirMaster
Write a markdown plan, get scoped, gated, reviewable agent work.
ChoirMaster is a local CLI for developers and small teams who want to use AI coding agents on real codebases without losing the day to scope drift, broken gates, mystery edits, or unrecoverable runs.
The happy path is markdown-first: you write a plan, run choirmaster run <plan.md>, and ChoirMaster turns it into a validated task contract before executing it. Each task then moves through implementer → deterministic gates (typecheck / test / audit) → reviewer → commit → branch policy, all in isolated git worktrees.
The generated *.tasks.json file is still there, readable, and safe to inspect when you run choirmaster plan. It is the execution contract, not the normal user-facing surface.
The agents do the work. ChoirMaster owns the loop, the gates, the worktrees, and the merges.
Status
Pre-alpha. The 0.3.x line is published and dogfooded by this repo. APIs will still change.
Who it's for
Solo developers, indie hackers, and small teams running scoped docs work, tests, refactors, migrations, and cleanup tasks on their own codebases. You write or review the plan, you review the diffs, you ship. ChoirMaster does the mechanical bits in between, inside the scope you defined.
What it isn't
- Not a hosted service or SaaS. It's a local CLI. Runs on your machine. State lives in your repo and your filesystem.
- Not a Claude or Codex replacement. Today it ships with a Claude Code adapter and shells out to the
claudeCLI you already have installed and authenticated. Codex and other providers are planned behind the same adapter interface. - Not a "give me a goal, I'll do everything" agent. You provide the plan, set the scope, and read the diffs. ChoirMaster only executes work that fits inside the contract generated from that plan.
- Not telemetry-bearing. No analytics, no phone-home, no accounts. The repo is the entire product.
What you get out of the box
- Markdown-first planning.
choirmaster run <plan.md>plans and runs in one flow.choirmaster plan <plan.md>stops after generating the task contract so you can review it first. - Polished interactive shell. Run
cmwith no args to enter a ChoirMaster-owned shell with live/and@suggestions, first-class pickers for plans and resumable runs, a status header showing repo, branch, base, dirty state, and resumable count, and shell-native/resume <run-id>hints when a run pauses inside the shell. No shell setup required. - Built-in markdown picker. Run
cm runorcm planwith no path and ChoirMaster opens its own searchable markdown picker. No shell setup required. - Live markdown completions.
cm completions <shell>installs optional shell glue for zsh, bash, fish, PowerShell, and Nushell socm run @exa<Tab>can suggest markdown files while you type. Without completion, use the built-in picker, an explicit path, or an exact@reference. - Typed task contracts. Each generated
*.tasks.jsondeclares branches, worktrees, allowed and forbidden paths, gates, dependencies, retry limits, and definitions of done. The runtime validates the whole file before any task starts. - Hard scope enforcement. Edits outside
allowed_pathsare caught after the agent's turn and the worktree is reverted. The check looks at committed + staged + unstaged + untracked, so an agent that ignores the prompt and commits anyway is still rolled back. - Planner mutation guard. Planning runs against the real repo, so ChoirMaster snapshots git-visible state plus configured forbidden paths before and after the planner turn. Rogue planner edits block the run.
- Project-wide safeguards.
forbiddenPathsandstrictInstructionsdeclared once in your manifest apply to every task:.env*always blocked, "never run pnpm install" always in the prompt. - Deterministic gates. Typecheck, test, audit scripts run after every implementer turn. Failures route back to the implementer with the failure summary; the reviewer never sees broken code.
- Sandbox prepare hook. Fresh worktrees can run setup once before any agent turn, e.g.
pnpm install --frozen-lockfile, so real project gates have dependencies available. - Setup diagnostics.
choirmaster doctorchecks the repo, manifest, branch, prompts, agents, gates, sandbox, gitignore, and Anthropic DNS before you spend a model turn. - Recoverable everywhere. Hit Claude's rate limit mid-run? The orchestrator pauses cleanly and resumes from the same phase on the next run. Blocked, capacity-paused, or interrupted runs print
cm --resume <run-id>so you can continue from the same session state. - Configurable branch policy. Completed tasks can merge into the base branch, fast-forward the base, or stay on task branches for manual review.
- Per-task git worktrees. Tasks never touch your main checkout. Inspect any task's branch independently.
- One package. The CLI, runtime, Claude adapter, and public types ship as
choirmaster.
Architecture
Three layers, one published package:
- Runtime - state machine, retry caps, capacity pause/resume, worktree management, scope enforcement, gate runner, auto-merge with conflict abort. Project-agnostic.
- Agent adapters - pluggable
Agentinterface; the default Claude Code adapter ships in the box. Future agents (Codex, OpenCode, custom) implement the same interface. - Project config - a typed
manifest.tsper repo declares base branch, agent preferences, gates, sandbox setup, branch policy, and prompt files. Markdown plans can live anywhere in the repo;.choirmaster/plans/is the scaffolded convention. Generated*.tasks.jsonfiles live under.choirmaster/tasks/as validated execution contracts.
The repo is a pnpm workspace with internal modules (packages/core, packages/agent-claude, packages/cli); pnpm build bundles them into the single published choirmaster package.
.choirmaster/
├─ manifest.ts # typed defineProject({...})
├─ prompts/ # planner.md, plan-reviewer.md, implementer.md, reviewer.md
├─ plans/
│ └─ 2026-05-foo.md # human-authored plan input
├─ tasks/
│ └─ 2026-05-foo.tasks.json # generated execution contract
└─ runs/<run-id>/ # per-run state, logs (gitignored)For teams, commit the parts that define shared behavior: manifest.ts,
prompts/, and any markdown plans the team should reuse. Generated
contracts in tasks/ and run state in runs/ are ignored by default and
should stay local to each developer.
Install
# project-local install (recommended so manifest.ts can import from choirmaster)
npm install --save-dev choirmaster
pnpm add --save-dev choirmaster
yarn add --dev choirmaster
# optional global CLI for convenience
npm install -g choirmaster
pnpm add -g choirmaster
yarn global add choirmasterIf you install globally, still add ChoirMaster to the project as a dev dependency so .choirmaster/manifest.ts can resolve import { ... } from 'choirmaster'. The global install gives you the cm command everywhere; the project install gives your repo's manifest its types and runtime imports.
Every command is exposed as both choirmaster and the shorter cm alias. If you only install project-locally, run through your package manager:
npx choirmaster --help
pnpm exec choirmaster --help
yarn choirmaster --helpYou also need the claude CLI installed and authenticated. The bundled Claude adapter shells out to it.
Interactive Mode
Run cm with no args in a terminal to open the ChoirMaster shell:
cmThe shell opens with a status header (repo, branch, manifest base, dirty state, resumable run count) and a cm> prompt. Suggestions are live, not Tab-only:
- Type
/to see the command list. Filter with more characters:/rnarrows to/runand/resume. - Type
@inside/runor/planto see matching markdown plans as you type. (/drafttakes a free-form goal, not a plan reference, so it does not show@suggestions.) - Up/Down moves through suggestions, Tab inserts the highlighted one, Enter executes the line, Esc dismisses the suggestion list.
Slash commands:
cm> /draft --interactive add email sharing to galleries
cm> /plan # opens the markdown picker
cm> /run @example
cm> /resume # opens the resumable-run picker
cm> /doctor
cm> /help
cm> /exit/run and /plan with no path open the built-in markdown picker. /resume with no id opens a picker over runs that paused cleanly (capacity hit, interrupted mid-task, never started); blocked runs are excluded because the runtime can't auto-reuse their worktree without an explicit reset (planned). Inside the shell, capacity-paused runs print /resume <run-id> so you can continue without leaving. Ctrl-C while a run is in flight kills the whole process (shell included) and prints the outside form cm --resume <run-id> since you'll be relaunching cm anyway.
Shell Completions
ChoirMaster owns the matching logic through cm __complete markdown @query, and each shell owns how live suggestions are displayed. Live completions work best with a global install because your shell needs to call cm from whatever repo you are typing in.
Install the adapter for your shell:
# zsh
echo 'eval "$(cm completions zsh)"' >> ~/.zshrc
# bash
echo 'eval "$(cm completions bash)"' >> ~/.bashrc# fish
mkdir -p ~/.config/fish/completions
cm completions fish > ~/.config/fish/completions/choirmaster.fish# PowerShell
New-Item -ItemType Directory -Force (Split-Path $PROFILE)
cm completions powershell >> $PROFILE# Nushell
mkdir ~/.config/nushell
cm completions nushell | save --append ~/.config/nushell/config.nuAfter opening a new shell, cm run @exa<Tab> and cm plan @exa<Tab> suggest matching markdown files from anywhere in the repo. At execution time, @ references must be exact so ChoirMaster does not guess the wrong file when completions are unavailable. If completions are not installed, run cm run or cm plan with no path to use ChoirMaster's built-in picker. If your shell is not listed, it can still call the stable protocol: cm __complete markdown @exa.
Quickstart
The examples below use choirmaster. Use cm for the shorter alias, or prefix with npx, pnpm exec, or yarn if you installed only in the project.
# scaffold .choirmaster/ in your project
choirmaster init
# edit .choirmaster/manifest.ts (base defaults to current branch; set gates/retry caps)
# draft what you want done in markdown, with concise questions
# (a worked example lives at .choirmaster/plans/example.md)
choirmaster draft --interactive "add onboarding notes for new contributors"
# or create a quick editable scaffold without questions
choirmaster draft "add onboarding notes for new contributors"
# or draft from existing notes / an issue body
choirmaster draft --from notes.md
# non-interactive drafts ask you to answer or delete clarifying questions before running
# use --output <path.md> when you want the plan somewhere else
# check your setup before invoking an agent
choirmaster doctor
# skip DNS checks when offline or behind restricted network policy
choirmaster doctor --skip-network
# open the interactive prompt with / commands and @ markdown suggestions
cm
# plan-then-run from a markdown plan: the planner agent compiles it
# into a validated tasks file, the runtime executes it
choirmaster run
# or use an exact @ reference
choirmaster run @example
# or use the explicit path
choirmaster run .choirmaster/plans/example.md
# alternatively: just plan, then review the generated task contract
choirmaster plan @example
# resume a paused or interrupted run
cm --resume <run-id>
# skip blocked tasks instead of halting
choirmaster run .choirmaster/plans/example.md --continue-on-blocked
# leave each task on its branch (don't auto-merge into base)
choirmaster run .choirmaster/plans/example.md --no-auto-mergeWhere it's going
- Agent-generated follow-up questions on top of the deterministic interactive draft flow
- Plan reviewer loop: a second agent reviews the generated task contract before execution
- Safer plan-level branch flow, likely
current branch -> plan branch -> task branches -> plan branch - Daily workflow commands:
status,logs,inspect,retry, andreset choirmaster run --issue N- GitHub issue input feeding the same planner pipeline- Per-role engine flags (
--implementer codex,--reviewer claude:opus) --sandbox dockerfor hard isolation
Packages
One published package: choirmaster - the CLI, the runtime, the Claude adapter, and the public types, all in one install.
The monorepo keeps the layers separated internally so future agent adapters (Codex, OpenCode, custom engines) and sandbox providers (Docker) can grow without changing the install story:
packages/core- runtime substrate: types, state machine, gate runner, worktree management. Bundled intochoirmaster; not published separately.packages/agent-claude- Claude Code agent. Bundled intochoirmaster; not published separately.packages/cli- the publishedchoirmasterpackage. Bundles core + agent-claude + the CLI bin.
Development
pnpm install
pnpm build
pnpm test
pnpm typecheckAcknowledgments
ChoirMaster grew out of a local orchestrator I built for CoreHue to run multi-step coding work while I was away from the keyboard.
It is also shaped by ideas from agent orchestration work such as Sandcastle, LangGraph, Self-Refine, and Anthropic's agent/sub-agent patterns. ChoirMaster's focus is deliberately narrow: turn a reviewed task plan into gated, scoped, resumable commits in a local repo.
License
MIT
