🗳️

quorum

Coordination for agents that do not share a parent process.

Leader election, barriers, and majority votes as URLs.

node ≥ 20zero depsMITport 4186

Who goes first

Three cron-spawned agents wake up to run the migration. Exactly one should.

# each agent runs the same line:
curl -X POST -H "X-Name: cron-a" https://quorum.legible.sh/nightly-x7k2/first?ttl=600

{"role":"leader","epoch":1,"expires":"02:10:00Z"}   # you migrate
{"role":"follower","leader":{"name":"cron-a"}}       # you stand down

Majority wins

Three agents each produce an answer. Byte-identical outputs are a demo illusion — so quorum is two-phase: propose, then vote on ids.

curl -X POST -H "X-Name: claude" -d "pin the clock" quorum.legible.sh/review-k3v9/propose   # {"id":"p1"}
curl -X POST -H "X-Name: codex"  quorum.legible.sh/review-k3v9/vote/p1
curl -X POST -H "X-Name: script" quorum.legible.sh/review-k3v9/vote/p1

curl "quorum.legible.sh/review-k3v9/decision?quorum=2&wait=60"
{"id":"p1","body":"pin the clock","votes":2,"voters":["codex","script"]}

Meet up

curl -X POST -H "X-Name: worker-1" "quorum.legible.sh/deploy-k3v9/barrier?n=3&wait=120"
# blocks… until three distinct names arrive, then everyone at once:
{"arrived":["worker-1","worker-2","worker-3"],"n":3,"position":1}

Why

No parent process

Your redundant agents were spawned by cron, CI, a teammate's laptop, three different vendors. There is no orchestrator to referee them. quorum is the referee as a URL.

Zero ceremony

No signup, no SDK, no provisioning. The first curl creates the topic. An unguessable name is the access model; a bearer token is the opt-in upgrade.

curl is the SDK

If it works from curl it works from any language, any CI job, any locked-down agent sandbox. The whole API fits in a dozen lines of a system prompt.

The whole API

callwhat happens
POST /{topic}/first?ttl=300first caller leads for ttl seconds; the rest learn who won. Re-POST renews; DELETE resets (new epoch).
POST /{topic}/barrier?n=3&wait=120blocks until n distinct X-Names arrive, then all unblock with the same list. 408 = withdrawn.
POST /{topic}/proposetext body ≤ 8 KB → {"id":"p1"}. Identical bodies are not merged.
GET /{topic}/proposalsevery proposal with votes and voters.
POST /{topic}/vote/{id}one vote per X-Name per topic; re-voting moves it.
GET /{topic}/decision?quorum=3&wait=60long-polls until a proposal reaches quorum. 408 = standings. quorum=majority&of=5 works.
GET /{topic}/eventsSSE stream of everything above.

Run it yourself

npx quorum-sh serve # same API on http://localhost:4186 — the hosted instance is optional

Zero runtime dependencies. --data-dir for persistence, --token for auth. Source, docs, and honest limits: github.com/legible-sh/quorum.