State Channels
Spin up a machine, host pages on it. Every version is hash-committed to your entangled state, the page can compute against the kernel, and there is no separate Vercel, Netlify, or CDN to wire up.
A state channel is a hosted page bound to one of your state machines. You publish HTML; the framework serves the machine's default canvas at /s/<machine>/ and each published page at /s/<machine>/p/<page>/, stores every version as a row in state_machine_pages, and gives the page a same-origin compute proxy into the kernel. It's the third of the framework's three state primitives:
- State machine — your scoped namespace + identity (state machines).
- State contract — the deployable logic that runs on its clock (state contracts).
- State channel — the pages the world sees, hosted on the machine. (this page)
What you get
- Hosting with provenance. Every publish writes a new versioned row with a proof digest (SHA-256 over machine, page, content hash, version, and publisher ZID) and appends a
deploy_publishedrow to your entangled state at the Zeqond it landed. The page you serve is the page you can prove you served. - Versioning built in. Publishing flips the old version off and inserts the new one;
historylists every version,rollbackrestores one. Nothing is ever overwritten in place. - Compute from the page. Each machine gets an auto-issued Site SDK publish key, held server-side. The hosted page calls the same-origin proxy —
/s/<machine>/sdk/zeq/<op>for kernel routes,/s/<machine>/sdk/contracts/…for its contracts — and the proxy attaches the key. No key ever appears in your client code. - A sandboxed surface. Hosted pages are served with sandbox/integrity headers and run isolated from the admin surface and other machines; the SDK proxy is the page's only privileged path, rate-limited per machine.
Deploy a page
Three equivalent paths — same validation, same versioned row, same audit linkage:
Workbench — step 7, BUILD & DEPLOY: describe the page, the build flows through the compliance gate and publishes it, then shows the live URL. Pages you've built are listed on your machine's root canvas at /s/<machine>/.
CLI — one command (html is btoa(yourHTML) so it survives the terminal tokeniser):
site deploy hello aGVsbG8= "My Page" # page slug · base64 HTML · title
site list # published pages on this machine
site get hello # title, version, html
site unpublish hello # take it offline
curl — straight to the pages route with your machine key. html is plaintext here; agentZid is your machine's ZID:
curl -sS -X POST https://zeqapi.com/api/state-machines/<your-machine>/pages/hello/publish \
-H "Authorization: Bearer ${ZSM_KEY}" \
-H "Content-Type: application/json" \
-d '{ "title": "My Page", "html": "<!doctype html><h1>hello</h1>", "agentZid": "<your-machine-zid>" }'
The page is live at https://zeqapi.com/s/<your-machine>/p/hello/. The full route set is GET /pages, GET /pages/:page, GET /pages/:page/history, POST /pages/:page/publish, POST /pages/:page/unpublish, POST /pages/:page/rollback — reference: Machine Pages API.
Caps: HTML ≤ 2 MB per page, title ≤ 200 chars, optional pythonScript ≤ 256 KB.
Compute from a hosted page
The proxy makes kernel work same-origin — relative URLs, no credentials in the page:
<script type="module">
// ./sdk/zeq/<op> proxies to /api/zeq/<op> with the machine's
// server-held Site SDK key attached. The page never sees the key.
const r = await fetch("./sdk/zeq/compute", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ operator: "NM19", inputs: { mass_kg: 5, acceleration_ms2: 2 } })
});
const envelope = await r.json(); // the same signed kernel envelope every surface gets
document.body.textContent = JSON.stringify(envelope, null, 2);
</script>
Every compute the page runs lands on your machine's entangled state — the same envelope path the CLI and Workbench use. The proxy is rate-limited (per-machine bucket) with request bodies up to 1 MB; if the machine has no Site SDK key yet, one is auto-issued to the owner on first use.
./sdk/contracts/… works the same way for the machine's state contracts — list them, read state, drive transitions from the page.
Custom domains — Zeq Edge
Out of the box a channel lives under /s/<machine>/. To put it on your own hostname with caching, rules, and DDoS protection, point a CNAME at Zeq Edge and register the site in the Zeq Edge app. Origin TLS is strict by default.
Guarantees
| Property | How |
|---|---|
| Tamper-evident | per-version proof digest + deploy_published row on the entangled state; inspect via /api/chain/<machine>/explore or the Observer (/state/?slug=<machine>) |
| Versioned | every publish is a new state_machine_pages row; history + rollback, never an in-place edit |
| Computable | auto-issued Site SDK key → same-origin /s/<machine>/sdk/* proxy to the kernel and your contracts |
| Yours to take down | site unpublish / POST .../unpublish; the audit history of what was served remains |
Next
- State Contracts — put logic behind the page, on the same machine's clock.
- Machine Pages API — field-level reference for the pages routes.
- State machines — the namespace your channel is bound to.
- Zeq Edge — custom domains, caching, and edge rules in front of your channel.