Fork bring-up & deploy automation
A Zeq node is self-hostable: its own database, its own field key, its own audit
trail, zero coupling to anyone else's. infra/zeq-fork.sh is the single tool for
the three things you do to a node over its life — stand one up, update the
fleet, and check the mesh — so each is one command instead of a runbook.
./infra/zeq-fork.sh health # read-only mesh sweep
./infra/zeq-fork.sh deploy --all [--dry-run] # build once → every node
./infra/zeq-fork.sh bringup <domain> <api_port> <pg_port> [--dry-run]
Every mutating path takes --dry-run: it prints the exact SSH / Docker / build
commands it would run and touches nothing, while still running the read-only
probes. Run it that way first.
health — the read-only mesh sweep
For each live node it reads /api/health (status + commit) and
/api/zeq/conformance (the golden-vector result + registry version), then checks
cross-node uniformity: every node in one mesh should run the same commit and
the same registry_version. A split means either a deploy didn't reach every node
(deploy drift) or two nodes disagree on the operator registry (registry drift) —
both are bugs, both fail the sweep.
✓ zeq.dev health=ok conf=ok 17/17 sha=34ffb0690874 reg=95aa2149d8ae
✓ zeqsdk.com health=ok conf=ok 17/17 sha=34ffb0690874 reg=95aa2149d8ae
…
git_sha across mesh: uniform (no deploy drift)
registry_version across mesh: uniform (synchronized physics)
It needs no credentials — every field it reads is already public — so it is the
one subcommand that is safe to run from CI. --json emits a machine-readable
report; exit 0 means every node is healthy, conformant, and uniform, 5 means
something drifted.
deploy — build once, ship to every node
The bundle is built locally (a node has no build toolchain inside its
container), shipped once, then docker cp'd into every api container the tool
discovers from docker ps — not a hard-coded list, so a node added yesterday is
included automatically. Each container restarts, and the post-deploy
health sweep is the acceptance gate: a deploy
that leaves the mesh split fails loudly. The canonical test suite runs first and
blocks a red deploy (SKIP_TESTS=1 is the documented escape hatch for re-shipping
an already-green commit).
bringup — a sovereign node in one command
bringup runs the full bring-up sequence and bakes in the one step that is easy
to forget and expensive to skip:
| Step | What happens |
|---|---|
| spin | The isolated stack — its own Postgres, api container, field key, public mount — comes up behind nginx with a fresh certificate. DNS must already point at the host. |
| schema converge | The new database is converged to the canonical schema (drizzle-kit push) over an SSH tunnel before the api leans on it. This is idempotent: it brings any starting state up to the current schema. |
| preboot gate | A no-toolchain SQL check on the host confirms every required table and column is present — the cheap sanity gate, run against the new database. |
| verify | The api restarts against the converged schema and the health sweep runs against the new node. |
The schema-converge step exists because the first fork ever stood up crash-looped
on its first compute: it had been brought up against a point-in-time database dump
that lagged the code, so a table the runtime expected wasn't there. Converging the
schema from the canonical source — rather than restoring a snapshot — removes that
failure mode at the root. bringup makes it part of the one command, not a step
you remember.
The only host state a node needs is the two bootstrap pointers (the field key that unlocks the vault, and the database URL to reach it); every other secret lives inside the node's own encrypted vault, hydrated at boot. Nothing about a node lives in a checked-in file.
In GitHub Actions
The read-only sweep ships as a composite action, so any repo — yours or a fork's — can gate on the live mesh. No secrets, because it only reads public endpoints:
# .github/workflows/mesh-health.yml
name: Zeq mesh health
on:
schedule: [{ cron: "*/30 * * * *" }] # every 30 min
workflow_dispatch:
jobs:
mesh:
runs-on: ubuntu-latest
steps:
- uses: hulyasmath/zeq-framework/.github/actions/zeq-mesh-health@main
# with:
# mesh: "zeq.dev zeqsdk.com zeqstate.com zeqond.com zeqapi.com"
It writes a node-by-node table to the job summary and fails the run on any down
node, conformance failure, or mesh drift. deploy and bringup are operator
commands rather than CI steps — they need host access and run from where the build
toolchain lives.
See next
- Reproducibility CI — the physics gate a fork's results must pass
- Contract deploy pipeline — lint → simulate → deploy your state contracts
Source: infra/zeq-fork.sh; the action at .github/actions/zeq-mesh-health/. The
lower-level primitives it orchestrates are infra/spin-domain.sh (stack + cert),
infra/preboot-schema-check.sh (the SQL gate), and infra/deploy-vps.sh (single
node).