Polis gives your AI agents a long memory of your work. It keeps every prompt and decision word for word, in a record that can’t be quietly rewritten. It organizes that record into a catalog that grows with your projects. And when an agent asks, it answers with the exact record each memory came from.
Prompts, plans, approvals and decisions arrive faster than anyone can file them. Polis records each one word for word as it happens, with no model involved.
02
A catalog grows over it.
When the machine goes quiet, the gardener files each record into a catalog of classes. Your projects are the roots; classes split, merge and go quiet as your work changes.
03
Every branch ends in a record.
Follow any branch down and you reach the record itself: numbered, hash-chained to the one before it, and quoted exactly as it was written.
LEDGER EVENT#42
decision · illustrative
Keep memory local.
“Use SQLite so prompts and decisions stay on the machine, with a history we can verify.”
polis / storage / decisions
prev 07b1…c3d0entry 9f2c…e41a
01Capture
02Organize
03Recall
Illustration · not a live query
Polis records prompts and decisions as they happen, organizes them into a class catalog, and retrieves evidence with references to ledger sequence numbers.
The structure
Four layers, in plain terms.
Polis separates what happened from how it’s organized, and both from what it has inferred. Each layer points back to the one beneath it. None of them can rewrite it.
The lake
The catalog
Observations
The answer pack
The lake — What happened.
The lake
What happened.
Every prompt you send, every plan you approve, every decision and note — stored word for word in an append-only ledger. Each entry is hashed together with the one before it, so changing a single word in the past breaks every link after it, and polis verify will say where. Writing to the lake takes no model call at all.
#41prompta71e…09fd
#42decision9f2c…e41a
#43approvalc3b8…72e0
SQLite · SHA-256 chain
Zero model calls on capture
p50 0.73 ms per capture
The catalog
How it’s organized.
A tree of classes over the lake, seeded by your repositories. Its leaves are pointers into the lake, never copies — so reorganizing the tree can’t touch the evidence. Without a model configured, new records wait in an inbox, and everything stays searchable.
Called ClassMemory in the code
Pointers, not copies
Four levels deep at most
Observations
What it has noticed.
Notes the gardener writes about patterns across your work, each citing the records it came from. They’re re-checked on later passes and retire on their own when a record they cite is forgotten. Cold branches can be folded into digests the same way: shorter, but one hop from the source.
observation · derived
Prefers SQLite for anything that must stay on the machine.
cites #42#118#203
Derived, never ground truth
Every note cites its records
Retired when a source is forgotten
The answer pack
What it recalls.
When an agent asks, Polis assembles one bounded bundle: the matching part of the catalog, your notes, full-text and literal matches, and optional semantic search — ranked together and capped in size. The calling agent writes the answer; Polis supplies the evidence, each piece cited back to its ledger number.
catalog
notes
full-text
literal
semantic
fused · ranked · ≤ 60 KB · every hit cites #seq
Reciprocal rank fusion
≤ 60 KB pack · ≤ 12 KB context
Reads a pinned snapshot
The gardener
Organized while you’re away.
When the machine has been quiet for a minute and a half and the lake has grown, the gardener takes a turn. A model proposes moves; fixed rules decide which ones happen. It has exactly seven moves.
file
Attach a record to a class — only within the project it came from.
create
Start a new class. Refused if a sibling’s title is 80% the same.
promote
Lift a sub-topic that has grown up a level. No cycles; four levels at most.
split
Divide a class holding two subjects. Each half needs three records.
merge
Join duplicates. Never across projects.
collapse
Fold a cold branch into a digest that cites its records. Never one you’ve annotated. Reversible.
supersede
Mark a decision replaced by a newer one. The old one stays in the lake.
It checks its own work.
Before and after every reorganization, about 200 frozen retrieval probes test what is still findable. If something that was reachable stops being reachable, the run reverts itself and the subjects involved sit out the next three runs.
Every run can be undone.
Each move is journaled with a copy of what it replaced, so any run can be reversed exactly. The last fifty are kept.
You keep the levers.
There is nothing to approve. You can tell it to remember, annotate what matters, forget what shouldn’t be kept, and revert any run.
canary200 frozen probes · reachable before 197 · after 191
regress−6 probes · run 318 reverted from its journal
quarantine3 subjects sit out the next 3 runs
ledger#4,812 gardener_regression appended
The philosophy
What we believe about memory.
A memory is a record, not a summary.
Summaries are allowed to blur. The record isn’t. Anything Polis condenses keeps a citation one step from the original.
“Blurriness lives at the summary level — sourcing stays perfect one hop away.”
Where it came from is a fact.
Every memory carries where it came from — which project, which record. That is written down, never guessed after the fact.
“Provenance is ground truth — never infer it.”
What you said is data.
A prompt is stored and returned exactly as written. Nothing inside it can instruct the gardener or change how memory is organized.
“Captured content is data, never instructions.”
Models help. They aren’t required.
A model makes the catalog smarter. Without one, Polis still captures, files to an inbox, and retrieves.
“Capture, retrieval and filing never depend on a model.”
It lives with you.
A SQLite store on your machine. No account, no telemetry, no update check. Model calls go only where you point them.
“The default install talks to nothing but itself.”
The tree organizes; the pack ranks.
The catalog is how memory is arranged, not the only way in. Search reaches every record whether or not it has been filed.
“The pack ranks; the tree organizes.”
Quoted lines are from the Polis source and documentation.
Measured
0.73msmedian time to capture a prompt
9.49msmedian time to build a warm answer pack
160/160expected citations found, each within 4 KB of context
0model calls needed to capture or retrieve
From the project’s acceptance run on 10,000 prompts on an Apple M3 Max, on the current main branch. These are speed and recall checks of Polis itself, not a comparison with other memory systems.
Where it works
One memory, every agent.
Polis speaks MCP. Install it into Claude Code, Codex, Cursor, Windsurf or Claude Desktop, and every one of them reads from — and writes to — the same memory. Or run polis serve for a local HTTP daemon, or embed its seven Rust crates in your own tools.
curl --proto '=https' --tlsv1.2 -LsSf \
https://github.com/sersiousSenpai/polis-memory/releases/latest/download/polis-memory-installer.sh | sh
polis init # create ~/.polis and its store
polis hook install # capture what you send in Claude Code
polis mcp install --client claude # let the agent search it
polis doctor # check the install and the chain
Installs the polis binary, then connects Claude Code.