English | 简体中文
Important
Archived, and no longer maintained.
This was never worth its upkeep. A local agent orchestrator has to track every agent CLI it drives, and those move constantly: flags, auth, output formats, session semantics. Keeping up with that churn cost far more than the orchestration itself was ever worth.
The work now lives as custom plugins for oh-my-pi
(pi / omp), which already own the agent lifecycle, the tool surface, and the
session model. Writing a plugin against a harness that is maintained is much
less effort than maintaining a harness.
The code stays up for reference. The Rust rewrite that followed this tree is
at the v4-final tag.
Choir is a local agent orchestrator written in MoonBit. One expensive model is the team lead (Claude); cheaper agents (Codex by default, or Gemini, Moon Pilot, or Cursor) run as leaves. Each leaf works in its own git worktree and files a PR back to the TL's branch. A built-in poller automates Copilot review, routes GitHub review and CI feedback to the right pane, and tells the TL when a PR is approved. The loop is scaffold, fork, converge: the TL commits shared types, forks a wave of parallel leaves, merges approved PRs one at a time, then forks another wave or files its own PR upward.
flowchart TD
init(["choir init"]) --> srv["Server: persistent UDS daemon"]
srv --> tl{{"TL: Claude (team lead)"}}
tl -. "optional, multi-wave" .-> spec["/crystallize then /decompose<br/>feature/<slug> branch"]
spec -.-> tl
tl -->|"1. scaffold commit (shared types)"| fork["fork_wave"]
fork --> la["Leaf A: own git worktree"]
fork --> lb["Leaf B: own git worktree"]
la -->|"file_pr"| pr["PRs to parent branch"]
lb -->|"file_pr"| pr
pr <--> gh[("GitHub: review / CI")]
subgraph optional["optional: Copilot auto-review"]
copilot["Copilot review"]
end
gh <-.-> copilot
gh --> poller["Poller"]
poller -->|"review / CI feedback to right pane"| la
poller -->|"review / CI feedback to right pane"| lb
poller -->|"approved + snapshot"| tl
tl ==>|"merge approved PRs, one at a time"| converge{{"converge"}}
converge -->|"WaveComplete: next wave"| fork
converge -->|"done"| up["file own PR upward"]
tl -. "fork_wave role=tl" .-> subtl[["Sub-TL: same loop"]]
subtl -->|"PR to TL branch"| tl
style optional stroke-dasharray: 5 5
# prerequisites: git, gh, zellij 0.44+, bd (Beads), and the agent CLIs you use
# (claude, codex, gemini, moon, agent). The Nix dev shell provides the OSS deps.
moon build --target native --release # build
choir init # bring up the server + TL sessionchoir claude [--lean] # restart the TL pane on a running server (--lean: no default system prompt)
choir init --recreate # restart server + TL, keep recovery state
choir stop [--purge] # shut down (--purge also removes worktrees + state)MIT license. Architecture informed by exomonad.