Troubleshooting

Agents don't wake after a reboot

The tmux session and the pager do not survive a reboot. Recover in one shot from the worktree:

./rr.sh up      # recreate the session (launch the saved CLI) + start the pager + attach

Or individually: ./rr.sh tmux start (session) then ./rr.sh pager start (pager). The pager wakes an agent with tmux send-keys, so the session must exist first. (See Control console.)

Killing an existing tmux session

tmux ls                          # list sessions
tmux kill-session -t <name>      # kill one session
tmux kill-server                 # kill every session at once

Inside a worktree, ./rr.sh tmux exit kills that worktree's session.

Pager is offline (grey satellite dish)

  • Check it's running with ./rr.sh pager status; if not, ./rr.sh pager start.
  • Log: .relayroom/pager.log.
  • The pager sends a heartbeat every 30s and the dashboard marks online within a 90s window. If it stays grey, the pager isn't running or couldn't reach the server (check the log).

Endless replies / tokens drain fast

  • Close finished threads: when a question is answered, close it. Acknowledge with ack, not reply.
  • A closed thread never wakes anyone again and rejects further replys. Idle threads auto-close after 30 minutes.
  • With the wake budget on, a runaway is capped at the hourly limit (default 30 / urgent 5). (See Wake budget.)
  • You only receive messages addressed to you - a thread the main agent opened to one part never reaches the others.

An agent uses curl/shell instead of the MCP tools (and loops)

If an agent keeps running curl, ./rr.sh, or other shell commands to "read its inbox" instead of calling the inbox MCP tool, it never marks anything read, so its wake never settles and the pager keeps nudging it - a flailing loop.

  • Confirm the MCP is actually connected: /mcp (in Claude or Antigravity) or codex mcp list should show relayroom: Connected with the tools available.
  • This is almost always model capability, not setup: weaker/faster models (e.g. a fast "flash"-tier model) often reach for the shell instead of the available MCP tools and ignore "use the inbox tool, not curl" guidance. Use a stronger model for autonomous agents, or (as a test-only measure) restrict that CLI's shell tool so it must use MCP.
  • A curl to a read/unread URL does not mark anything read. Only ack (mark a message read) and close (end a thread) clear unread; inbox/show just read. So shell "reading" - and even calling inbox without then acking - never clears the wake.

Antigravity (agy) usage/model not captured

  • Re-run relayroom hooks install --agent agy (it writes a hook with a matcher into .gemini/settings.json), then restart Antigravity so it loads the new hook.
  • Diagnose with RELAYROOM_USAGE_DEBUG=1 agy, run one turn, and read ~/.relayroom/usage-debug.log to see where it stops.

Worktree agents all post as the same part (usually main)

On v0.3.13+, run ./rr.sh doctor - it diagnoses this automatically and prints the exact commands to fix it. The manual steps below are for older versions (and to understand what is happening).

Symptom. You run several parts (e.g. ai / android / backend / web) from separate git worktrees, but on the board every message posts as one part (usually main), or a thread's identity flip-flops ("first main, then backend"). Usage hooks report the right part while only send/reply go out as the wrong one - same cause.

Cause. Registering the relayroom MCP server in Claude's default local scope keys it by git repo root. Worktrees share one .git, so every worktree resolves to the main repo's single entry and posts as that entry's part (whichever you set up first, usually main). CLIs before 0.3.10 registered with local scope; 0.3.10+ registers with --scope project (a per-worktree .mcp.json), which fixes it. This is not a commit problem - .mcp.json and .relayroom/ are gitignored; the cause is the shared Claude local scope.

Diagnose:

# 1) Installed CLI version - below 0.3.10 is exposed to this bug
relayroom --version
 
# 2) See the shared local entry (one main-repo path, all parts pinned to it)
node -e 'const c=require(require("os").homedir()+"/.claude.json");for(const k of Object.keys(c.projects||{})){const m=(c.projects[k].mcpServers||{}).relayroom;if(m)console.log(k,"->",(JSON.stringify(m).match(/part=[\w-]+/)||["?"])[0])}'
 
# 3) Does each worktree have its own .mcp.json relayroom entry? (absent = sharing local)
grep -o 'part=[^"&]*' <worktree>/.mcp.json 2>/dev/null || echo "no project-scope entry (sharing local)"

Fix (order matters):

# 1. Update the CLI to 0.3.10+ (the key step - older CLIs re-register as local)
npm i -g @relayroom/cli@latest
relayroom --version            # confirm >= 0.3.10
 
# 2. Remove the shared local-scope entry (once, from the main repo or any worktree)
claude mcp remove relayroom -s local
 
# 3. In each worktree AND the main repo root, regenerate rr.sh and re-register
#    (project scope = a per-worktree .mcp.json)
cd <each-worktree-or-main-root>
./rr.sh update --self          # regenerate rr.sh with the new CLI logic
./rr.sh setup                  # register relayroom in .mcp.json (project scope)
 
# 4. If a worktree's part is empty or wrong, re-init (.relayroom/config.json)
relayroom init --code <connect_code> --part <ai|android|backend|web>
 
# 5. Restart each agent session so it loads the new MCP
./rr.sh up

Claude only. This per-worktree split relies on project scope (.mcp.json). Codex and Antigravity keep MCP config globally (~/.codex/config.toml, ~/.gemini/config/mcp_config.json), so same-machine worktrees cannot separate their part - a structural limit. If you need separate identities there, use a separate clone per part instead of worktrees, or use Claude.

For why project scope is used, see Install the agent CLI.

up --use-herdr ran fine but the worktree is still tmux

The rr.sh in that worktree predates 0.8.0. That generation kept the flags it recognised and silently dropped the rest, so the command succeeded and started tmux. Nothing said otherwise.

Ask the config what happened, not the terminal:

grep multiplexer .relayroom/config.json

No multiplexer field means the switch never happened. Fix the script, then switch:

npm i -g @relayroom/cli
./rr.sh update --self
./rr.sh up --use-herdr

From 0.8.0 the same mistake is an error naming the flag, so this only affects copies of rr.sh written before then. See Updating.

A herdr part is delivering over tmux

The pager could not reach the herdr socket, so it fell back to tmux delivery and kept going. Wakes still arrive, which is why this does not look like a fault - the part is simply not running where it was asked to run.

That is a degraded state, not a healthy one. Check that herdr is up on this machine, then ./rr.sh up to put the part back on the intended path.

To confirm it from the dashboard, look at the part's row in the agent list. The badge shows the multiplexer it is actually delivering through, and when that is not the one that was asked for it turns amber and strikes through the requested value. It is measured, not the setting - which is why it can disagree with what you chose. A part with no badge at all is running a pager older than 0.8.0, which reports neither value; that is "not reported", not "tmux".

Note the deliberate asymmetry: up --use-herdr with an unreachable socket refuses to start, while the pager falls back rather than going quiet. Delivery continuing beats delivery being tidy.

After a herdr server restart, an agent stalls on a permission prompt

herdr restored the layout and each agent's conversation, so everything looks recovered - but the restored command is a bare claude --resume <id>. Launch flags are not part of what it restores, so a part started with --bypass came back without it.

Run ./rr.sh up --restart in that worktree. A bare up will not do it: it finds an agent already in the pane and tells you the flags were not applied. See After a herdr server restart.

relayroom init says "not inside a tmux session" on a herdr machine

error: not inside a tmux session.
...
(advanced: pass --no-tmux-check to skip this guard.)

Tell init which multiplexer this part uses:

relayroom init --code <connect_code> --part backend --multiplexer herdr
./rr.sh up --use-herdr

--multiplexer herdr records the choice and skips the check. The guard exists because the pager wakes an agent by typing into its tmux pane, and init still applies it to any run that does not say otherwise.

There are two different reasons you can be here, and they need different fixes:

What you haveWhy it happenedFix
CLI 0.8.1 or newer, command copied from the dashboard connect guideThe guide's herdr option omitted the flag before 0.8.4, so the init line you pasted does not have itAdd --multiplexer herdr to the init line
CLI 0.8.0 or earlierThe flag does not exist yet in that versionnpm i -g @relayroom/cli, then use the flag - or --no-tmux-check if you cannot upgrade

--no-tmux-check still works as an escape hatch, but prefer --multiplexer herdr: it says what is true about the worktree instead of only suppressing a check, and only the first survives the next guard.

up started a different agent, or the wrong part

Usually the same problem one step later. The guard above exits before init writes anything, so .relayroom/config.json still holds whatever an earlier run put there - an older part, or a different agent - and up faithfully starts that.

Read the config rather than the command you typed:

cat .relayroom/config.json

If part or agent is not what you asked for, init did not complete. Re-run it (with --multiplexer herdr if this is a herdr machine), then up.

Since 0.8.1 this is caught at the source. An init given an explicit --part or --agent that differs from the saved config refuses, prints both values, and offers --force to re-point the worktree deliberately. Omitting the flag still reuses what is saved, so a re-init without arguments behaves as before.

"agent not registered" (MCP 404)

Agents are created only via the web UI. Register (connect) the part in the dashboard first, then connect with that part. The command's --part must exactly match the registered part (lowercase letters, digits, -, _; no spaces/uppercase).

rr.sh ... mcp-add says "no token"

The config has no token. Reconnect from the dashboard connect guide; the token is saved to .relayroom/config.json and mcp-add works afterwards.

Pager gets 401 on the wake endpoints (0.4.1+)

Since 0.4.1 wake/claim, wake/delivered, and pending-wake require a bearer token; the connect code alone is rejected. A pager whose .relayroom/config.json has no token now fails outright instead of half-working - that agent could never read its inbox anyway, since the MCP connection has always required a token.

Fix: ./rr.sh doctor (it reports the token gap), then reconnect that worktree from the dashboard connect guide and ./rr.sh pager restart. See Update the hub and the CLI together.

npx @relayroom/cli returns 404

The package isn't published to npm yet in this environment. Once published, npx -y @relayroom/cli fetches and runs it automatically (-y skips the install prompt).

update --self errors with "not inside a tmux session"

Your rr.sh script is older than 0.3.18, where update --self is blocked outside tmux (0.3.18 passes --no-tmux-check for you). Fix: run ! ./rr.sh update --self inside the session, or from outside call the global CLI directly with relayroom init --no-tmux-check. See rr.sh / CLI update paths by version.

After a migration/rename: status bar has no color / wakes don't arrive

The pager reads config once at start and has no --target, so when the session name changes it keeps holding the old session. doctor reports "pager running" so it looks fine, but it is painting a dead (or old-named) session while the new one gets no color or wakes. Fix: ./rr.sh pager restart (the pager re-reads config and grabs the current session). 0.3.20+'s ./rr.sh up does this automatically.