Shell-based orchestrator for managing multiple Claude Code sessions across local tmux panes and remote SSH hosts.
Run parallel Claude Code instances on different projects or machines, monitor their state from a single dashboard, and synchronize context between them — all without daemons or message brokers.
- bash (3.x+)
- tmux
- python3 with PyYAML (
pip install pyyaml) - claude CLI (Claude Code) installed on each host
- ssh with
ControlMastersupport (standard OpenSSH)
# 1. Clone the repo
git clone https://github.com/maflot/multi-clone-code.git
cd multiclaude
# 2. Edit config.yaml — add your sessions
vim config.yaml
# 3. Connect to remote hosts (authenticates once, reuses socket)
./orchestra.sh connect user@server
# 4. Start all sessions
./orchestra.sh start
# 5. Check status
./orchestra.sh statusEdit config.yaml to define your sessions:
orchestrator:
shared_fs: "" # shared filesystem path across hosts (optional)
sync_interval: 6h
ssh_socket_dir: ~/.ssh/sockets
poll_interval: 5 # seconds between health check polls
capture_lines: 50 # tmux lines captured for health detection
sessions:
my_pipeline:
host: user@server # omit for local sessions
path: /home/user/project
tmux: claude_pipeline # tmux session name on the host
role: pipeline # semantic label
env: "export PATH=$HOME/.local/bin:$PATH" # optional shell setup
claude_args: "--allowedTools Edit,Write,Bash" # optional
my_analysis:
path: ~/local-project
tmux: claude_analysis
role: analysis
blocked_by: [my_pipeline] # dependency ordering
dependencies:
- when: "my_pipeline completes step 7"
then: 'brief my_analysis "Data ready at /share/output"'| Command | Description |
|---|---|
start [name|all] |
Start Claude Code sessions in tmux |
stop [name|all] |
Stop sessions (sends /exit, then kills tmux) |
restart [name|all] |
Stop then start |
status |
Table of all sessions with health state |
health |
Full check: SSH sockets + tmux + Claude state |
connect <user@host> |
Establish SSH ControlMaster connection |
| Command | Description |
|---|---|
brief <session> "<prompt>" |
Send a prompt to a running session |
brief <session> @file.md |
Send a prompt from a file |
brief-all "<prompt>" |
Broadcast a prompt to all sessions |
approve <session> |
Auto-approve a permission prompt |
| Command | Description |
|---|---|
watch |
Live-refreshing dashboard of all sessions |
tail <session> [lines] |
Show last N lines from a session (default: 30) |
attach <session> |
Attach to a session's tmux interactively |
collect |
Capture full tmux output from all sessions |
| Command | Description |
|---|---|
insights [session] |
Collect status reports from all (or one) session via claude -p |
dream [session] |
Collect creative cross-pollination reflections |
sync |
Full cycle: insights + dream + build global CONTEXT.md |
orchestra.sh CLI entrypoint — all commands dispatch from here
config.yaml Session registry (hosts, paths, roles, dependencies)
prompts/ Briefing & synthesis templates
insight.md Status report prompt sent to each node
dream.md Creative reflection prompt
synthesize_*.md Synthesis prompts ({{REPORTS}} token replaced with collected output)
shared/CONTEXT.md Auto-generated global state, updated by `sync`
runs/ Timestamped output from insights/dream/sync runs
summary/ Latest synthesized summaries
briefings/ Logged briefings sent to sessions
- No daemons or message brokers. Everything runs through tmux, SSH ControlMaster sockets, and a shared filesystem.
- Python only for YAML parsing. The rest is pure bash.
- SSH ControlMaster sockets (
~/.ssh/sockets/) — authenticate once interactively, the orchestrator rides the socket withControlPersist=4h. - Health detection via
tmux capture-pane+ pattern matching for Claude Code states (idle, busy, permission, error). claude -p(print mode) for non-interactive insight collection during sync.tmux send-keysfor interactive briefings to running sessions.
MIT