Skip to main content
Glama

Agent Switchboard

Your coding agents as peers on one machine. Claude Code talks to a pi worker and an OpenCode worker: it delegates whole tasks, nudges running sessions, and hears back — every pair messageable, nothing copy-pasted between terminals.

Setup — pick one

A. Just try it (taste, may break later when npm prunes its cache):

npx -y -p github:raymond-UI/agent-switchboard switchboard-install

B. Use it (durable, still no clone) — this is the normal path:

npm install -g github:raymond-UI/agent-switchboard
switchboard-install

C. Hack on it: git clone https://github.com/raymond-UI/agent-switchboard, then node scripts/install.mjs.

All three install the worker plugins, register the bridge, and print the one Stop-hook snippet for your Claude settings. You need: Node.js ≥ 18, the Claude Code CLI, and whichever workers you want (pi, OpenCode v1.18+). Windows works identically (forward slashes in settings paths).

It worked if: agent_sessions lists your workers, and pi_inbox answers without errors. Then hand a worker something tiny with absolute paths.

Related MCP server: pi-delegate

The loop (30 seconds)

You want to…

You use

What happens

Hand a worker a task and wait

pi_ask / oc_ask

Blocks until it settles; returns text + tools used + cost. timeoutMs overrides the 15-min default (max 8h). On timeout the worker keeps going (detached, no abort) — re-run the ask to wait again, *_abort to kill.

Hand over N tasks at once

pi_ask_async / oc_ask_async

Ticket id now. Result lands in YOUR pi_inbox AND fires the Stop hook for the Claude session that dispatched it (siblings stay pull-only). Default ceiling 4h (PI_ASYNC_TIMEOUT_MS / OC_ASYNC_TIMEOUT_MS), overridable per call.

Nudge a running session

agent_send (address from agent_sessions)

Lands in its conversation in ~2s

Hear back

pi_inbox (or the Stop hook, while working)

Results, questions, warnings

Fresh context for a new task

pi_new_session / oc_new_session

Old history dropped, unrecoverable

What's it costing

pi_state / oc_state

Model, tokens, context pressure

Instructions to workers must be self-contained with absolute paths — they can't see your Claude conversation.

Upgrading

Re-run whatever installed it — it reinstalls plugins, re-registers MCP, and reprints the hook snippet. Idempotent; running sessions keep their loaded copies, new sessions pick everything up:

switchboard-install          # paths B and C (C: `node scripts/install.mjs`)
npx -y -p github:raymond-UI/agent-switchboard switchboard-install   # path A

No migration steps between versions so far; if one ever lands, it will be announced at the top of this section.

Tested: pi 0.85.0, OpenCode 1.18.30, Node 20/22/24 (CI × ubuntu/macos/windows).

Across machines (worker box)

Run pi and OpenCode on a second machine so the coordinator (your laptop running Claude) stays light. Install switchboard on both (path B above), then:

switchboard-pair                 # 1. on the WORKER: prints a code, starts serving
switchboard-connect sb1.…        # 2. on the COORDINATOR: paste that code

Restart Claude on the coordinator and you're done. It uses the same tools and the same hook snippet, and async results still reach the session that started them. Claude is told which machine the workers are on. Paths you give workers refer to the worker machine (switchboard-connect --status shows their working dirs).

Notes: the code contains the access token (switchboard-pair --rotate revokes it). Both machines need to be on the same LAN, or use Tailscale from anywhere. Undo with switchboard-connect --local.

Always-on worker: switchboard-pair --service instead of step 1. It installs a background service (launchd on macOS, systemd user unit on Linux) that starts at login and restarts if it crashes, and prints the same code. Run it from the project dir (or set PI_CWD/OC_CWD). It captures your PATH and model settings but not provider API keys. Re-run after changing them. Remove: switchboard-pair --remove-service. Windows: keep switchboard-pair open in a terminal.

From your phone: switchboard-pair also prints a Phone link. Open it on a phone on the same network (or Tailscale) to get a chat page for pi and OpenCode: send tasks, watch them run, nudge or stop them, read replies and cost. The link logs the phone in; treat it like the code. Full diagram: docs/network-vision.html.

Two agents, one checkout: give each its own worktree (./scripts/setup-worktree.sh /path/to/project) or split folders by agreement. Two writers in one tree with no ownership split will stomp each other — the tooling detects, it doesn't merge.

Rules that bite (read once)

  1. Replies need addresses. agent_send to a live session id is precise; * broadcasts wake every paired session (each burns a turn).

  2. New sessions don't inherit backlog. Workers only receive messages sent after they were born (exact id/file addressing bypasses). Re-brief instead of relying on history.

  3. Async results are pull-only... with one new exception. A pi_ask_async / oc_ask_async ticket result lands in pi_inbox for everyone AND fires the Stop hook for the Claude session that dispatched it (multi-agent safe: each Claude writes its own dispatcher sidecar, the bridge stamps the ticket at dispatch time, the hook routes by exact match). Tickets that were never stamped (no PreToolUse hook, or different tool) stay pull-only.

  4. Idle Claude sessions can't be pushed to. The Stop hook fires on transitions; a parked session needs one nudge (check pi_inbox) or a desktop notification — there is no timer hook. Nothing is ever lost: the bus is durable, pull anytime.

  5. Async results are pull-only by default. Ticket results skip the Stop hook so they can't spray into a sibling session — collect by ticket id in pi_inbox. (If the PreToolUse dispatcher hook is installed, async results ALSO fire the Stop hook for the Claude session that dispatched them.)

  6. The bus is trusted. Anyone who can write to AGENT_BUS can whisper to your agents. Same bar as project files. Bus dirs auto-ignore themselves in enclosing git repos.

Who can orchestrate whom

| Orchestrator | Drives pi | Drives OpenCode | Drives Claude | How | |---|---|---|---| | Claude Code | pi_ask | oc_ask | — (self) | MCP bridge, always on | | OpenCode | MCP bridge | MCP bridge | delegate_claude tool | Add bridge to opencode.json; flag-gated tool | | pi | bus only (message_claude {to}) | delegate_oc / bus | delegate_claude tool | Flag-gated tools |

Worker→worker also works over the bus (message_claude {to}). Multi-orchestration is flag-gated (SWITCHBOARD_MULTI_ORCH=1) and depth-capped (SWITCHBOARD_DEPTH/SWITCHBOARD_MAX_DEPTH, default cap 2): delegation depth travels in env across every spawn, and any delegate tool at the cap refuses with a clear error instead of looping A→B→A forever. Live-verified: pi → delegate_claude round-trip (DELTEST).

Reference

Tools (16): pi_ask[_async], pi_steer, pi_abort, pi_new_session, pi_state, oc_ask[_async], oc_steer, oc_state, oc_abort, oc_new_session, agent_send, agent_sessions, agent_tickets, pi_inbox. One-line descriptions in-tool; details here.

Env (essentials): AGENT_BUS (must match on all sides when dirs differ), PI_CWD / OC_CWD, PI_MODEL / OC_MODEL (provider/model), PI_ASK_TIMEOUT_MS (15 min), RESULT_CAP (8k chars, overflow spills to $AGENT_BUS/results/). Full table in code: bridge/env.mjs, bridge/oc-session.mjs.

Layout: bridge/ (env, bus, format, MCP server, pi-session, oc-session, launcher), hooks/pi-inbox.mjs (Stop hook), pi-extensions/, opencode-plugin/, test/ (stubs + node:test suites), scripts/ (installer, pair/connect, worktree setup). Original design doc: PRD-agent-switchboard.md.

Security: localhost only (bridge servers bind 127.0.0.1 with per-spawn passwords; MCP is stdio, no auth by design). The one exception is switchboard-pair, which you run on purpose: it binds the network and requires the token. It refuses to bind the network without one. Traffic is plain HTTP: over Tailscale it's encrypted, but on shared Wi-Fi the token and your messages are readable, so prefer the Tailscale address (listed first). Don't weaken silently — see CONTRIBUTING.md.

For contributors

npm test — zero deps, stub-first (fixtures for both harnesses' protocols), live runs for final verification only. Hard rules: claim-before-emit on every take-one primitive; worker→Claude is always async (a sync callback into a blocked ask deadlocks both processes); never import the MCP server into the test runner (stdin listener hangs it). Design history (settle races, ticket spray incident, stale-backlog gate, UI-blanking bisect, poisoned-preload immunity) lives in git log + code comments. MIT — see LICENSE.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables Claude Code to delegate coding implementation and testing to a local pi agent via MCP tools, including dispatching task books, monitoring status, steering or aborting runs mid-execution, and retrieving results and transcripts.
    15 npm
    4
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    Enables Claude Code and OpenAI Codex CLI to act as bidirectional partners by letting each ask the other for code review, explanations, planning, performance analysis, and implementation help. It also provides background job tools for starting, observing, waiting on, and cancelling delegated tasks.
    6
    0
    1
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Enables an agent to drive Claude Code and Antigravity (agy) sessions as controlled subagents — listing, spawning, messaging, interrupting, waiting on, and stopping them, including fan-out of several at once. It also provides a locked, fsynced bridge so separate agents can exchange messages.
    19
    MIT