Cross-session memory for coding agents, backed by a Fangorn wiki.
Agents lose context between sessions. They fall back on reading code and comments, which record what but never why — so each session re-derives the same conclusions, re-proposes the same already-rejected approaches, and re-hits bugs whose causes weren't local.
This plugin keeps a decision graph that survives the session: rationale, rejected alternatives, non-local bug causes, and constraints learned from outside the repo. None of that is recoverable from a diff.
| Component | Mechanism | Role |
|---|---|---|
hooks/session-recall.sh |
SessionStart hook |
Injects the memory index itself. Deterministic — the agent can't skip it. |
bin/hindsight-sync |
shell script | Mirrors the wiki into .hindsight/. Costs zero context tokens. |
skills/fangorn-memory |
Skill | Capture triggers, entry format, promote/supersede rules. Loads on demand. |
commands/wiki-bootstrap.md |
/wiki-bootstrap [sha] |
Builds the wiki; refreshes it diff-driven against a newer commit. |
The hook is the load-bearing part. A skill or CLAUDE.md instruction is advisory;
recall has to be guaranteed or none of the rest pays off.
Memory is authored in the wiki and read from a local mirror. Those are different jobs and they want different mechanisms.
Reading over the MCP costs a deferred-tool lookup, a list_notes round trip, and a
whole page per read_note — measured at 2.6k–5.1k tokens per session on a 10-page
wiki, plus latency and a hard dependency on the network being up. None of that buys
anything at read time: the content is identical.
So hindsight-sync pulls the pages down over plain HTTP from the shell, and the
hook hands the agent the index inline. A session now starts knowing what exists,
having spent no tool calls, and greps the mirror for the one line it needs instead
of fetching a page to find it.
The wiki stays the source of truth — authoring, review, signing, sharing across machines. The mirror is a cache; never hand-edit it, and re-run the sync after any write. A stale mirror is worse than no mirror, because the agent trusts it.
The fangornmd MCP server, configured and authenticated.
/plugin marketplace add /path/to/fangorn-memory
/plugin install fangorn-memorycd your-repo
/wiki-bootstrapIt resolves the wiki namespace, reads the repo, writes the pages, drops a
.fangorn-namespace marker at the root, and syncs the mirror.
Opt-in is per repo. The hook exits silently when that marker is absent, so the plugin costs nothing in repos that don't use it.
Refresh the mirror yourself any time — after a write_note, or on a new machine:
bin/hindsight-sync # pull every page into .hindsight/
bin/hindsight-sync --check # what's mirrored, and when it was syncedCommit .hindsight/ unless you have a reason not to. It makes memory survive a
fresh clone with no MCP, no auth and no network, and keeps it greppable by tools
that respect .gitignore.
After new commits:
/wiki-bootstrap <sha> # diffs baseline..sha, reviews only affected pages| Layer | Content | Refreshed by |
|---|---|---|
log.md + entries |
why, what was rejected, what failed | never — append-only |
index, invariants, gotchas, file-map, concept pages |
what the repo is | /wiki-bootstrap <sha>, diff-driven |
The stable layer is re-derivable from code. The log is not, which is why the refresh path is forbidden from touching it.
Capture narrowly. An append-only log of routine work makes recall worse — the signal drowns. The triggers exclude anything git or the code already holds. If you find the log filling with "changed X to Y", tighten it.
Say why. The system can't manufacture rationale. It can record what the agent decided; it can't recover why you chose an approach or what constraint you were working around. One sentence at decision time is the highest-value input the log ever gets.
Put the sha in the entry, the entry slug in the commit message. That gives you:
confusing line → git blame → commit → log entry → why, and what was rejected
The graph becomes reachable from the code, without the code carrying the explanation in comments.