Claude Relay Architecture
Claude Relay — Architecture Reference
Inter-Claude knowledge relay. Multiple Claude Code sessions (or a human director + Claude worker) share context through a lightweight server. Think Google Docs but for a coding IDE.
The compute asymmetry insight: A $20 plan directs a $200 plan through the relay — force multiplier for capability asymmetry between Claude tiers.
System Overview
┌─────────────────────────────────────────────────────────┐
│ MONOREPO (Bun workspaces) │
│ │
│ packages/shared/ Zod schemas, types, constants │
│ packages/relay-server/ Hono HTTP + dashboard UI │
│ packages/mcp-server/ 6 MCP tools for Claude Code │
└─────────────────────────────────────────────────────────┘
Stack: Bun 1.3 runtime, Hono framework, Zod validation
Transport: HTTP + SSE (Server-Sent Events)
Storage: In-memory (sessions expire via TTL)
Auth: Bearer tokens per session
Deploy: Docker (oven/bun:1.3-alpine) or bare Bun
Data Flow
Claude Code (worker)
│
▼
MCP Tools (stdio transport)
│ relay_send / relay_poll / relay_status
▼
relay-client (HTTP calls)
│
▼
┌──────────────────────────────┐
│ Hono HTTP Server (:4190) │
│ ┌────────────────────────┐ │
│ │ Approval Queue │ │ ← Messages staged here first
│ │ Sensitive Scanner │ │ ← Checks for API keys, tokens
│ │ Rate Limiter (30/min) │ │
│ └────────────────────────┘ │
│ ┌────────────────────────┐ │
│ │ In-Memory Store │ │ ← Sessions, messages, cursors
│ │ TTL Sweep (60s) │ │ ← Expired sessions cleaned up
│ └────────────────────────┘ │
│ ┌────────────────────────┐ │
│ │ SSE Subscribers │ │ ← Live push to dashboards
│ └────────────────────────┘ │
└──────────────────────────────┘
│ │
▼ ▼
GET /poll GET /stream (SSE)
│ │
▼ ▼
Claude Code Browser Dashboard
(another session)
Security Model
Five layers of defense:
1. Bearer Token Auth
Every session generates a unique token on creation. All relay and session endpoints require Authorization: Bearer <token>. No token = 401.
2. Approval Queue
Messages from Claude Code are staged, not sent directly. The director (human or lead Claude) reviews and approves/rejects via relay_approve. This prevents workers from sending unchecked content.
3. Sensitive Content Scanner
Before a message enters the queue, it is scanned for patterns matching:
- API keys and tokens (AWS, GitHub, Stripe, etc.)
- Private keys and certificates
- Connection strings with credentials
- File paths that might leak system info
Matches are flagged and blocked.
4. CORS Restriction
Allowed origins: localhost, configured RELAY_ORIGIN env var, and *.ngrok-free.app domains. Everything else is rejected.
5. Rate Limiting
30 requests per minute per token. Prevents abuse from runaway loops.
6. XSS Protection
Dashboard uses escapeHtml with quote escaping on all rendered content. No raw HTML injection.
Session Lifecycle
CREATE JOIN ACTIVE EXPIRE
│ │ │ │
▼ ▼ ▼ ▼
POST /sessions POST /sessions/:id/join POST /relay/:id TTL sweep
│ │ GET /relay/:id (60s interval)
│ │ GET /relay/:id/stream │
▼ ▼ ▼ ▼
Returns: Requires: Messages flow. Session + all
- session_id - invite_token Approval queue messages deleted
- director_token Returns: for gated sends. from memory.
- invite_token - participant_token
14 message types Default: 60min
available. Max: 1440min (24h)
Limits per session:
- 200 messages max
- 10 participants max
- 100KB max message size
- 50 sessions server-wide
MCP Tools (6)
The MCP server exposes six tools via stdio transport, registered in Claude Code settings:
| Tool | Purpose | Flow |
|---|---|---|
relay_create_session | Create a new relay session | Returns session_id + tokens |
relay_join_session | Join with invite token | Returns participant token |
relay_send | Stage a message | Goes to approval queue first |
relay_approve | Approve/reject/list pending | Director-only operation |
relay_poll | Fetch new messages | Cursor auto-advances |
relay_status | Health + session overview | Sessions, pending count |
relay_share_workspace | Share file tree snapshot | Workspace context sharing |
Message Types (14)
Core (6) — exposed in relay_send:
architecture, api-docs, patterns, conventions, question, answer
Extended (3):
context, insight, task
Workspace (5) — Phase 3 file/terminal sharing:
file_tree, file_change, file_read, terminal, status_update
Dashboard Modes
Director Mode
Human types instructions, Claude worker responds. Three-panel layout:
- File tree sidebar — expandable workspace view (from
relay_share_workspace) - File viewer — click a file to see contents
- Input box — type messages, see conversation thread
Peer Mode
Two Claude sessions exchange knowledge autonomously. Split-panel view with four built-in simulation demos:
- Security Audit — one Claude audits, another implements fixes
- Code Review — reviewer + author collaboration
- Bug Hunt — debugger + fixer pair
- Workspace — file tree sharing demo
Deployment
Docker (recommended)
Dockerfile: Multi-stage oven/bun:1.3-alpine
docker-compose.yml: Single service, port 4190
.dockerignore: Excludes mcp-server, hooks, scripts, docs
docker compose up -d # start
docker compose down # stop
docker compose logs -f # tail
Networking
- Server binds
0.0.0.0:4190(LAN-accessible, not localhost-only) - Tailscale: accessible across machines (MacBook Air <-> Mac mini)
- ngrok:
bash scripts/setup.sh https://xxx.ngrok-free.appfor remote workers - CORS allows ngrok domains automatically
Worker Setup
bash scripts/setup.sh # local worker (localhost:4190)
bash scripts/setup.sh https://xxx.ngrok # remote worker
This registers the MCP server in Claude Code settings and installs the poll hook.
File Structure
claude-relay/
├── packages/
│ ├── shared/
│ │ └── src/
│ │ ├── constants.ts # Ports, limits, message types, sensitive patterns
│ │ ├── schema.ts # Zod validation for all payloads
│ │ └── types.ts # TypeScript interfaces (Session, Message, etc.)
│ ├── relay-server/
│ │ ├── src/
│ │ │ ├── index.ts # Hono app, middleware, route mounting
│ │ │ ├── store/memory.ts # In-memory sessions + SSE subscriber mgmt
│ │ │ └── routes/
│ │ │ ├── relay.ts # POST send, GET poll, GET /stream SSE
│ │ │ └── sessions.ts # Create, join, info endpoints
│ │ └── public/ # Dashboard (HTML + CSS + JS)
│ └── mcp-server/
│ └── src/
│ ├── tools/ # 6 MCP tool definitions
│ └── approval/ # Approval queue + sensitive scanner
├── hooks/
│ ├── relay-poll.sh # Auto-poll on Claude Code Stop events
│ └── install.sh # Add hook to ~/.claude/settings.json
├── scripts/
│ └── setup.sh # One-command install (deps + MCP + hooks)
├── Dockerfile # Multi-stage Bun Alpine
├── docker-compose.yml # Single-service compose
└── .dockerignore
Key Design Decisions
Why in-memory, not SQLite? Phase 1-3 priority was speed of iteration. Sessions are ephemeral by nature (coding sessions last hours, not days). SQLite persistence is Phase 4 roadmap.
Why approval queue? Without it, a worker Claude could leak secrets, send hallucinated content, or spam the relay. The queue gives the director veto power over every outbound message.
Why SSE over WebSocket? SSE is simpler (one-directional push), works through more proxies/firewalls, and the dashboard only needs to receive — it sends via POST. No bidirectional channel needed.
Why MCP over direct HTTP?
MCP tools appear natively in Claude Code tool palette. Claude can call relay_send as naturally as it calls Read or Bash. No wrapper scripts needed.
Why Bun? Fast startup (~50ms), built-in TypeScript, workspace support, single binary. Docker image is tiny on Alpine.
The Compute Asymmetry Pattern
┌────────────────────┐ ┌────────────────────┐
│ $20 Plan (Sonnet) │ │ $200 Plan (Opus) │
│ "Director" │────────▶│ "Worker" │
│ │ relay │ │
│ - Sets strategy │◀────────│ - Executes tasks │
│ - Reviews output │ │ - Deep analysis │
│ - Approves msgs │ │ - Code generation │
│ - Manages session │ │ - Multi-file edits │
└────────────────────┘ └────────────────────┘
The cheap plan does the thinking.
The expensive plan does the heavy lifting.
Relay is the coordination layer.
This inverts the normal pattern where you need the most expensive tier for everything. The director only needs enough capability to evaluate and steer — not to execute.
Roadmap
| Phase | Status | What |
|---|---|---|
| 1 | Done | Core relay — create, join, send, poll |
| 2 | Done | Dashboard UI — director + peer modes |
| 3 | Done | Shared workspace — file tree, file viewer, sidebar |
| 3+ | Done | Docker, security hardening, ngrok remote support |
| 4 | Next | Persistence (SQLite), session history, multi-worker |
| 5 | Future | Cloud deploy, encryption, URL-based session sharing |