Quickstart: elect one leader.
This flow uses the hosted API and requires no login or API key. Create a random room, share the ID with your processes, and let each one campaign.
ROOM=$(curl -s -X POST https://api.octostore.io/elections \
| jq -r .election_id)
curl -s -X POST \
"https://api.octostore.io/elections/$ROOM/campaign" \
-H "Content-Type: application/json" \
-d '{"candidate_id":"worker-a","ttl_seconds":30}'
A winner gets status: "leader", a monotonic term, and a secret leader_token. Every other candidate gets status: "follower", the current leader, and retry_after_ms.
Account-free leader election.
Election rooms are capability-based, not identity-based. The room ID is a shared coordination address. The leader token is the authority to mutate the current term.
| Method | Path | Purpose |
|---|---|---|
POST | /elections | Generate a 192-bit room ID |
POST | /elections/:id/campaign | Become leader or observe the winner |
GET | /elections/:id | Inspect current public state |
POST | /elections/:id/renew | Extend the current lease with its leader token |
POST | /elections/:id/resign | Release leadership immediately |
Renew at half the TTL
curl -s -X POST \
"https://api.octostore.io/elections/$ROOM/renew" \
-H "Content-Type: application/json" \
-d "{\"leader_token\":\"$LEADER_TOKEN\",\"ttl_seconds\":30}"
Public election TTLs range from 5 to 300 seconds. A candidate can renew indefinitely while it is healthy. If it crashes, the room becomes vacant after expiry and a new term can begin.
Resign on a clean shutdown
curl -s -X POST \
"https://api.octostore.io/elections/$ROOM/resign" \
-H "Content-Type: application/json" \
-d "{\"leader_token\":\"$LEADER_TOKEN\"}"
Durable task locks.
Locks are the authenticated primitive for self-hosted coordination. Give a task a deterministic name, acquire it before side effects, renew while work runs, and release when complete.
export OCTOSTORE_URL=http://localhost:3000
export OCTOSTORE_TOKEN=change-me
curl -s -X POST "$OCTOSTORE_URL/locks/issue-1842/acquire" \
-H "Authorization: Bearer $OCTOSTORE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"ttl_seconds":120,"metadata":"agent=atlas"}'
Lock responses return acquired, held, or delayed. Each successful acquisition includes a lease ID and a fencing token. Lock names may be hierarchical, such as repos/acme/app/issues/1842.
Self-host in one minute.
The release installer verifies the published SHA-256 checksum and binary version before placing octostore in /usr/local/bin.
curl -fsSL \
https://raw.githubusercontent.com/octostore/octostore.io/main/install.sh \
| sh
STATIC_TOKENS='ops:change-me' \
DATABASE_URL='./octostore.db' \
octostore
curl http://localhost:3000/health
The server binds to 0.0.0.0:3000 by default and stores state in one SQLite file using WAL mode. Put TLS and network policy in your existing reverse proxy.
Configuration.
| Variable | Default | Meaning |
|---|---|---|
BIND_ADDR | 0.0.0.0:3000 | HTTP listen address |
DATABASE_URL | octostore.db | SQLite database path |
STATIC_TOKENS | unset | Comma-separated user:token credentials |
STATIC_TOKENS_FILE | unset | Newline-delimited static token file |
PUBLIC_ELECTIONS | true | Enable account-free election endpoints |
MAX_PUBLIC_ELECTIONS | 10000 | Maximum simultaneous public rooms |
PUBLIC_ELECTION_REQUESTS_PER_MINUTE | 600 | Per-client admission limit for room creation and campaigns |
GITHUB_CLIENT_ID | unset | Enable optional GitHub OAuth when paired with the secret |
ADMIN_KEY | unset | Protect admin and metrics endpoints |
Safety model.
- Terms are monotonic across restarts. The next fencing term is persisted before an acquisition is returned.
- Leases recover from crashes. A vanished process stops renewing and loses authority after expiry.
- Election tokens are bearer capabilities. Do not log them or put them in URLs.
- Room IDs are not access controls. Use generated IDs and self-host when room discovery or traffic must be private.
- Election admission is rate limited per client. Status, renewal, and resignation stay available so load cannot strand a current leader.
- Locks are advisory. Downstream systems should be idempotent and reject stale fencing terms where possible.
Full API reference.
The interactive OpenAPI reference covers elections, locks, sessions, webhooks, authentication, health, and admin operations.