maggraph 0.2.5__cp39-abi3-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- maggraph/__init__.py +53 -0
- maggraph/__init__.pyi +205 -0
- maggraph/_maggraph.pyd +0 -0
- maggraph/py.typed +0 -0
- maggraph-0.2.5.dist-info/METADATA +248 -0
- maggraph-0.2.5.dist-info/RECORD +8 -0
- maggraph-0.2.5.dist-info/WHEEL +4 -0
- maggraph-0.2.5.dist-info/sboms/maggraph.cyclonedx.json +4862 -0
maggraph/__init__.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""MagGraph — Python bindings for the Rust graph engine."""
|
|
2
|
+
|
|
3
|
+
from maggraph._maggraph import (
|
|
4
|
+
GraphIndex,
|
|
5
|
+
LakehouseReader,
|
|
6
|
+
MagGraphError,
|
|
7
|
+
Node,
|
|
8
|
+
NodeWithContent,
|
|
9
|
+
ResolvedConfig,
|
|
10
|
+
ResolvedContent,
|
|
11
|
+
TraversalNode,
|
|
12
|
+
TraversalResult,
|
|
13
|
+
load_config,
|
|
14
|
+
open_index,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
async def _graph_read_node_async(self: GraphIndex, node_id: str) -> Node:
|
|
18
|
+
return self.read_node(node_id)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
async def _graph_traverse_async(
|
|
22
|
+
self: GraphIndex, from_id: str, depth: int = 2, order: str = "bfs"
|
|
23
|
+
) -> TraversalResult:
|
|
24
|
+
return self.traverse(from_id, depth, order)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
async def _lakehouse_read_node_async(
|
|
28
|
+
self: LakehouseReader, index: GraphIndex, node_id: str
|
|
29
|
+
) -> NodeWithContent:
|
|
30
|
+
return self.read_node(index, node_id)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# Keep async convenience methods on the Python side so they follow Python 3.14
|
|
34
|
+
# asyncio semantics while reusing the Rust sync methods as the source of truth.
|
|
35
|
+
GraphIndex.read_node_async = _graph_read_node_async
|
|
36
|
+
GraphIndex.traverse_async = _graph_traverse_async
|
|
37
|
+
LakehouseReader.read_node_async = _lakehouse_read_node_async
|
|
38
|
+
|
|
39
|
+
__all__ = [
|
|
40
|
+
"GraphIndex",
|
|
41
|
+
"LakehouseReader",
|
|
42
|
+
"MagGraphError",
|
|
43
|
+
"Node",
|
|
44
|
+
"NodeWithContent",
|
|
45
|
+
"ResolvedConfig",
|
|
46
|
+
"ResolvedContent",
|
|
47
|
+
"TraversalNode",
|
|
48
|
+
"TraversalResult",
|
|
49
|
+
"load_config",
|
|
50
|
+
"open_index",
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
__version__ = "0.2.5"
|
maggraph/__init__.pyi
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
from typing import Awaitable, Literal, Optional, TypedDict
|
|
2
|
+
|
|
3
|
+
class SearchResult(TypedDict):
|
|
4
|
+
id: str
|
|
5
|
+
type: str
|
|
6
|
+
relative_path: str
|
|
7
|
+
score: int
|
|
8
|
+
matched: list[str]
|
|
9
|
+
summary: str
|
|
10
|
+
modified_unix: Optional[int]
|
|
11
|
+
|
|
12
|
+
class GraphChange(TypedDict):
|
|
13
|
+
id: str
|
|
14
|
+
relative_path: str
|
|
15
|
+
modified_unix: int
|
|
16
|
+
|
|
17
|
+
class RecallBundle(TypedDict):
|
|
18
|
+
id: str
|
|
19
|
+
type: str
|
|
20
|
+
summary: str
|
|
21
|
+
body_excerpt: str
|
|
22
|
+
links: list[str]
|
|
23
|
+
backlinks: list[str]
|
|
24
|
+
metadata: dict[str, object]
|
|
25
|
+
relevance_reason: str
|
|
26
|
+
markdown: str
|
|
27
|
+
|
|
28
|
+
class MagGraphError(Exception): ...
|
|
29
|
+
|
|
30
|
+
class ResolvedConfig:
|
|
31
|
+
@property
|
|
32
|
+
def root_path(self) -> str: ...
|
|
33
|
+
@property
|
|
34
|
+
def config_path(self) -> str: ...
|
|
35
|
+
@property
|
|
36
|
+
def storage_mode(self) -> Literal["local", "lakehouse"]: ...
|
|
37
|
+
def open_index(self) -> GraphIndex: ...
|
|
38
|
+
def open_lakehouse_reader(self) -> LakehouseReader: ...
|
|
39
|
+
|
|
40
|
+
class GraphIndex:
|
|
41
|
+
@classmethod
|
|
42
|
+
def open(cls, root_path: str) -> GraphIndex: ...
|
|
43
|
+
@property
|
|
44
|
+
def root_path(self) -> str: ...
|
|
45
|
+
def __len__(self) -> int: ...
|
|
46
|
+
def list_nodes(self) -> list[str]: ...
|
|
47
|
+
def read_node(self, node_id: str) -> Node: ...
|
|
48
|
+
def search(
|
|
49
|
+
self,
|
|
50
|
+
query: str = "",
|
|
51
|
+
node_type: str | None = None,
|
|
52
|
+
tags: list[str] | None = None,
|
|
53
|
+
include_suppressed: bool = False,
|
|
54
|
+
limit: int = 50,
|
|
55
|
+
modified_since_unix: int | None = None,
|
|
56
|
+
) -> list[SearchResult]: ...
|
|
57
|
+
def backlinks(self, node_id: str) -> list[str]: ...
|
|
58
|
+
def changed_since(self, since_unix: int) -> list[GraphChange]: ...
|
|
59
|
+
def update_file(self, path: str) -> Optional[str]: ...
|
|
60
|
+
def read_node_async(self, node_id: str) -> Awaitable[Node]: ...
|
|
61
|
+
def create_node(
|
|
62
|
+
self,
|
|
63
|
+
node_id: str,
|
|
64
|
+
node_type: str = "note",
|
|
65
|
+
body: str = "",
|
|
66
|
+
links: list[str] | None = None,
|
|
67
|
+
) -> Node: ...
|
|
68
|
+
def create_memory_node(
|
|
69
|
+
self,
|
|
70
|
+
node_id: str,
|
|
71
|
+
kind: Literal[
|
|
72
|
+
"preference",
|
|
73
|
+
"project_fact",
|
|
74
|
+
"decision",
|
|
75
|
+
"task",
|
|
76
|
+
"session_summary",
|
|
77
|
+
"bookmark",
|
|
78
|
+
"tool_failure",
|
|
79
|
+
],
|
|
80
|
+
body: str = "",
|
|
81
|
+
links: list[str] | None = None,
|
|
82
|
+
) -> Node: ...
|
|
83
|
+
def update_node(self, node_id: str, body: str) -> None: ...
|
|
84
|
+
def delete_node(self, node_id: str) -> None: ...
|
|
85
|
+
def suppress_node(self, node_id: str, reason: str | None = None) -> None: ...
|
|
86
|
+
def unsuppress_node(self, node_id: str) -> None: ...
|
|
87
|
+
def merge_nodes(self, target_id: str, source_id: str) -> None: ...
|
|
88
|
+
def recall_bundle(
|
|
89
|
+
self, node_id: str, reason: str = "", body_chars: int = 1200
|
|
90
|
+
) -> RecallBundle: ...
|
|
91
|
+
def traverse(
|
|
92
|
+
self,
|
|
93
|
+
from_id: str,
|
|
94
|
+
depth: int = 2,
|
|
95
|
+
order: Literal["bfs", "dfs"] = "bfs",
|
|
96
|
+
) -> TraversalResult: ...
|
|
97
|
+
def traverse_async(
|
|
98
|
+
self,
|
|
99
|
+
from_id: str,
|
|
100
|
+
depth: int = 2,
|
|
101
|
+
order: Literal["bfs", "dfs"] = "bfs",
|
|
102
|
+
) -> Awaitable[TraversalResult]: ...
|
|
103
|
+
def read_node_with_content(
|
|
104
|
+
self, reader: LakehouseReader, node_id: str
|
|
105
|
+
) -> NodeWithContent: ...
|
|
106
|
+
|
|
107
|
+
class Node:
|
|
108
|
+
@property
|
|
109
|
+
def id(self) -> str: ...
|
|
110
|
+
@property
|
|
111
|
+
def node_type(self) -> str: ...
|
|
112
|
+
@property
|
|
113
|
+
def source(self) -> Optional[str]: ...
|
|
114
|
+
@property
|
|
115
|
+
def links(self) -> list[str]: ...
|
|
116
|
+
@property
|
|
117
|
+
def body(self) -> str: ...
|
|
118
|
+
@property
|
|
119
|
+
def relative_path(self) -> str: ...
|
|
120
|
+
def to_markdown(self) -> str: ...
|
|
121
|
+
def to_dict(self) -> dict[str, object]: ...
|
|
122
|
+
|
|
123
|
+
class TraversalNode:
|
|
124
|
+
@property
|
|
125
|
+
def id(self) -> str: ...
|
|
126
|
+
@property
|
|
127
|
+
def depth(self) -> int: ...
|
|
128
|
+
@property
|
|
129
|
+
def path(self) -> list[str]: ...
|
|
130
|
+
|
|
131
|
+
class TraversalResult:
|
|
132
|
+
@property
|
|
133
|
+
def start(self) -> str: ...
|
|
134
|
+
@property
|
|
135
|
+
def max_depth(self) -> int: ...
|
|
136
|
+
@property
|
|
137
|
+
def order(self) -> str: ...
|
|
138
|
+
@property
|
|
139
|
+
def nodes(self) -> list[TraversalNode]: ...
|
|
140
|
+
def to_markdown(self, index: GraphIndex) -> str: ...
|
|
141
|
+
|
|
142
|
+
class ResolvedContent:
|
|
143
|
+
"""Content resolved from a node source — local markdown or an external asset.
|
|
144
|
+
|
|
145
|
+
Check ``.kind`` to determine how to interpret the other attributes:
|
|
146
|
+
|
|
147
|
+
* ``"local"`` — ``.body`` is the markdown, ``.uri`` / ``.format`` are ``None``
|
|
148
|
+
* ``"text"`` — ``.uri`` and ``.body`` are set, ``.format`` is ``None``
|
|
149
|
+
* ``"external_asset"`` — ``.uri`` and ``.format`` are set, ``.body`` is ``None``
|
|
150
|
+
"""
|
|
151
|
+
@property
|
|
152
|
+
def kind(self) -> Literal["local", "text", "external_asset"]: ...
|
|
153
|
+
@property
|
|
154
|
+
def body(self) -> Optional[str]: ...
|
|
155
|
+
"""Markdown body (``"local"`` and ``"text"`` only; ``None`` for external assets)."""
|
|
156
|
+
@property
|
|
157
|
+
def uri(self) -> Optional[str]: ...
|
|
158
|
+
"""External URI (``"text"`` and ``"external_asset"`` only)."""
|
|
159
|
+
@property
|
|
160
|
+
def format(self) -> Optional[str]: ...
|
|
161
|
+
"""Detected format, e.g. ``"parquet"`` (``"external_asset"`` only)."""
|
|
162
|
+
@property
|
|
163
|
+
def size_bytes(self) -> Optional[int]: ...
|
|
164
|
+
"""Size in bytes of the external asset, if known."""
|
|
165
|
+
@property
|
|
166
|
+
def parquet_magic_valid(self) -> Optional[bool]: ...
|
|
167
|
+
"""Whether the PAR1 magic header is valid (Parquet assets only)."""
|
|
168
|
+
@property
|
|
169
|
+
def snippet(self) -> Optional[str]: ...
|
|
170
|
+
"""Optional text snippet for external assets."""
|
|
171
|
+
def to_markdown(self) -> str: ...
|
|
172
|
+
"""Markdown-friendly summary for agent consumption."""
|
|
173
|
+
|
|
174
|
+
class NodeWithContent:
|
|
175
|
+
"""A graph node paired with its resolved external content."""
|
|
176
|
+
@property
|
|
177
|
+
def node(self) -> Node: ...
|
|
178
|
+
@property
|
|
179
|
+
def content(self) -> ResolvedContent: ...
|
|
180
|
+
|
|
181
|
+
class LakehouseReader:
|
|
182
|
+
"""Resolves node content according to the configured storage mode.
|
|
183
|
+
|
|
184
|
+
Construct via :meth:`ResolvedConfig.open_lakehouse_reader`.
|
|
185
|
+
|
|
186
|
+
Example::
|
|
187
|
+
|
|
188
|
+
config = maggraph.load_config("maggraph.toml")
|
|
189
|
+
index = config.open_index()
|
|
190
|
+
reader = config.open_lakehouse_reader()
|
|
191
|
+
|
|
192
|
+
result = reader.read_node(index, "my_asset")
|
|
193
|
+
print(result.content.to_markdown())
|
|
194
|
+
"""
|
|
195
|
+
def read_node(self, index: GraphIndex, node_id: str) -> NodeWithContent: ...
|
|
196
|
+
def read_node_async(
|
|
197
|
+
self, index: GraphIndex, node_id: str
|
|
198
|
+
) -> Awaitable[NodeWithContent]: ...
|
|
199
|
+
def cache_len(self) -> int: ...
|
|
200
|
+
"""Number of entries in the in-memory content cache."""
|
|
201
|
+
def cache_bytes(self) -> int: ...
|
|
202
|
+
"""Total bytes currently held in the cache."""
|
|
203
|
+
|
|
204
|
+
def load_config(path: str) -> ResolvedConfig: ...
|
|
205
|
+
def open_index(root_path: str) -> GraphIndex: ...
|
maggraph/_maggraph.pyd
ADDED
|
Binary file
|
maggraph/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: maggraph
|
|
3
|
+
Version: 0.2.5
|
|
4
|
+
Classifier: Development Status :: 3 - Alpha
|
|
5
|
+
Classifier: Intended Audience :: Developers
|
|
6
|
+
Classifier: Intended Audience :: Science/Research
|
|
7
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
8
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
+
Classifier: Programming Language :: Rust
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
19
|
+
Classifier: Topic :: Database
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Dist: pytest>=8.0 ; extra == 'dev'
|
|
23
|
+
Requires-Dist: pytest-asyncio>=0.24 ; extra == 'dev'
|
|
24
|
+
Requires-Dist: maturin>=1.7 ; extra == 'dev'
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Summary: In-process graph engine for AI semantic layers — powered by Rust
|
|
27
|
+
Keywords: graph,knowledge-graph,agent,ai,mcp,lakehouse,rust
|
|
28
|
+
Author-email: Alex Merced <alexmercedcoder@gmail.com>
|
|
29
|
+
License: MIT OR Apache-2.0
|
|
30
|
+
Requires-Python: >=3.9
|
|
31
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
32
|
+
Project-URL: Changelog, https://github.com/AlexMercedCoder/MagGraph/blob/main/planning/PROGRESS.md
|
|
33
|
+
Project-URL: Documentation, https://github.com/AlexMercedCoder/MagGraph/tree/main/planning
|
|
34
|
+
Project-URL: Homepage, https://github.com/AlexMercedCoder/MagGraph
|
|
35
|
+
Project-URL: Issue Tracker, https://github.com/AlexMercedCoder/MagGraph/issues
|
|
36
|
+
Project-URL: Repository, https://github.com/AlexMercedCoder/MagGraph
|
|
37
|
+
|
|
38
|
+
# MagGraph
|
|
39
|
+
|
|
40
|
+
**In-process Git-backed graph engine for AI semantic layers — powered by Rust**
|
|
41
|
+
|
|
42
|
+
[](https://github.com/AlexMercedCoder/MagGraph/actions)
|
|
43
|
+
[](https://pypi.org/project/maggraph/)
|
|
44
|
+
[](https://pypi.org/project/maggraph/)
|
|
45
|
+
[](https://github.com/AlexMercedCoder/MagGraph)
|
|
46
|
+
|
|
47
|
+
> **Why "MagGraph"?** The name is short for **Magpie** — a Corvid. Corvids (ravens,
|
|
48
|
+
> crows, jays, and magpies) are renowned in animal cognition research for their
|
|
49
|
+
> remarkable intelligence, long-term memory, and sophisticated tool use.
|
|
50
|
+
> MagGraph is built to be the memory and knowledge layer for AI agents with those
|
|
51
|
+
> same qualities: a graph that thinks, remembers, and uses tools.
|
|
52
|
+
|
|
53
|
+
MagGraph stores knowledge as versioned Markdown nodes in your Git repository,
|
|
54
|
+
with BFS/DFS traversal, Git-backed sync, external lakehouse content resolution,
|
|
55
|
+
and a built-in MCP server scaffold — all from a zero-dependency `pip install`.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Install
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pip install maggraph
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Pre-built wheels are available for:
|
|
66
|
+
|
|
67
|
+
| Platform | Architectures |
|
|
68
|
+
|----------|---------------|
|
|
69
|
+
| Linux (manylinux_2_28) | x86\_64 · aarch64 |
|
|
70
|
+
| macOS | Intel (x86\_64) · Apple Silicon (arm64) |
|
|
71
|
+
| Windows | x86\_64 |
|
|
72
|
+
|
|
73
|
+
> **No Rust toolchain required** — the Rust core is compiled into the wheel.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Quick start
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
import maggraph
|
|
81
|
+
|
|
82
|
+
# Load config + open the graph index
|
|
83
|
+
config = maggraph.load_config("maggraph.toml")
|
|
84
|
+
index = config.open_index()
|
|
85
|
+
|
|
86
|
+
# List nodes
|
|
87
|
+
print(index.list_nodes()) # ['getting_started', 'welcome', ...]
|
|
88
|
+
|
|
89
|
+
# Read a node
|
|
90
|
+
node = index.read_node("welcome")
|
|
91
|
+
print(node.body) # full markdown body
|
|
92
|
+
|
|
93
|
+
# Search, backlinks, and recall
|
|
94
|
+
print(index.search("Welcome")[0]["id"])
|
|
95
|
+
print(index.backlinks("welcome"))
|
|
96
|
+
bundle = index.recall_bundle("welcome", reason="quick start")
|
|
97
|
+
print(bundle["markdown"])
|
|
98
|
+
|
|
99
|
+
# BFS traversal
|
|
100
|
+
result = index.traverse("welcome", depth=2, order="bfs")
|
|
101
|
+
print(result.to_markdown(index)) # formatted traversal report
|
|
102
|
+
|
|
103
|
+
# CRUD and memory helpers
|
|
104
|
+
index.create_memory_node("prefers_cli", "preference", "User prefers CLI-first UX.")
|
|
105
|
+
index.create_node("new_note", node_type="note", body="# Hi\n", links=["welcome"])
|
|
106
|
+
index.update_node("new_note", "# Updated\n")
|
|
107
|
+
index.suppress_node("new_note", reason="example")
|
|
108
|
+
index.unsuppress_node("new_note")
|
|
109
|
+
index.delete_node("new_note")
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Async support
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
import asyncio, maggraph
|
|
118
|
+
|
|
119
|
+
async def main():
|
|
120
|
+
index = maggraph.open_index("examples/basic/knowledge_graph")
|
|
121
|
+
node = await index.read_node_async("welcome")
|
|
122
|
+
result = await index.traverse_async("welcome", depth=3, order="dfs")
|
|
123
|
+
print(result.to_markdown(index))
|
|
124
|
+
|
|
125
|
+
asyncio.run(main())
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Blocking Rust work runs on a Tokio thread pool — Python's event loop stays responsive.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Lakehouse content resolution
|
|
133
|
+
|
|
134
|
+
Resolve external data sources (S3, file://, HTTP) referenced from node frontmatter:
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
import maggraph
|
|
138
|
+
|
|
139
|
+
config = maggraph.load_config("maggraph.toml") # mode = "lakehouse"
|
|
140
|
+
index = config.open_index()
|
|
141
|
+
reader = config.open_lakehouse_reader()
|
|
142
|
+
|
|
143
|
+
# Resolve a node's external source (e.g. s3://bucket/data.parquet)
|
|
144
|
+
result = reader.read_node(index, "customer_churn_q2")
|
|
145
|
+
print(result.content.kind) # "external_asset"
|
|
146
|
+
print(result.content.uri) # "s3://corp-data/lake/churn.parquet"
|
|
147
|
+
print(result.content.format) # "parquet"
|
|
148
|
+
print(result.content.to_markdown()) # agent-friendly summary
|
|
149
|
+
|
|
150
|
+
# Cache stats
|
|
151
|
+
print(reader.cache_len()) # 1
|
|
152
|
+
print(reader.cache_bytes()) # ~128
|
|
153
|
+
|
|
154
|
+
# Also callable directly on the index
|
|
155
|
+
result2 = index.read_node_with_content(reader, "customer_churn_q2")
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**`maggraph.toml`** for lakehouse mode:
|
|
159
|
+
|
|
160
|
+
```toml
|
|
161
|
+
[storage]
|
|
162
|
+
mode = "lakehouse"
|
|
163
|
+
root_path = "./knowledge_graph"
|
|
164
|
+
|
|
165
|
+
[lakehouse]
|
|
166
|
+
remote_sources = [
|
|
167
|
+
{ uri = "s3://corp-data/lake", format = "parquet" }
|
|
168
|
+
]
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## MCP server scaffold
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
maggraph scaffold --mcp --output ./mcp_server
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Generates a ready-to-run FastMCP server at `./mcp_server/server.py` wired to
|
|
180
|
+
your graph index — expose `list_nodes`, `read_node`, `traverse`, `create_node`,
|
|
181
|
+
and `delete_node` as MCP tools with one command.
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Git-backed sync
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
# Leader pushes a snapshot
|
|
189
|
+
maggraph sync push --message "Add Q2 analysis nodes"
|
|
190
|
+
|
|
191
|
+
# Follower (read-only) pulls
|
|
192
|
+
maggraph sync pull
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## API reference
|
|
198
|
+
|
|
199
|
+
| Class / Function | Description |
|
|
200
|
+
|-----------------|-------------|
|
|
201
|
+
| `load_config(path)` | Load `maggraph.toml` → `ResolvedConfig` |
|
|
202
|
+
| `open_index(root_path)` | Open graph index directly → `GraphIndex` |
|
|
203
|
+
| `ResolvedConfig.open_index()` | Open index from config |
|
|
204
|
+
| `ResolvedConfig.open_lakehouse_reader()` | Create a `LakehouseReader` |
|
|
205
|
+
| `GraphIndex.list_nodes()` | All node ids (sorted) |
|
|
206
|
+
| `GraphIndex.read_node(id)` | `Node` with metadata + body |
|
|
207
|
+
| `GraphIndex.search(...)` | Structured search over ids, types, tags, frontmatter, links, body, and recency |
|
|
208
|
+
| `GraphIndex.backlinks(id)` | Node ids that link to `id` |
|
|
209
|
+
| `GraphIndex.changed_since(unix)` | Files modified after a Unix timestamp |
|
|
210
|
+
| `GraphIndex.update_file(path)` | Refresh one changed markdown file in the index |
|
|
211
|
+
| `GraphIndex.recall_bundle(id, ...)` | Compact agent retrieval dict with Markdown |
|
|
212
|
+
| `GraphIndex.read_node_async(id)` | Async version |
|
|
213
|
+
| `GraphIndex.traverse(id, depth, order)` | BFS/DFS → `TraversalResult` |
|
|
214
|
+
| `GraphIndex.traverse_async(...)` | Async version |
|
|
215
|
+
| `GraphIndex.create_node(...)` | Write new node to disk + index |
|
|
216
|
+
| `GraphIndex.create_memory_node(...)` | Create typed memory nodes (`preference`, `project_fact`, `decision`, `task`, `session_summary`, `bookmark`, `tool_failure`) |
|
|
217
|
+
| `GraphIndex.update_node(id, body)` | Update body on disk |
|
|
218
|
+
| `GraphIndex.delete_node(id)` | Delete node from disk + index |
|
|
219
|
+
| `GraphIndex.suppress_node(id)` / `unsuppress_node(id)` | Mark/unmark stale or duplicate nodes |
|
|
220
|
+
| `GraphIndex.merge_nodes(target, source)` | Merge duplicate source into canonical target |
|
|
221
|
+
| `GraphIndex.read_node_with_content(reader, id)` | Resolve external content |
|
|
222
|
+
| `LakehouseReader.read_node(index, id)` | → `NodeWithContent` |
|
|
223
|
+
| `LakehouseReader.read_node_async(index, id)` | Async version |
|
|
224
|
+
| `LakehouseReader.cache_len()` | Entries in content cache |
|
|
225
|
+
| `LakehouseReader.cache_bytes()` | Bytes in content cache |
|
|
226
|
+
| `Node.id / .node_type / .body / .links / .source` | Node properties |
|
|
227
|
+
| `Node.to_markdown()` | Full node as Markdown string |
|
|
228
|
+
| `Node.to_dict()` | Node as plain Python dict |
|
|
229
|
+
| `ResolvedContent.kind` | `"local"` / `"text"` / `"external_asset"` |
|
|
230
|
+
| `ResolvedContent.body / .uri / .format` | Content details |
|
|
231
|
+
| `ResolvedContent.to_markdown()` | Agent-friendly summary |
|
|
232
|
+
| `NodeWithContent.node / .content` | Node + resolved content |
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## Links
|
|
237
|
+
|
|
238
|
+
- [GitHub](https://github.com/AlexMercedCoder/MagGraph)
|
|
239
|
+
- [Architecture & planning docs](https://github.com/AlexMercedCoder/MagGraph/tree/main/planning)
|
|
240
|
+
- [Examples](https://github.com/AlexMercedCoder/MagGraph/tree/main/examples)
|
|
241
|
+
- [CONTRIBUTING.md](https://github.com/AlexMercedCoder/MagGraph/blob/main/CONTRIBUTING.md)
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## License
|
|
246
|
+
|
|
247
|
+
MIT OR Apache-2.0
|
|
248
|
+
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
maggraph/__init__.py,sha256=2bzbIbAF3Jdih7wP6zbpytJ1sAVEhoIklLjRshfU0_c,1386
|
|
2
|
+
maggraph/__init__.pyi,sha256=Q6xSgvVNmvD1jtyMpm577qywuBYF0De4BKneo5hMbac,6659
|
|
3
|
+
maggraph/_maggraph.pyd,sha256=cN88xofwCtexCOhZF6PrxGip0x1JzuWerEktYRx-fIo,3180032
|
|
4
|
+
maggraph/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
maggraph-0.2.5.dist-info/METADATA,sha256=_TMfGgneOUWk0Y-Op52_SK9ppq0M6YKqZgNZp1p1fiA,9309
|
|
6
|
+
maggraph-0.2.5.dist-info/WHEEL,sha256=dB50znGoqD95tHNeV5UBZvlfLNwgEh0iQcswp5YahQ4,95
|
|
7
|
+
maggraph-0.2.5.dist-info/sboms/maggraph.cyclonedx.json,sha256=MYRV4-eyW85LDzL45X_Xt6gKRykSJr9TAaLPEh087iA,155112
|
|
8
|
+
maggraph-0.2.5.dist-info/RECORD,,
|