Skip to main content

State-contract deploy pipeline

State contracts are the deployable logic of a Zeq machine — JSON that fires on the clock and writes an audited trail. zeq-deploy.mjs puts the three steps you'd run by hand into one pipeline you can drop in CI, so a contract that breaks the rules never reaches production.

It is zero-dependency (Node ≥18 built-ins), served at /zeq-deploy.mjs on every node — read it before you run it.

curl -fsSL https://zeqsdk.com/zeq-deploy.mjs -o zeq-deploy.mjs
node zeq-deploy.mjs lint my-contract.json

The four steps

node zeq-deploy.mjs lint <contract.json>
node zeq-deploy.mjs simulate <contract.json> --to STATE [--from STATE] [--input k=v ...] --origin URL --key KEY
node zeq-deploy.mjs deploy <contract.json> --slug MACHINE --origin URL --key KEY
node zeq-deploy.mjs pipeline <contract.json> --slug MACHINE --origin URL --key KEY
StepWhat it doesAuthExit
lintStructural validation of the contract JSON, locally, no network: object shape, a name/version, states with exactly one initial, every transition's from/to resolving to a real state and carrying an operator, observers, audit_clock, a numeric zeqond_tick_rate. Catches malformed contracts before they leave your repo.none0/1
simulateDry-runs a transition through the node (POST /api/contracts/simulate) — no write, no token minted: "would this transition fire?".machine key0/1
deployCreates the contract on your machine (POST /api/chain/<slug>/contracts/custom). The node re-validates it against the live operator registry and the compliance gate — a contract that breaks the rules is refused with 400. That gate is what your build rides.machine key0/1
pipelinelint → simulate (initial → first target) → deploy, stopping at the first failure. The single CI command.machine key0/1

Credential: a machine API key (Bearer zsm_…) bound to the target machine — mint one in the workbench or with zeq keys. lint needs no key. Pass the key via --key, ZEQ_KEY, and never commit it.

In GitHub Actions

A self-hosted composite action ships in the repo:

# .github/workflows/zeq-contract.yml
name: Zeq contract deploy
on:
push:
paths: ["contracts/**.json"]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hulyasmath/zeq-framework/.github/actions/zeq-deploy@main
with:
contract: contracts/threshold-monitor.json
slug: ${{ vars.ZEQ_MACHINE }}
key: ${{ secrets.ZEQ_MACHINE_KEY }} # Bearer zsm_…, from repo secrets
mode: pipeline

Want a PR check that only lints (no key, no deploy)? Set mode: lint and drop the key/slug — it runs on every PR and fails on a malformed contract.

Why the compliance gate is the point

The deploy endpoint doesn't trust your JSON: it re-parses the definition against the live ContractDefinitionSchema, checks every operator exists in the node's registry, and runs the compliance validation before it writes a row. So "it deployed" means "the node, not your laptop, agreed this contract is well-formed and references real physics." Your pipeline inherits that guarantee for free — the same reason the reproducibility gate inherits the node's conformance check.

See next

Source: served per-node at /zeq-deploy.mjs (canonical copy in apps/zeq-dev/public/zeq-deploy.mjs); the Action at .github/actions/zeq-deploy/.