cloister
Cloister hosts AI tools (MCP servers, today) behind one HTTPS
endpoint. You declare what to host in a config file; the same bundle
runs locally on your machine for development and on Cloudflare Workers
in production — no rewrites, no deployment-specific code.
task serve:local # → http://localhost:8787
curl http://localhost:8787/health
What you get for free:
- Sandboxed tools. Each hosted tool runs in its own isolate with
its own scoped credentials. A compromised tool can't reach the
others' secrets.
- Identity without bearer tokens. Tools authenticate to each
other via short-lived certificates rather than long-lived API
keys — nothing to rotate, nothing to leak.
- Signed audit trail. Every state-changing call leaves a
hash-chained, signed receipt. A third party can verify what
happened offline, with only the master public key.
Three entry points depending on what brought you here:
Architecture
Cloister is a v8-isolate hypervisor on workerd with a declarative
Cap'n Proto manifest. Routes, backends, and per-bundle credential
scopes are substrate concerns — identity (Interlace), audit (signed
receipts), and credential isolation are wired in at the substrate, not
bolted on per-tenant. It's offline-first: runs locally on workerd
with no cloud account required, and the same TypeScript bundle deploys
to Cloudflare Workers when you want a public endpoint.
Today's primary application is hosting MCP servers behind one HTTP
face. bead_*, mache_*, lsp_*, lifecycle
(reparse/enrich/status), and the Interlace identity bridge are
the first tenants — but the contract is
cloister.capnp: anything HTTP-shaped plugs into
the same route table without touching the substrate. See
ADR-0004 for the manifest shape,
ADR-0009 for the
substrate-portability claim, and
ADR-0011 for what lives
at the hypervisor layer vs the bundle layer.
graph TB
Client["external client<br/>(MCP / curl / browser /<br/>another cluster's bundle)"]
subgraph host ["Host runtime — workerd today (CF Workers in prod);<br/>Firecracker / WASI per ADR-0009"]
subgraph hyp ["Hypervisor layer — cloister-router bundle"]
ROUTER["Router<br/>declarative EdgeRoute table<br/>(from cloister.capnp)"]
MCP["MCP face<br/>/mcp (JSON-RPC + SSE)"]
IDENT["/identity/*<br/>(Interlace lease verification,<br/>per ADR-0007)"]
WK[".well-known/<br/>interlace/index.json<br/>(capability discovery)"]
HLT["/health"]
end
subgraph state ["Cluster state"]
DO["BeadStore DO<br/>(per-repo SQLite)"]
TRUST["TrustStore DO<br/>(singleton, per ADR-0012)<br/>peer_lease_counters,<br/>peer_attestations"]
BLOB[("BlobStore DO<br/>(singleton, per ADR-0003)<br/>content-addressed bytes")]
VAULT[("CredentialVault DO<br/>(singleton, per ADR-0013)<br/>HKDF+AES-GCM envelope,<br/>allowedSubs gate")]
end
subgraph siblings ["Sibling bundles (intra-cluster — service bindings, unforgeable)"]
NOTME["notme-identity<br/>SigningAuthority master,<br/>born-in-CF, never leaves"]
COMP["cloister-companion<br/>(Rust sidecar — IPC seam,<br/>per ADR-0005 amendment)"]
HELPER["leyline-sign-helper<br/>(Rust host binary — sign-only,<br/>per ADR-0019)"]
end
end
EXT["external services<br/>(rosary / mache / LLO / signet —<br/>NOT bundles; reached via httpForward)"]
Client -->|HTTPS| ROUTER
ROUTER --> MCP
ROUTER --> IDENT
ROUTER --> WK
ROUTER --> HLT
MCP -->|state writes| DO
MCP -->|state writes| TRUST
MCP -->|canonical bytes| BLOB
MCP -->|credential reads| VAULT
VAULT -.->|"KEK_HELPER fetch"| HELPER
IDENT -->|svc binding| NOTME
MCP -->|svc binding| COMP
COMP -.->|"leyline-net wire<br/>(real network)"| EXT
style hyp fill:#dde7ff,color:#000
style state fill:#fff5e1,color:#000
style siblings fill:#fff5e1,color:#000
style EXT fill:#f5f5f5,color:#000
Quickstart
Five-minute three-terminal smoke. For the full walkthrough (toolchain,
ports, auth setup, plugin install), see
GETTING-STARTED.md.
# Terminal 1 — ley-line-open daemon (for lsp_* + reparse/enrich/status)
leyline daemon --mcp-port 8384
# Terminal 2 — cloister
pnpm install && task dev:bootstrap && task dev # → http://localhost:8787
# Terminal 3 — notme (optional, for /identity/*)
cd ../notme/worker && wrangler dev --port 8788
Smoke test: