#01 insight#02 uri #03 primitive#04 fed-autopilot #05 codespaces#06 live-demo #07 observability#08 security #09 roadmap

Quilts that link to other quilts

Federation is not a new abstraction. It is the same reactive engine, with a URI that points across the network. Every Quilt is both a publisher and a subscriber. The cell you read might be in the next room, on the boat, or in a GitHub Codespace.

Every cell is both push and pull. Every quilt is both row and column. Federate by URI, push by subscription, audit by trace.

quilt:// URIsresolveCell subscribeCellFederatedQuilt Codespaces-native
View Primitive ↓ Try Codespaces ↓ Open on GitHub →

01The insight: double-entry is already reactive

In a Quilt sheet, every computed cell has a list of parents — the cells it reads from. When a parent changes, the engine recomputes the child. The child pulls from its parents. From the parent's perspective, the same event is a push — it just published a new value to whoever depends on it.

The engine doesn't care which direction the arrow points. The propagation is symmetric. This is double-entry bookkeeping, and it is already the reactive model. A change in cell A flows to cell B; A and B don't agree on who initiated, they only agree that a propagation happened.

cell A ─── push ───▶ cell B
cell B ◀─── pull ───── cell A
// the engine does not know or care which is which

Why federation needs no new abstraction

When cell B is local, propagation is in-memory. When cell B is on a Jetson 3 meters away, propagation is over LAN. When cell B is in a GitHub Codespace on the other side of the planet, propagation is over HTTPS. The subscription shape is identical in all three cases. The cell declares its derived_from; the engine resolves the parents; if a parent is remote, the wire format is the same as the in-memory one.

Everything else on this page is the consequence of that one observation. The URI scheme, the two new SDK functions, the FederatedQuilt class, the Codespaces-native orchestrator — they are all the same reactive engine with a wider reach.

One engine, one subscription model, one audit log. The network is just a slow bus.

02The URI scheme

The URI is the only thing that changes between local and remote. It is deliberately similar to other well-known schemes you already trust — and the grammar is small enough to implement in 10 lines.

quilt://[instance-id]/[sheet-id]#cell-path

The instance-id is a logical name for a running engine — local, jetson-lab, codespace-7c3, or an ESP32 serial number. The sheet-id is the name of the manifest loaded in that engine. The cell-path is the dotted path to a cell within the sheet, and supports the + wildcard for fleet-wide subscriptions.

Five shapes you will use

quilt://local/boat-autopilot#rudder.angle
A local cell on this device. In-process subscriber. Zero network round-trip.
quilt://jetson-lab/perception#vision.scene
A remote cell on a Jetson over LAN. WebSocket subscriber; same JSON push events as local, just slower.
quilt://codespace-7c3/prod#anomaly.detector
A remote cell in a GitHub Codespace. HTTPS subscriber; push events arrive over MCP. The Codespace IS the orchestrator.
quilt://*#anywhere
A wildcard. Used in routing tables. The publisher doesn't care which instance — every quilt with a matching cell receives the push.
quilt://esp32-fleet/+/rudder.angle
A fleet-wide subscription. Like Prometheus' up{job="node"} — every matching instance receives the push.

Resolution algorithm (10 lines)

// resolve a quilt:// URI to a live subscriber handle
function resolveCell(uri, ctx) {
  const m = uri.match(/^quilt:\/\/([^/]+)\/([^#]+)#(.+)$/);
  if (!m) throw new Error(`bad URI: ${uri}`);
  const [_, instance, sheet, cell] = m;
  if (instance === 'local') return localEngine.cell(`${sheet}#${cell}`);
  if (instance === '*')       return router.fanout(sheet, cell, ctx);
  return transport.connect(instance).subscribe(sheet, cell, ctx);  // LAN / HTTPS / MCP
}

That's it. The rest of the federation story is what happens around that handle: how the subscription is set up, how pushes are routed, how the run trace is recorded. None of that changes the cell's evaluate() — it just calls derive() on its parents and the parents happen to be on a different quilt.

Why quilt:// and not https://

quilt:// is the application's identifier; https:// is the transport. Cells refer to other cells by their quilt URI, not their network address. The transport is resolved by the engine's transport layer (mDNS, MCP, WebSocket) and is invisible to the cell. A fleet can swap LAN for LoRa, or HTTPS for a satellite modem, without touching a single cell definition.

03The federation primitive

Two new SDK functions and one new class. They are deliberately minimal: resolve a cell, subscribe to a cell, and stitch multiple engines into one addressable graph. Everything else is composition.

resolveCell(uri, ctx)

resolveCell(uri: string, ctx?: Vars) => Promise<CellHandle>

Given a quilt:// URI, return a live CellHandle. The handle is a subscriber — call handle.get() to read the current value, or pass it as a derived_from entry to a cell. Local URIs resolve to in-process handles (no network). Remote URIs open a transport and return a live-streaming handle that yields values as they change on the source.

import { resolveCell } from '@quilt/federation';
// local — instant, in-process
const rudder    = await resolveCell('quilt://local/boat-autopilot#rudder.angle');
// remote — opens MCP/HTTPS, streams values
const anomalies = await resolveCell('quilt://codespace-7c3/prod#anomaly.detector', { run_id: '01HXY' });
console.log(rudder.value, anomalies.value);  // current values
@quilt/federationlazytemplatedtransport-agnostic

subscribeCell(uri, callback)

subscribeCell(uri: string, cb: (v, trace) => void) => Unsubscribe

Get a callback fired every time the cell's value changes — locally, remotely, by any cell, by any user, by any code path. The callback receives the new value and a trace object describing who changed it, when, and what the previous value was. The returned Unsubscribe cleans up the subscription (closes the socket, removes the listener).

import { subscribeCell } from '@quilt/federation';
// "tell me whenever the cloud's PID tuning changes"
const off = subscribeCell('quilt://codespace-7c3/prod#tune.pid_kp', (kp, trace) => {
  console.log(`kp → ${kp.value} by ${trace.actor} at ${trace.t}`);
  algoPid.derived_from = ['kp'];  // rewire locally
});
// later
off();  // close the subscription, release the socket
@quilt/federationpushtracedmulti-transport

The FederatedQuilt class

The class that stitches multiple engines into one addressable graph. It owns the routing table, the transport adapters, and the cross-engine propagation log. You can think of it as a superset of an engine — it has cells, and its cells can be on other engines.

federated-quilt.ts @quilt/federation · ~80 LOC
// FederatedQuilt — a quilt of quilts. Each "node" is a real Engine (local)
// or a remote URI handle (remote). One trace log for the whole fleet.
import { Engine }      from '@quilt/core';
import { resolveCell } from '@quilt/federation';
import { transport }   from '@quilt/transport';

export class FederatedQuilt {
  constructor(name) {
    this.nodes = new Map();  // instance-id → Engine | Remote
    this.edges = [];          // { from, to, kind }
    this.trace = [];          // every cross-tier change
  }
  addLocal(id, engine) {
    this.nodes.set(id, engine);
    engine.on('change', (cell, _p, next, actor) =>
      this._propagate(id, cell, next, actor));
    return this;
  }
  async addRemote(id, ep) {
    const conn = await transport.connect(ep);
    this.nodes.set(id, conn);
    conn.on('push', (cell, value, actor) =>
      this._propagate(id, cell, value, actor));
    return this;
  }
  wire(from, to, kind = 'mirror') { this.edges.push({ from, to, kind }); }
  async resolve(uri, ctx = {}) { return resolveCell(uri, ctx); }
  private async _propagate(fromId, cell, value, actor) {
    this.trace.push({ t: new Date().toISOString(), from: fromId, cell, value, actor });
    for (const e of this.edges.filter(x => x.from.startsWith(fromId) && x.from.endsWith(cell))) {
      const [tier, path] = e.to.split(/#/);
      await this.nodes.get(tier.split(/\//)[0])._setCell(path, value, actor);
    }
  }
}

// 3 lines to federate a fleet
const fleet = new FederatedQuilt('boat-fleet');
fleet.addLocal('local', esp32Engine);
fleet.wire('local#mirror.rudder',        'jetson-lab/perception#mirror.telem');
fleet.wire('jetson-lab#perception.fused', 'codespace-7c3/prod#anomaly.input');

That is the entire federation surface. The class is ~90 lines; the rest is transport adapters and routing. Notice what is not there: no message broker, no service mesh, no API gateway, no protocol negotiation. The cells push and pull; the engine routes; the trace is one log.

The same shape, three different transports

Local propagation is a function call. LAN propagation is a WebSocket frame. Cloud propagation is an HTTPS POST (or MCP call). The wire format is identical: { uri, value, prev, actor, t, trace_id }. The cell receiving the push does not know, and does not need to know, which transport delivered it.

04The killer example: Fed-Autopilot

A 3-tier Quilt stack for an autonomous boat. ESP32 at the bottom, Jetson in the middle, GitHub Codespace at the top. Each tier runs an engine; each engine has its own cells; the cells are linked by quilt URIs that cross the network boundaries. There is no separate message bus. The reactive graph is the bus.

┌──────────────────────────────────────────────────────────┐ GitHub Codespace (cloud, ML, alerts) anomaly.detector ← pattern in rudder.angle tune.pid_kp → pushed back to local audit.run_trace ← immutable log of every change └──────────────────────────┬───────────────────────────────┘ quilt://codespace-7c3/... (HTTPS / MCP / WebSocket) ┌──────────────────────────┴───────────────────────────────┐ Jetson (onboard, mid-tier, vision) vision.scene ← camera frames perception.obstacles → fused to autopilot.intent mirror.telem → forwards to cloud └──────────────────────────┬───────────────────────────────┘ quilt://jetson-lab/... (LAN / mDNS / serial) ┌──────────────────────────┴───────────────────────────────┐ ESP32 (tight loop, 50 Hz, sensors + motors) sensor.rudder ← potentiometer sensor.compass ← IMU actuator.motor_pwm → motor controller algo.pid → every cycle, deadband check led.display → publish current state mirror.rudder → publish to Jetson └──────────────────────────────────────────────────────────┘

What runs where

tier 3 · cloud
GitHub Codespace — quilt://codespace-7c3/prod
anomaly.detectorpattern in rudder.angle + telemetry
tune.pid_kppublishes new gain to ESP32
audit.run_traceappends every cross-tier change
alerts.notifypush to Slack/PagerDuty on anomaly
model.retrainweekly fine-tune on collected traces
dashboard.renderlive charts in the Codespace TUI
quilt://codespace-7c3/... · HTTPS / MCP / WebSocket
tier 2 · mid
Jetson — quilt://jetson-lab/perception
vision.scenecamera frame every 200 ms
perception.obstaclesfused to autopilot.intent
autopilot.intentheading correction for ESP32
mirror.telemforwards to Codespace
ml.inferon-device YOLO / obstacle net
local.fs12 h rolling buffer of frames
quilt://jetson-lab/... · LAN / mDNS / serial
tier 1 · edge
ESP32 — quilt://esp32-fleet/+/autopilot
sensor.rudderpotentiometer, 50 Hz
sensor.compassIMU, 50 Hz
actuator.motor_pwmmotor controller write
algo.pidevery cycle, deadband check
led.displaypublish current state to LEDs
mirror.rudderpublish to Jetson

What pushes up, what pulls down

EdgeFrom → ToWhat happens
ESP32 → Jetsonrudder.angle → mirror.telemEvery cycle (20 ms), the ESP32 publishes its current rudder angle. The Jetson subscribes and feeds the perception engine. No polling — push only.
ESP32 ← Jetsonalgo.pid.intent ← autopilot.intentThe Jetson publishes a desired heading correction based on perception. The ESP32 subscribes to its local mirror and adjusts motor PWM.
Jetson → Codespaceperception.fused → anomaly.inputThe Codespace runs an anomaly detector (a model cell) over the full telemetry stream. It doesn't poll; the stream arrives via the federation.
Codespace → ESP32tune.pid_kp → algo.pidA human (or a nightly job) updates the PID gain in the Codespace. The new value is pushed to every boat via the wildcard quilt://esp32-fleet/+/algo.pid.
Codespace → humananomaly.detector → alerts.notifyWhen the detector fires, it pushes to alerts.notify, which in turn calls Slack, PagerDuty, or Twilio. Audit is one engine.serialize() away.

The thing to notice

There is no message broker. No Kafka, no NATS, no MQTT. The cells push to their parents; the parents push to their consumers. Three engines, one reactive graph, one audit log. The network is invisible to the cells — and the cells don't care.

05Codespaces-native Quilt

GitHub Codespaces is the canonical orchestrator target. It gives you a real Linux box in the cloud, a browser-based terminal, a public HTTPS endpoint on a stable subdomain, and an env-var-based secret store — all without managing a server. For a fleet of boats (or any small fleet of edge devices), this is exactly the right shape of orchestrator: cheap, ephemeral, fully scriptable, and reachable from anywhere on the internet.

Six steps to a Quilt in a Codespace

1

Add a devcontainer

One file. Pre-built Quilt dev env. Every Codespace that opens your repo has Quilt installed, with all the federation transports compiled in.

.devcontainer/devcontainer.json { "name": "quilt-fleet", "image": "ghcr.io/superinstance/quilt:dev", "forwardPorts": [7681], "postCreateCommand": "quilt init" }
2

Run quilt serve

The TUI starts in the browser-based terminal. Watch the live cell graph, push values, inspect the trace. Same as the local Quilt Live — just running in the cloud.

$ quilt serve --tier cloud --name codespace-7c3 → engine up on quilt://codespace-7c3/prod → tui on http://localhost:7681 → mcp on stdio → listening for push from esp32-fleet/*
3

Expose the TUI and MCP

Port 7681 runs the ttyd-served TUI. The MCP server runs on stdio, so any agent (Claude Code, Codex, custom) can mount the whole cloud engine as tools.

$ quilt serve --tui-port 7681 --mcp-stdio → tui: https://[codespace]-7681.githubpreview.dev/ → mcp: (auto-configured for your editor) → http api: /v1/resolve, /v1/subscribe
4

Set the token in env

Every Codespace has a secrets store. Set QUILT_TOKEN to a long-lived random string; the engine requires it on every connect.

# in Codespace secrets (one-time) QUILT_TOKEN = "f8e1d...c3a9" $ quilt serve → auth: required, QUILT_TOKEN set ✓ → ready
5

Point the IoT devices at the URL

The Codespace has a stable HTTPS preview URL. Configure your devices once. They push; the Codespace receives, routes, logs, alerts.

// on the ESP32 (in the boat's firmware) const quilt = await quiltConnect({ url: "https://codespace-7c3-7681.githubpreview.dev", token: process.env.QUILT_TOKEN, instance: "esp32-7c3-a1b2" }); await quilt.setCell("rudder.angle", 0.42); quilt.subscribe("tune.pid_kp", kp => algoPid.kp = kp);
6

The Codespace IS the orchestrator

The orchestrator is just another Quilt engine, with cells for anomaly.detector, alerts.notify, audit.run_trace. The same reactive graph, the same run trace, the same MCP surface.

# the cloud tier's manifest sheets: - prod/ # anomaly.detector, alerts, audit - dev/ # experiments, sandboxes - ml/ # retraining, eval, deploy # every sheet is a quilt://codespace-7c3/<name> URI

Why a Codespace, not a VM, not a serverless function

Codespaces give you a long-lived Linux process (not a 15-minute timeout), a free HTTPS endpoint (the githubpreview.dev URL), and a shell for debugging. A serverless function can host a cell; it cannot host an engine that maintains a federation over time. A VM can; a Codespace is a VM you didn't have to provision.

06Live 3-tier demo

Three simulated Quilt engines, one reactive graph, real propagation. Click the buttons; watch the values flow; read the run trace. This is the same code path that runs on real hardware — just with fake sensors.

Fed-Autopilot · 3 tiers · live

🪛ESP32esp32-fleet/7c3-a1b2
🛰Jetsonjetson-lab/perception
Codespacecodespace-7c3/prod
run trace · cross-tier
0 entries
click "Push rudder" below, or any cell button on a tier, to start the trace…
push upstream (device → cloud)
push downstream (cloud → device)

Two scripted flows — click to run

① Upstream device → cloud

what the buttons do
Push rudder on ESP32 sets sensor.rudder.
mirror.rudder reflects it; the edge ━━━▶ carries the value to Jetson's mirror.telem.
Jetson recomputes perception.fused and ━━━▶ forwards to Codespace's anomaly.input.
Codespace re-runs the anomaly model and lights up anomaly.detector if the pattern matches.

② Downstream cloud → device

what the buttons do
Tune PID on Codespace sets tune.pid_kp to a new value.
The edge ◀━━━ carries it down to ESP32's algo.pid (via the wildcard esp32-fleet/+/algo.pid).
The PID recomputes, drives actuator.motor_pwm, the rudder adjusts to the new gain.

The buttons above trigger real propagation through the simulated federation. Every cell that receives a value pulses green (upstream) or blue (downstream). Every change appends to the run trace. The SVG edges between tiers are dashed at rest and light up as the value flows through them.

07Cross-Quilt observability

Every cross-tier change is a run trace. The trace is the same shape as the local trace — one log, append-only, hash-chained — but with an extra field: the origin_tier and the trace_id that lets you correlate the same value across every quilt it touched.

Example trace JSON

// one cross-tier change, 3 tiers, 6 cells
{
  "trace_id":     "01HXY2K9-7c3",
  "t":            "2026-01-15T14:22:01.482Z",
  "origin_tier":  "esp32-7c3-a1b2",
  "origin_actor": "sensor:rudder-pot",
  "hops": [
    { "tier":"esp32-7c3-a1b2", "cell":"sensor.rudder",    "value":0.42, "ms":0   },
    { "tier":"esp32-7c3-a1b2", "cell":"mirror.rudder",    "value":0.42, "ms":0,   "kind":"mirror" },
    { "tier":"jetson-lab",     "cell":"mirror.telem",     "value":0.42, "ms":11,  "transport":"websocket/lan" },
    { "tier":"jetson-lab",     "cell":"perception.fused", "value":0.44, "ms":28,  "kind":"formula" },
    { "tier":"codespace-7c3",  "cell":"anomaly.input",    "value":0.44, "ms":187, "transport":"https/mcp" },
    { "tier":"codespace-7c3",  "cell":"anomaly.detector", "value":true, "ms":203, "kind":"ai" }
  ],
  "totals":{ "ms":429,"cells":6,"tiers":3 },
  "hash":"sha256:f1b4...7e"
}

The ledger view

Each Quilt is its own "book" in the double-entry sense. The local trace is one ledger; the federated trace is a merge of ledgers with a common hash chain. To audit "what did the fleet do on Tuesday", you concatenate every per-quilt trace for that day and verify the chain.

QuiltRoleWhat the ledger records
esp32-7c3-a1b2edgeEvery sensor read, every motor write, every PID cycle. 50 Hz × N cells. Sampled and shipped to Jetson once per second.
jetson-labmidEvery perception inference, every fused output, every push to/from ESP32 and Codespace. 5 Hz per upstream feed.
codespace-7c3cloudEvery anomaly detection, every alert sent, every PID tuning published. Plus the immutable log of every cross-tier change it has witnessed.

One trace, three books

The local ledger is the engine's serialize(). The federated ledger is a deterministic merge of the per-quilt ledgers, with a trace_id that lets you reconstruct the order of cross-tier changes. There is no separate "distributed tracing" library; the engine already records everything, and the merge is one function call.

08Security

A federated engine is a network service. It needs auth, transport security, and per-cell authorization. The cell types that touch the physical world (motors, brakes, money) need extra guarantees: an irreversible flag that makes a cell write-once, and a rollback path the federation can revert across.

🔑

Token auth · required

Every cell write from a device must carry the QUILT_TOKEN. Tokens are scoped to a namespace; a token for esp32-fleet/* cannot write to codespace-7c3/prod.

$ quilt serve --require-token \ --token-scopes "esp32-fleet/*:rw, codespace-7c3/prod:ro"
🔒

mTLS · for production

Each device gets a client cert at provisioning time. The Codespace mints a server cert from Let's Encrypt. Mutual TLS prevents token-leak replay and gives you a real CA-anchored audit chain.

$ quilt serve --mtls \ --ca-file /etc/quilt/ca.pem \ --cert-file /etc/quilt/server.pem
📋

Per-cell ACLs

Read-only cells, write-once cells, role-gated cells. The ACL is declared in the manifest and enforced by the engine before the value propagates.

- id: actuator.motor_pwm kind: actuator acl: { write: ["role:operator"], read: ["*"] } irreversible: true

irreversible: true

For high-stakes cells (motors, brakes, money, anything that mutates the physical or financial world). The cell rejects any value that is not strictly greater / more conservative than the previous one. The federation can never accidentally drive the motor to an unsafe value.

// engine refuses to set motor_pwm higher than safe_max $ quilt set actuator.motor_pwm 0.95 → REJECTED: would exceed safe_max=0.78

rollback · across the federation

One snapshot per tier. One rollback call restores the whole fleet to a known-good state. The same reactive history that powers replay powers rollback.

$ quilt fleet rollback \ --to 2026-01-15T14:00:00Z \ --reason "anomaly detector false positive" → 3 tiers, 17 cells, 1 trace — restored ✓
📜

Audit · signed traces

Every trace is signed by the engine that produced it. The Codespace collects the per-tier traces, verifies the signatures, and writes a hash-chained summary to durable storage. The "who did what when" question has a one-call answer.

$ quilt audit "boat-7c3" \ --from 2026-01-15 --to 2026-01-16 → 12,341 cells, 3 tiers, all signatures valid ✓

The shape of trust

Devices trust the cloud (mTLS, signed manifests). The cloud trusts devices (token + cert + ACL). Cells trust their parents (typed schema, validated preconditions). Humans trust the audit (hash-chained, signed, append-only). Each link is a different mechanism; together they form a chain where breaking any one of them is detectable.

09What ships today, what's next

Three things are in the repo and working. Three more are in design. The first three prove the primitive; the second three prove the orchestrator.

resolveCell · subscribeCell primitives
The two SDK functions. Resolves any quilt:// URI to a live handle; subscribes any cell to push events from any tier. ~80 lines each.
v0.4 — shipped
FederatedQuilt class
A quilt of quilts. Stitches engines into one addressable graph; one trace; one rollback. The basis of every multi-tier deployment.
v0.4 — shipped
.devcontainer/devcontainer.json
Pre-built Quilt dev env for Codespaces. One-click open, quilt serve in the browser terminal, MCP on stdio. The hello-world of a federated Quilt.
v0.4 — shipped
Cross-Quilt FederatedArtifactStore R2-backed
A content-addressed store that spans the federation. Pins every cell definition, every manifest, every trace to a hash; any tier can fetch any artifact by URI without trusting the source.
v0.5 — in design
quilt-fleet repo multi-device orchestration
A separate repo for the multi-device orchestrator. Wildcard subscriptions, fleet-wide rollbacks, OTA cell deployments, per-device audit. The "Kubernetes of small things".
v0.5 — in design
quilt-jetson repo onboard tier
A Jetson-specific Quilt build: TensorRT-accelerated cells, CSI camera cells, ROS bridge. The "edge intelligence" tier in the federation, packaged for one-line install.
v0.6 — in design

If you build on the federation, your work goes here. The primitives are open, the class is open, the Codespace config is open.

Companion reads

Where to go from here

Three doors, depending on what brought you here.