Project
Identity โ the pup, not the box
Your Pup ID โ a key that is you rather than your server. It signs papers for your badges, carries you to a new box in pup.json, and is what a Handler will collar. How it is kept, sealed, moved and retired, and what its signatures do and do not say.
On this page
Tip
New to the Pup ID or packs? Start with Pup ID and packs, explained โ what they are, and why you might want them.
What ships now
The Pup ID is built: the key, sealing it under a passphrase, seal-at-rest, the recovery
sheet, papers for every badge, pup.json, restoring a whole bundle, and moving between
boxes โ and, with Packs, collars and countersignatures. Handles are not
built yet.
The idea
A Pup ID is a key that is you. The instance is a place a pup plays; the key is who is playing. It signs the papers for your badges, it is what a Handler's collar will bind, and it moves with you when the box does not.
Make it on the Pup ID page (linked from the header chip and from Settings โ System). Until you do, nothing changes: the game works exactly as it always has.
The rules that do not move
- The key is the pup, and nobody else ever holds it. It is never escrowed and never regenerated. Losing your box must not lose your pup; losing your key is losing your pup โ and the app says so at the moment the key is made, not at the moment it is gone.
- Badges are stored; papers are signed claims about them. A badge is a row, frozen at the moment it was won โ its evidence, its module, its XP โ and never revoked. A paper is your signature on "I earned this, then". Arriving somewhere new never mints: papers you bring are shown as papers, and the new box's badges start empty.
- A paper is only as strong as who signed it, and it says who. Your own signature is your own word, shown as your own word. The app never implies more than the signature carries โ the word verified does not appear anywhere papers are shown.
- Identity never depends on a service. No account anywhere is needed to be a pup.
- The journal is not the identity. Moving your pup takes the key, the profile, the papers, and the kit and photos you mark to travel. Prose travels only inside the full backup.
- Your AI never witnesses you. A local AI Handler runs on your box, under your key. Anything it signed would be you signing twice, so it signs nothing โ your papers stay self-signed while only an AI handles you.
Making it
The page asks for a name and what you are making the key as โ a pup, a Handler (a person), or an AI Handler (for an AI kennel's own box). That is your own declaration: it is signed into everything the key signs, nobody checks it, and it can never change. An AI identity can never become a pup.
This key IS your pup
If you lose this box and your passphrase and your recovery sheet, your pup is gone. Nobody can recover it โ not the app, not the person who wrote it, not a Handler. Your volume backups contain this key in plain form unless you turn on seal-at-rest.
Its fingerprint (four groups of four, AZMI-BDUF-ZSBR-PHGU) is what you read aloud to a
Handler to check you are talking about the same pup.
Two keys, and only one is you
| Box key | Member key (your Pup ID) | |
|---|---|---|
| Answers | which box is this | which pup is this |
| File | identity/instance.key, made on first pack use |
identity/pup.key |
| Leaves the box | never | only sealed: pup.key.enc, inside pup.json and the bundle |
| Signs | the envelopes a pack's messages travel in | papers, pup.json, the box binding, collars |
| If lost | the next pack sync binds a new one | the pup is gone |
A box binding is your member key's signed statement that you are on this box, with an
epoch that only ever climbs (max(now in ms, the last one + 1, whatever a den has seen + 1)),
so a box restored from an old bundle โ or the same bundle restored twice โ always binds above
what came before. A move is a rebind, not a new pup.
Key custody
- The file.
identity/pup.key(mode 0600, in a 0700 directory) holds the seed. Your volume backups and snapshots contain this key in plain form unless seal-at-rest is on. The Pup ID page warns if either file is readable by anyone else. - The sealed copy. Setting a passphrase (at least 12 characters) writes
identity/pup.key.enc: the seed under scrypt (n = 2ยนโท, r = 8, p = 1) and AES-256-GCM, bound to your did, your kind and those parameters. That sealed copy โ never the plain key โ is whatpup.jsonand the backup zip carry. Changing the passphrase needs the current one โ and it re-seals the copy on this box only: apup.jsonor backup zip you already made still opens with the old passphrase, and a recovery sheet needs none. If one of those leaked, your key leaked; there is no key rotation yet. - Seal-at-rest. Keeps only the sealed file on disk: the plain file is zero-overwritten and
deleted, and the key is held in memory until the app restarts โ then it waits,
locked, for your passphrase. It needs a seal first (the passphrase form asks twice; this one asks once, and deleting the plain file under a mistyped word would lose the pup), and the passphrase you give here must open it. On a hosted instance your key lives on the host's computer: seal-at-rest keeps it off the host's disk and backups, but the host runs the app that holds it and receives your passphrase โ a hosted Pup ID is only as private as the host. - The recovery sheet. Your key written out by hand (
LATCH2-โฆ, groups of four, with check digits that catch a mistyped group). It needs a seal and its passphrase to print, is shown once and never stored, and anyone holding it holds your pup. It is used only to arrive โ on a fresh box, or back onto a box that lost its key. - Wrong passphrases. Every try costs the box a fifth of a second of hard work, so one box takes one try at a time (a second, while the first is being checked, is refused at once) and, after five wrong ones in a row, makes you wait โ a second, then two, doubling up to a minute. A right one clears the count; restarting the app forgets it.
- No escrow. There is no "sign in to recover", not ever. This is the one place the app must not be helpful.
Key states
| State | Means | What to do |
|---|---|---|
| none | no Pup ID on this box | make one, or arrive |
| ready | the key is here and matches | nothing |
| locked | only the sealed copy is here (seal-at-rest after a restart, or a restore without the passphrase) | unlock on the Pup ID page |
| missing | this box knows your did and has no key for it | bring the key home: arrive your pup.json or recovery sheet right here (Arriving) |
| mismatch | the key file (or its kind) is not the did this box expects | put the right file back, or restore your bundle onto a fresh box (a restore never goes onto a box holding a key file) |
| moved | this box was retired โ another box holds this pup (the banner says since when, and which box when it knows) | bring it back, if you mean to |
Every signature fails closed unless the state is ready โ and while you are packing to move
(below). Anything that cannot be signed is simply not sent; nothing is signed with a key that
is not yours. A state other than ready puts an amber banner on every page.
Papers
Every badge you hold gets a paper on the next tick: your key's signature on the badge's title, icon, period, frozen evidence, XP, the module that awarded it, and the instant it describes. A kit badge names the item by its travelling uid, never by its name. The trophy case is Pup ID โ Papers.
- A paper's id is the sha256 of what was signed, so re-signing an identical claim is the same paper, and a countersignature added later never changes which paper it is.
- Its serial counts up per box. A pup running on two boxes at once could reuse a serial; the ids stay unique.
- Undo does not touch a paper. It is a record of what was true when it was signed โ the same promise a stamped photo makes. Badges are never revoked, so neither are papers.
- Papers brought from another box are your history: shown under Brought with you, counted toward nothing here โ not XP, not rank, not your badges, not a share card.
- Papers signed by an earlier Pup ID โ a backup restored without its key, then a new Pup ID
made or arrived on that box โ stay, under Signed by an earlier Pup ID. They are never shown
as your word and never travel in
pup.json; every badge you hold gets a fresh paper from the key the box holds now. (A name a Handler gave the old key with their collar does not carry over to the new one either.) - A summary paper is a dated table of figures, as signed; not recomputed.
pup.jsoncarries a lifetime one.
What a countersignature says
With packs, a Handler can countersign a paper. Read it for exactly what it says:
- on a collar paper, attests: party โ "I am the other party to this collar";
- on a badge or summary, attests: in window โ "this is dated inside my collar", not "I saw it happen". A summary lists which of its figures the Handler checked against their own records.
A signer's kind is their own signed declaration โ "Sir signed that they are a person", "Byte signed that it is an AI Handler". It is attributable (a lie is signed) and never verifiable. A did that has signed both is shown as disputed, and nothing is ever silently marked bad: a signature that does not match reads "read this as unsigned".
Stray and collared
Stray โ no Handler. Every paper is your own word. This is not a lesser state; most pups are
strays most of the time. Collared (with packs) โ a Handler's collar, and papers from inside
it may carry their countersignature. The header chip says which: ๐พ stray, ๐ Sir,
๐พ stray ยท ๐ค your AI.
A collar that ended is not a collar that never happened: its papers stay. (The level-one rank is runt, so stray means only the social state.)
Moving to a new box
Moving is explicit:
- Prepare to move (Pup ID page). Everything that talks to anyone else โ packs, your AI, papers, bindings โ stops, so nothing is signed twice from two boxes. Your own game keeps working, the emergency key included. Cancel any time.
- Take your pup: the whole game (
bundle.zip, restored withpython -m latch.restore), or just the pup (pup.json, arrived on the new box).pup.jsoncarries no pack: each den keeps your membership through this box and refuses a join from the new one until it lets go of this one, so leave your packs before you prepare โ the Pup ID page and the export page name every pack apup.jsonwould leave behind, with a link to leave each. The bundle keeps your packs. - Once your pup is alive on the new box, Retire this box: its plain key is zero-overwritten and deleted; the sealed copy stays. It refuses while no sealed copy exists โ this box would be holding the only one โ and it asks for your passphrase, which must open that sealed copy: the proof that the copy the new box relies on works, before this box lets go of the plain key. A retired box records no fingerprint of where you went (it cannot know). It is no longer "packing": it has moved โ Cancel is gone, and bringing it back is the only way home. While you are packing, and once this box is retired, a Handler's, a pack's or your AI's command is refused as paused โ and one sent meanwhile never lands afterwards: not after Cancel, not after bringing the pup back, and not on a box restored from a bundle made while packing (the record of when you were away rides the restore).
- Bring my pup back to this box (passphrase and a tick) undoes a retire and bumps the binding epoch, so every den re-binds to it.
With packs, a den that has seen your key on a newer box answers the old one with that box's binding, signed by your own key โ and the old box retires itself. If there is no sealed copy to keep, it does not shred the key; it stops signing and says, in red, that your key was copied. An unsigned "you are gone" from a den never changes anything.
Two exports, two jobs
bundle.zip โ the whole game |
pup.json โ your pup |
|
|---|---|---|
| For | moving everything, restoring a machine | arriving on your own new box with your identity |
| Key | pup.key.enc when you set a passphrase |
the sealed key โ required |
| Log, reflections, prose | every table, verbatim | never |
| Badges | rows and papers | papers only; the new box's badges start empty |
| Kit | everything | toys and gear marked ๐งณ, owned or retired โ no notes, no prices, no text fields |
| Photos | the originals | photos marked ๐งณ, re-encoded (no location, no camera details, no caption) |
| Grants, packs | yes โ and paused on restore | no |
pup.json holds your sealed key โ never hand it to anyone
Not a Handler, not a pack, not a support thread. Whoever has it and your passphrase is your pup. It is for arriving on your own box. A papers-only file to show other people is future work.
Arriving
On a box with no Pup ID, the Pup ID page takes your pup.json and its passphrase โ or your
recovery sheet alone and a new passphrase, typed twice, to seal it there. A box whose key went
missing takes its own key back the same way, and nobody else's: only the key comes home,
with any papers the box lacks. The game on that box stays exactly as it is โ its kit, its photos
and its profile are its own, so a toy you deleted there after making that pup.json stays deleted.
It checks everything
before it writes anything: the file's signature under its own did before the key is tried,
the key against the passphrase (and its kind against the file's), every paper against your key,
every photo's hash and size before the image decoder sees its pixels. A countersignature that
does not check out is dropped and said so; the paper stays yours. A name "given by" a Handler
arrives only with a collar paper that Handler countersigned over that very collar โ and the
name shown as the giver is the one the Handler's collar paper carries, never one the file adds.
The photos are decoded and written before the database is touched (a box full of photos never
holds up your emergency key while it works); the key files are written last, and together with
everything else or not at all.
It never mints: one Arrived from another box line in the log, no XP, no badge, no counted photo. Carried kit does not count toward the kit-collection badges. Carried photos show on their item and under What travels, and may travel again.
Not built yet
- Handles (a Matrix, fediverse or Bluesky name attached to the key, proven once, revocable) โ planned. The key is never derived from a handle.
- Pup key rotation after a compromise, and a papers-only file for others.
Questions, answered
- A paper when the event under it is undone later? The paper stands, dated โ see above.
- More than one identity? One key, one pup, one box: a second persona is a second pup with its own box, and the app is not the thing that links them.
- Is a lost key recoverable? No, loudly, at generation โ with the optional recovery sheet.
- Do papers expire? Never. They are dated; a reader can weigh an old one.
- Whose papers does the trophy case show? Yours. A pack-mate sees only what you grant, paper by paper.
- Does a pup name themselves, or does a Handler? Both, and the record keeps who: a name you were given (with a collar) is kept apart from one you picked, and choosing your own clears it.
The consent rules in The spirit of the game and in Packs outrank everything here.
This page also ships inside the app, at /guide โ so your own instance always serves the guide for the version you are running, with the internet unplugged. Get Latch ยท Something wrong here? Tell me.