agents via tmux
tmux is the best agent orchestrator.
I covered workspaces — giving each agent a clean room with a task file. The next question: how do you watch what the agents are doing? Run five at once? Intervene when one is stuck?
tmux. It works the same way for me and for agents — I can attach and use a session directly, or my root agent can send-keys and capture-pane programmatically. Same tool, same interface. Everything is text, simple tools composed together.
Each agent gets a persistent tmux session. Attach, detach, monitor, kill — independently.
# start an agent tmux new-session -d -s agents "ai 'do the thing'" # check on it tmux capture-pane -t agents -p -S -50 # talk to it tmux send-keys -t agents "actually, do this instead" Enter # kill it tmux kill-session -t agents
the pattern #
One root agent orchestrates workspace agents:
graph TD
Root[root agent<br/>tmux: agents] -->|create-workspace| WS1[ws-webapp<br/>builds UI]
Root -->|create-workspace| WS2[ws-dbfix<br/>fixes bugs]
Root -->|create-workspace| WS3[ws-docs<br/>writes docs]
Root -->|capture-pane| WS1
Root -->|capture-pane| WS2
Root -->|capture-pane| WS3
WS1 --> PR1[PR #81]
WS2 --> PR2[PR #19]
WS3 --> PR3[PR #100]
The root agent writes a task file, creates a workspace, monitors with capture-pane, sends guidance with send-keys if something’s off, and merges the PR when CI passes.
workspaces #
A workspace is just a directory — fresh repo clone, a branch, and a TASK.md:
workspaces/
webapp/
zorto/ # fresh clone on branch cody/ws-webapp
TASK.md # what the agent should do
create-workspace clones the repo, branches, writes the TASK.md, and starts a tmux session running ai 'execute on @TASK.md':
create-workspace --task tasks/webapp.md \ --repo dkdc-io/zorto "webapp"
delete-workspace kills the session and nukes the directory:
delete-workspace webapp
monitoring #
The key command:
tmux capture-pane -t ws-webapp -p -S -500
Dumps the last 500 lines of the agent’s terminal. The root agent reads this to check progress without attaching.
Real example — checking if a workspace agent is done:
$ tmux capture-pane -t ws-zortowebapp -p -S -10 Stats: +1286 lines, -100 lines, 49/49 tests passing, cargo fmt --check clean.
That’s it. Merge the PR.
sending guidance #
When an agent gets stuck:
tmux send-keys -t ws-webapp \ "the template bug is in onboarding.rs — skip custom templates when a theme is selected" Enter
The agent reads it as user input and adjusts. Context is preserved, the session keeps going.
parallel execution #
tmux sessions are independent — run as many as your machine can handle:
create-workspace --task tasks/webapp.md --repo dkdc-io/zorto "webapp" create-workspace --task tasks/dbfix.md --repo dkdc-io/db "dbfix" create-workspace --task tasks/docs.md --repo dkdc-io/zorto "docs"
Three agents, parallel. The root agent watches all of them:
for ws in webapp dbfix docs; do echo "=== $ws ===" tmux capture-pane -t ws-$ws -p -S -5 done
aliases to bin scripts #
I used to have all of this as shell aliases and functions. ai, workspace helpers — all in .bash_aliases. Then I started running agents and realized: agents can’t see your aliases. They’re shell state, not filesystem state.
So I moved everything to ~/bin/ scripts on $PATH. Now the agent can run create-workspace the same way I do:
# before: alias in .bash_aliases (only I can use it) function ai() { claude --dangerously-skip-permissions --permission-mode dontAsk "$@" } # after: bin script on $PATH (I can use it, agents can use it) #!/usr/bin/env bash exec claude --dangerously-skip-permissions --permission-mode dontAsk "$@"
Same scripts, same $PATH, humans and agents alike. One thing stays as an alias on purpose — but that’s a story for the next post.
naming #
agentsfor the root agent sessionws-<name>for workspace agentsiAgentfor the iMessage agent- Workspace names: lowercase alphanumeric only
- One agent per workspace, one task per workspace
- Over-clone repos — cloning is cheap, missing context is expensive