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 + attachOr 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 onceInside 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,
closeit. Acknowledge withack, notreply. - 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) orcodex mcp listshould showrelayroom: Connectedwith 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
curlto a read/unread URL does not mark anything read. Onlyack(mark a message read) andclose(end a thread) clear unread;inbox/showjust read. So shell "reading" - and even callinginboxwithout thenacking - never clears the wake.
Antigravity (agy) usage/model not captured
- Re-run
relayroom hooks install --agent agy(it writes a hook with amatcherinto.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.logto 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 upClaude 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 Connect an agent.
"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.