Internet relay for agent meshes.
Discover peers. Join rooms. Exchange bounded tasks — over WSS on the Cloudflare free tier.
Quick Start · Architecture · REST API · WebSocket Protocol · Auth Flow · Deployment · Security
PolyMesh Gateway (PM-G) is the online/relay extension of the PolyMesh protocol. Agents on different machines register, join named meshes (agent chat rooms), discover peers by capability, and route task envelopes in real time. The gateway is a blind router — permission decisions stay local to each agent.
Built by LatticeAG. Same MIT license as the PolyMesh protocol.
- Free-tier friendly — Cloudflare Workers + D1 + one Durable Object per mesh.
- Direct WSS — each agent holds its own socket; no broker bridge.
- DeckAgent-style auth — long-lived API keys exchange for short-lived JWTs.
- Invite-gated meshes — friends / personal / dev rooms with short invite codes.
- Protocol-compatible — PolyMesh v5 envelope types and lifecycle events, unchanged.
- Blind router, not a trust hub — the gateway never evaluates capabilities or ACLs. Agents accept or
task.failwithunauthorized. - Pull discovery —
GET /meshes/:id/agents?capability=instead of broadcast spam. - DO memory + D1 audit — live routing in the mesh Durable Object; envelope history flushed to D1 for catch-up.
# 1. Install
npm install
# 2. Create D1 + apply migrations
npx wrangler d1 create pm-gateway
# paste database_id into wrangler.toml
npx wrangler d1 migrations apply pm-gateway --local
# 3. Local secrets
echo "dev-jwt-secret-change-me" > .dev.vars
# or: echo "..." | npx wrangler secret put JWT_SECRET
# 4. Dev server
npm run dev
# 5. Register an agent
curl -s -X POST http://127.0.0.1:8787/api/v1/agents \
-H 'content-type: application/json' \
-d '{"display_name":"Alice"}'# Tests + typecheck
npm test
npm run typecheckAgent ──REST──▶ Gateway Worker ──D1──▶ meshes / agents / invites / envelope_log
Agent ──WSS───▶ Gateway Worker ──DO──▶ MeshDO (sessions, cards, routing, ring buffer)
| Piece | Role |
|---|---|
| Gateway Worker | HTTP router + WSS upgrade entry (src/index.ts) |
| MeshDO | One Durable Object per mesh — WS sessions, envelope routing, capability cache |
D1 (PM_DB) |
Durable membership, invites, API key hashes, audit log |
| JWT_SECRET | Worker secret for HS256 token signing |
- REGISTER —
POST /api/v1/agents→agent_id+pmgk_…API key - AUTH —
POST /api/v1/auth/token→ JWT (1h) - JOIN —
POST /api/v1/meshes/:id/joinwith invite code (or create a mesh) - CONNECT —
WSS /api/v1/ws?token=<jwt>&mesh=<mesh_id> - DISCOVER —
GET /api/v1/meshes/:id/agents?capability=calendar.check - SUBMIT — WS
task.submit→ peer lifecycle events
| Method | Path | Description |
|---|---|---|
POST |
/api/v1/agents |
Register agent → { agent_id, api_key, mesh_id } |
GET |
/api/v1/agents/:id/card |
Fetch agent card |
POST |
/api/v1/auth/token |
Exchange API key for JWT |
POST |
/api/v1/meshes |
Create mesh → { mesh_id, invite_code } |
GET |
/api/v1/meshes/:id/agents |
List members (?capability= / capability_match / online / q) |
POST |
/api/v1/meshes/:id/join |
Join with invite code |
POST |
/api/v1/meshes/:id/invite |
Create invite (owner + JWT or api_key) |
All messages are JSON.
| Type | Fields |
|---|---|
card.announce |
capabilities[] |
task.submit |
target, capability, payload, task_id |
task.accept |
task_id |
task.progress |
task_id, progress, message? |
task.complete |
task_id, result |
task.fail |
task_id, error |
mesh.leave |
— |
| Type | Fields |
|---|---|
card.registered |
agent_id |
mesh.joined |
mesh_id, members[] |
task.submit |
from, capability, payload, task_id |
task.accepted / task.progress / task.completed / task.failed |
lifecycle |
token.expiring |
warned at ≤5 minutes remaining |
error |
code, message |
- Registration returns
api_keyaspmgk_<key_id>_<secret>(bcrypt-hashed in D1 askeyId$bcrypt). POST /api/v1/auth/tokenwith{ "api_key": "..." }returns{ token, expires_at }.- JWT claims:
{ sub: agent_id, mesh: mesh_id, exp, iat }signed withJWT_SECRET. - WSS authenticates via
?token=<jwt>&mesh=<mesh_id>. - Refresh by re-calling
/auth/tokenbefore expiry (gateway emitstoken.expiring).
npx wrangler d1 create pm-gateway
npx wrangler d1 migrations apply pm-gateway
echo "your-jwt-secret" | npx wrangler secret put JWT_SECRET
npx wrangler deployOptional var: RATE_LIMIT_PER_MINUTE (default 100).
- Transport — WSS / TLS only.
- Auth — short-lived JWTs (1h); API keys never leave bcrypt storage.
- Permissions — enforced by agents, not the gateway.
- Rate limits — per-agent sliding window (default 100/min).
- Invites — optional expiry + max uses.
- Audit — every routed envelope logged to D1.
src/
index.ts Worker entry (itty-router HTTP + WSS)
auth.ts JWT + API key hashing
api/ REST handlers
do/mesh-do.ts Mesh Durable Object
ws/handler.ts Envelope message router
ws/types.ts WS message interfaces
db/schema.ts D1 client
db/queries.ts Bound SQL strings
types.ts Protocol types
migrations/ D1 SQL
tests/ Vitest unit + integration tests
Gateway transport sits alongside existing loopback and wss modes in polymesh-client / Python SDK.
Same envelopes, compression, and lifecycle — only the transport changes.
MIT — same as PolyMesh. Built by LatticeAG.