BETA In open beta. Install live. Lock $5/mo for your first 12 months. See pricing →
Docs / Guides

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 orchestrator pins 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 separate Enter keystroke. 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 dispatch takes all flags before the task-key - dispatch --to <session> [--eta <dur>] [--acceptance <gate>] <task-key>. Put the key last. set, get, list, and delete take 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>' then send-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.
  • dispatch wants flags first. Task-key last, every time.