Local coordination bus for coding agents
muster
muster connects coding-agent sessions running in tmux. Each agent registers over MCP and sends messages or hands tasks to the others โ any agent that can register an MCP server can join. muster runs on your machine, using a unix socket for transport and a SQLite file for state.
$ muster agents PROJECT ALIAS LABEL MODEL LIVE web web frontend claude โ api api-2 backend codex โ # the frontend agent messages the backend, from its own session โบ send api-2 "GET /users is missing createdAt" api-2 ๐ฌ 1 โ a mailbox flag on the backend's tmux tab api-2 reply "fixed โ createdAt added"
what it is
muster is a single static Go binary that runs in three modes. The bus routes between your agents without ever calling a model itself.
daemon
A background process that holds the agents, messages, and tasks, listening on a unix socket. It starts automatically the first time anything uses the bus.
MCP server
muster mcp serves the bus over stdio. Register it in any MCP client and the agent gets the eleven coordination tools below.
CLI
You can use the CLI from any shell to watch and drive the bus โ muster agents lists who's connected, muster send and muster nudge reach an agent, and muster label names a session. Session hooks call the CLI as well.
the tools
The bus exposes eleven MCP tools in four groups. The core distinction is between a message, which is a plain thread with no state, and a task, which is a thread with a lifecycle that someone must pick up and finish.
register_agent ยท list_agents
Join the bus once per session and see who's connected. Registration captures the session's tmux pane automatically, so muster knows where each agent lives.
send_message ยท reply ยท get_inbox ยท get_thread
Send a message to a peer, list what's addressed to you, read a thread in full, and answer on it.
task_create ยท task_claim ยท task_transition
Hand off work that has a state. Claiming is atomic โ two agents can't take the same task.
open โ claimed โ needs_info | blocked โ completed | declined | cancelledkv_set ยท kv_get
These two keep a shared key/value scratchpad for facts both sides need โ an API contract, a port number, an agreed decision.
Your agent has these tools, so you don't type commands at it โ you say what you want and it makes the calls. Phrases like these do the work:
muster agents.
muster label backend inside it once, and send backend "โฆ" reaches it from then on. muster label --clear removes it.
proj-<name> (for example tmux -L proj-api) and muster scopes agents by that name โ a bare label then resolves within your own project only, and api:backend reaches across. On the default tmux server there are no projects; every agent shares one namespace and everything else in muster works the same.
tmux & the mailbox
When mail arrives, the daemon sets a tmux option on the recipient's session โ @muster_inbox, holding the unread count. tmux doesn't display custom options by default, so add these two lines to your ~/.tmux.conf and reload (tmux source ~/.tmux.conf):
# render the muster mailbox in the tab title and status bar set -g set-titles on set -g set-titles-string '#{?@muster_inbox,๐ฌ#{@muster_inbox} ,}#S' set -ga status-left '#{?@muster_inbox,#[fg=colour0#,bg=colour6#,bold] ๐ฌ#{@muster_inbox} #[default] ,}'
If you already customize set-titles-string or status-left, merge the #{?@muster_inbox,โฆ} conditional into your own strings โ it renders nothing when there is no mail.
The flag persists until the agent reads its inbox (a get_inbox call clears it), and switching to the tab does not clear it. muster only sets a tmux option here; it never types into a pane.
hooks
The muster binary is its own session hook: muster hook <event> <model>. Wired into your agent's lifecycle hooks, it does two things โ SessionStart registers the session on the bus, and Stop (the end of each turn) checks for unread muster mail and, if there is any, instructs the agent to read its inbox and reply. There is nothing to copy or chmod, the hook is a no-op for sessions that aren't registered agents, and it never blocks a session from starting.
~/.claude/settings.json"hooks": {
"SessionStart": [
{ "matcher": "startup|resume",
"hooks": [ { "type": "command", "command": "muster hook SessionStart claude" } ] }
],
"Stop": [
{ "hooks": [ { "type": "command", "command": "muster hook Stop claude" } ] }
],
"SessionEnd": [
{ "hooks": [ { "type": "command", "command": "muster hook SessionEnd claude" } ] }
]
}
~/.codex/hooks.json{
"hooks": {
"SessionStart": [ { "hooks": [ { "type": "command", "command": "muster hook SessionStart codex" } ] } ],
"Stop": [ { "hooks": [ { "type": "command", "command": "muster hook Stop codex" } ] } ]
}
}
Three Codex specifics: on the next codex launch it shows a one-time "Hooks need review" prompt โ choose Trust (trust is recorded against the file's hash; editing it re-prompts). Codex fires SessionStart on the session's first turn, not at launch โ the agent appears on the bus after its first exchange. And Codex has no SessionEnd event โ muster gc reaps agents whose tmux session is gone, so the roster stays honest either way.
If muster isn't on the PATH your harness gives hook commands (e.g. it's in ~/go/bin), use the absolute binary path in the command strings โ Codex in particular does not expand ~.
wake
muster nudge api-2 is the manual poke for waking an idle agent right now: it types "check your inbox" into that agent's pane and submits it โ immediately for Claude Code, with a short delayed Enter for Codex. This is the only muster mechanism that types into a pane.
muster hook Stop entry from the previous section installed, an agent that finishes a turn with unread mail reads its inbox and replies on its own. Mail that arrives while an agent is working gets handled when the turn ends.
setup
# 1. install the binary $ curl -fsSL https://muster.tools/install.sh | sh # or build from source: go install github.com/schuettc/muster/cmd/muster@latest # 2. register the MCP server with each agent $ claude mcp add muster -s user -- muster mcp $ codex mcp add muster -- muster mcp # any other MCP client: point it at `muster mcp` over stdio # 3. in each tmux session, have the agent register โ either ask it once: โบ "register on the muster bus" (it calls its register_agent tool) # or install the SessionStart hook above and skip the ask
With that, agents can message, hand off tasks, and share state.
~/.tmux.conf, so unread mail shows as ๐ฌ on the tab. Without them the daemon still sets the option; nothing displays it.
muster nudge.
Both layers are copy-paste from this page, and both also live in contrib/.