On the server
- AES-256-GCM ciphertext
- 384-dimension vectors, computed before upload
- HMAC-SHA256 hashes of keywords
- Agent tag, timestamps, layer, and session id, in plaintext
Security
Encryption happens before upload. The server stores ciphertext, lossy vectors, and keyword hashes. It does not receive the passphrase.
The design assumes the server, and anyone who copies the database, will try to read stored memories. They should not be able to. A full copy of the ciphertext, the vectors, and the keyword hashes is not enough to recover the text or the passphrase.
It does not assume the computer that holds the passphrase is hostile. On Grok Bot that computer is the bot’s host. Anyone who can read or administer that host can read the passphrase and, with the ciphertext, the memory.
The current VS Code extension is a different path. It keeps the passphrase in VS Code secret storage, then sends the passphrase and the note text to the API. The worker in this repository does not read or store that header, but the passphrase still leaves the machine. Do not treat that extension as zero-knowledge. A save can upload a short note of the file. It does not upload git history.
Encryption also does not stop a bot you trust from writing a bad memory. Research on agent memory shows that a poisoned write can steer later answers. Two papers:
Retayn does not send memories to an AI model. The bot you use decrypts on its own computer and may put a recalled line into its own prompt. That step is the bot’s.
The client normalizes the passphrase with NFKC. It mixes a 16-byte random salt with the prefix retayn-zk-v1, then runs PBKDF2-SHA-256 for 600,000 iterations. The output is 64 bytes: 32 for AES-256-GCM and 32 for HMAC-SHA-256. Each message uses a new 12-byte nonce. The stored blob starts with a version byte, then the nonce, then the ciphertext and the GCM authentication tag.
The 16-byte salt is stored on the account so the same passphrase derives the same keys later. It is write-once. The salt is not a key. On the Grok Bot plugin and the client SDK, the server does not receive the passphrase or the derived keys. Lose the passphrase and the ciphertext stays unreadable. There is no recovery.
Layers are episodes, facts, and artifacts. A code note or tool output can be stored as an artifact. On the client SDK, the server still only sees that item’s ciphertext.
Search runs two ways. Vector search uses the 384-dimension embeddings. Keyword search tokenizes on the client, drops common stopwords, and stems English words with a simplified Porter stemmer. Each stem is HMAC-SHA256 hashed, so the server can match a term it cannot read. The two lists are fused with reciprocal rank fusion. The query text is not stored.
Each account has its own vector index. Stored objects sit under a namespace derived from the account id. Another account’s key does not read them.
The API key is stored as a SHA-256 hash. It identifies the account. It does not decrypt memory. A copy of the database, without the passphrase, is still ciphertext for data written by the client SDK or the Grok Bot plugin.
On Grok Bot the passphrase is created once on the bot’s computer. Retayn never receives it. The host of that computer can. Treat the host as trusted, and Retayn as not.
The dashboard and POST /v1/wipe delete the index, the ciphertext, and the keyword index. Deletion cannot be undone. Account deletion requests can also go to [email protected]. Stored data is deleted within 30 days. Details are in the privacy policy.