Fabric Architecture
Physical layout, transport contract, and session flow as of 2026-10-16 (HEAD 2288a91924).
Physical topology
INTERNET
│
┌──────────────┼──────────────┐
│ │
fabric.optimal.miami fabric.optimal.miami
(CF orange-cloud) (CF orange-cloud)
│ │
▼ ▼
CF Tunnel: fabric-prod CF Tunnel: a6f4487b-…
UUID 00633812-46c8-4e70-… (Pi's existing tunnel)
│ │
▼ ▼
┌──────────┐ ┌──────────┐
│ HETZNER │ ◀── pair ──▶ │ PI 5 │
│ CX32 │ │ 16 GB │
│ Debian12 │ │ Bookworm │
│ 178.156. │ │ 100.94. │
│ 203.234 │ │ 77.114 │
└────┬─────┘ └────┬─────┘
│ │
cloudflared cloudflared
optimalos.service optimalos.service
caddy.service n8n / strapi / openclaw-gateway
(Caddy unused for tunnel) optimal-discord / optimal-docsBoth origins serve the same bundle; legacy vs fabric is decided at runtime via hostname.
Deployment modes
Two modes, one bundle:
- Legacy mode —
fabric.optimal.miami(Pi). Home / Board / Loom / Settings + tmux attach +[XFER]. Fabric-only API routes return 410 GONE. - Fabric mode —
fabric.optimal.miami(Hetzner). Everything legacy mode has, plus Sessions tab, Feed, Jev Playground, Spine tab, and World (three.js).
The gate runs at request-time:
- Server —
process.env.DEPLOYMENT === "hetzner-cloud"insrc/server.tscontrols whether/api/auth,/api/devices,/api/openclaw,/api/jev,/api/spine,/api/system/tmuxare mounted. - Client —
client/fabric-mode.tsisFabricMode()checkswindow.location.hostnameagainstFABRIC_HOSTNAMES.
Hetzner box
| Property | Value |
|---|---|
| Type | CX32 (€5.83/mo, 2 vCPU, 7.6 GB RAM) |
| IPv4 | 178.156.203.234 |
| OS | Debian 12 bookworm |
Filesystem layout:
/opt/optimalos/app/— bundled Bunserver.js+ Viteclient/assets/opt/optimalos/workflows/— Loom workflow modules/opt/optimalos/operations/— Loom operation modules/opt/optimalos/data/— runtime data (SQLite)/opt/optimalos/secrets.env— JWT signing key, invites, Supabase keys
Transport contract
Wire-locked in commit 7f55c3b. Minimal contract for NATS/QUIC swap.
- Channel:
wss://fabric.optimal.miami/ws/device(device) or/ws/browser(browser) - Encoding: NDJSON, one envelope per line
- Auth: JWT in
Sec-WebSocket-Protocolheader (HS256) - Direction: device dials out; cloud has no inbound device port
- Heartbeat: device → cloud every 20s with capabilities digest
- Envelope shape:
{type, sessionId, corrId, ts, payload}
Session flow
Browser Cloud (Hetzner) Device (Pi/laptop)
│ │ │
│ POST /api/sessions │ │
│ { harness, prompt } │ │
├─────────────────────────▶ │ │
│ │ envelope { type: "session.start" } │
│ ├──────────────────────────────▶ │
│ │ │ spawn harness
│ │ stdout chunks │ pipe stdout
│ │ ◀──────────────────────────────┤
│ SSE: data lines │ │
│ ◀────────────────────── ─┤ │
│ │ envelope { type: "session.exit" } │
│ │ ◀──────────────────────────────┤
│ SSE: close │ │
│ ◀────────────────────── ─┤ │Multiplex
src/server/ws-multiplex.ts maintains:
- One device connection per
deviceId(new connection evicts old) - Many browser connections (one per tab)
- Pending-request map keyed by
corrIdfor routing
Heartbeat evicts devices stale > 60s.
Device routing
src/server/device-router.ts implements Phase 12-1 capability-aware scheduler:
- Hard filter: harness installed AND required capabilities present
- Soft score: weighted combination of RAM headroom (0.50), inverse session load (0.30), and heartbeat freshness (0.20)
- Tie-break: lexicographic deviceId sort
Components
- World (three.js) —
client/world/; 3D orbital deployment view with planet/spacecraft visualization - Feed —
client/feed/; unified agent activity timeline - Spine —
client/spine/+src/routes/spine.ts; device-routed ReturnPro worker relay - Jev Playground —
client/jev/+src/routes/jev.ts; TypeSafe System One API proxy - Skill usage —
src/fabric/skill-usage.ts+src/server/skill-usage-store.ts; library's server record of Skill calls - Landmarks —
src/fabric/landmarks.ts+src/routes/landmarks.ts; owner-pinned surface landmarks - Office —
client/office/+src/server/office-store.ts; in-memory agent map (2026-09-07)