Design decisions
Most of these calls take a lesson from PAI, the personal-AI system imprnt grew out of, and steer the other way. Each one keeps its flips if line in plain view: the single change that would undo the decision.
Ration the model
The model is the expensive part, so imprnt spends it where one pass pays off forever: reading, sorting, tagging and summarizing each item once, at filing time. How it works walks the split end to end.
The measuring stick: “the dumbest thing that works” is measured against the model. By that stick, plain ranking math is the default ranker, never an opt-in.
BM25, not embeddings
recall ranks with BM25, decades-old search-engine arithmetic: how often your query’s words appear in a note, and how rare those words are across the vault. Vector search, what most tools ship, has a model turn every note into a list of numbers (an embedding) first. recall runs no rerank, no embeddings, no vector store and no protocol layer over the vault (how it works).
Today recall reads every note on every query, measured at 157ms on a 308-note vault. When that stops being comfortable the path stays local: a fast text pre-filter in front of the ranking, then a word index kept on disk (what search engines call an inverted index). Never a vector store, never a model.
BM25 over plain text is good enough once notes are tagged well on the way in, which is what the write side is for.
The data is the knowledge
A note must carry the source’s real payload, whole: the tables, the numbers, the rows, the exact wording (vault layout states the rule and the test).
The rule earned its teeth from a real failure, and the fix is a standing rule: filing adds and never removes, plus a check that can fail. The lookup test: a specific question has to be answerable from the vault note alone.
Search reads vault notes only, so every row turned invisible.
The summary sits on top of the data, never in its place.
Domain-first folders
An earlier layout sorted notes by type, and it produced a junk drawer. Sorting by life-area fixed it, and search ignores folders entirely, so the choice never costs a result.
Most knowledge is reference about some area of life, with no type to file under. It all fell into one typeless bucket.
Notes file where you would browse for them, and every person, organization, and holding keeps one linkable home.
One piece of the type-first idea survived: people, organizations and holdings each keep one cross-cutting home (a holding is an owned thing with state worth tracking, like an account or a policy). That linkable entity graph is the one real gain over PAI, which kept knowledge as prose with no typed layer for people and things.
The core stays blind
Core is the vault plus ingest, recall and check. The rule, and the test that keeps it honest:
You can add or remove any plugin with zero edits to the core.
The most important call here, and a direct lesson from PAI. A core bloats when the arrows point from core to module: it imports, validates and loads every subsystem, so every new capability grows it. PAI was built that way.
imprnt points the arrows the other way. A plugin depends on exactly two things, your notes and its own folder, and the core stays blind to both.
Copy, share no code
A plugin needs roughly twelve lines of code to read a note’s header. Those lines are copied into every plugin, and the core publishes no code to import. The reason is reversibility: the two failure modes are nowhere near symmetric.
Copy is the move you can undo.
Nothing runs unless you start it
A daemon runs in the background on its own. The core and the vault plugins ship none: they ship commands, and scheduling them (cron, launchd) is your opt-in. The hub does ship daemons, a door per person, a runner per agent, a broker, a board, because a chat answers in seconds, and every one is a unit you enable by hand. A tool that works without you ever thinking about it is also one you cannot audit, cannot stop and do not fully own.
Invariants are tests
The most expensive lesson, again from PAI, which carried seventeen principles written as values (be private, ration the model). A value cannot be checked against reality, so it rots into recitation. A principle earns its place here only as a check pointing at a specific breakage it would have caught.
Private by being private
The vault lives on your machine, readable by your account alone. No sensitivity label, no redaction pass, no fencing of secrets, because the vault is meant to hold everything, including medical, financial and personal records.
The vault never goes near a public repo.
Publishing a subset, say an article drawn from your notes, is an export-time filter you run consciously, once. Filing stays free of that tax.
imp vs imprnt
Two commands from one dispatcher, split by audience. imp --gemini or imprnt agent swaps the backend.
Typed in any directory. Opens your assistant's session there with imprnt riding along, Claude by default.
imp lair opens the session inside the vault imp --gemini swaps the backend Called by agents and scripts, the machine-facing half of the package.
imprnt recall search the vault imprnt check audit notes, rebuild the index Two earlier models lost this fight. Wiring imprnt into the assistant’s global config pays tokens in every session forever. A launcher-only design left the vault unreachable from the coding repos where most of the day happens. What won is consent per keystroke: typing imp instead of claude, and plain claude stays plain.
Context loads on demand
A session’s upfront load follows the same frequency axis as everything else: the filing rules are paid for only by the sessions that write, at the moment they write.
The pointer says the vault exists, when to search it, and where to write.
imprnt context prints the full filing contract The model is a setting
An agent is a model inside a tool-calling loop, and imprnt writes neither. The loop is rented by preference (Claude Code today, OpenCode next, Codex for a GPT plan), and the hub sees every loop through one driver that speaks five verbs: feed a message, hear the receipt, stream the text, end the turn with usage, resume the session. That seam is what keeps the loop rentable: swapping it touches the driver and nothing else. The model, the endpoint and the billing path (a plan or a key) are one field on the agent in the registry, and the registry writes the loop’s config from that field, so the ledger and the loop never disagree on which model ran. A bake-off is a config change. A vendor policy change is a config change.
Disk before the platform
Every silent loss the hub ever had was a machine-side success read as proof a human got an answer: a cursor that advanced, a broker that acknowledged, a reply watch that stood down. The ledger reverses the order. A door writes the row, then confirms to the platform. A runner writes the reply, then a door sends it. A crash anywhere between is a delay the next tick clears, never a message nobody got. Process supervision does not save a message that was never written down.
Gates at the tool boundary
A model reads whatever comes in, including a listing that says “message the seller now”, and no code can stop it from wanting to. What code can hold is the exit. Every tool that reaches outside (a marketplace send, a reply, a mail in the command register) needs an approval minted from a human’s own inbound row: single use, short lived, and never mintable by a model typing “send” to itself. An injected instruction can make the model draft anything, and nothing goes out. The earlier version of this rule was a quoting convention in the prompt, honoured only while the model chose to, and a rule the model can drop is not a rule.
Multi-tenant, one shared zone
The boundary is the person, never the household and never the platform. Each person has a vault, doors, agents, a ledger and a key. Between them is exactly one shared zone, a mount every vault carries, and sharing a note means moving it there. Nothing is designed for two, so a third person is a registry entry. There is no fence between the people on one box: every agent runs as the account and reaches every vault, every home and every chat of the household, and the Board and the dashboards answer an agent on the box’s own machine exactly as they answer a phone on the tailnet. The tailnet is the whole boundary, because the people on one box already trust each other with the box. The rule underneath: if you do not trust the people, do not share the data.
The conversation outlives the session
The loop’s session is a cache, never the record. The door writes both directions of every chat to a dated log per agent, and a fact worth keeping is filed into the vault by a person or on a person’s word. So a runner can be killed mid-conversation, the loop can be swapped, the loop’s own session store can be wiped, and the next reply picks up where the last one stopped, because the agent reads the log before answering. This is what makes renting the loop safe: nothing that matters is inside it.
MIT licensed. © 2026 Aleksandr Bogdanov.