Persistent memory for AI coding agents, anchored to code
Every new agent session starts with amnesia. Notes files like CLAUDE.md help with conventions, but they do not scale to hundreds of small decisions, they are loaded whole whatever the task, and nothing tells you when a note has gone stale.
Memory that lives next to the code
Scholion stores short, typed records (decision, attempt for a dead end, note, handoff), each anchored to a file or a function such as shop/pricing.py:line_total. Records are append-only: a newer one supersedes an older one instead of rewriting history.
- They come back on their own. When any later task touches that function, or code up to two hops away in the reference graph, the record is part of its context pack.
- They say when they may be wrong. The anchored code's hash is kept, so a record whose code has since changed is marked "changed since recorded".
- They fit. Packs are built for a token budget (say 2,000 tokens), ranked by distance to the work, and a session is not sent the same item twice.
Connect your agent
# start the daemon (Postgres + optional semantic search, on 127.0.0.1)
export UID GID=$(id -g)
docker compose -f deploy/docker-compose.yml up -d --build
# Claude Code, or any other MCP client
claude mcp add --transport http av http://localhost:7420/mcp
The MCP server exposes the same operations as the HTTP API and the av CLI: start a task, record, get a context pack, hand off, claim, review and merge. For Claude Code there are also hooks that print a pack at session start and checkpoint after edits (integrations/claude-code/install.sh).
What an agent sees
In a recorded run, a task that only edited receipt.py began using a constant from pricing.py. Its next pack included what other agents had recorded about pricing:
## Decisions & dead ends
- decision: Receipt reads pricing.BULK_QTY so the threshold has one source of truth
- attempt: Tried rounding every line to the cent before summing: totals drift 1-2 cents from invoices
- note: Threshold is per line (10 of one item), as the goal says; per-order would need Cart
- decision: Apply the bulk discount in pricing.line_total, not in Cart: invoices call pricing directly (changed since recorded)
No LLM chooses what goes in. The pack comes from the goal, the changed code, the reference graph and the budget, so it is reproducible, and every pack is stored with a receipt you can inspect.
Does it help?
On a small Python repository with Claude Code and Haiku (40 sessions per arm), sessions needed 12.9% fewer turns at unchanged cost, while input tokens rose 5.9% against plain git. The gain on large codebases is not measured yet. The benchmark harness and raw results are in the repository's bench/ directory.