In-process Git-backed graph engine for AI semantic layers — powered by Rust
Why "MagGraph"? The name is short for Magpie — a Corvid. Corvids (ravens, crows, jays, and magpies) are renowned in animal cognition research for their remarkable intelligence, long-term memory, and sophisticated tool use. MagGraph is built to be the memory and knowledge layer for AI agents with those same qualities: a graph that thinks, remembers, and uses tools.
MagGraph stores knowledge as versioned Markdown nodes in your Git repository,
with BFS/DFS traversal, Git-backed sync, external lakehouse content resolution,
and a built-in MCP server scaffold — all from a zero-dependency pip install.
pip install maggraphPre-built wheels are available for:
| Platform | Architectures |
|---|---|
| Linux (manylinux_2_28) | x86_64 · aarch64 |
| macOS | Intel (x86_64) · Apple Silicon (arm64) |
| Windows | x86_64 |
No Rust toolchain required — the Rust core is compiled into the wheel.
import maggraph
# Load config + open the graph index
config = maggraph.load_config("maggraph.toml")
index = config.open_index()
# List nodes
print(index.list_nodes()) # ['getting_started', 'welcome', ...]
# Read a node
node = index.read_node("welcome")
print(node.body) # full markdown body
# Search, backlinks, and recall
print(index.search("Welcome")[0]["id"])
print(index.backlinks("welcome"))
bundle = index.recall_bundle("welcome", reason="quick start")
print(bundle["markdown"])
# BFS traversal
result = index.traverse("welcome", depth=2, order="bfs")
print(result.to_markdown(index)) # formatted traversal report
# CRUD and memory helpers
index.create_memory_node("prefers_cli", "preference", "User prefers CLI-first UX.")
index.create_node("new_note", node_type="note", body="# Hi\n", links=["welcome"])
index.update_node("new_note", "# Updated\n")
index.suppress_node("new_note", reason="example")
index.unsuppress_node("new_note")
index.delete_node("new_note")import asyncio, maggraph
async def main():
index = maggraph.open_index("examples/basic/knowledge_graph")
node = await index.read_node_async("welcome")
result = await index.traverse_async("welcome", depth=3, order="dfs")
print(result.to_markdown(index))
asyncio.run(main())Blocking Rust work runs on a Tokio thread pool — Python's event loop stays responsive.
Resolve external data sources (S3, file://, HTTP) referenced from node frontmatter:
import maggraph
config = maggraph.load_config("maggraph.toml") # mode = "lakehouse"
index = config.open_index()
reader = config.open_lakehouse_reader()
# Resolve a node's external source (e.g. s3://bucket/data.parquet)
result = reader.read_node(index, "customer_churn_q2")
print(result.content.kind) # "external_asset"
print(result.content.uri) # "s3://corp-data/lake/churn.parquet"
print(result.content.format) # "parquet"
print(result.content.to_markdown()) # agent-friendly summary
# Cache stats
print(reader.cache_len()) # 1
print(reader.cache_bytes()) # ~128
# Also callable directly on the index
result2 = index.read_node_with_content(reader, "customer_churn_q2")maggraph.toml for lakehouse mode:
[storage]
mode = "lakehouse"
root_path = "./knowledge_graph"
[lakehouse]
remote_sources = [
{ uri = "s3://corp-data/lake", format = "parquet" }
]maggraph scaffold --mcp --output ./mcp_serverGenerates a ready-to-run FastMCP server at ./mcp_server/server.py wired to
your graph index — expose list_nodes, read_node, traverse, create_node,
and delete_node as MCP tools with one command.
# Leader pushes a snapshot
maggraph sync push --message "Add Q2 analysis nodes"
# Follower (read-only) pulls
maggraph sync pull| Class / Function | Description |
|---|---|
load_config(path) |
Load maggraph.toml → ResolvedConfig |
open_index(root_path) |
Open graph index directly → GraphIndex |
ResolvedConfig.open_index() |
Open index from config |
ResolvedConfig.open_lakehouse_reader() |
Create a LakehouseReader |
GraphIndex.list_nodes() |
All node ids (sorted) |
GraphIndex.read_node(id) |
Node with metadata + body |
GraphIndex.search(...) |
Structured search over ids, types, tags, frontmatter, links, body, and recency |
GraphIndex.hybrid_search(...) |
Explainable lexical + graph + recency + optional semantic retrieval with temporal/project filters |
GraphIndex.backlinks(id) |
Node ids that link to id |
GraphIndex.changed_since(unix) |
Files modified after a Unix timestamp |
GraphIndex.update_file(path) |
Refresh one changed markdown file in the index |
GraphIndex.recall_bundle(id, ...) |
Compact agent retrieval dict with Markdown |
GraphIndex.read_node_async(id) |
Async version |
GraphIndex.traverse(id, depth, order) |
BFS/DFS → TraversalResult |
GraphIndex.traverse_async(...) |
Async version |
GraphIndex.create_node(...) |
Write new node to disk + index |
GraphIndex.create_memory_node(...) |
Create typed memory nodes (preference, project_fact, decision, task, session_summary, bookmark, tool_failure) |
GraphIndex.apply_memory_batch(...) |
Preview or apply reviewed update/suppress/unsuppress/merge operations as one rollback-capable batch |
GraphIndex.update_node(id, body) |
Update body on disk |
GraphIndex.delete_node(id) |
Delete node from disk + index |
GraphIndex.suppress_node(id) / unsuppress_node(id) |
Mark/unmark stale or duplicate nodes |
GraphIndex.merge_nodes(target, source) |
Merge duplicate source into canonical target |
GraphIndex.read_node_with_content(reader, id) |
Resolve external content |
LakehouseReader.read_node(index, id) |
→ NodeWithContent |
LakehouseReader.read_node_async(index, id) |
Async version |
LakehouseReader.cache_len() |
Entries in content cache |
LakehouseReader.cache_bytes() |
Bytes in content cache |
Node.id / .node_type / .body / .links / .source |
Node properties |
Node.to_markdown() |
Full node as Markdown string |
Node.to_dict() |
Node as plain Python dict |
ResolvedContent.kind |
"local" / "text" / "external_asset" |
ResolvedContent.body / .uri / .format |
Content details |
ResolvedContent.to_markdown() |
Agent-friendly summary |
NodeWithContent.node / .content |
Node + resolved content |
MIT OR Apache-2.0