The making of Spool

A product-and-engineering account of a local-first project context hub: who it serves, what crosses the network boundary, what an AI may write, and what changed only after the system met real work.

Who it is for

Spool is for people carrying several long-lived workstreams across tools that do not share memory: researchers, graduate students, developers, and people building something alone. The common cost is not “taking notes.” It is having to reconstruct the same project for every new AI conversation — which paper matters, which decision already failed, and what changed since last week.

The product sets a deliberately narrow target: re-entering a project should cost one paste, not an archaeological dig through chats, mail, tabs, and half-remembered decisions. It sits upstream of document tools. A project is a quiet, append-only log, not a collaborative canvas or a replacement for Notion.

Research boundary. The first version was built by dogfooding against the developer’s own multi-project workload. That produced useful reversals, but it is not external user research; validation with other users remains a post-release step.

What the product does

Three verbs form one loop. None of them needs a model in the critical path.

  1. Capture Double-tap Option after copying to file the clipboard with its time and source, while a confirmation overlay accepts the thought that made it worth saving.
  2. Project Keep fragments in a time-ordered log with exactly two levels of structure: Workspace, then Project.
  3. Pack Assemble the current project into deterministic Markdown that can be pasted into any AI client. The same project produces the same bytes on the same day.
An isolated Spool demo capture scene: a browser page remains in place while the Spool confirmation overlay appears in the upper-right corner with the captured source and note field
Capture in the isolated demo build: the source application stays visible while Spool confirms the saved fragment in a corner.

How the three surfaces relate

The desktop interface, MCP server, and CLI engine slot are three local surfaces around one source of truth. The diagram separates “runs on your machine” from “belongs to the Spool process” so the network claim can be inspected rather than inferred.

Spool’s local architecture and three outbound paths The Spool process contains its desktop GUI, capture overlay, Rust and Tauri core, spool --mcp stdio server, and one SQLite database. An external MCP client connects over stdio. The core can spawn Claude Code, Codex CLI, or Gemini CLI as a separate subprocess, and when the API engine is switched on it spawns the bundled spool-ai subprocess as well. Those three programs contact their respective providers over three distinct network paths. No arrow crosses from the Spool process itself to the network. YOUR MACHINE SPOOL · ONE LOCAL BINARY Desktop GUI React · TypeScript Capture overlay global gesture · local window Rust / Tauri core capture · IPC · policy deterministic packer subprocess boundary no HTTP client SQLite one local file single source of truth FTS5 spool --mcp stdio MCP server External MCP client Claude Desktop · Cursor · … Codex in ChatGPT desktop client owns provider connection CLI engine subprocess Claude Code · Codex CLI Gemini CLI · no Follow Up user-installed · user-authenticated API engine subprocess spool-ai · bundled binary off by default · your own key the only socket in the app MCP client’s provider network path 1 · outside Spool CLI’s provider network path 2 · outside Spool The endpoint you chose network path 3 · your own key IPC local SQL stdio · MCP spawn + stdio spawn + stdio NETWORK PATH 1 NETWORK PATH 2 NETWORK PATH 3 Spool’s own process sends no HTTP requests. NETWORK BOUNDARY — ONLY THE THREE ACCENT PATHS CROSS IT
The network boundary is literal, and it is drawn at the process edge rather than promised: the external MCP client, the CLI you logged into, and — once you switch the API engine on — the bundled spool-ai subprocess each contact a provider. Spool’s own process makes no HTTP request and listens on no network port; it has no HTTP client compiled into it at all. The API engine is the one route that holds a key, it is off until you turn it on, and the key lives in the system Keychain rather than in Spool’s settings file.

The GUI and capture overlay communicate with the Rust/Tauri core locally. That core owns one SQLite database. Running spool --mcp exposes the same library over stdio to an AI client; the CLI engine slot instead starts Claude Code, Codex CLI, or Gemini CLI as a separate process. Gemini supports Weekly Review and draft goals, but not Follow Up. The API engine is the third route and the newest: it starts spool-ai, a small binary shipped inside the app that takes one JSON request on stdin, makes one HTTPS call, and writes one JSON envelope back. It refuses plain http://, and the key reaches it only through stdin — never through the command line, where any process on the machine could read it. All three routes preserve the same distinction: what Spool does locally, and what another process does on the network.

The Machine learning course project in an isolated Spool demo library, showing the fixed Workspace and Spool sidebar, numbered timeline blocks, a note used as a title, and the AI client activity rail
One current project surface: fixed navigation and Spool panels on the left, numbered blocks in the log, annotations that can act as titles, and AI client activity on the right.

Privacy and the write boundary

Reading and writing are separate permissions. Content leaves the machine only inside a program the user installed and authorised; the program that crosses the network is named at each path.

PathWhat can crossNetwork client
MCP clientWhat the client explicitly reads from the local stdio serverThe external AI client
CLI engine actionThe project blocks required by the chosen actionClaude Code, Codex CLI, or Gemini CLI; Gemini excludes Follow Up
Anything elseNothingNone
  • AI may append; it may not overwrite. Machine-written blocks carry a server-enforced source label and cannot replace a user-authored block.
  • AI may not borrow the user’s authority. Annotation authorship is stored, so a machine note renders as machine framing rather than as the user’s judgement.
  • AI may propose a correction; the user decides. The original stays visible and searchable. Retiring material is a human action.
A current isolated demo project detail: user-authored block number four followed by block number five, badged Claude · MCP and carrying a citation back to the earlier source
The write boundary in the current build: an attributed Claude · MCP block is appended after the user’s source and cites it; it does not overwrite it or present itself as the user.

Distribution, signing, and notarisation

On macOS, Spool ships directly as a Developer ID–signed, Apple-notarised disk image. The Mac App Store is not the distribution path because sandboxing conflicts with the system-wide capture gesture. The application and the disk image are checked separately: users download the wrapper, so a notarised application inside an unnotarised disk image is not enough. The Windows installer is produced by CI and ships unsigned in this first release — a certificate is a recurring cost against an unproven platform, and pretending otherwise on the download page would be worse than SmartScreen's warning.

Release evidence

v0.4.0 signing and notarisation receipt

App submission
89ebaceb-f883-4b1c-a6eb-86392769d132 Accepted
DMG submission
f7a15d9a-737d-4132-a54e-578d9f41fd7f Accepted
Tagged commit
84625db
Artifact
Spool_0.4.0_aarch64.dmg
SHA-256
933b9a7fb10a25f72cbd922c7c0a1d89fe02ef83b6a3885fba0dc0ec08b7df54
Gatekeeper
accepted · source=Notarized Developer ID · both artifacts

Source: Case Study Ledger §1.2, captured 2026-08-08.

Inspect the release and its assets on GitHub. The website’s stable download URL points to the fixed-name copy published alongside the versioned artifact.

What measurement changed

The case-study ledger records commands and source evidence for every public figure. Two measurements changed product priorities rather than merely describing the finished system.

Deduplication was a one-time recovery

The measured duplicate pair occupied 13% of the pack. Retirement solved the immediate volume problem while keeping the older block in the library and search.

The external write path was discoverable

From one plain-language request, an external client created a project and filed 11 blocks averaging 970 characters. It recovered from 2 errors without help, then used the pack tool to check its work.

A separate live web-search run cost approximately $0.45 and exposed failures that mocks and prompt inspection had not revealed.

Failures that changed the system

The useful unit in a postmortem is not the patch; it is the guard that remains.

The live database was wiped

A development build met a newer live schema and took an unconditional rebuild path. Recovery carved 33 blocks from SQLite free pages, but project titles were gone. The durable changes were fail-closed migrations, a named migration registry with cross-language version checks, automatic pre-migration snapshots, isolated on-device builds, and a rule that first-run seed data is reachable only from an empty database.

A prompt rule failed on its first real run

Follow-up findings required a source URL, yet 2 of 3 proposals omitted it because the model placed links in its closing message. The prompt was made field-specific; the next measured run produced links in 5 of 5 proposals. The standing rule is now simple: text in a prompt is not a behaviour until a real run proves it.

The packaged window was blank while every automated check passed

A state selector allocated a new array on each call and triggered an infinite render. Nothing in the automated suite opened a packaged window. Release verification now includes looking at the isolated signed build; visual health is no longer inferred from compilation.

Boundaries, not promises

  • Two platforms, not equally deep. Windows arrived in 0.5.0 and runs the same library and the same capture gesture, read through Raw Input rather than a keyboard hook. What did not cross over is the macOS-specific work around focus handling and browser-tab source capture, so the Windows build records the source app rather than the page you were reading.
  • No auto-update. A new version is a manual download from the direct release.
  • Source-visible, all rights reserved. The repository has no licence granting reuse.
  • Two checks remain human. The authorised capture gesture sits upstream of synthetic events, and the packaged webview cannot be trusted from synthetic clicks; both are escalated to a person rather than claimed as automated.
  • Spool is not a server, sync service, team workspace, or document editor. It stores one local project log and prepares context for tools the user already chose.

There is no placeholder video. The interactive browser demo walks through the capture → project → pack loop; the screenshots above are from the current isolated desktop build.


Spool is designed and built by Ocean (KIM-ocean-HZ). Source, roadmap, and the full product constitution are on GitHub; reproducible public figures live in the Case Study Ledger.