New service
Using The Armory
How to use Zipper’s warrant mesh: create an app, sign someone in, spend a write cartridge, mint the next one. Spent warrants, hatch-bound sessions, musters, kit, and the roll — not a JWT farm.
Cloudflare analogue: Firebase Auth + Firestore (skill map only)
What this is
The Armory is a backend for iOS, Android, and the web that lives on this Zipper node. It is not Firebase, not a JWT farm, not FCM, and not Kubernetes.
You create an app, copy two keys, sign a person in, then send a warrant with every read or write. A write warrant is a spent cartridge: one fire, then mint another.
Words
These names are the product. Map them once, then the API reads plainly.
- ▸App — One backend for one product. Creating it prints an endpoint, an anon key, and a service key (once).
- ▸Anon key (za_anon_…) — Public key for the device or browser. It can sign people in. It cannot skip rules.
- ▸Service key (za_svc_…) — Server-only key. It opens every rack. Never put it in an IPA, APK, or public JS.
- ▸Session (za_sess_…) — Proof that a person signed in. It is bound to the Origin that minted it (the hatch).
- ▸Warrant (zw.…) — Permission to use one rack. A write warrant is a spent cartridge: it fires once, then you mint another.
- ▸Hatch — The browser Origin. A session minted at https://app.example stays there. Native apps omit Origin.
- ▸Muster — A named bag of sealed documents (like a table). Rules fail closed: public write is refused.
- ▸Kit — Uploaded files. Palace Guard scans bytes before they persist. Hostile kit returns 422.
- ▸Roll — Live events on this Zipper process as SSE. Not FCM, not APNs, not a world bus.
- ▸Spend Receipt (zr.…) — World-first: every spent write returns zr.… — a signed proof of what fired, on which hatch, chained to the audit head. Not a JWT. Verify with POST /receipts/verify.
- ▸Warrant Peel — World-first: attenuate a read warrant into a one-shot peel scoped to one muster. First list/get/look spends it — like a spent cartridge for reads.
- ▸Roll Witness — World-first: every Roll SSE event carries an HMAC witness. POST /roll/witness to prove the live event came from this node.
- ▸Vault Seal (zv.…) — World-first: service key mints zv.… — a notarized hash of the sealed vault for compliance. No blockchain. POST /seal/verify.
- ▸Zipper AI design — Optional prompt at create-app time. Designs musters, seed rows, and Scrolls on this node. Not a global schema migrator.
- ▸Hook — Outbound HTTPS POST on writes. Registered with the service key. Signed with X-Armory-Signature. SSRF-guarded egress.
- ▸Rack — One duty in the twenty-container mesh (identity, records, kit, …). Docker isolates them when ARMORY_MESH=docker.
- ▸Hatch URL — The live door for this app: /hatch/{name}. Same data as REST. Bind your website Origin here.
- ▸Wire — One POST /wire door: { do: "who" | "look" | "put" | "charge" }. Same warrants. Easier than many REST paths.
- ▸Look — A query: POST /look with { muster, where }. Returns only rows this warrant may see.
- ▸Scroll — A small function you write in the dashboard and charge from the app. It can who() and look(). Not a Worker isolate.
- ▸Devbook — Generated docs for this app: GET /docs, /openapi.json, /llms.txt. Always matches the live musters and scrolls.
Five steps
Work top to bottom. After step 3 you have a stored row. After step 4 you can write again.
- ▸1. Create an app Dashboard → Services → The Armory → Create app. Pick a kit. Paste your web origin if the client is a browser. Copy the endpoint, anon key, and service key. The service key is shown once.
- ▸2. Sign a person in POST https://tinyzipper.com/api/v1/armory/{id}/auth/signup with X-Armory-Key: za_anon_… and { email, password }. The JSON includes access_token, warrants.write, and warrants.read.
- ▸3. Write once POST /musters/{name} with Authorization: Bearer za_sess_… and X-Armory-Warrant: zw.… The write warrant is spent. A second use returns spent_cartridge.
- ▸4. Mint the next write POST /warrants with the session and { "verb": "write", "rack": "records" }. Keep the read warrant for GET /musters/{name}.
- ▸5. Stay on this hatch Browsers must send the same Origin that minted the session. Native apps omit Origin. A browser cannot replay a native session.
- ▸6. Fetch who you are GET /who (or POST /wire { "do": "who" }) with the session. That is the signed-in person. Use it for a profile screen.
- ▸7. Fetch rows (Look) POST /look with a read warrant and { "muster": "events", "where": { "title": "gate-up" } }. Service key can list people with GET /people.
- ▸8. Charge a Scroll Write a Scroll in the dashboard (who_am_i and look_first ship with a kit). POST /scrolls/{name} with a warrant. That is your “function”.
Kits
A kit plants musters so you can write on day one. Pick watch unless you already know you need lists or chat.
- ▸Watch — events — owner writes, signed-in users read. Incident logs, audit trails, “what just happened” feeds.
- ▸Roll — presence — owner writes, signed-in users read. Who is here on this node. Pair with GET /roll/presence.
- ▸Todos — todos — owner reads and writes. Private lists. Only the signed-in owner sees their rows.
- ▸Chat — rooms (signed-in read/write) and messages (owner write, signed-in read). Small rooms on this node. Fan-out is SSE here, not a world bus.
- ▸Blank — none until you POST /musters with the service key. Start empty and name your own musters.
Headers
Every client call uses some of these. The service key never leaves your server.
- ▸X-Armory-Key — za_anon_… on the device, or za_svc_… on the server.
- ▸Authorization — Bearer za_sess_… after sign-in.
- ▸X-Armory-Warrant — zw.… from signup or POST /warrants. Required on musters, kit, and roll.
- ▸X-Armory-Device — Optional stable device id. Binds the warrant to that device.
- ▸Origin — Required for browsers. Native clients omit it.
Copy-paste
Replace APP_ID and the keys printed at create-app. Signup returns warrants.write — spend it once.
Sign up
curl -sS -X POST https://tinyzipper.com/api/v1/armory/APP_ID/auth/signup \
-H "X-Armory-Key: za_anon_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"email":"you@example.com","password":"long-password"}'Spend a write warrant
curl -sS -X POST https://tinyzipper.com/api/v1/armory/APP_ID/musters/events \
-H "X-Armory-Key: za_anon_YOUR_KEY" \
-H "Authorization: Bearer za_sess_YOUR_SESSION" \
-H "X-Armory-Warrant: zw.YOUR_WRITE_WARRANT" \
-H "Content-Type: application/json" \
-d '{"data":{"title":"gate-up"}}'Mint the next write
curl -sS -X POST https://tinyzipper.com/api/v1/armory/APP_ID/warrants \
-H "X-Armory-Key: za_anon_YOUR_KEY" \
-H "Authorization: Bearer za_sess_YOUR_SESSION" \
-H "Content-Type: application/json" \
-d '{"verb":"write","rack":"records"}'Who am I
curl -sS https://tinyzipper.com/api/v1/armory/APP_ID/who \ -H "X-Armory-Key: za_anon_YOUR_KEY" \ -H "Authorization: Bearer za_sess_YOUR_SESSION"
Look (query)
curl -sS -X POST https://tinyzipper.com/api/v1/armory/APP_ID/look \
-H "X-Armory-Key: za_anon_YOUR_KEY" \
-H "Authorization: Bearer za_sess_YOUR_SESSION" \
-H "X-Armory-Warrant: zw.YOUR_READ_WARRANT" \
-H "Content-Type: application/json" \
-d '{"muster":"events","where":{"title":"gate-up"}}'Wire charge a Scroll
curl -sS -X POST https://tinyzipper.com/api/v1/armory/APP_ID/wire \
-H "X-Armory-Key: za_anon_YOUR_KEY" \
-H "Authorization: Bearer za_sess_YOUR_SESSION" \
-H "X-Armory-Warrant: zw.YOUR_READ_WARRANT" \
-H "Content-Type: application/json" \
-d '{"do":"charge","scroll":"who_am_i","body":{}}'Live URLs and generated docs
Every app has two doors on this node: REST /api/v1/armory/{id} and a live hatch /hatch/{name}. They share the same sealed state.
GET /hatch/{name}/docs is the Devbook for that app. OpenAPI is /openapi.json. Machine brief is /llms.txt. Those pages always match the musters and Scrolls you wrote in the dashboard.
Dashboard coding (Scrolls)
Inside the app you can write Scrolls — small functions your client charges. who() is the signed-in person. look(muster) returns rows this warrant may see. Keep Scrolls short. They are not Worker isolates.
A kit plants who_am_i and look_first so a mobile or web client can prove reads on day one. Add your own Scrolls when you need a query that is not a simple look.
Web profile
A Next.js site needs the signed-in person and their events.
- Create an app. Paste the site Origin as the hatch.
- Sign up from that Origin. Store access_token and warrants.read.
- GET /who for the profile. POST /look for events. Charge look_first if you want one round-trip.
iOS / Android
A Swift or Kotlin client has no Origin header.
- Omit Origin on signup so the hatch is native.
- Keep za_anon_ in the app. Keep za_svc_ on your BFF.
- GET /who, POST /look, POST /scrolls/who_am_i. Do not later call the same session from a website.
When it refuses
Fail-closed is the product. These codes are expected, not outages.
- ▸need_warrant — The data plane did not see X-Armory-Warrant. Sign in, then send warrants.write or mint one.
- ▸spent_cartridge — That warrant already fired (write or peel). POST /warrants for a new write cartridge, or attenuate a new peel.
- ▸muster_scope — Warrant is scoped to a different muster. POST /warrants/attenuate with the muster you need.
- ▸hatch_mismatch — Origin does not match the session hatch. Call from the same origin, or mint a native session without Origin.
- ▸fail_closed — Public write is refused. Use owner or user write rules. Service key to create musters.
- ▸cordon — Palace Guard held JSON string fields. Remove hostile content. EICAR in a field is refused.
- ▸quarantine — Palace Guard held a kit upload. Do not persist that file. Scan locally first.
- ▸rev_conflict — PATCH rev does not match the stored muster. GET the row, then PATCH with the current rev.
- ▸denied — Fail-closed rules blocked the actor. Sign in as the owner, or use the service key on the server.
Honest limits
The roll is SSE on this Zipper process. It will not wake a phone via FCM or APNs.
Twenty Docker racks isolate duties on this Global Server node. They are not a Kubernetes replica set.
Zipper does not send email. Recovery tokens are returned to your backend for you to deliver.
What it takes: an Armory app, the anon key on the device, the service key only on your server, and a hatch Origin for websites. Web: fetch the hatch URL from the same Origin that signed in. iOS/Android: omit Origin. Never ship za_svc_ in an IPA or APK. Every look/put/charge sends X-Armory-Warrant. A write cartridge fires once. Mint another. Live is SSE on this node, not FCM. This hatch is a Zipper Global Server node. It is production HTTP (fail-closed, sealed, spent warrants). Plan quotas cap users and rows here.
Next: The Crown · All docs · Create a free account