An Arches-inspired RDF knowledge-graph MCP server giving Claude Code persistent, structured long-term memory. Facts are stored as typed resources (Person, Project, Decision, Pattern, …) in per-instance named graphs, connected by cross-links and shared concept nodes, so recall can traverse multi-hop chains ("what decisions affect the projects Stuart works on?") instead of grepping flat notes.
- Storage: in-memory pyoxigraph triple store, persisted as NQuads after every mutation (atomic write). Default location
~/.claude/memory-graph/store/graph.nq— human-readable, greppable, diffable. - Self-extending ontology: the LLM must reuse the built-in relations; if none fits it can add a new one (with a description and provenance timestamp) that persists in the schema graph.
- Token-lean: tool outputs are terse text designed for LLM consumption — no IRIs, no timestamps, no pretty-printed JSON.
The repo is its own plugin marketplace. One plugin sets up everything: the MCP server (run via uvx from the bundled source — requires uv), the conversation context-file protocol (injected each session, dirs auto-created), the /memory-graph:distill and /memory-graph:ingest skills, and hook-kit — a standalone hook-extension framework (own plugin, also usable without memory-graph) whose installable extensions add session-start memory auto-priming (memory-recall) and mechanical context-log enforcement (context-counter: an overdue log blocks the Stop event until written; a heavy grep/read turn gets asked for a trace entry — see docs/ORCHESTRATION.md): enable them with /hook-kit:install or claude-hooks enable <name>.
claude plugin marketplace add <git-url-or-local-path>
claude plugin install memory-graph@claude-memory-graph --scope userOptional: set MEMORY_GRAPH_PATH to change the data directory (defaults to ~/.claude/memory-graph/store).
claude-memory-graph serve --host 0.0.0.0 --port 8848 --token <secret> # on the host
claude mcp add --transport http memory-graph http://host:8848/mcp \
--header "Authorization: Bearer <secret>" # on each clientOne process owns the store (no last-writer-wins between sessions). Non-localhost binds require the token. v1 scope: the MCP tools travel; ambient injection/capture hooks stay per-machine — see docs/tasks/remote-server.md.
uv tool install git+<repo-url> # or from a checkout: uv tool install .
claude mcp add --scope user memory-graph -- claude-memory-graphThis registers just the MCP server — no context protocol or distill skill.
- During every session, Claude keeps a running context file in
~/.claude/context/(decisions, problems solved, preferences, codebase orientation and dig findings — a handoff log any LLM can pick up; graph-worthy points are written as structured entries that distill promotes directly instead of re-deriving). - Distill happens by itself: every new session's server starts by mechanically promoting structured entries into the graph (no LLM, idempotent, refuses anything questionable to a residue report;
MEMORY_GRAPH_AUTO_DISTILL=0to disable)./memory-graph:distillis for the residue — narrative bullets, near-duplicates, ontology extensions — and archives clean files to~/.claude/context/archive/(never deleted). Also available on demand as thememory_distillMCP tool and theclaude-memory-graph distillCLI. - Recall happens naturally: Claude calls
memory_recall/memory_querywhen past context is relevant, traversing links between projects, decisions, gotchas, and people.
| Tool | Purpose |
|---|---|
memory_store_resource |
Create/update a typed resource (Person, Project, Company, Task, Technology, Decision, Pattern). Upserts by model+name; any camelCase properties accepted. |
memory_store_concept |
Create a shared concept node (Skill, Concept, Constraint, Preference). |
memory_link / memory_unlink |
Cross-graph relationships. Unknown relations error with the valid list; pass new_relation_description to extend the ontology when nothing fits. Links are bi-temporal: single-valued relations (employedBy, assignedTo) auto-close a conflicting earlier edge (worldChange) instead of keeping two current facts, and unlink closes by default (worldChange/correction) — mode: remove for hard delete. Recall shows only currently-valid edges; history stays queryable. |
memory_recall |
A resource, its properties, and linked resources — depth 1 or 2 (multi-hop via shared nodes). |
memory_forget |
Soft-delete (invalidated, kept for provenance, hidden from retrieval). |
memory_query |
Raw SPARQL (prefixes rdf, rdfs, xsd, mem pre-loaded). |
memory_reflect |
Graph overview: counts, available relations, recent additions, mechanical link-gap candidates. |
memory_distill |
Mechanical promotion of structured context entries (no LLM): parse → fold → apply, refusing anything questionable to a residue report. In-session equivalent of the distill CLI. |
claude-memory-graph recall Person Stuart --depth 2
claude-memory-graph reflect
claude-memory-graph query 'SELECT ?name WHERE { GRAPH ?g { ?n rdf:type mem:Project ; mem:name ?name } }'Writes are deliberately MCP-only: a running server holds the graph in memory and saves after each mutation, so terminal writes would be overwritten by the next in-session save.
docs/HANDBOOK.md is the operator's guide: what each subsystem is doing at runtime (with the code and log locations to dig into), the terminology with examples, setup verification steps, the symptom→knob tuning table, how to prompt so retrieval works with you, and the command cadence.
Each resource instance lives in its own named graph (…/graph/resource/<uuid>); cross-links live in a dedicated links graph; shared concepts in a concepts graph; the ontology (including LLM-added relations) in a schema graph. See claude_memory_graph/base.ttl for the base ontology.
Multiple Claude Code sessions each spawn their own server process over the same NQuads file — last writer wins per mutation. This is fine for a personal memory store; if it ever outgrows that, the upgrade path is pyoxigraph's RocksDB-backed store behind a single shared daemon.