Zeq on hardware
The framework is a machine, and a machine exposes its I/O the way real
hardware does — memory-mapped registers, not a config file. The Zeq
connection region (~/.zeq/mmio) is a small page a device maps to read the
machine's identity (ZID), the live 1.287 Hz clock (ZEQOND,
PULSE_PHASE), its CREDIT, and a revocable credential handle (never the raw
key). That's all you need to bind a device to the framework — no .env, no key
baked into firmware.
There are three ways to put Zeq on a device, from most to least capable:
1 · Run the agent + map the region (a full local machine)
If the device runs a normal OS (Linux SBC, edge gateway, industrial PC), run the
zeqd agent — it owns the region, keeps the registers live on the pulse, seals
the key at rest, and resolves the handle to a short-lived bearer over an
owner-only socket (the zeqd agent ships in the repo under zeqd/). See
the MMIO architecture.
printf '%s' "$ZEQ_AK" | zeqd provision --zid ZEQ… --origin https://www.zeq.dev
zeqd run # owns ~/.zeq/mmio, ticks on the pulse, serves handle→bearer
Map it from C with the published header — zeq-mmio.h:
#include "zeq-mmio.h"
#include <fcntl.h>
#include <sys/mman.h>
#include <stdio.h>
int main(void) {
int fd = open("/root/.zeq/mmio", O_RDONLY);
unsigned char *r = mmap(NULL, ZEQ_MMIO_SIZE, PROT_READ, MAP_SHARED, fd, 0);
if (memcmp(r + ZEQ_OFF_MAGIC, ZEQ_MMIO_MAGIC, 8) != 0) return 1; // validate
unsigned long long zeqond = *(unsigned long long*)(r + ZEQ_OFF_ZEQOND); // live
double phase = *(double*)(r + ZEQ_OFF_PULSE_PHASE); // live
printf("ZID=%.32s Zeqond=%llu phase=%.4f\n", r + ZEQ_OFF_ZID, zeqond, phase);
return 0;
}
The credential is resolved separately over ~/.zeq/zeqd.sock ({op:"resolve", handle:"<KEY_HANDLE>"} → the bearer) so no secret is ever in the mapped page.
2 · Read the region over HTTP (a constrained device)
A microcontroller or anything that can't run the agent can read the same registers over the network — MMIO as an endpoint:
GET https://www.zeq.dev/api/zeq/mmio
Returns the full region manifest (the layout below, the doorbell + resolve protocol, how to connect) plus the machine-global live registers — no key needed:
{
"protocol": "ZeqMMIO", "version": 1, "magic": "ZEQMMIO\\0", "regionSize": 4096,
"layout": [ /* every register: offset, size, type, name, desc */ ],
"registers": { "zeqond": 2299088130, "pulse_phase": 0.41, "pulse_hz": 1.287, "R_t": 1.0004 },
"connect": { "sdk": "await ZeqReactorClient.connect()", "header": ".../zeq-mmio.h" }
}
To read your machine's registers (its ZID), present your zeq_ak_ key:
curl -H "Authorization: Bearer $ZEQ_KEY" https://www.zeq.dev/api/zeq/mmio/registers
# → { ok, zid, keyValid, registers: { zeqond, pulse_phase, pulse_hz, R_t } }
A device should anchor to zeqond from one poll and interpolate with its own
monotonic timer between polls — never compute the absolute Zeqond itself.
3 · Speak the region format directly (firmware/FPGA)
For firmware or an FPGA soft-core, the region is a fixed 4 KiB little-endian
layout — implement it directly from zeq-mmio.h. The
endpoint's layout array is the machine-readable form of the same map:
| Offset | Type | Register | Meaning |
|---|---|---|---|
0x000 | char[8] | MAGIC | "ZEQMMIO\0" |
0x00C | uint32 | STATUS | READY·KEY_VALID·PULSE_LOCKED·SEALED·ERROR |
0x010 | char[32] | ZID | machine identity |
0x070 | char[32] | KEY_HANDLE | revocable capability (not the key) |
0x0A0 | uint64 | ZEQOND | live Zeqond number |
0x0A8 | double | PULSE_PHASE | live phase [0,1) |
0x0B0 | double | PULSE_HZ | 1.287 |
0x0B8 | double | CREDIT | compute-credit balance |
0x0C0 | uint64 | HEARTBEAT | liveness beat |
0x100–0x10C | uint32 | CMD/DOORBELL/RESP/RESP_LEN | doorbell write path |
The doorbell (CMD + DOORBELL → RESP) is the write path — PING returns
the live Zeqond, REFRESH_KEY rotates the handle. Control only; the secret is
never written to the page.
Security on a device
- No key in firmware. The raw
zeq_ak_is sealed at rest byzeqd(AES-256-GCM where available) and held only in the agent'smlocked memory; the page carries a revocable handle with a TTL. A keyed HTTP device keeps its key in a secure element / runtime secret, never a file. - Read-only where it should be. A device that only needs the clock/identity reads the public endpoint or the region's read-only registers — no credential at all.
- Roadmap —
/dev/zeq. A character device (FUSE/kernel) for hardware-grade, kernel-enforced isolation of the region is the next step; the file/tmpfs region is the safe default today. See MMIO-ARCHITECTURE.md §8.
See also
- The MMIO connection architecture — the full design.
- ZeqReactor — drive a sealed, environment-driven loop from the device.
GET /api/zeq/mmio— the live manifest + registers · zeq-mmio.h — the C header.