Skip to content

Quilltap 4.5.0

Choose a tag to compare

@csebold csebold released this 21 May 02:25
· 2537 commits to main since this release

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.
  • --json on every verb, --limit N defaulting 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.tsdeleteMemoryWithUnlink 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 — prospero was missing a case in getMessageAvatar and 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 relatedMemoryIds dangling edges. Fixed at the chokepoint. 9,390 edges repaired by migration. memories validate now guards against recurrence.
  • doc_mount_file_links.folderId drift. The filesystem scanner was writing every link with folderId = NULL, causing docs ls and any join through folderId to return partial or wrong results. Fixed by deriving folderId from relativePath inside the link-write transactions; repaired by migration.
  • docs subcommands against post-link-table schema. docs show, docs files, docs read, and docs export were still issuing pre-doc_mount_file_links queries. Every invocation failed with no such column: mountPointId on a migrated database. Rewrote every query through the new schema.
  • docs rejecting global flags before the verb. quilltap docs --instance Friday read ... failed with Unknown docs subcommand: --instance because the dispatcher was taking args[0] as the verb before parsing flags. Fixed to parse flags across the whole arg list first.
  • completion zsh doubled argument definition. The top-level subcommand spec used double-quoted array expansion, causing _arguments to receive each verb as a separate positional spec and reject the duplicates. Replaced with the canonical _arguments -C '1: :->subcommand' + _describe pattern.
  • CLI silent fallback to platform default. When neither --instance nor --data-dir was 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 via QUILLTAP_QUIET_HINTS=1.
  • CLI failing deep inside a prepared statement on the wrong schema. docs verbs now do a pre-flight check for the doc_mount_file_links table 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 the memories table and removes relatedMemoryIds entries that no longer resolve to a live row.
  • repair-doc-mount-file-link-folderids-v1 — derives and back-fills folderId for every doc_mount_file_links row that the filesystem scanner wrote with NULL.

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
quilltap

Open 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.0

Or 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 | iex

Standalone 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
quilltap

On 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.0

See the README for setup instructions.