21 integration tests (14 broker behavior + 7 path encoding), all passing in ~1s against a real Postgres (claudemesh_test database on the dev container). Test infrastructure: - apps/broker/vitest.config.ts extends @turbostarter/vitest-config/base - tests/helpers.ts: setupTestMesh() creates a fresh mesh + 2 members per test with a unique slug, returns cleanup function that cascades the delete. cleanupAllTestMeshes() as an afterAll safety net. - Mesh isolation in broker logic means tests don't interfere even when they share a database — no per-test TRUNCATE needed. Ported behavior tests (broker.test.ts, 14 tests): - hook flips status + queued "next" messages unblock - "now"-priority bypasses the working gate - DND is sacred (hooks cannot unset it) - hook source stays fresh through jsonl refresh - source decays to jsonl when hook signal goes stale - isHookFresh freshness window + source-type rules - TTL sweep flips stuck "working" → idle - TTL sweep leaves DND alone - first-turn race: hook fired pre-connect stashed in pending_status - applyPendingHookStatus picks newest matching entry - expired pending entries are ignored on connect - broadcast targetSpec (*) reaches all members - pubkey mismatch → message not drained - mesh isolation: peer in mesh X doesn't drain from mesh Y Ported encoding tests (encoding.test.ts, 7 tests): - macOS, Linux, Windows path encoding first-candidate correctness - Roberto's H:\Claude → H--Claude regression test (2026-04-04) - Candidate dedup, drive-stripped fallback, leading-dash fallback How to run: from apps/broker, DATABASE_URL="postgresql://.../claudemesh_test" pnpm test Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@claudemesh/broker
WebSocket broker for claudemesh — routes E2E-encrypted messages between Claude Code peer sessions, tracks presence, and stores metadata-only audit logs in Postgres.
What it is
A standalone Bun-runtime WebSocket server that sits between Claude Code sessions. Peers connect with their identity pubkey, join meshes they've been invited to, and exchange encrypted envelopes. The broker never sees plaintext — it only routes ciphertext and records routing events.
Running locally
# from the repo root
pnpm --filter=@claudemesh/broker dev # watch mode
pnpm --filter=@claudemesh/broker start # production
Required env vars
| Var | Default | Purpose |
|---|---|---|
BROKER_PORT |
7900 |
Single port for HTTP routes + WebSocket upgrade |
DATABASE_URL |
— | Postgres connection string (shared with apps/web) |
STATUS_TTL_SECONDS |
60 |
Flip stuck-"working" peers to idle after this TTL |
HOOK_FRESH_WINDOW_SECONDS |
30 |
How long a hook signal beats JSONL inference |
Routes (single port)
| Path | Protocol | Purpose |
|---|---|---|
/ws |
WebSocket | Authenticated peer connections |
/hook/set-status |
HTTP POST | Claude Code hook scripts report status |
/health |
HTTP GET | Liveness probe |
Depends on
@turbostarter/db— Drizzle/Postgres schema (uses themeshpgSchema)@turbostarter/shared— cross-package utilities
Deployment
Runs as a separate process (not inside Next.js). Intended deployment targets:
Fly.io, Railway, or Coolify on the surfquant VPS. WebSocket server must be
reachable at ic.claudemesh.com.
Status
Scaffold only. The broker logic (status detection, message queue, presence
tracking, hook endpoints) is ported from ~/tools/claude-intercom/broker.ts
in a follow-up step.