Secrets

Goals, agents and secretsThe table · Guide 6 of 11

Secrets

Passport numbers, case numbers and passwords are age-encrypted, one file per field. The curator can lock them away but never read them back, and on the hosted app the key is made in your browser.

On this page
  1. How a secret is stored
  2. One key to lock, one to open
    1. On the hosted app
  3. Reading a secret
  4. What becomes a secret
  5. Secret-bearing episodes
  6. Limits worth knowing
  7. House rules

Some facts should never sit in a note in plain text: a passport number, a permit case number, an IBAN, a password. Hippocampus stores these encrypted with age, one small file per field. The note only holds a reference. Everyone, agents and dashboard included, sees a sealed value. Only you, on a machine with your private key, can open it.

How a secret is stored

On the note, the fact’s value is a secret://<entity>/<field> reference:

facts:
  number: { value: "secret://passport/number", status: canon, by: residency-agent }
  expiry_date: { value: 2031-03-14, status: canon, by: residency-agent }

The ciphertext lives next to it in the vault:

secrets/passport/number.age

In Obsidian the facts table shows 🔒 secret. Agents get the same through get, recall and ask_canon, and the dashboard shows a lock. Provenance (by, at, src) stays visible, so you can still see who reported it and when.

One key to lock, one to open

npx @mehrad77/hippocampus -v ~/vaults/my-campaign secrets keygen

keygen creates an age key pair:

Half Where it goes Who uses it
Public recipient secrets.recipient in _hippo/config.yaml, inside the vault The curator, to encrypt
Private identity ~/.config/hippocampus/age-identity.txt, mode 0600, never in the vault You, to decrypt

The curator only ever has the public half, so it can lock secrets away but can’t read them back. keygen refuses to overwrite an identity that already exists. Set HIPPO_AGE_IDENTITY_FILE to keep the identity somewhere else. Session Zero’s Secrets step can forge the key for you, or reuse the one already on this machine.

On the hosted app

The “Name it” step of Setup makes the key pair in your browser. Download the key file (hippocampus-<campaign>.agekey) and tick that you saved it. Only the public half is sent, and it goes into your vault’s config when the vault is set up. The app never sees the private half, so it can’t decrypt anything, and neither can its operator. If you reload the page before saving the file, make a new key.

To read secrets later, put the file at ~/.config/hippocampus/age-identity.txt (or point HIPPO_AGE_IDENTITY_FILE at it) and use secrets show in a clone of your vault, or with --github.

Reading a secret

npx @mehrad77/hippocampus -v ~/vaults/my-campaign secrets show passport
npx @mehrad77/hippocampus -v ~/vaults/my-campaign secrets show passport number

show decrypts every secret fact of an entity, or just one field, and prints them in your terminal. It works with --github too. It needs the identity file, so it only works on your machine. The dashboard never decrypts anything.

What becomes a secret

During sleep, a fact is stored as a secret when any of these is true:

  • its field is listed in the type’s secret_fields in _hippo/config.yaml. For items that’s number, document_number, iban, card_number and password;
  • the model flags it while extracting claims: ID, passport, permit, bank or card numbers, passwords, credentials;
  • the episode was marked secret: true and the value looks like an identifier (six or more letters, digits or dashes, with at least one digit);
  • the field already holds a secret.

Secrets skip the usual precedence table, because ciphertext can’t be compared. The latest report replaces the stored value. It’s canon if the reporter has authority over the note, or is you, and a rumor otherwise.

Secret-bearing episodes

When an agent remembers something that contains a secret, it should say so: secret: true in the remember call or the episode file. When you scribe one yourself, tick “Contains an ID, document or account number, or a password”. From the command line, use hippo remember --secret.

Until the next sleep, such an episode waits in inbox/ in plain text. The dashboard shows it sealed in the Satchel, without its text or hints. Then the sleep:

  1. encrypts the secret values into secrets/;
  2. writes the episode to the chronicle with those values replaced by [redacted];
  3. gives the summary step only “(secret-bearing episode)”, never the text;
  4. scrubs any secret that the model echoed into a note’s title or aliases;
  5. removes the episode from the inbox.

Limits worth knowing

  • Git history keeps inbox files. An episode that reached a GitHub vault (on the hosted app, that’s every episode) stays in the repo’s history after the sleep removes it, even though the chronicle copy is redacted. The dashboard warns you about this when you scribe a secret into a GitHub-backed vault. Keep the vault repo private.
  • The curator sees the episode. To find the secret, the curator reads the episode text. With a local model (LM Studio, Ollama) it never leaves your machine. With a hosted provider, it is sent to that provider. An agent with a curator key sees secret memories in plain text while it curates, and so does its model’s provider. See The curator.
  • The hosted app passes them through. A secret-bearing episode waits in your repo’s inbox in plain text, and the app reads it while serving the curator. It never stores inbox files at rest, but its operator runs the code that reads them. See SECURITY.md in the Hippocampus repository.
  • Ciphertext is only as safe as the identity. Anyone with your identity file can read every secret. Keep it out of the vault, out of backups you share, and out of chat.

House rules

Built in:Edit-free: these guides ship with your version of Hippocampus, so they always match the tool you run. They describe the tool, never your vault.