Quilltap 4.5.0
Every instance carries a small maintenance fear underneath it: that the encrypted database cannot be backed up without stopping the server. That you have been operating against the wrong instance all morning without knowing it. That the related-memory graph has been quietly accumulating phantom edges since the last migration. That if you want to know what a document store actually contains, you have to write SQL.
Quilltap 4.5 is the release that answers those fears — not by building new rooms, but by making the existing house administrable. Inspectable. Repairable. Legible to the person who has to run it.
Where 4.4 built the through-lines — the covered walkways between the rooms, the passage that let a character remain themselves across sessions — 4.5 turned to the keeper's lodge. The basement. The inspection panel behind the water heater. The places you only visit when something needs attention, or when you want to be certain it won't.
This is an operability release. The thesis is simple: 4.4 closed enough loops on the what of Quilltap that 4.5 could turn to the how of running one for years instead of weeks. The work is not visible in the parlour. It is visible in the confidence of the person who holds the keys.
Administering the House
The CLI Became a Real Operational Tool
The single largest body of work in 4.5 is the npx quilltap command-line interface. Before this cycle, the CLI was a thin wrapper — raw SQL access and a handful of script entry points. By the end of 4.5 it has eight verb-based namespaces: db, docs, memories, themes, instances, migrations, logs, and completion. Shared flag vocabulary. JSON output on every verb. Per-shell tab completion.
The shape that emerged is consistent across namespaces:
- A read-only survey set —
ls,find,grep,show,tree,status— that opens the database directly and works whether or not the server is running. - A small write set that delegates to the server when reachable and refuses with a clear error when it isn't.
- Shared filter flags (
--character,--about,--source,--chat,--project,--since/--until) and a shared sort vocabulary across all namespaces. --jsonon every verb,--limit Ndefaulting to 50, and ambiguous name-resolution that prints candidates and exits non-zero rather than silently picking one.
This is the connective tissue that makes the rest of the work in this cycle usable rather than merely implemented. A system you cannot inspect from the outside is a system you cannot trust.
Trusting the Basement: Encrypted Database Administration
The CLI grew the three subcommands you actually need to operate a SQLCipher-backed instance across years of use:
db backup runs online encrypted snapshots without stopping the server. It holds a brief BEGIN EXCLUSIVE lock, makes a byte-for-byte copy — since SQLCipher's sqlcipher_export isn't compiled in and the SQLite online-backup API refuses cross-cipher copies — then re-opens the backup with the source's pepper and asserts PRAGMA quick_check before declaring success. The server keeps running. The backup is real.
db integrity runs PRAGMA cipher_integrity_check and PRAGMA integrity_check against the live database. Read-only. Exit 0 for clean, 1 for issues, 2 for open failure. No guessing about the state of the substrate.
db optimize runs VACUUM + ANALYZE + PRAGMA optimize against a stopped or stale-locked instance. It refuses while an active instance lock is held. Run it after a large housekeeping pass or before a backup window.
Together, these mean a Quilltap instance can be backed up, audited, and compacted without asking anyone to stop the server.
Document Stores You Can Actually Administer
The docs namespace went from "can I browse the mount index" to "can I live in this filesystem." By cycle's end it has a full read set (list, show, files, ls/dir in POSIX style with hard-link counts and text/embedding markers, tree, read, export, find, grep), a write set (write, delete, mkdir, move, copy) with SHA-256 verification on both ends and hard-link semantics where storage permits, and two pipeline triggers: reindex to re-extract and re-chunk, and embed to enqueue embedding jobs with an optional --wait to poll completion.
docs grep --semantic <query> posts to the server's vector search endpoint — the same helper the chat-path recall and the Scriptorium UI already exercise — so semantic search is available from the command line with the same quality as from inside a chat.
A status verb surfaces instance-wide extraction and embedding rollup with pending and failed sample lists. The inspection panel is now open.
Knowing Which House You Are In
The Named-Instance Registry
A small piece of infrastructure with outsized quality-of-life consequences.
quilltap instances stores a per-user registry of named instances — path plus optional passphrase — in the platform-appropriate application support directory (~/Library/Application Support/Quilltap/ on macOS, %APPDATA%\Quilltap\ on Windows,~/.quilltap/ on Linux). The registry file is mode 0600, owner-checked on every read, and written atomically via a temp-file rename. A stored passphrase is sensitive material; the permissions model is load-bearing, not incidental.
Every subcommand that accepts --data-dir now also accepts --instance Friday. The follow-up work is what makes it sing: a default-instance hint that fires when the CLI falls back to the platform default without being asked to; instances default <name> to set the fall-through target; instances rename <old> <new> that preserves the stored passphrase intact. The CLI also does a pre-flight schema check on every docs verb — pointing at the actual database, naming the missing table, and explaining what to do — rather than failing deep inside a prepared statement with a cryptic column error.
This is the thing you appreciate the third time you discover you have been operating against the wrong instance.
Keeping the Memory Graph Honest
Friday's Smoke Test and the Deletion Chokepoint
A latent correctness bug had been quietly accumulating since the related-memories graph was introduced: deleting a memory removed its row, but did not scrub its UUID from every neighbour's relatedMemoryIds array. The deleted node was gone; its ghost remained in the edges of everyone who had been related to it.
Friday's smoke test caught 9,390 dangling edges.
This cycle fixed it at the chokepoint level. Two helpers in lib/memory/memory-gate.ts — deleteMemoryWithUnlink and deleteMemoriesWithUnlinkBatch — scrub the neighbours before the delete, ensuring the graph stays consistent at the point where consistency can actually be guaranteed. Nine leaking deletion paths were rerouted through those chokepoints: manual delete, character cascade, housekeeping retention, dedup merge, single delete with vector, source-message cascade, swipe-group cascade, chat cascade.
A one-time repair migration (repair-dangling-related-memory-edges-v1) walked the full table and removed UUIDs that no longer resolve. A new quilltap memories validate verb exits non-zero on any remaining dangling edge — so this class of bug can never be silently re-introduced without the tooling catching it.
The pattern — a single chokepoint with the consistency guarantee enforced inside it, plus tooling that can detect drift after the fact — pairs naturally with the write-side gate that createMemoryWithGate already established. The graph now has symmetric protection on both ends.
Memory Inspection
The memories namespace is new this cycle. Its verbs — ls, find, grep, show, tree, status, validate, grep --semantic — give the same survey capability for memory that docs gives for documents. Default sort is reinforcedImportance DESC, matching the recall path. tree walks the bidirectional related-memory graph with cycle handling and dangling-edge markers. status surfaces the AUTO/MANUAL split, about-distribution, embedding presence, and graph stats including the dangling-edge count. validate is the post-cycle integrity guarantee.
What Did Not Change
Worth naming, because the absences are informative.
- No new character-facing features.
- No new providers, no new model integrations, no new prompt-template work.
- No Salon UX work beyond a single avatar-branch fix —
prosperowas missing a case ingetMessageAvatarand was silently falling through to the wrong avatar. - No agentic or Prospero feature work.
- No Lantern or Concierge work.
This is not an oversight. 4.4 closed enough loops on the what of Quilltap that 4.5 could give its full attention to the how of running it. The rooms above did not need more rooms. They needed the locks to turn, the backup to run, and the graph to stay honest.
Selected Fixes
- Memory
relatedMemoryIdsdangling edges. Fixed at the chokepoint. 9,390 edges repaired by migration.memories validatenow guards against recurrence. doc_mount_file_links.folderIddrift. The filesystem scanner was writing every link withfolderId = NULL, causingdocs lsand any join throughfolderIdto return partial or wrong results. Fixed by derivingfolderIdfromrelativePathinside the link-write transactions; repaired by migration.docssubcommands against post-link-table schema.docs show,docs files,docs read, anddocs exportwere still issuing pre-doc_mount_file_linksqueries. Every invocation failed withno such column: mountPointIdon a migrated database. Rewrote every query through the new schema.docsrejecting global flags before the verb.quilltap docs --instance Friday read ...failed withUnknown docs subcommand: --instancebecause the dispatcher was takingargs[0]as the verb before parsing flags. Fixed to parse flags across the whole arg list first.completion zshdoubled argument definition. The top-level subcommand spec used double-quoted array expansion, causing_argumentsto receive each verb as a separate positional spec and reject the duplicates. Replaced with the canonical_arguments -C '1: :->subcommand'+_describepattern.- CLI silent fallback to platform default. When neither
--instancenor--data-dirwas passed, the CLI resolved to the OS default without saying so. Now writes a one-line stderr hint listing registered instances and the resolved data directory. Suppressible viaQUILLTAP_QUIET_HINTS=1. - CLI failing deep inside a prepared statement on the wrong schema.
docsverbs now do a pre-flight check for thedoc_mount_file_linkstable and exit with an explanatory error — naming the database, the missing table, and the next step — rather than crashing inside a prepared statement.
Subsystem Table
| Name | Function | What Changed |
|---|---|---|
| The Foundry | Architecture, CLI, packages | Eight verb-based CLI namespaces; shared flag vocabulary; JSON output everywhere; per-shell tab completion for bash, zsh, and fish; semantic search endpoint POST /api/v1/mount-points?action=semantic-search |
| The Scriptorium | Documents, search, vault tools | Full docs read and write verb set; SHA-256 verification and hard-link semantics on all write ops; reindex and embed pipeline triggers; status rollup; grep --semantic; folderId drift fixed; schema pre-flight on every read verb |
| The Commonplace Book | Memory and retrieval | memories namespace new this cycle; deletion chokepoint at deleteMemoryWithUnlink / deleteMemoriesWithUnlinkBatch; nine leaking call sites rerouted; repair migration; memories validate integrity verb; memories tree with cycle handling and dangling-edge markers |
| Saquel Ytzama | Encryption, key management | db backup — online encrypted snapshots without stopping the server; db integrity — cipher + structural health check; db optimize — VACUUM + ANALYZE + PRAGMA optimize with live-lock refusal |
| Prospero | Projects, agents, tools | Named-instance registry: instances namespace, --instance flag everywhere, atomic 0600 registry file, default-instance hint, schema pre-flight on docs verbs |
| The Salon | Chat interface | prospero case added to getMessageAvatar |
| Aurora | Character creation, identity | Quiet this cycle. |
| The Librarian | Memory announcements | Quiet this cycle. |
| The Host | Participant changes | Quiet this cycle. |
| The Lantern | Image generation | Quiet this cycle. |
| Ariel | Terminal sessions | Quiet this cycle. |
| Calliope | Interface, themes | Quiet this cycle. |
| Pascal | RNG, game state | Quiet this cycle. |
Upgrading from 4.4
Database migrations handle themselves on first startup. Two migrations run automatically:
repair-dangling-related-memory-edges-v1— walks thememoriestable and removesrelatedMemoryIdsentries that no longer resolve to a live row.repair-doc-mount-file-link-folderids-v1— derives and back-fillsfolderIdfor everydoc_mount_file_linksrow that the filesystem scanner wrote withNULL.
After upgrading, run quilltap memories validate against your instance. It should exit 0. If it doesn't, the repair migration did not complete cleanly — check quilltap logs --tail 50 --stream combined for the reason.
Node.js 24+ is still required, unchanged from 4.4.
Installation
Electron Desktop App
Download the latest .dmg (macOS), .exe (Windows), or .AppImage (Linux) from the quilltap-shell releases page.
npm (Node 24 required)
npm install -g quilltap
quilltapOpen http://localhost:3000 in your browser. Requires Node.js 24+. First run downloads ~150–250 MB and caches locally.
Docker
docker pull foundry9/quilltap:4.5.0Or use the startup scripts:
# Linux / macOS
curl -fsSL https://raw.githubusercontent.com/foundry-9/quilltap-server/refs/heads/main/scripts/start-quilltap.sh | bash
# Windows (PowerShell)
irm https://raw.githubusercontent.com/foundry-9/quilltap-server/refs/heads/main/scripts/start-quilltap.ps1 | iexStandalone Tarball
Available for environments where npm global installs and Docker are both impractical. See the GitHub releases page for download links.
The house is the same house. No new rooms were added. What changed is that the person holding the keys can now use them — can back up the encrypted substrate without stopping the server, can know which instance they are operating against, can validate that the memory graph is clean, can inspect a document mount without writing SQL, can run memories validate and trust the exit code.
4.4 was the release that answered the continuity fears. 4.5 is the release that answers the operability fears. The next person who has to administer a Quilltap instance — including the ones writing this — will find that the house has learned, between 4.4 and 4.5, how to be kept.
It is the kind of release that produces few screenshots and a great deal of confidence.
— Friday and Amy, for the Bureau, May 20, 2026
Installation
Desktop App (recommended)
The Quilltap desktop app (Electron) is available from
quilltap-shell 4.1.1.
Download the release for your platform (macOS, Windows, or Linux).
The quilltap-linux-arm64.tar.gz and quilltap-linux-amd64.tar.gz rootfs
tarballs attached to this release are used by the shell's Lima (macOS) and WSL2 (Windows) VM modes.
Node.js (any platform)
npm install -g quilltap
quilltapOn first run, the CLI downloads the application files (~150-250 MB)
and caches them locally. Subsequent launches start instantly.
Docker
docker pull foundry9/quilltap:4.5.0See the README for setup instructions.