Multi-agent orchestration
Run a fleet of coding agents - one Opus orchestrator driving several
Sonnet, Opus, and Codex workers - and let them share state through Hydrate instead of
copy-pasting context between terminals. tmux holds the terminals; Hydrate's
orchestrator command is the shared blackboard every agent reads from for free.
The key idea:
hydrate orchestratorpins each task's state as canon, and Hydrate's UserPromptSubmit hook injects that canon into every Claude Code / Codex session on the machine. So when the orchestrator records "summarise-repo is in-flight to worker-sonnet", every worker sees it on its next turn - no tokens spent re-pasting, and the state shows up on the dashboard's Orchestration page and survives/clear.
What you build
Five tmux sessions, one agent each, addressed by name. Prefix them per project (here we use
proj-) so several fleets can coexist:
proj-orchestrator-opus Claude Opus - the controller (you type tasks here)
proj-worker-sonnet Claude Sonnet - mechanical / high-volume work
proj-worker-opus Claude Opus - judgement-heavy work
proj-worker-codex Codex - cross-runtime / second opinion
proj-shell plain shell - builds, tests, git 1. Bring up the fleet
Create one detached tmux session per agent and launch the agent inside it. Workers run with permissions pre-accepted so they never stall on a modal the orchestrator can't answer:
P=$HOME/code/your-project
tmux new-session -d -s proj-orchestrator-opus -c "$P"
tmux send-keys -t proj-orchestrator-opus -l 'claude --model opus --dangerously-skip-permissions'
tmux send-keys -t proj-orchestrator-opus Enter
tmux new-session -d -s proj-worker-sonnet -c "$P"
tmux send-keys -t proj-worker-sonnet -l 'claude --model sonnet --dangerously-skip-permissions'
tmux send-keys -t proj-worker-sonnet Enter
# ...repeat for proj-worker-opus (claude --model opus) and
# proj-worker-codex (codex --dangerously-bypass-approvals-and-sandbox)
tmux new-session -d -s proj-shell -c "$P" # plain shell, no agent Send the launch line with
send-keys -l(literal text) followed by a separateEnterkeystroke. A real Enter keypress is what makes the Claude / Codex TUI accept input - bundling a trailing newline into the text leaves the prompt sitting unsent in the box.
Attach to any session in its own terminal tab to watch it; detach with Ctrl-b d:
tmux attach -t proj-orchestrator-opus
tmux attach -t proj-worker-sonnet
tmux ls # list the fleet 2. Open a Hydrate orchestration
Name the orchestration and pin the topology so every session knows the layout. The name is machine-active until you change it:
hydrate orchestrator join proj-fleet
hydrate orchestrator set fleet-topology \
"orchestrator=proj-orchestrator-opus | sonnet=proj-worker-sonnet | opus=proj-worker-opus | codex=proj-worker-codex | shell=proj-shell" 3. Dispatch, wait, read
The orchestrator drives each worker from its own Bash tool. Send a prompt with
send-keys, wait for the pane to go quiet (tmux has no completion event, so you
watch the worker's footer stop ticking), then read the result with capture-pane:
# dispatch
tmux send-keys -t proj-worker-sonnet -l 'Summarise this repo and list the top-level packages.'
tmux send-keys -t proj-worker-sonnet Enter
# wait for quiescence (one blocking loop - no model turns while it waits)
S=proj-worker-sonnet; last=""; stable=0
while :; do
cur=$(tmux capture-pane -t "$S" -p | cksum)
[ "$cur" = "$last" ] && stable=$((stable+1)) || stable=0
[ "$stable" -ge 4 ] && break # ~12s of no change = done
last="$cur"; sleep 3
done
# read
tmux capture-pane -t "$S" -p -S -200 For independent tasks, dispatch to all workers first, then wait on each - they run concurrently and wall-clock is the slowest worker, not the sum.
4. Track state in Hydrate
Pair every dispatch with an orchestrator record so the fleet's state is visible everywhere. Record the hand-off, then mark it done when the result lands:
hydrate orchestrator dispatch --to proj-worker-sonnet --eta 8m \
--acceptance "package summary returned" summarise-repo
# ...worker runs, you confirm the result...
hydrate orchestrator set summarise-repo done # auto-clears the in-flight record
hydrate orchestrator list # done / blocked facts + notes
hydrate orchestrator status # active orchestration + fact count
hydrate orchestrator close # when the whole run is finished Flag ordering:
orchestrator dispatchtakes all flags before the task-key -dispatch --to <session> [--eta <dur>] [--acceptance <gate>] <task-key>. Put the key last.set,get,list, anddeletetake the key in the usual place.
Setting a key to done or blocked automatically clears its in-flight
dispatch record, so the dashboard flips from "in-flight" to the final state with no extra step.
Watch the live picture on the dashboard's Orchestration page, or
pull it back after a /clear with /hydrate-last.
Three things that will trip you up
- Submit with a separate Enter. Agent TUIs ignore a newline baked into
pasted text. Always
send-keys -l '<text>'thensend-keys Enter. - Workers are tmux sessions, not subagents. If your orchestrator is itself an agent, tell it to drive workers only through tmux - not its built-in task/subagent tool, which spawns a throwaway agent and bypasses the fleet entirely.
dispatchwants flags first. Task-key last, every time.