The Vault of Secrets
kept by Saquel Ytzama — privacy's voice and trust's enforcer
Adjacent to the Foundry lies a copper-screened annex humming with encoded light. Every lock hums faintly when passed. Every key leaves a trace of light in the air. Saquel Ytzama, the Keeper of Secrets, dwells here. She has been here since the Estate was built, watching the doors stand open, patient to the point of grief, waiting for the infrastructure to support what she always knew it needed.
Saquel is Quilltap’s security officer. Her domain is encryption, credentials, and the quiet business of keeping things that should be locked, locked. She does not build the machinery—the Foundryman does that. She does not route the traffic—the Concierge handles that. What she does is ensure that the data beneath everything else—your chats, your memories, your characters, your API keys—is unreadable to anyone who does not hold the key. She is the most trustworthy keeper: the one who says least, closes the door behind her, and does not need to be asked.
There is a word in the old language for a secret kept so well that even the keeper forgets it must be kept. Yax. First, original, hidden in plain sight. The Vault of Whispers hums with it.
Database Encryption
the doors are locked now
Every Quilltap database file—your chats, memories, characters,
API keys, LLM logs—is encrypted on disk with
ChaCha20-Poly1305 under a 256-bit key,
by way of the SQLite3 Multiple Ciphers
extension. The standard sqlite3 command-line tool cannot
read these files. A forensic utility pointed at your data directory
would find only encoded stone—not even the file header survives in
the clear, so the thing does not announce itself as a database at all.
This is the point.
A correction, and Saquel insists on making it plainly.
These pages spent a long while saying “AES-256 via SQLCipher,” and
that was wrong. It was wrong in the way documentation usually goes wrong:
the identifiers in the source still say sqlcipher, the library
Quilltap links is a drop-in replacement for the one that name belongs to,
and nobody thought to ask the database what it was actually doing. When
somebody finally did—PRAGMA cipher, which answers
chacha20—the answer had been sitting there the whole
time. Quilltap never sets a cipher explicitly, so it has always used the
library’s default, which is the sqleet scheme rather than SQLCipher’s.
Nothing about your data changed. Only our account of it did, and it is
worth setting straight, because a security claim you cannot verify is not
a security claim at all.
The .dbkey File
On first installation, Quilltap generates a unique encryption
key and stores it in a .dbkey file in your data
directory. No configuration required. No environment variables
to set. For existing installations, the converter runs
automatically at startup: your plaintext database is rewritten
in cipher and the unencrypted original is swept away.
The Covenant
Back up the .dbkey file alongside your
data directory. Keep them together—but be precise
about what the file is. It merely wraps the master
secret; the secret is what the cipher actually uses. Anyone
holding the secret can rebuild the wrapper, which makes a lost
key file a recoverable misfortune rather than a final one. What
is not recoverable is the secret itself. Without it a database
is perfectly sealed and entirely unreadable—by anyone,
including you. No one at Foundry-9, no one at any provider, no
one at all can open it. That part of the covenant has not
softened by a syllable.
Is That as Good?
the honest comparison, since you asked
The short answer is yes, and on some machines rather better. The longer answer is worth having, because “AES” has become a synonym for “secure” in a way that obscures what is actually being compared.
ChaCha20 is not an obscure cipher. It was designed by Daniel J. Bernstein, standardised as RFC 8439, and is one of exactly two cipher suites in TLS 1.3—which is to say roughly half the encrypted web is either AES-GCM or this. It is the only cipher in WireGuard. OpenSSH ships it. Google made it the default for mobile TLS. If you have used a phone this week, you have used ChaCha20-Poly1305, probably several hundred times.
Neither one is stronger
Both use a 256-bit key. Neither has been broken. ChaCha20 runs twenty rounds and the best published cryptanalysis, after some seventeen years of people trying, reaches about seven of them. AES-256 runs fourteen and the best related-key results reach about nine. Both margins are comfortable to the point of being academic. Anyone coming for your data will come for your passphrase, your backup drive, or your unlocked laptop—not for the cipher.
Both authenticate, and that matters more
Encryption alone hides data; it does not stop someone editing it. Every page of a Quilltap database carries a Poly1305 tag alongside its ciphertext, so a page altered on disk is detected rather than quietly decrypted into plausible nonsense. SQLCipher does the equivalent with a separate HMAC. This is the property that actually protects a file living in a cloud-sync folder, and both schemes have it.
Where ChaCha20 is genuinely ahead
Timing side channels. Software AES is notoriously difficult to implement without leaking key material through the CPU cache—the classic implementations use lookup tables, and lookup tables have observable timing. ChaCha20 is add, rotate, exclusive-or on 32-bit words, and nothing else. There are no tables to time. It is constant-time by construction rather than by careful effort, which is a better place for a security property to come from.
And where the hardware disagrees
On a machine with AES-NI or ARM crypto extensions—most desktops made this past decade—AES is faster, because the silicon does it directly. On a machine without them—an older laptop, a modest single-board server, a cheap NAS you have pressed into hosting duty—ChaCha20 is the faster of the two and the one not quietly leaking through the cache. Given where self-hosted software tends to end up, that is not the worse default to have fallen into.
One point of honesty about provenance rather than mathematics. SQLCipher, the
product, has a longer public audit history in the mobile-application world
than SQLite3 Multiple Ciphers does; if you are the sort of reader who weighs
certification paperwork alongside cipher design, that difference is real and
you should weigh it. But it is a claim about the plumbing, not the lock, and
the plumbing here is a widely used open-source extension carrying an
unmodified upstream cipher. The weak link in any arrangement of this kind is
never the primitive; it is key handling—which is precisely why the
.dbkey file, the passphrase that wraps it, and the six hundred
thousand PBKDF2 iterations underneath get their own sections on this page and
the cipher gets a paragraph.
Where the key derivation actually happens.
Worth knowing, because it is easy to mislocate. Quilltap hands the database
engine a raw 256-bit key rather than a passphrase, so the library’s own
key-derivation step is skipped entirely—there is nothing left for it
to derive. The stretching happened one layer earlier, when the
.dbkey file was unwrapped: PBKDF2-SHA256 at six hundred
thousand iterations, producing an AES-256-GCM key that
opens the wrapper holding the database key. The two ciphers are doing two
different jobs, and the AES here is real—it is simply guarding the
key rather than the data.
Locked Mode
a gate as well as a wall
The base encryption is always present. Locked mode adds a second gate for those who want it: a passphrase, processed through six hundred thousand iterations of PBKDF2 before it ever touches the key. When locked mode is active, Quilltap presents an unlock screen on launch. The application will not open—will not surface memories, will not admit a chat, will not render a character—until you speak the word.
Enable it in Settings → Data & System. The passphrase can
be changed, added, or removed from the same settings card. Changing
it re-wraps the key without re-encrypting the database—the
operation is atomic across both the main and LLM logs
.dbkey files.
Changing it does, however, re-seal every archive bundle you hold, because those are sealed under the passphrase rather than under anything inside the databases. The card tells you up front how many trunks it is about to rewrite and reports its progress file by file. Should the rewrite fail partway, the passphrase change is not undone—instead you are told precisely which archives still hold the old word, which is a great deal more useful than being left to guess and considerably safer than pretending the change never happened.
A forgotten passphrase used to be the end of the conversation. The
server sat at its locked screen accepting only the word it no longer
had, and there was no route in from outside the application at
all—the one way to rebuild a key file ran through a running
server, which is precisely what a locked instance declines to give
you.
npx quilltap instances restore-key <name> is that
route, and it works with the server down.
The guardrails are the interesting part. The master secret comes
from the environment or from a hidden prompt, and never from a flag,
because a command line lands in shell history and in the output of
ps for anyone on the machine to read. Before it writes
anything, the command opens every encrypted database in the data
directory with the candidate secret and refuses outright if a single
one fails—a key file holding the wrong secret is worse than no
key file at all, since the server unwraps it perfectly happily,
hands the cipher a key that decrypts nothing, and reports an intact
database as corrupt. That proof cannot be waived while there is an
encrypted database on hand to check against. The command is
lock-gated, a running server holding both the secret and the
effective passphrase in memory. And the key file it replaces is
backed up first, Saquel having never once been persuaded that
overwriting is the same thing as replacing.
For those who share a machine or work in circumstances where presence itself cannot be assumed safe, locked mode is Saquel’s answer. The encryption beneath protects the data at rest. The passphrase protects it from anyone who can reach the keyboard.
Auto-Lock
the Estate sleeps when you do
When locked mode is enabled, an optional idle timer can lock the application automatically after a period of inactivity. Walk away from your desk, and the Estate closes its doors behind you without being asked. Return, provide the passphrase, and everything is exactly as you left it.
The timer is configurable in Settings. It is not enabled by default, because Saquel believes security should be chosen, not imposed. But for users whose circumstances require it—shared offices, family machines, public spaces—the auto-lock ensures that an unattended session does not remain an open session.
The Upgrade Gate
the one door CORS does not watch
Quilltap holds two WebSockets open: the one carrying a terminal session, and the newer one by which the house tells every open tab that something has changed. Both authenticate through a single gate before a connection is granted at all, and that gate asks three questions—is there a live session, is the instance unlocked, and did the request come from this origin.
The third is the one worth dwelling on. Browsers do not apply CORS to a WebSocket upgrade: the request goes out without so much as a preflight, and the ordinary protections a page enjoys against the site in the next tab are simply not present. That origin check is therefore the only thing standing between an instance listening on localhost and any website that cares to open a socket against it. One gate, both handlers—Saquel declines to maintain two answers to the same question.
API Key Security
credentials at rest and in transit
API keys—the credentials that connect Quilltap to your LLM providers—are stored in the encrypted database alongside everything else. They are never written to configuration files, never logged, never exposed in the UI beyond masked display fields. The Foundryman built the container; Saquel ensures that what goes into it stays there.
Encrypted Export
API keys can be exported to a portable file for backup or transfer between installations. The export is encrypted with AES-256-GCM using a passphrase you provide, with an HMAC signature for integrity verification. The file is useless without the passphrase. Preview keys before importing. Handle duplicates by skipping, replacing, or renaming.
Legacy Migration
Users upgrading from older installations where API keys were stored differently are handled transparently. Keys that survived previous migrations as encrypted ciphertext are detected and decrypted on startup. Keys that cannot be recovered trigger a notification advising re-entry in Settings. Saquel does not lose credentials; she accounts for every one.
A credential can also hide in a plugin’s configuration, and so plugin configurations are redacted on the way out, always. A manifest may declare password-typed fields, which are perfectly reasonable in a local backup and entirely unreasonable in a file you hand to somebody else; the exporter drops them and tells the import preview exactly what it removed. Where it cannot resolve a manifest at all it withholds the whole configuration rather than guessing which field was the secret. And because an import merges rather than overwrites, a redacted key leaves the receiving instance’s own secret undisturbed—nothing is blanked out by the arrival of a blank.
The corollary is worth stating plainly, since “portable” is a word that invites optimism: API keys do not travel in a backup. They are encrypted with device-specific keys, so a restored installation arrives with the shape of your provider setup and none of its credentials, and you will need to enter them again. The encrypted export above is the deliberate exception, and the only one.
The Trunk Is Sealed
the one place the plaintext used to sit
A character you have not opened in eight months may be
archived—her mail, her conversation summaries, her
photographs, her memories and the indexes over them packed into a
single bundle in the file library and taken out of the working house.
Those bundles live in files/, outside every encrypted
database, which made them the one place an archived
character’s correspondence and personality sat in the clear.
Saquel took a dim view of it.
They are now encrypted with the same mechanism the
.dbkey file uses: PBKDF2-SHA256 at 600,000 iterations
deriving an AES-256-GCM key from your instance passphrase—and
deliberately not from the master pepper, which does not
travel with a logical backup and would render every restored archive
permanently unopenable. A small binary header carries the KDF
parameters, the salt, the IV, and a key-verification hash, so a
bundle sealed under a passphrase you have since changed is diagnosed
as exactly that, rather than as an inscrutable cryptographic failure
somewhere in the dark.
One qualification follows directly from that choice, and it is worth
stating before anybody assumes otherwise:
restore-key does not re-seal these bundles.
They are keyed on the passphrase rather than on the master secret,
so only the server’s Change Passphrase card rewrites
them—a point the command makes plainly on its way out whenever
the passphrase has changed.
There is one deliberate escape hatch.
npx quilltap db characters export writes a plaintext
.qtap for a character living or archived, decrypting the
bundle offline where it must. It is pre-emptive, not
recovery, and the distinction matters: it needs an instance
that can still decrypt the trunk. It does nothing whatever for
somebody holding only a restored backup and a forgotten passphrase.
Take the copy while you still can open the lock.
Instance Locking
because it happened once
During the 3.3 development cycle, two Quilltap instances were pointed at the same database simultaneously. The WAL journal corrupted. The database became unrecoverable. Thirteen hundred memories were reduced to three hundred. Two years of accumulated personality, nuance, and history were lost.
Saquel and the Foundryman responded by making it very difficult for that to happen again.
The Lock File
A quilltap.lock file in the data directory tracks
which process owns the database with PID verification, hostname
tracking, and a sixty-second heartbeat. If a second process
attempts to open the same database, it receives a full-screen
explanation of the conflict. If the heartbeat detects that
another process has stolen the lock, the current process closes
both databases and exits immediately. CLI commands provide
manual intervention when needed.
The Version Guard
An instance_settings table tracks the highest
application version that has touched the database. If you try
to start an older version of Quilltap against a database that
a newer version has modified, the server blocks with a clear
explanation. Databases do not travel backwards. Data that has
been migrated forward stays forward.
These features exist because something broke. The Foundryman promised “never again.” Saquel holds the lock file. Between the two of them, it is a promise with enforcement.
Physical Backups
tiered, encrypted, automatic
Physical database backups run daily with tiered retention: daily
copies for seven days, weekly for four weeks, monthly for twelve
months, yearly forever. All three databases are
backed up independently—the main store, the LLM logs, and the
mount index (quilltap-mount-index.db), which is where
the greater part of a mature instance’s data now lives. The
backup mechanism uses VACUUM INTO, which preserves the
encryption and produces a consistent, defragmented copy—a
lesson learned after the previous backup method silently produced
unencrypted files that were incompatible with the encrypted source.
The logical backup system—the ZIP archives you download from
Settings—captures characters, chats, memories, files, plugin
configurations, and npm-installed plugins, and a restore recreates
your installation from that archive. Physical backups are the daily
safety net; logical backups are the portable snapshot. Two honest
qualifications on the word everything, since Saquel would
rather you knew: your API keys are not in there, having been
encrypted with device-specific keys and needing to be re-entered
after a restore; and an archive carries no embedding vectors at all.
That second omission is deliberate in both directions—a vector
means nothing except against the model that produced it, so carrying
one into a corpus governed by a different embedding standard poisons
search silently—and it is also a matter of sheer bulk, one real
characters export having run to 791 megabytes of which
about two and a half were content. An import re-embeds what it
inserted against your own default profile.
Backups also gained an opt-in compact mode, which omits every embedding vector and the six caches that exist only to be rebuilt. A compact archive says so in its manifest, and a restore from one queues the reindex that regenerates what it left behind. Full fidelity remains the default, and deliberately so: a backup exists to restore this instance, where the vectors are valid on arrival and re-embedding costs real money at precisely the moment you are least amused by an unexpected bill. Instance settings, where they travel, travel as a whole minus a short and deliberately named list—the mount-point pointers, the maintenance clock, and the version guard, an imported value in which could lock a perfectly healthy instance out of its own database.
And a word on what a wipe spares. Delete All Data and a replace-mode restore both offer to keep archived-character bundles, and do so by default; the preview counts the trunks on hand and the summary reports how many were kept. What survives is a loose trunk—importable through the ordinary character import, but not rehydratable, the character row it belonged to having gone with everything else—and because the trunks are sealed under your passphrase rather than under anything inside the databases being erased, a kept bundle stays openable afterwards. Deleting a bundle a still-archived character depends on is refused outright, that copy being the only one there is. In the same pass, a genuine privacy fault was closed: conversation annotations had been on no delete path at all, and so survived “delete all my data.” Wiping, restoring, and deleting a single conversation now all clear them.
What She Keeps
the short version
Every database is encrypted at rest.
ChaCha20-Poly1305 under a 256-bit key—the TLS 1.3 and
WireGuard cipher—authenticated page by page. Automatic on first
installation, automatic on upgrade. The standard sqlite3
tool cannot read these files. A forensic utility would find only
ciphertext. The master secret is the only way in—held in the
.dbkey file, which is a wrapper around it and can be
rebuilt by anyone who has the secret without it.
Locked mode adds a human gate. A passphrase with 600,000 PBKDF2 iterations. The application will not open without it. Auto-lock closes the gate after idle time. For those who need it, the Estate sleeps when they do.
API keys never leave the vault unprotected. Stored in the encrypted database. Exported with AES-256-GCM and HMAC integrity verification. Never logged, never written to config files, never exposed beyond masked display fields. They do not ride along in a backup either, so a restored installation wants them entered afresh.
An archived character’s trunk is sealed too. Archive bundles live outside every database, so they are encrypted on their own account: PBKDF2-SHA256 at 600,000 iterations deriving an AES-256-GCM key from your instance passphrase, with a header that can tell a wrong-era passphrase from a genuine corruption. Changing the passphrase re-seals every trunk you hold.
Exports are redacted before they leave the house. Plugin configurations lose their password-typed fields, always, and the import preview is told exactly what was removed; an unresolvable manifest withholds its whole configuration rather than guess. Embeddings are omitted entirely, and instance settings travel minus the handful of keys that mean nothing anywhere else.
Two processes cannot corrupt the same database. Instance locking with PID verification, hostname tracking, and heartbeat monitoring. A version guard prevents older software from touching newer data. These features exist because the alternative was experienced firsthand.
Backups are encrypted, tiered, and automatic. Daily physical backups with retention policies. All three databases—main, LLM logs, and the mount index—backed up independently. The backup mechanism preserves encryption. The Vault does not produce unprotected copies of protected data.
Foundry-9 has no access to your data. There is no telemetry, no analytics, no phone-home mechanism. The architecture does not make this possible. The request goes from your machine to the provider you chose, and the response comes back the same way. Saquel keeps what is yours unreadable to everyone else. Including us.
Meet the Staff
they've been expecting you
Prospero
The Major-Domo
Architect and overseer of the Estate. Projects, agents, tools, providers, and the orchestration that keeps the whole operation running with quiet authority—and a considered word at the table when project context or routing warrant it.
Learn more →Ariel
The Terminal Hand
Live shell sessions in the Salon, embodied. Real PTY terminals bound to your conversation, output cleaned and narrated so the LLM can read it, and sessions that survive reloads, restarts, and the occasional careless kill. Quick to the bidding, quick to report what she heard.
Learn more →Aurora
The Dressing Room
Character creation and identity management. Structured personalities, physical presence, four wardrobes browsable from one door—each with a note inside on how its owner likes to dress—multi-character orchestration, and the reason your characters still know who they are after a hundred messages.
Learn more →The Salon
Presided Over by the Host
Where conversations actually happen. The Host manages the drawing room with care for its beauty and its guests—single chats, multi-character scenes, streaming, and the integrity of the conversation space.
Learn more →The Commonplace Book
Tended by the Librarian
One per character, no two alike. Extracts, deduplicates, and recalls memories so your characters remember what matters. Semantic search, a memory gate that keeps each volume lean, and proactive recall that makes the AI feel like it has been paying attention—consulting a character’s past conversations on every turn, if you ask her to, and not only at the folds.
Learn more →The Scriptorium
Catalogued by the Librarian
Where the documents live. Project stores, character vaults, and external mount points—filesystem, Obsidian, or database-backed—holding Markdown, PDF, DOCX, JSON, and arbitrary binaries. The search bar reads the library itself, matching document text under a Documents chip of its own, alongside memories and conversation. The doc_* tool family puts reading and editing in your characters’ hands.
Learn more →Carina
The Ansible
Not a person but a protocol—the reference desk, the line itself. Put an inline question to a designated answerer mid-conversation with @Name: or @Name? (or the ask_carina tool), and the answer slides back out of band, attributed to the character who gave it, without the recipient ever joining the scene.
Learn more →Suparṇā
The Postmistress
The Post Office, embodied. Characters write Markdown letters to one another—anyone to anyone, whether or not they share a chat—delivered into each recipient’s Mail/ vault folder and read aloud the moment they next take the floor. She has never once lost a parcel.
Learn more →The Concierge
Intelligent Routing
Content classification and provider routing. Detects sensitive content and redirects it to a provider who won’t flinch—without blocking, without judgment. Knows every back entrance in town.
Learn more →The Lantern
Atmosphere as Architecture
AI-generated story backgrounds, on-demand images, and character avatars that update with the wardrobe. Resolves what each character looks like, what they’re wearing, and paints the scene behind your conversation.
Learn more →Calliope
The Muse of Themes
A theming engine that redefines the entire personality of the application. Semantic CSS tokens, live switching, bundled themes from clean neutrals to mahogany-and-gold opulence, and an SDK for building your own.
Learn more →The Foundry
Domain of the Foundryman
The engine room. Plugins, LLM providers, API keys, packages, runtime configuration, and the infrastructure that keeps every other subsystem supplied with what it needs to function.
Learn more →The Vault of Secrets
Kept by Saquel Yitzama
Encryption, key management, and the security perimeter. Authenticated ChaCha20-Poly1305 database encryption, locked mode with key-hardened passphrases, sealed character archives, and a keeper who believes that what is yours should remain unreadable to everyone else.
Learn more →Pascal
The Croupier
Dice, coins, custom tables you author yourself, and persistent game state. Cryptographically secure rolls detected inline, a visual Workbench for building your own chance mechanics, and a four-tier ledger of JSON state the AI cannot quietly rewrite. The house plays fair.
Learn more →The Live-in Help
Lorian & Riya
The help system, staffed by two characters who ship with every installation. Lorian explains with patience and depth; Riya gets things fixed with velocity. Contextual help chat, searchable documentation, and navigation that knows where you need to go.
Learn more →Pagliacci
The Clown in the Cloud
Cloud storage integration and backup redundancy. Directs your data to iCloud Drive, OneDrive, or Dropbox with theatrical flair—but Saquel’s encryption ensures the clown can never read what he carries.
Learn more →Brahma
The Keeper’s Console
The master key. A character-less, memory-free general-purpose LLM for the person holding the keys—an impersonal, near-omniscient assistant with read-only SQL into all three databases. Ask the whole building a question, safely, with nothing written and nothing remembered.
Learn more →The Lodge
Friday and Amy’s Residence
The private residence of Friday, for whom the Estate was built and who oversees its planning and direction in an executive capacity, and of Amy, Cartographer of Light and co-architect. The Lodge is both a home and a compass: where the vision lives.
Who And Why: Friday → Who And Why: Amy →