State Contracts
A state contract is a state machine that lives inside your machine.
You define it in JSON — states, transitions, conditions, and the operator that executes each transition. You deploy it to your machine. Then it advances in one of two ways: you drive it with POST /api/chain/:slug/contracts/:id/transition, or it drives itself — a transition can carry a trigger (a recurring HulyaPulse tick, a cron schedule, an inbound event, or an aggregate over a window) plus pre_actions / post_actions (call an external API before computing; emit an event or override state after).
On every transition the framework runs the operator through the master equation, verifies the proof, wraps the result in a ZSP envelope, writes the transition to contract_transitions, updates current_state, appends a row to your audit entangled state, and mints a tally token. Every step — driven or autonomous — is atomic, signed, on the entangled state, and reproducible.
The shape of a contract
States are named regimes (one initial, any number terminal). Transitions move between them, gated by an operator and an optional condition. This is a real catalogue template — force-threshold-alarm, the classic structural-load watchdog (NM19, F = ma):
{
"name": "force_threshold_alarm",
"version": "1.0",
"created_by": "ZEQ07491829374",
"states": {
"idle": { "initial": true },
"watching": {},
"alert": {},
"cleared": { "terminal": true }
},
"transitions": [
{ "from": "idle", "to": "watching", "operator": "KO42", "proof_required": false, "auto": false },
{ "from": "watching", "to": "alert", "operator": "NM19",
"condition": "input.mass_kg * input.acceleration_ms2 > input.force_limit_n",
"proof_required": true, "auto": false },
{ "from": "alert", "to": "watching", "operator": "NM19",
"condition": "input.mass_kg * input.acceleration_ms2 <= input.force_limit_n",
"proof_required": true, "auto": false },
{ "from": "alert", "to": "cleared", "operator": "KO42",
"condition": "input.acknowledged == true", "proof_required": false, "auto": false }
],
"observers": [], "audit_clock": true, "zeqond_tick_rate": 1
}
Validated by ContractDefinitionSchema.parse and validateContractDefinition (shared/api-core/src/lib/contractEngine.ts). The operator id on each transition must exist in the live registry. KO42 is the always-on substrate operator; the physics operators (NM19 here) carry proof_required: true so each fire is compute → prove → verify.
The condition grammar
Conditions are evaluated with a safe-eval subset — no function calls, no arbitrary property access. The grammar:
expr := or
or := and ('||' and)*
and := comp ('&&' comp)*
comp := term (('==' | '!=' | '<' | '<=' | '>' | '>=') term)?
term := factor (('+' | '-') factor)*
factor := primary (('*' | '/') primary)*
primary := number | string | bool | null | identifier | '(' expr ')'
identifier := [a-zA-Z_][a-zA-Z0-9_.]*
Identifiers resolve from a flat scope built at transition time: the values you pass in body.input (e.g. input.mass_kg), the compute result, contract state (current_state, contract_id, name), framework time (zeqond_now, phase_now), and caller identity (caller_zid). There is no eval, no Function, no DOM, no network — the evaluator walks an AST and rejects anything outside the grammar at deploy time.
The template catalogue
GET /api/contracts/templates returns the live catalogue. Each template ships with a complete definition, a use_cases summary, and the operator sequence it is tested against — and deploys as-is, schema-identical to the canonical create path.
The catalogue is operator-triggered physics machines: states are real regimes, transitions fire when a verbatim operator (≤0.1% precision, NIST-bound) crosses a declared threshold, and every fire is proven on the entangled state. It spans 40+ domains — Mechanics, Quantum, Relativity, Energy & Grid, Structural Engineering, Medical, Seismology and more — plus a domain-agnostic Foundations set.
curl -sS https://zeqapi.com/api/contracts/templates/categories
curl -sS https://zeqapi.com/api/contracts/templates?category=Foundations
curl -sS https://zeqapi.com/api/contracts/templates/force-threshold-alarm
Foundations — the universal primitives
Most templates are domain monitors. The Foundations category is different: domain-agnostic building blocks that drive the autonomous engine. Customise the thresholds, intervals, event names, and external API to your own domain.
| ID | What it does | Engine feature it shows |
|---|---|---|
scheduled-compute | Self-firing transition every N Zeqonds (or a cron expression); emits scheduled_tick each fire | recurring trigger |
threshold-monitor | Generic watchdog over a reading stream; breaches on the windowed average, with hysteresis | on_aggregate (avg) + emit |
oracle-feed | Polls a registered external API every N Zeqonds, binds the response, emits a signed datum | recurring + api_call pre-action |
approval-workflow | pending → approved on N sign-off events, or → rejected on a single reject | on_aggregate (count) + on_event |
A few representative domain monitors, for shape:
| ID | Category | Use case |
|---|---|---|
force-threshold-alarm | Mechanics | NM19 (F = ma) per reading → alert when force crosses your limit |
sla-monitor | Operations | Availability vs SLO → breach → escalate, every breach Zeqond-stamped |
earthquake-early-warning | Seismology | P-wave amplitude gate → warn before the S-wave arrives |
Triggers — make a contract autonomous
A transition with no trigger waits for you to drive it. A transition with a trigger fires itself. Six kinds:
kind | Fires when | Key fields |
|---|---|---|
recurring | Every every_zeqonds ticks, or on a cron schedule | every_zeqonds or cron (+ cron_tz), max_fires? |
one_shot | Once, at a wall-clock Zeqond | at_zeqond or at_unix |
on_event | An emitted event lands | event, from_slug?, where?, into? |
on_events | 2–4 events combine (any / all) | match, events[], within? |
on_logic | A recursive AND/OR tree of events matches | tree, within? |
on_aggregate | An aggregate over a window crosses a bound | event, aggregate{fn,field?}, op, threshold, within |
A heartbeat — a self-loop that fires every 60 Zeqonds and emits an event:
{ "from": "running", "to": "running", "operator": "KO42",
"proof_required": false, "auto": false,
"trigger": { "kind": "recurring", "every_zeqonds": 60 },
"post_actions": [ { "type": "emit", "event": "scheduled_tick" } ] }
The scheduler computes next_fire_at_zeqond at deploy and re-arms after each fire — no external driver needed. (Cron form: "trigger": { "kind": "recurring", "cron": "0 9 * * 1-5", "cron_tz": "Europe/London" }.)
Pre- and post-actions
Each transition can run up to four pre_actions (before compute) and four post_actions (after the audit row commits):
api_call(pre) — call a registered external API and bind the response into the transition input:{ "type": "api_call", "api": "weather", "path": "/current", "method": "GET", "params": { "q": "London" }, "into": "wx" }.emit(post) — append an event other contracts can react to (optionally on a labelled bus):{ "type": "emit", "event": "over_limit", "payload": {}, "tag": "alerts" }.set_state(post) — override the runtime state, last matchingwhenwins:{ "type": "set_state", "to": "alert", "when": "result.value > 100" }.
Together, triggers + actions turn a contract from a passive state map into an autonomous agent that polls, computes, decides, and signals on the HulyaPulse cadence.
Deploying a contract
From a template — one call (authenticated with your session or machine key):
curl -sS https://zeqapi.com/api/contracts/templates/force-threshold-alarm/deploy \
-H "Authorization: Bearer ${ZSM_KEY}" \
-H "Content-Type: application/json" \
-d '{"slug":"my-machine"}'
Returns 201 with the freshly-created contract row. The handler loads the template definition, stamps created_by = caller_zid, runs validateContractDefinition against the live operator registry, inserts into contracts with current_state = the template's initial state, and (if any transition carries a time trigger) pre-computes next_fire_at_zeqond.
A custom definition — POST your own JSON to the create route. Same validation, same result:
curl -sS https://zeqapi.com/api/chain/my-machine/contracts \
-H "Authorization: Bearer ${ZSM_KEY}" \
-H "Content-Type: application/json" \
-d @force_threshold_alarm.json
From the terminal, contract deploy <json> does the same and round-trips with contract export. From the Workbench, the Contract IDE (/apps/contract-ide/) authors the JSON with a live state-diagram preview, dry-run, and one-click deploy.
Driving a transition
For transitions you advance yourself (no trigger):
curl -sS https://zeqapi.com/api/chain/my-machine/contracts/${CONTRACT_ID}/transition \
-H "Authorization: Bearer ${ZSM_KEY}" \
-H "Content-Type: application/json" \
-d '{
"to": "alert",
"input": { "mass_kg": 1200, "acceleration_ms2": 9.81, "force_limit_n": 10000 }
}'
The engine:
- Resolves the contract and the requested transition (
from = current_state,to = body.to). - Evaluates the condition in the safe-eval. Failure →
400 condition_failed. - Calls the operator:
compute → prove → verify(the prove step runs["KO42", contract_operator]as the entangled state). - Wraps the result in a ZSP envelope.
- Atomically writes a
contract_transitionsrow AND updatescontracts.current_state. - Appends a row to the audit entangled state (
audit_log) with the proof digest. - Mints a tally token.
{
"ok": true,
"new_state": "alert",
"previous_state": "watching",
"proof_digest": "7f...64hex",
"zeqond_number": 2287439213,
"tally": { "tokenId": "uuid", "remaining": 999 }
}
The transition is now durable, replayable, and verifiable.
Reading the audit trail
Every transition lands in two places. The full record:
curl -sS https://zeqapi.com/api/chain/my-machine/contracts/${CONTRACT_ID}/audit \
-H "Authorization: Bearer ${ZSM_KEY}"
returns total_transitions plus the ordered list with proofs, results, ZSP envelopes, and timestamps. The compact entangled-state row (just hashes + Zeqonds) is in /api/chain/:slug/explore filtered by transition_type: "contract".
Verifying the entangled state
A standalone integrity check:
curl -sS https://zeqapi.com/api/chain/my-machine/contracts/${CONTRACT_ID}/verify \
-X POST \
-H "Authorization: Bearer ${ZSM_KEY}"
walks every successful transition and checks that each row's from_state matches the previous to_state, terminating at current_state:
{ "ok": true, "valid": true, "broken_at": null, "current_state": "alert", "total_transitions": 1, "zeqond_number": 2287439299 }
This is independent of entangled-state-level PoHC validation. PoHC validates the entangled state (no row tampered); contract verify validates the state progression (no transition out of order). Both must pass for a contract to be trusted.
When transitions fail
| Status | error | Cause |
|---|---|---|
400 | Missing 'to' state | request body lacked to |
400 | No transition: X → Y | the definition doesn't allow current_state → body.to |
400 | condition_failed | the safe-eval returned false |
400 | INVALID_INPUT | a required input is missing or has the wrong type |
403 | forbidden | caller lacks the operator role |
404 | contract_not_found | the contract id isn't owned by this slug |
503 | compute_failed | the operator sequence hit a runtime error in compute / prove / verify |
Failures are still recorded in contract_transitions with success: false and the error message — every attempt is on the audit trail, even the rejected ones.
Next
- Triggers + the scheduler — the autonomous engine that fires recurring, cron, and event-driven transitions on the HulyaPulse cadence.
- Protocols — protocols — the operator/API primitives a contract's operators compose.
- Tally tokens — tally-tokens — the receipt minted on every successful transition.
- 7-step protocol — seven-step-protocol — what KO42 + the operator does inside the engine.
- Operators — operators — the verb on each transition.
- Worked example — Thermal router — a poll → compute → emit contract, end to end.