Aletheia
The problem
Coding agents forget everything between sessions, so they re-read the same files every time. Memory tools fix the forgetting, but they rank memories by similarity, and an outdated memory looks just as relevant as the fact that replaced it. The agent then builds on something that stopped being true weeks ago. A confidently wrong memory is worse than no memory.
Related MCP server: cogmem
How it works
Memories carry evidence. Each memory is a claim plus anchors: a function that must still exist, a line that must still match, a file that must still be there.
Evidence is checked on every recall. The checks are mechanical: no model calls, no embeddings, no network. A memory whose evidence broke is hidden from the agent, and a one-line note says so.
Recall points at lines. A pointer such as
builtin_test.go:263is computed from the files right now, so the agent opens the right lines instead of searching for them.Maps write themselves. When the agent stops, Aletheia reads the session transcript and records which files the task changed. The next task of the same kind starts there, and the agent spends no turns writing it down.
Nothing is deleted. Replaced memories are superseded and long-stale ones archived by
aletheia lethe(Lethe, the river of forgetting).
Quick start
Install it in whichever way suits you. Every option gives you the same single binary:
go install github.com/firatmio/aletheia/cmd/aletheia@latest # Go 1.24+
scoop bucket add firatmio https://github.com/firatmio/scoop-bucket; scoop install aletheia # Windows
brew install --cask firatmio/tap/aletheia # macOS, Linux
npm install -g @firatmio/aletheia # Node 18+, any of the threeMCP clients configured with npx need no install: {"command": "npx", "args": ["-y", "@firatmio/aletheia", "serve"]}.
Prebuilt archives for Linux, macOS and Windows are on the releases page.
Then set it up in your project:
cd your-project
aletheia init --agents # creates .aletheia/ and adds usage notes to CLAUDE.md and AGENTS.mdClaude Code plugin. The plugin brings the MCP server and both hooks. /aletheia:setup then initializes the project:
/plugin marketplace add firatmio/aletheia
/plugin install aletheia@aletheia
/aletheia:setupWithout the plugin, add the two hooks yourself. Recall then happens on every prompt and costs the agent nothing:
aletheia init --claude-hooks # merges them into .claude/settings.json, keeps your other settings
aletheia hook --dry-run # what an agent would get (add a prompt to try one); changes nothingRun init --claude-hooks yourself. Agents are usually not allowed to change their own hooks, and that is by design. To edit the file by hand instead, use this:
{
"hooks": {
"UserPromptSubmit": [{ "hooks": [{ "type": "command", "command": "aletheia hook" }] }],
"Stop": [{ "hooks": [{ "type": "command", "command": "aletheia hook" }] }]
}
}An agent can also do the rest of the setup from the agent guide. It hands the hook step to you as that single command.
Memories live in .aletheia/memories/*.md as plain Markdown. Commit them and your team, and every agent, shares one memory that verifies itself on each machine.
Upgrading: scoop update aletheia, brew upgrade --cask aletheia or npm update -g @firatmio/aletheia. With Go, run the same go install again.
On Windows, a running agent keeps
aletheia.exeopen through the MCP server, so the install fails with "file in use". Quit the agent first, or move the old binary aside and install. Windows allows renaming a running exe.Which version runs: the hooks use the new binary right away. The MCP server keeps the old one until the agent restarts.
The Windows command works on every upgrade. It removes old copies that are no longer in use, and the random name never collides with one that is still running:
$bin = "$(go env GOPATH)\bin"
Remove-Item "$bin\aletheia-old*.exe" -ErrorAction SilentlyContinue
Rename-Item "$bin\aletheia.exe" "aletheia-old-$(Get-Random).exe"
go install github.com/firatmio/aletheia/cmd/aletheia@latestResults
We measured with headless Claude Code (Opus 5.5) on real repositories. Each task ran with and without Aletheia, and the same hidden acceptance tests judged success.
Repository | Tasks | Cost | Also | Tasks passed |
gohugoio/hugo, a large site generator (233k lines of Go) | 14 tasks of five kinds, one run each | −15%: −22% on seven tasks of one kind, −7% on a mix | input tokens −27%, turns −21% | 14/14, same as without |
expr-lang/expr, a mid-size expression language | 7 tasks, two runs | −9% in both runs | code read before the first edit −48% | 14/14, same as without |
go-chi/chi, a small, tidy router | 7 small tasks, two runs | +5% and −5%: break-even | 14/14, same as without |
Aletheia pays off where finding the right place is expensive, in mid-size and larger codebases, and most when the same kind of change comes back. Expect the mixed figure for everyday work. On a small package that an agent reads in one or two calls there is little to save. The method, the raw numbers and what did not work are in docs/dogfood-4.2.md.
Reference
Anchor | Holds while | Example |
| the file still declares that function, method ( |
|
| the file still matches the regular expression |
|
| the path still exists |
|
| the file's content is unchanged (hash sealed when saved) |
|
Use
symbolfor claims about one declaration andcontainsfor one thing in a file. Usefileonly when any change should trigger a re-check.Recall shows where
symbolandcontainsevidence is right now, e.g.(store.go:15-21). Go declarations get their full range fromgo/parser; other languages get the declaring line.Moved code. A Go
symbolanchor is sealed with a fingerprint of the declaration (symbol:store.go::Store.Get@3f9a…). The fingerprint ignores comments and layout.Edits in place: they never stale the anchor. If the declaration is still in its file, the fingerprint is not even consulted.
A moved declaration: if the declaration leaves its file, Aletheia searches the project for it. When exactly one declaration with that name has the same fingerprint, the memory comes back as
[moved: old.go → new.go]with the new lines, andverify <id> --resealrecords the new path.Anything less certain stays stale and hidden: the code changed on the way, several copies match, or the claim names the old file.
containsanchors in Go code: when one matches inside a single declaration,rememberadds a sealedsymbolanchor for that declaration. Thecontainsanchor then moves with it, but only if its pattern still matches inside that declaration at the new place.
In a
containspattern, a run of spaces matches any run of spaces or tabs, so reformatting does not stale it.Files named in a claim get an
exists:anchor automatically.rememberwarns when acontainsanchor only matches comments, since a comment can stay while the code changes.A memory without anchors comes back as
[?], ranked below verified facts, and expires after 90 days unless re-confirmed.
When a memory goes stale, re-check the claim, then:
aletheia verify 3f9a1c --reseal # still true: refresh the evidence
aletheia remember "…new claim…" --anchor … --supersedes 3f9a1c # changed: replace it--reseal refuses when a contains, exists or symbol anchor no longer holds, so a false claim cannot be quietly blessed.
aletheia map "<topic>" lists the files most relevant to a topic, each with its key declarations and their current lines:
optimizer/fold.go: fold.Visit 15-311, fold 10-13, toFloat 329-335
builtin/builtin.go: Builtins 35-1081, Index 18Files are ranked first, as in Aider's repo map, by how well their path and declaration names match the topic. Hidden, dependency and generated files are skipped. For a question about building, testing or shipping, and for the overview without a topic, the map starts with the build files: build and CI: go.mod, Makefile, scripts/, .github/workflows/ci.yml. The hook sends a map with the first prompt of a session, sized to the project: none under 25 source files, then 300 or 600 tokens (--map-budget N overrides it).
Aletheia speaks MCP over stdio with four tools (recall, remember, get, verify) and works as a plain CLI, so any agent that can run a shell command can use it.
{
"mcpServers": {
"aletheia": { "command": "aletheia", "args": ["serve", "--dir", "/absolute/path/to/your-project"] }
}
}VS Code (
.vscode/mcp.json): use"servers"instead of"mcpServers", and${workspaceFolder}as the directory.Claude Code:
claude mcp add aletheia -- aletheia serve. The hooks above matter more, because Claude Code loads MCP tool descriptions on demand.Agents without MCP (Codex, Aider, custom agents):
aletheia init --agentswrites a short block toAGENTS.mdthat teaches the agent to call the CLI. Add--jsonto any read command for machine-readable output.
---
id: "3f9a1c"
claim: "Auth tokens are issued in src/auth/jwt.go"
confidence: 0.8
status: "active"
source: "claude-code"
created: "2026-10-21T09:12:44Z"
updated: "2026-10-21T09:12:44Z"
tags:
- "auth"
anchors:
- "symbol:src/auth/jwt.go::IssueToken"
- "exists:src/auth/jwt.go"
---
Tokens are HS256 with a 15 minute expiry. Refresh lives in refresh.go.Edit memories by hand, review them in pull requests, grep them. They are just files.
aletheia init [dir] [--agents] [--claude-hooks]
aletheia remember <claim> [--anchor SPEC]... [--body TEXT|-] [--tag T]... [--ttl 30d]
[--confidence 0.8] [--supersedes ID]... [--source NAME] [--force]
aletheia remember - [--source NAME] [--force] # several at once: one JSON object per line on stdin
aletheia recall [query] [--budget N] [--limit N] [--full] [--stale] [--tag T] [--session ID] [--json]
aletheia get <id> [--json]
aletheia verify [id] [--reseal] [--ttl 30d] [--json] # exits 1 if anything is stale (CI-friendly)
aletheia map [topic] [--budget 600]
aletheia hook [--budget N] [--map-budget N] [--dry-run [prompt]] # Claude Code hook; every command takes --help
aletheia lethe [--days 30] [--apply] # archive superseded and long-stale memories
aletheia stats [--json]
aletheia serve [--dir DIR] # MCP server on stdioremember exits with code 3 when the claim duplicates or closely matches an existing memory, and names it so the agent can --supersedes it instead.
remember - saves several memories in one call. Each stdin line is a JSON object with the MCP tool's keys, and each memory is saved on its own:
aletheia remember - <<'EOF'
{"claim": "Builtins are registered in builtin/registry.go", "anchors": ["symbol:builtin/registry.go::Builtins"]}
{"claim": "go.mod targets Go 1.18", "anchors": ["contains:go.mod::^go 1\\.18$"], "tags": ["toolchain"]}
EOFIt prints one result per line, in order. It exits 0 when all are saved, 3 when the only failures are conflicts, and 1 otherwise. A regex whose \\ became \ on the way through the shell (1\.18) is still accepted. The MCP remember tool takes the same objects as memories.
Never executes anything. Anchors only read files; there is no "run this command to verify" anchor.
Stays inside the project. Anchor paths are relative and cannot escape the root, including through symlinks.
Memories are data, not instructions. The MCP server tells agents so, and the
CLAUDE.md/AGENTS.mdblock repeats it.No network, no telemetry, no dependencies. A single static binary using only the Go standard library.
Roadmap
Evidence-anchored memories, checked on every recall
Recall hook, live line pointers, code map, task maps from the Stop hook
Benchmark harness with paired runs on real repositories
Longer benchmarks with more repositories and repeated kinds of change
Follow file renames with git and suggest re-anchoring
Prebuilt binaries, Homebrew, Scoop and an
npxwrapperGlobal, cross-project memory for personal preferences
Contributing
Issues and pull requests are welcome. See CONTRIBUTING.md.
License
Apache-2.0 © Fırat Tuna Arslan
This server cannot be deployed
Maintenance
Related MCP Connectors
Persistent memory for AI agents, for code, research and everyday life. Stale facts retire.
Agent memory that refuses to guess: evidence-gated recall, exact-source reads, verifiable deletion.
Shared memory for coding agents. Stop re-explaining your codebase every session.
Related MCP Servers
- AlicenseBqualityNot gradedmaintenanceProvides repository-scoped safe memory for AI coding agents with just-in-time verification against file changes to ensure facts remain accurate. It links memories to specific code citations and automatically marks them as stale if the underlying source code is modified or deleted.5-
- AlicenseAqualityFmaintenanceSelf-improving, verifiable memory for AI coding agents. Learns how you work, stops repeating mistakes, models each project, recalls the right lesson at the right moment. Every memory is signed and tamper-evident. Local-first.82Apache 2.0
- AlicenseNot gradedqualityAmaintenancePersistent memory for AI coding agents that knows when it has gone stale.3MIT
- AlicenseBqualityDmaintenanceRepository-scoped memory with code citations and just-in-time verification, preventing stale information for AI coding agents.51MIT