PROJECT / MEMORY

MagGraph

MagGraph stores what an agent knows as versioned Markdown nodes in your repository. Edges come from wiki-style links, Git provides history and sync, and a Python API plus a generated protocol server make it usable by agents other than mine.

Project

What it is

MagGraph is an in-process graph database designed for AI semantic layers, with a Rust core and Python bindings. Knowledge is stored as versioned Markdown nodes in a Git repository. Edges emerge automatically from wiki-style links inside the content. Git provides versioning and sync. A generated protocol server makes the same memory reachable from agents that are not mine.

The name comes from the magpie, a corvid, chosen for the family's association with memory and tool use. The naming is not decoration: memory is the organizing idea rather than one feature.

The design bet

The bet is that the substrate matters more than the algorithm.

Most agent memory systems are databases with an API. They work, and they have a property I found disqualifying in practice: you cannot see what is in them without tooling, you cannot correct a wrong fact without tooling, and you cannot take the contents anywhere else without an export path someone remembered to build.

Memory accumulates errors. That is not a defect, it is what happens when a system draws conclusions from partial information. A store where correcting an error requires a special interface is a store where errors persist, and an agent operating on persistent wrong beliefs is worse than one with no memory at all, because it is confidently wrong in a stable way.

So the substrate is Markdown files. You can open one in any editor and read it. You can fix a wrong line. You can grep the whole store. You can diff it, review it, and move it. Everything else in the design follows from deciding that first.

The test I applied

When an agent behaves strangely, can I open its memory and see why? If the answer requires special tooling, I will stop trusting the memory, and the usual next step is turning it off.

Nodes and edges

A node is a Markdown file with frontmatter carrying a name, a description, and metadata such as type. The body is the content: a fact, a decision, a convention, an observation about a project.

Edges are not declared separately. They emerge from wiki-style links inside the body. Writing a link to another node creates the relationship, and backlinks are derived rather than maintained.

This is the part of the design I would defend hardest, because it addresses the reason most knowledge graphs fail. A graph needs edges. If creating an edge is a separate modeling step, nobody does it consistently, and within a few weeks you have a slower key value store with a graph API on top. Making the link the natural way to reference another node means edges accumulate as a side effect of writing normally.

It also means the content and the structure cannot drift apart. There is no separate edge table to fall out of sync with the text, because the text is the edge.

Recall as a subgraph

The retrieval operation returns a connected subgraph rather than a ranked list of text fragments, and this is the functional difference from similarity search over a document store.

Consider what an agent actually needs to know about a codebase convention. Not just the convention, but the constraint that motivated it, the decision it came from, whether a later decision superseded part of it, and who owns the area it applies to. Those are five nodes connected by edges.

Similarity search returns the convention and, if you are lucky, something related that happens to use similar wording. Subgraph recall returns the convention and its neighborhood. In practice this shows up as an agent that can explain why a rule exists rather than only that it does, which is the difference between one that follows rules and one that can judge exceptions.

Recall bundles let a caller ask for a starting point and a traversal depth, which is the knob that controls the tradeoff between context and completeness. Too shallow and you lose the reasoning. Too deep and recall crowds out the task, which is a real failure mode and one worth measuring rather than guessing at.

Why Git is the sync layer

Using Git rather than building sync was the least original decision in the project and probably the best one.

Memory needs history, because the useful question is often not what does the agent believe but when did it start believing that. It needs conflict handling, because two machines will write. It needs backup. It needs the ability to review changes before accepting them. Building all of that is months of work that Git already does.

It also brings properties I did not initially plan for and now rely on. Changes to what an agent believes arrive as commits, which means they can be reviewed like code. Reverting a bad learning session is a revert. Blame tells you which session introduced a fact.

The leader and follower sync arrangement handles the multi-machine case without requiring a server, which keeps the whole thing local-first. Nothing about this memory requires a service to be running somewhere.

Why the core is Rust

The core is Rust with Python bindings, which is a choice worth explaining because it looks like a preference and is actually about a specific latency budget.

Memory recall happens inside the agent loop, often several times per task, and it happens before the model call rather than in parallel with it. Every millisecond of recall is a millisecond the user waits with nothing on screen. In an agent taking twelve steps, a recall that takes two hundred milliseconds adds nearly two and a half seconds of pure waiting to a single task.

Parsing Markdown, maintaining an index over it, resolving links, and traversing a graph are exactly the kind of work where a compiled implementation matters, and where a pure Python one becomes noticeable as the store grows past a few thousand nodes. Since the whole point is that memory improves as it accumulates, a design that gets slower as it accumulates is self-defeating.

The bindings matter as much as the core. Agent tooling is overwhelmingly Python, and a memory layer that requires a separate process or a network hop to reach from Python would have given back much of the speed it gained. In-process bindings keep recall cheap enough that an agent can afford to check memory when it is unsure rather than only when it is confident it should.

None of this would justify Rust for a store of a few hundred notes. It justifies it for one that a person uses daily for years, which is the case I was building for.

Why it is a separate project

MagGraph could have been a module inside MagAgent. Keeping it separate was deliberate and I think it is the more important half of the pair.

Memory is the artifact that cannot be recreated. Everything else in an agentic system can be rebuilt from knowledge you still have: the harness, the tools, the prompts, the model choice. What an agent has learned about your work over months is the one thing that has no other source.

That makes it exactly the wrong thing to trap inside a runtime. If memory lives in the harness, then changing harnesses means losing the accumulated learning, which means you will not change harnesses, which means the harness has become a commitment rather than a choice.

Separating it, giving it a Python API, and generating a protocol server means another agent can read the same memory. That is the layering this whole site argues for, applied to the piece where it matters most.

Lakehouse mode

MagGraph includes a reader that connects graph memory to lakehouse tables, which is where my data work and my agent work meet.

The motivation is a boundary that keeps causing trouble. Agent memory is what an agent learned. Organizational data is what the business knows. Systems that blur these end up writing business facts into agent memory, where nobody governs them, or writing agent observations into analytical tables, where they pollute reporting.

The useful arrangement is that memory holds the interpretive layer, meaning what tables mean, which one is authoritative, what a metric is defined as, what was concluded from previous analyses, while the tables hold the facts. An agent recalls the interpretation and queries the data. Neither substitutes for the other.

This is also why I care about semantic definitions living somewhere machine-readable. A memory node saying which revenue table is authoritative, linked to the decision that established it, is a semantic layer with provenance attached.

Using it outside MagAgent

MagGraph is usable on its own, and I would rather people used it that way than not at all.

  • As a Python library. Read, search, traverse, and write nodes directly, with async support.
  • As a CLI. Query, search, recall, scaffold, and sync from a terminal, which makes it scriptable.
  • As a protocol server. Generated from your graph, so any agent speaking the Model Context Protocol can read the same memory. This is the path that matters for interoperability.
  • As a personal knowledge base. It is Markdown with links. A human can use it without any agent involved, and several people do.

That last one is not a joke. A memory format that is also a usable note-taking format means the agent and the person are writing into the same store, which removes a synchronization problem that otherwise appears immediately.

Limits and honest caveats

  • It is a data store. Whatever an agent learned is written down, including anything sensitive it encountered. Treat the repository with the care you would give the code it describes.
  • Edges need writing habits. If nodes are written without links, you have a slower key value store. The format encourages links; it cannot force them.
  • Recall depth needs tuning. Too deep and memory crowds out the task. This is worth measuring rather than assuming, which is why MagAgent ships memory evaluations.
  • Git is not a database. Very large graphs and very high write rates are not what this is built for. It is built for a person or a team, not for a service tier.
  • Curation is required. A store that accumulates without pruning or supersession degrades recall precision over time. That is unavoidable and it is why promotion should be deliberate.

Two things I would change

Being honest about a project I maintain: two decisions I would revisit. Automatic edge derivation from links is excellent when people write links and invisible when they do not, and I have not found a good way to prompt for the missing ones without becoming annoying. And I underestimated how much supersession matters. Marking that a new fact replaces an old one is more work at write time and it is the thing that keeps a long-lived store coherent, so it should have been more prominent in the design rather than something you can skip.

What it is not

MagGraph is not a vector database. It does not replace embedding search for finding relevant text in a large corpus. It is for structured, curated knowledge with relationships, which is a different job.

MagGraph is not an agent. It stores and retrieves. Deciding what to store and when to recall belongs to the harness.

MagGraph is not the organization's data layer. Facts that other systems need belong in governed storage. Memory is the interpretive layer on top, and keeping that boundary clear is what stops either one from becoming a shadow version of the other.

Where to learn more

Primary sources first. Repositories and specifications move faster than any summary, so treat the links below as the authority and this page as orientation.