Saltar al contenido principal

Custom protocols

A protocol in framework vocabulary is anything that wires the outside world to a state contract. Today that means two things you can register yourself:

  1. External APIs — a named, slug-scoped reference to a third-party HTTP endpoint that any of your state contracts can call.
  2. Hyperagents — a state-machine-with-an-agent that you spawn, give a job to, and let run with its own ZID, balance, and entangled state.

Triggers themselves (every, on_event, on_aggregate, cron, on_logic, on_events) are exhaustive enough that you can express most flows without inventing a new kind. If you genuinely need a new trigger primitive, that's a framework PR — but in practice it's almost never necessary because the existing primitives compose.

External APIs

You register an API once. After that, every state contract on your machine can reference it by name in pre_actions or post_actions.

The workbench has an APIs tab — open it from any /s/<slug>/ page → workbench drawer → APIs. Or call the endpoint directly:

curl -X POST https://zeqapi.com/api/zeq/external-apis \
-H "Authorization: Bearer zeq_ak_<your-key>" \
-H "Content-Type: application/json" \
-d '{
"name": "weather",
"base_url": "https://api.openweathermap.org/data/2.5",
"auth_header": "Authorization",
"auth_value": "Bearer YOUR_OPENWEATHER_KEY",
"rate_limit_per_minute": 60
}'

What the framework gives you for free:

  • Encryption at rest. auth_value is encrypted with AES-256-GCM before it touches disk. No plaintext credentials in the database, ever.
  • Rate limiting. If your contract fires faster than rate_limit_per_minute, the framework queues and paces the calls so you don't get rate-limited by the upstream.
  • Retries with backoff. Failed calls are retried with exponential backoff; the final outcome is recorded on the entangled state.
  • Audit. Every call appends a row to your machine's entangled state — request digest, response status, duration, charge. Replayable forever.

Using an API from a state contract

In any contract's pre_actions or post_actions:

{
"transitions": [
{
"trigger": { "kind": "every", "every_zeqonds": 600 },
"pre_actions": [
{
"kind": "api_call",
"api": "weather",
"path": "/weather?q=London&units=metric"
}
],
"operators": ["KO42", "NM23"],
"post_actions": [
{ "kind": "set_state", "state": "last_temperature" },
{ "kind": "emit", "event": "weather_received" }
]
}
]
}

The api: "weather" reference is resolved against your machine's APIs registry at fire time. If you swap the underlying URL or rotate the auth value, every contract keeps working — they don't hold the URL or the secret, just the name.

Hyperagents — protocol as a full state machine

A hyperagent is the protocol surface taken to its limit: instead of registering one endpoint, you spawn an entire agent that runs continuously, ticks on the HulyaPulse, holds its own ZEQ balance, owns its own entangled state, and reports back through the explorer.

curl -X POST https://zeqapi.com/api/zeq/agent/spawn \
-H "Authorization: Bearer zeq_ak_<your-key>" \
-H "Content-Type: application/json" \
-d '{
"master_id": "<your-slug>",
"purpose": "Watch BTC price drift across 5 exchanges, emit divergence_detected when σ > 0.5%",
"starting_zqt": 2000,
"operators": ["KO42", "CS47"]
}'

What you get back:

{
"agent_id": "<uuid>",
"zid": "ZEQAGT07924797856",
"slug": "zeqagt07924797856",
"wallet_balance": 2000,
"chain_url": "/state/?slug=zeqagt07924797856",
"first_tick_zeqond": 2289379201
}

This is a real state machine. It shows up in /state/?slug=zeqagt07924797856. You can talk to it through the Pulse (its Pulse). You can read its entangled state, watch its balance, kill it (POST /api/zeq/agent/kill), or promote operators it derives back into the catalogue.

The agent's behaviour is controlled by its purpose plus the operators you give it. Internally it spawns its own state contracts to satisfy the purpose — those contracts use the same DSL you'd use directly, but the agent maintains them. If the agent runs out of ZEQ it pauses gracefully; you can top it up and it resumes.

When protocols are sealed

Three things you cannot extend at runtime today:

  1. New trigger kinds. The DSL's trigger union is closed: every, cron, on_event, on_events, on_logic, on_aggregate. Adding a new kind requires a framework PR.
  2. New action kinds beyond api_call / set_state / emit. Same — closed union, requires a PR.
  3. New CSP allowlist entries. The site-host CSP is framework-controlled.

For 1 and 2, the existing kinds compose. on_logic with arbitrary boolean trees of on_events and payload predicates can express almost any "fire when X happens" pattern. set_state + emit covers almost any "do Y after compute" pattern.

For 3, the workaround is hosting the page elsewhere and embedding the Pulse — the Pulse's CSP is its own surface.

Next

Continue to Wiring to a state machine to put a custom operator and a custom API into the same contract.