Human-like memory for AI coding assistants.
I got tired of watching Claude do 15 greps to answer a question the knowledge graph already knew. Tired of losing context every compaction. Tired of my CLAUDE.md dumping 600 tokens of graph metadata when a 6-token freshness check would do.
So I built engram — three small tools that treat the knowledge graph like long-term memory and Claude's context window like working memory. You don't load your entire filing cabinet onto your desk. You know where the cabinet is and pull the right folder when needed.
| Human memory | engram | Loaded when |
|---|---|---|
| Working memory (7±2 items) | Context window | Always |
| Procedural ("check the graph") | CLAUDE.md rules | Always — kept tiny |
| Semantic ("orchestrator has 284 edges") | graphify query / mempalace search |
On demand |
| Episodic ("last week's deploy broke") | GitHub issues + git log | On demand |
| Long-term storage | graph.json | Never auto-loaded |
Hooks into Claude Code's PreToolUse event. Counts Grep/Glob calls. Escalates.
Search #1-3: quiet — "knowledge graph available"
Search #4: gentle — "consider querying the graph"
Search #5+: strong — "STOP. Use the graph."
Resets after 120s of no searches (new train of thought)
The idea came from watching Claude burn through 12 search calls for something graphify query would have answered in one.
Audits graph health at session start. Catches problems before they cost you tokens.
$ python tools/context_watchdog.py
Context Budget Report
=====================
Backend: graphify
Staleness: FRESH (0.2h old)
Ghost nodes: none
Graph size: 2344 nodes, 2919 edges
Bleed check: PASS
"Bleed check" catches graph data hardcoded into CLAUDE.md — node counts, community IDs, things that go stale. If it's in CLAUDE.md, it's loaded every single session whether you need it or not.
Self-healing graph maintenance. Prunes ghost nodes (references to files you renamed or deleted), backs up before modifying, dry-run by default.
python tools/graph_rebuild.py --prune --no-dry-run # remove ghost nodes
python tools/graph_rebuild.py --rebuild # trigger backend rebuild
python tools/graph_rebuild.py # report statusgit clone https://github.com/harreh3iesh/engram.git /tmp/engram
bash /tmp/engram/install.sh .That's it. install.sh copies three tools into tools/, one skill into .claude/skills/, and merges hooks into .claude/settings.json. It never clobbers your existing hooks.
If you don't have a knowledge graph yet:
pip install graphifyy && graphify install && graphify hook install
bash /tmp/engram/install.sh .engram doesn't care what your knowledge graph is. It detects what's available and adapts:
| Backend | Detected by | Stuck detector suggests |
|---|---|---|
| graphify | graphify-out/graph.json |
graphify query "<q>" --budget 2000 |
| mempalace | .mempalace/ directory |
mempalace search "<q>" |
| Raw graph.json | graph.json in project root |
read GRAPH_REPORT.md |
| None | — | Audit + prune still work, no nudge |
Using graphify + mempalace together gives you structural knowledge (code graph) and conversational memory (past sessions). That's basically complete coverage.
Session starts
→ context_watchdog.py --brief "engram: OK — 2344 nodes"
(~6 tokens. that's it.)
Claude searches for something
→ graph_stuck_detector.sh fires
#1: quiet
#5: "STOP. query the graph." (escalating nudge)
Claude edits a file
→ graph_rebuild.py --prune (silent ghost cleanup)
You invoke /memory-librarian
→ Graduated retrieval:
Level 0: fast path (training) 0 tokens
Level 1: graph query --budget 500 ~500 tokens
Level 2: + GitHub issues ~2000 tokens
Level 3: GRAPH_REPORT.md sections ~5000 tokens
Level 4: raw file search last resort
| Variable | Default | What it does |
|---|---|---|
SEARCH_THRESHOLD |
5 | Searches before the strong nudge |
SEARCH_WINDOW |
120 | Seconds before the counter resets |
ENGRAM_LOG |
/tmp/engram-graph-hooks.log |
Where hooks log |
From a production project where I've been running this:
- 84 tokens/session passive cost (was 600+ before)
- Ghost pruning catches 1-3 stale nodes per week
- The stuck detector fires its strong nudge about twice per deep debugging session
- 49 tests, zero external dependencies
PRs welcome. The tools are intentionally simple — stdlib only, no pip dependencies, works with any graph.json. If you're building on this for a different backend, I'd love to see it.
MIT