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 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
+ [![CI](https://github.com/AlexMercedCoder/MagGraph/actions/workflows/ci.yml/badge.svg)](https://github.com/AlexMercedCoder/MagGraph/actions)
43
+ [![PyPI](https://img.shields.io/pypi/v/maggraph)](https://pypi.org/project/maggraph/)
44
+ [![Python](https://img.shields.io/pypi/pyversions/maggraph)](https://pypi.org/project/maggraph/)
45
+ [![License](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue)](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,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: maturin (1.13.3)
3
+ Root-Is-Purelib: false
4
+ Tag: cp39-abi3-win_amd64