graphifyy 0.3.0__tar.gz → 0.3.2__tar.gz
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.
- {graphifyy-0.3.0 → graphifyy-0.3.2}/PKG-INFO +65 -19
- {graphifyy-0.3.0 → graphifyy-0.3.2}/README.md +60 -18
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphify/__main__.py +93 -6
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphify/analyze.py +9 -5
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphify/cache.py +15 -3
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphify/detect.py +64 -2
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphify/export.py +22 -13
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphify/extract.py +463 -5
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphify/hooks.py +25 -16
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphify/ingest.py +8 -5
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphify/security.py +34 -2
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphify/serve.py +2 -2
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphify/skill.md +1 -1
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphify/watch.py +3 -4
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphifyy.egg-info/PKG-INFO +65 -19
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphifyy.egg-info/requires.txt +4 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/pyproject.toml +5 -1
- {graphifyy-0.3.0 → graphifyy-0.3.2}/tests/test_detect.py +35 -1
- {graphifyy-0.3.0 → graphifyy-0.3.2}/tests/test_extract.py +2 -1
- {graphifyy-0.3.0 → graphifyy-0.3.2}/tests/test_install.py +74 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/tests/test_languages.py +121 -1
- {graphifyy-0.3.0 → graphifyy-0.3.2}/LICENSE +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphify/__init__.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphify/benchmark.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphify/build.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphify/cluster.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphify/manifest.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphify/report.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphify/skill-claw.md +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphify/skill-codex.md +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphify/skill-opencode.md +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphify/validate.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphify/wiki.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphifyy.egg-info/SOURCES.txt +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphifyy.egg-info/dependency_links.txt +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphifyy.egg-info/entry_points.txt +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/graphifyy.egg-info/top_level.txt +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/setup.cfg +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/tests/test_analyze.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/tests/test_benchmark.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/tests/test_build.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/tests/test_cache.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/tests/test_claude_md.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/tests/test_cluster.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/tests/test_confidence.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/tests/test_export.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/tests/test_hooks.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/tests/test_hypergraph.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/tests/test_ingest.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/tests/test_multilang.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/tests/test_pipeline.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/tests/test_rationale.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/tests/test_report.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/tests/test_security.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/tests/test_semantic_similarity.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/tests/test_serve.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/tests/test_validate.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/tests/test_watch.py +0 -0
- {graphifyy-0.3.0 → graphifyy-0.3.2}/tests/test_wiki.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: graphifyy
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: AI coding assistant skill (Claude Code, Codex, OpenCode, OpenClaw) - turn any folder of code, docs, papers, or images into a queryable knowledge graph
|
|
5
5
|
License: MIT License
|
|
6
6
|
|
|
@@ -46,6 +46,10 @@ Requires-Dist: tree-sitter-c-sharp
|
|
|
46
46
|
Requires-Dist: tree-sitter-kotlin
|
|
47
47
|
Requires-Dist: tree-sitter-scala
|
|
48
48
|
Requires-Dist: tree-sitter-php
|
|
49
|
+
Requires-Dist: tree-sitter-swift
|
|
50
|
+
Requires-Dist: tree-sitter-lua
|
|
51
|
+
Requires-Dist: tree-sitter-zig
|
|
52
|
+
Requires-Dist: tree-sitter-powershell
|
|
49
53
|
Provides-Extra: mcp
|
|
50
54
|
Requires-Dist: mcp; extra == "mcp"
|
|
51
55
|
Provides-Extra: neo4j
|
|
@@ -68,10 +72,12 @@ Dynamic: license-file
|
|
|
68
72
|
|
|
69
73
|
# graphify
|
|
70
74
|
|
|
75
|
+
[English](README.md) | [简体中文](README.zh-CN.md)
|
|
76
|
+
|
|
71
77
|
[](https://github.com/safishamsi/graphify/actions/workflows/ci.yml)
|
|
72
78
|
[](https://pypi.org/project/graphifyy/)
|
|
73
79
|
|
|
74
|
-
**An AI coding assistant skill.** Type `/graphify` in Claude Code, Codex, OpenCode, or
|
|
80
|
+
**An AI coding assistant skill.** Type `/graphify` in Claude Code, Codex, OpenCode, OpenClaw, or Factory Droid - it reads your files, builds a knowledge graph, and gives you back structure you didn't know was there. Understand a codebase faster. Find the "why" behind architectural decisions.
|
|
75
81
|
|
|
76
82
|
Fully multimodal. Drop in code, PDFs, markdown, screenshots, diagrams, whiteboard photos, even images in other languages - graphify uses Claude vision to extract concepts and relationships from all of it and connects them into one graph.
|
|
77
83
|
|
|
@@ -89,15 +95,29 @@ graphify-out/
|
|
|
89
95
|
└── cache/ SHA256 cache - re-runs only process changed files
|
|
90
96
|
```
|
|
91
97
|
|
|
98
|
+
Add a `.graphifyignore` file to exclude folders you don't want in the graph:
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
# .graphifyignore
|
|
102
|
+
vendor/
|
|
103
|
+
node_modules/
|
|
104
|
+
dist/
|
|
105
|
+
*.generated.py
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Same syntax as `.gitignore`. Patterns match against file paths relative to the folder you run graphify on.
|
|
109
|
+
|
|
92
110
|
## How it works
|
|
93
111
|
|
|
94
112
|
graphify runs in two passes. First, a deterministic AST pass extracts structure from code files (classes, functions, imports, call graphs, docstrings, rationale comments) with no LLM needed. Second, Claude subagents run in parallel over docs, papers, and images to extract concepts, relationships, and design rationale. The results are merged into a NetworkX graph, clustered with Leiden community detection, and exported as interactive HTML, queryable JSON, and a plain-language audit report.
|
|
95
113
|
|
|
114
|
+
**Clustering is graph-topology-based — no embeddings.** Leiden finds communities by edge density. The semantic similarity edges that Claude extracts (`semantically_similar_to`, marked INFERRED) are already in the graph, so they influence community detection directly. The graph structure is the similarity signal — no separate embedding step or vector database needed.
|
|
115
|
+
|
|
96
116
|
Every relationship is tagged `EXTRACTED` (found directly in source), `INFERRED` (reasonable inference, with a confidence score), or `AMBIGUOUS` (flagged for review). You always know what was found vs guessed.
|
|
97
117
|
|
|
98
118
|
## Install
|
|
99
119
|
|
|
100
|
-
**Requires:** [Claude Code](https://claude.ai/code)
|
|
120
|
+
**Requires:** Python 3.10+ and one of: [Claude Code](https://claude.ai/code), [Codex](https://openai.com/codex), [OpenCode](https://opencode.ai), [OpenClaw](https://openclaw.ai), or [Factory Droid](https://factory.ai)
|
|
101
121
|
|
|
102
122
|
```bash
|
|
103
123
|
pip install graphifyy && graphify install
|
|
@@ -113,8 +133,9 @@ pip install graphifyy && graphify install
|
|
|
113
133
|
| Codex | `graphify install --platform codex` |
|
|
114
134
|
| OpenCode | `graphify install --platform opencode` |
|
|
115
135
|
| OpenClaw | `graphify install --platform claw` |
|
|
136
|
+
| Factory Droid | `graphify install --platform droid` |
|
|
116
137
|
|
|
117
|
-
Codex users also need `multi_agent = true` under `[features]` in `~/.codex/config.toml` for parallel extraction. OpenClaw uses sequential extraction (parallel agent support is still early on that platform).
|
|
138
|
+
Codex users also need `multi_agent = true` under `[features]` in `~/.codex/config.toml` for parallel extraction. Factory Droid uses the `Task` tool for parallel subagent dispatch. OpenClaw uses sequential extraction (parallel agent support is still early on that platform).
|
|
118
139
|
|
|
119
140
|
Then open your AI coding assistant and type:
|
|
120
141
|
|
|
@@ -122,23 +143,31 @@ Then open your AI coding assistant and type:
|
|
|
122
143
|
/graphify .
|
|
123
144
|
```
|
|
124
145
|
|
|
125
|
-
### Make
|
|
146
|
+
### Make your assistant always use the graph (recommended)
|
|
126
147
|
|
|
127
148
|
After building a graph, run this once in your project:
|
|
128
149
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
150
|
+
| Platform | Command |
|
|
151
|
+
|----------|---------|
|
|
152
|
+
| Claude Code | `graphify claude install` |
|
|
153
|
+
| Codex | `graphify codex install` |
|
|
154
|
+
| OpenCode | `graphify opencode install` |
|
|
155
|
+
| OpenClaw | `graphify claw install` |
|
|
156
|
+
| Factory Droid | `graphify droid install` |
|
|
157
|
+
|
|
158
|
+
**Claude Code** does two things: writes a `CLAUDE.md` section telling Claude to read `graphify-out/GRAPH_REPORT.md` before answering architecture questions, and installs a **PreToolUse hook** (`settings.json`) that fires before every Glob and Grep call. If a knowledge graph exists, Claude sees: _"graphify: Knowledge graph exists. Read GRAPH_REPORT.md for god nodes and community structure before searching raw files."_ — so Claude navigates via the graph instead of grepping through every file.
|
|
159
|
+
|
|
160
|
+
**Codex, OpenCode, OpenClaw, Factory Droid** write the same rules to `AGENTS.md` in your project root. These platforms don't support PreToolUse hooks, so AGENTS.md is the always-on mechanism.
|
|
132
161
|
|
|
133
|
-
|
|
162
|
+
Uninstall with the matching uninstall command (e.g. `graphify claude uninstall`).
|
|
134
163
|
|
|
135
|
-
|
|
164
|
+
**Always-on vs explicit trigger — what's the difference?**
|
|
136
165
|
|
|
137
|
-
|
|
166
|
+
The always-on hook surfaces `GRAPH_REPORT.md` — a one-page summary of god nodes, communities, and surprising connections. Your assistant reads this before searching files, so it navigates by structure instead of keyword matching. That covers most everyday questions.
|
|
138
167
|
|
|
139
|
-
|
|
168
|
+
`/graphify query`, `/graphify path`, and `/graphify explain` go deeper: they traverse the raw `graph.json` hop by hop, trace exact paths between nodes, and surface edge-level detail (relation type, confidence score, source location). Use them when you want a specific question answered from the graph rather than a general orientation.
|
|
140
169
|
|
|
141
|
-
|
|
170
|
+
Think of it this way: the always-on hook gives your assistant a map. The `/graphify` commands let it navigate the map precisely.
|
|
142
171
|
|
|
143
172
|
<details>
|
|
144
173
|
<summary>Manual install (curl)</summary>
|
|
@@ -165,12 +194,18 @@ When the user types `/graphify`, invoke the Skill tool with `skill: "graphify"`
|
|
|
165
194
|
/graphify ./raw # run on a specific folder
|
|
166
195
|
/graphify ./raw --mode deep # more aggressive INFERRED edge extraction
|
|
167
196
|
/graphify ./raw --update # re-extract only changed files, merge into existing graph
|
|
197
|
+
/graphify ./raw --cluster-only # rerun clustering on existing graph, no re-extraction
|
|
198
|
+
/graphify ./raw --no-viz # skip HTML, just produce report + JSON
|
|
168
199
|
/graphify ./raw --obsidian # also generate Obsidian vault (opt-in)
|
|
169
200
|
|
|
170
201
|
/graphify add https://arxiv.org/abs/1706.03762 # fetch a paper, save, update graph
|
|
171
202
|
/graphify add https://x.com/karpathy/status/... # fetch a tweet
|
|
203
|
+
/graphify add https://... --author "Name" # tag the original author
|
|
204
|
+
/graphify add https://... --contributor "Name" # tag who added it to the corpus
|
|
172
205
|
|
|
173
206
|
/graphify query "what connects attention to the optimizer?"
|
|
207
|
+
/graphify query "what connects attention to the optimizer?" --dfs # trace a specific path
|
|
208
|
+
/graphify query "what connects attention to the optimizer?" --budget 1500 # cap at N tokens
|
|
174
209
|
/graphify path "DigestAuth" "Response"
|
|
175
210
|
/graphify explain "SwinTransformer"
|
|
176
211
|
|
|
@@ -179,17 +214,28 @@ When the user types `/graphify`, invoke the Skill tool with `skill: "graphify"`
|
|
|
179
214
|
/graphify ./raw --svg # export graph.svg
|
|
180
215
|
/graphify ./raw --graphml # export graph.graphml (Gephi, yEd)
|
|
181
216
|
/graphify ./raw --neo4j # generate cypher.txt for Neo4j
|
|
217
|
+
/graphify ./raw --neo4j-push bolt://localhost:7687 # push directly to a running Neo4j instance
|
|
182
218
|
/graphify ./raw --mcp # start MCP stdio server
|
|
183
219
|
|
|
184
|
-
|
|
185
|
-
graphify
|
|
220
|
+
# git hooks - platform-agnostic, rebuild graph on commit and branch switch
|
|
221
|
+
graphify hook install
|
|
222
|
+
graphify hook uninstall
|
|
223
|
+
graphify hook status
|
|
224
|
+
|
|
225
|
+
# always-on assistant instructions - platform-specific
|
|
226
|
+
graphify claude install # CLAUDE.md + PreToolUse hook (Claude Code)
|
|
227
|
+
graphify claude uninstall
|
|
228
|
+
graphify codex install # AGENTS.md (Codex)
|
|
229
|
+
graphify opencode install # AGENTS.md (OpenCode)
|
|
230
|
+
graphify claw install # AGENTS.md (OpenClaw)
|
|
231
|
+
graphify droid install # AGENTS.md (Factory Droid)
|
|
186
232
|
```
|
|
187
233
|
|
|
188
234
|
Works with any mix of file types:
|
|
189
235
|
|
|
190
236
|
| Type | Extensions | Extraction |
|
|
191
237
|
|------|-----------|------------|
|
|
192
|
-
| Code | `.py .ts .js .go .rs .java .c .cpp .rb .cs .kt .scala .php` | AST via tree-sitter + call-graph + docstring/comment rationale |
|
|
238
|
+
| Code | `.py .ts .js .go .rs .java .c .cpp .rb .cs .kt .scala .php .swift .lua .zig .ps1` | AST via tree-sitter + call-graph + docstring/comment rationale |
|
|
193
239
|
| Docs | `.md .txt .rst` | Concepts + relationships + design rationale via Claude |
|
|
194
240
|
| Papers | `.pdf` | Citation mining + concept extraction |
|
|
195
241
|
| Images | `.png .jpg .webp .gif` | Claude vision - screenshots, diagrams, any language |
|
|
@@ -214,7 +260,7 @@ Works with any mix of file types:
|
|
|
214
260
|
|
|
215
261
|
**Auto-sync** (`--watch`) - run in a background terminal and the graph updates itself as your codebase changes. Code file saves trigger an instant rebuild (AST only, no LLM). Doc/image changes notify you to run `--update` for the LLM re-pass.
|
|
216
262
|
|
|
217
|
-
**Git hooks** (`graphify hook install`) - installs post-commit and post-checkout hooks. Graph rebuilds automatically after every commit and every branch switch. No background process needed.
|
|
263
|
+
**Git hooks** (`graphify hook install`) - installs post-commit and post-checkout hooks. Graph rebuilds automatically after every commit and every branch switch. If a rebuild fails, the hook exits with a non-zero code so git surfaces the error instead of silently continuing. No background process needed.
|
|
218
264
|
|
|
219
265
|
**Wiki** (`--wiki`) - Wikipedia-style markdown articles per community and god node, with an `index.md` entry point. Point any agent at `index.md` and it can navigate the knowledge base by reading files instead of parsing JSON.
|
|
220
266
|
|
|
@@ -230,11 +276,11 @@ Token reduction scales with corpus size. 6 files fits in a context window anyway
|
|
|
230
276
|
|
|
231
277
|
## Privacy
|
|
232
278
|
|
|
233
|
-
graphify sends file contents to
|
|
279
|
+
graphify sends file contents to your AI coding assistant's underlying model API for semantic extraction of docs, papers, and images — Anthropic (Claude Code), OpenAI (Codex), or whichever provider your platform uses. Code files are processed locally via tree-sitter AST — no file contents leave your machine for code. No telemetry, usage tracking, or analytics of any kind. The only network calls are to your platform's model API during extraction, using your own API key.
|
|
234
280
|
|
|
235
281
|
## Tech stack
|
|
236
282
|
|
|
237
|
-
NetworkX + Leiden (graspologic) + tree-sitter +
|
|
283
|
+
NetworkX + Leiden (graspologic) + tree-sitter + vis.js. Semantic extraction via Claude (Claude Code), GPT-4 (Codex), or whichever model your platform runs. No Neo4j required, no server, runs entirely locally.
|
|
238
284
|
|
|
239
285
|
<details>
|
|
240
286
|
<summary>Contributing</summary>
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# graphify
|
|
2
2
|
|
|
3
|
+
[English](README.md) | [简体中文](README.zh-CN.md)
|
|
4
|
+
|
|
3
5
|
[](https://github.com/safishamsi/graphify/actions/workflows/ci.yml)
|
|
4
6
|
[](https://pypi.org/project/graphifyy/)
|
|
5
7
|
|
|
6
|
-
**An AI coding assistant skill.** Type `/graphify` in Claude Code, Codex, OpenCode, or
|
|
8
|
+
**An AI coding assistant skill.** Type `/graphify` in Claude Code, Codex, OpenCode, OpenClaw, or Factory Droid - it reads your files, builds a knowledge graph, and gives you back structure you didn't know was there. Understand a codebase faster. Find the "why" behind architectural decisions.
|
|
7
9
|
|
|
8
10
|
Fully multimodal. Drop in code, PDFs, markdown, screenshots, diagrams, whiteboard photos, even images in other languages - graphify uses Claude vision to extract concepts and relationships from all of it and connects them into one graph.
|
|
9
11
|
|
|
@@ -21,15 +23,29 @@ graphify-out/
|
|
|
21
23
|
└── cache/ SHA256 cache - re-runs only process changed files
|
|
22
24
|
```
|
|
23
25
|
|
|
26
|
+
Add a `.graphifyignore` file to exclude folders you don't want in the graph:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
# .graphifyignore
|
|
30
|
+
vendor/
|
|
31
|
+
node_modules/
|
|
32
|
+
dist/
|
|
33
|
+
*.generated.py
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Same syntax as `.gitignore`. Patterns match against file paths relative to the folder you run graphify on.
|
|
37
|
+
|
|
24
38
|
## How it works
|
|
25
39
|
|
|
26
40
|
graphify runs in two passes. First, a deterministic AST pass extracts structure from code files (classes, functions, imports, call graphs, docstrings, rationale comments) with no LLM needed. Second, Claude subagents run in parallel over docs, papers, and images to extract concepts, relationships, and design rationale. The results are merged into a NetworkX graph, clustered with Leiden community detection, and exported as interactive HTML, queryable JSON, and a plain-language audit report.
|
|
27
41
|
|
|
42
|
+
**Clustering is graph-topology-based — no embeddings.** Leiden finds communities by edge density. The semantic similarity edges that Claude extracts (`semantically_similar_to`, marked INFERRED) are already in the graph, so they influence community detection directly. The graph structure is the similarity signal — no separate embedding step or vector database needed.
|
|
43
|
+
|
|
28
44
|
Every relationship is tagged `EXTRACTED` (found directly in source), `INFERRED` (reasonable inference, with a confidence score), or `AMBIGUOUS` (flagged for review). You always know what was found vs guessed.
|
|
29
45
|
|
|
30
46
|
## Install
|
|
31
47
|
|
|
32
|
-
**Requires:** [Claude Code](https://claude.ai/code)
|
|
48
|
+
**Requires:** Python 3.10+ and one of: [Claude Code](https://claude.ai/code), [Codex](https://openai.com/codex), [OpenCode](https://opencode.ai), [OpenClaw](https://openclaw.ai), or [Factory Droid](https://factory.ai)
|
|
33
49
|
|
|
34
50
|
```bash
|
|
35
51
|
pip install graphifyy && graphify install
|
|
@@ -45,8 +61,9 @@ pip install graphifyy && graphify install
|
|
|
45
61
|
| Codex | `graphify install --platform codex` |
|
|
46
62
|
| OpenCode | `graphify install --platform opencode` |
|
|
47
63
|
| OpenClaw | `graphify install --platform claw` |
|
|
64
|
+
| Factory Droid | `graphify install --platform droid` |
|
|
48
65
|
|
|
49
|
-
Codex users also need `multi_agent = true` under `[features]` in `~/.codex/config.toml` for parallel extraction. OpenClaw uses sequential extraction (parallel agent support is still early on that platform).
|
|
66
|
+
Codex users also need `multi_agent = true` under `[features]` in `~/.codex/config.toml` for parallel extraction. Factory Droid uses the `Task` tool for parallel subagent dispatch. OpenClaw uses sequential extraction (parallel agent support is still early on that platform).
|
|
50
67
|
|
|
51
68
|
Then open your AI coding assistant and type:
|
|
52
69
|
|
|
@@ -54,23 +71,31 @@ Then open your AI coding assistant and type:
|
|
|
54
71
|
/graphify .
|
|
55
72
|
```
|
|
56
73
|
|
|
57
|
-
### Make
|
|
74
|
+
### Make your assistant always use the graph (recommended)
|
|
58
75
|
|
|
59
76
|
After building a graph, run this once in your project:
|
|
60
77
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
78
|
+
| Platform | Command |
|
|
79
|
+
|----------|---------|
|
|
80
|
+
| Claude Code | `graphify claude install` |
|
|
81
|
+
| Codex | `graphify codex install` |
|
|
82
|
+
| OpenCode | `graphify opencode install` |
|
|
83
|
+
| OpenClaw | `graphify claw install` |
|
|
84
|
+
| Factory Droid | `graphify droid install` |
|
|
85
|
+
|
|
86
|
+
**Claude Code** does two things: writes a `CLAUDE.md` section telling Claude to read `graphify-out/GRAPH_REPORT.md` before answering architecture questions, and installs a **PreToolUse hook** (`settings.json`) that fires before every Glob and Grep call. If a knowledge graph exists, Claude sees: _"graphify: Knowledge graph exists. Read GRAPH_REPORT.md for god nodes and community structure before searching raw files."_ — so Claude navigates via the graph instead of grepping through every file.
|
|
87
|
+
|
|
88
|
+
**Codex, OpenCode, OpenClaw, Factory Droid** write the same rules to `AGENTS.md` in your project root. These platforms don't support PreToolUse hooks, so AGENTS.md is the always-on mechanism.
|
|
64
89
|
|
|
65
|
-
|
|
90
|
+
Uninstall with the matching uninstall command (e.g. `graphify claude uninstall`).
|
|
66
91
|
|
|
67
|
-
|
|
92
|
+
**Always-on vs explicit trigger — what's the difference?**
|
|
68
93
|
|
|
69
|
-
|
|
94
|
+
The always-on hook surfaces `GRAPH_REPORT.md` — a one-page summary of god nodes, communities, and surprising connections. Your assistant reads this before searching files, so it navigates by structure instead of keyword matching. That covers most everyday questions.
|
|
70
95
|
|
|
71
|
-
|
|
96
|
+
`/graphify query`, `/graphify path`, and `/graphify explain` go deeper: they traverse the raw `graph.json` hop by hop, trace exact paths between nodes, and surface edge-level detail (relation type, confidence score, source location). Use them when you want a specific question answered from the graph rather than a general orientation.
|
|
72
97
|
|
|
73
|
-
|
|
98
|
+
Think of it this way: the always-on hook gives your assistant a map. The `/graphify` commands let it navigate the map precisely.
|
|
74
99
|
|
|
75
100
|
<details>
|
|
76
101
|
<summary>Manual install (curl)</summary>
|
|
@@ -97,12 +122,18 @@ When the user types `/graphify`, invoke the Skill tool with `skill: "graphify"`
|
|
|
97
122
|
/graphify ./raw # run on a specific folder
|
|
98
123
|
/graphify ./raw --mode deep # more aggressive INFERRED edge extraction
|
|
99
124
|
/graphify ./raw --update # re-extract only changed files, merge into existing graph
|
|
125
|
+
/graphify ./raw --cluster-only # rerun clustering on existing graph, no re-extraction
|
|
126
|
+
/graphify ./raw --no-viz # skip HTML, just produce report + JSON
|
|
100
127
|
/graphify ./raw --obsidian # also generate Obsidian vault (opt-in)
|
|
101
128
|
|
|
102
129
|
/graphify add https://arxiv.org/abs/1706.03762 # fetch a paper, save, update graph
|
|
103
130
|
/graphify add https://x.com/karpathy/status/... # fetch a tweet
|
|
131
|
+
/graphify add https://... --author "Name" # tag the original author
|
|
132
|
+
/graphify add https://... --contributor "Name" # tag who added it to the corpus
|
|
104
133
|
|
|
105
134
|
/graphify query "what connects attention to the optimizer?"
|
|
135
|
+
/graphify query "what connects attention to the optimizer?" --dfs # trace a specific path
|
|
136
|
+
/graphify query "what connects attention to the optimizer?" --budget 1500 # cap at N tokens
|
|
106
137
|
/graphify path "DigestAuth" "Response"
|
|
107
138
|
/graphify explain "SwinTransformer"
|
|
108
139
|
|
|
@@ -111,17 +142,28 @@ When the user types `/graphify`, invoke the Skill tool with `skill: "graphify"`
|
|
|
111
142
|
/graphify ./raw --svg # export graph.svg
|
|
112
143
|
/graphify ./raw --graphml # export graph.graphml (Gephi, yEd)
|
|
113
144
|
/graphify ./raw --neo4j # generate cypher.txt for Neo4j
|
|
145
|
+
/graphify ./raw --neo4j-push bolt://localhost:7687 # push directly to a running Neo4j instance
|
|
114
146
|
/graphify ./raw --mcp # start MCP stdio server
|
|
115
147
|
|
|
116
|
-
|
|
117
|
-
graphify
|
|
148
|
+
# git hooks - platform-agnostic, rebuild graph on commit and branch switch
|
|
149
|
+
graphify hook install
|
|
150
|
+
graphify hook uninstall
|
|
151
|
+
graphify hook status
|
|
152
|
+
|
|
153
|
+
# always-on assistant instructions - platform-specific
|
|
154
|
+
graphify claude install # CLAUDE.md + PreToolUse hook (Claude Code)
|
|
155
|
+
graphify claude uninstall
|
|
156
|
+
graphify codex install # AGENTS.md (Codex)
|
|
157
|
+
graphify opencode install # AGENTS.md (OpenCode)
|
|
158
|
+
graphify claw install # AGENTS.md (OpenClaw)
|
|
159
|
+
graphify droid install # AGENTS.md (Factory Droid)
|
|
118
160
|
```
|
|
119
161
|
|
|
120
162
|
Works with any mix of file types:
|
|
121
163
|
|
|
122
164
|
| Type | Extensions | Extraction |
|
|
123
165
|
|------|-----------|------------|
|
|
124
|
-
| Code | `.py .ts .js .go .rs .java .c .cpp .rb .cs .kt .scala .php` | AST via tree-sitter + call-graph + docstring/comment rationale |
|
|
166
|
+
| Code | `.py .ts .js .go .rs .java .c .cpp .rb .cs .kt .scala .php .swift .lua .zig .ps1` | AST via tree-sitter + call-graph + docstring/comment rationale |
|
|
125
167
|
| Docs | `.md .txt .rst` | Concepts + relationships + design rationale via Claude |
|
|
126
168
|
| Papers | `.pdf` | Citation mining + concept extraction |
|
|
127
169
|
| Images | `.png .jpg .webp .gif` | Claude vision - screenshots, diagrams, any language |
|
|
@@ -146,7 +188,7 @@ Works with any mix of file types:
|
|
|
146
188
|
|
|
147
189
|
**Auto-sync** (`--watch`) - run in a background terminal and the graph updates itself as your codebase changes. Code file saves trigger an instant rebuild (AST only, no LLM). Doc/image changes notify you to run `--update` for the LLM re-pass.
|
|
148
190
|
|
|
149
|
-
**Git hooks** (`graphify hook install`) - installs post-commit and post-checkout hooks. Graph rebuilds automatically after every commit and every branch switch. No background process needed.
|
|
191
|
+
**Git hooks** (`graphify hook install`) - installs post-commit and post-checkout hooks. Graph rebuilds automatically after every commit and every branch switch. If a rebuild fails, the hook exits with a non-zero code so git surfaces the error instead of silently continuing. No background process needed.
|
|
150
192
|
|
|
151
193
|
**Wiki** (`--wiki`) - Wikipedia-style markdown articles per community and god node, with an `index.md` entry point. Point any agent at `index.md` and it can navigate the knowledge base by reading files instead of parsing JSON.
|
|
152
194
|
|
|
@@ -162,11 +204,11 @@ Token reduction scales with corpus size. 6 files fits in a context window anyway
|
|
|
162
204
|
|
|
163
205
|
## Privacy
|
|
164
206
|
|
|
165
|
-
graphify sends file contents to
|
|
207
|
+
graphify sends file contents to your AI coding assistant's underlying model API for semantic extraction of docs, papers, and images — Anthropic (Claude Code), OpenAI (Codex), or whichever provider your platform uses. Code files are processed locally via tree-sitter AST — no file contents leave your machine for code. No telemetry, usage tracking, or analytics of any kind. The only network calls are to your platform's model API during extraction, using your own API key.
|
|
166
208
|
|
|
167
209
|
## Tech stack
|
|
168
210
|
|
|
169
|
-
NetworkX + Leiden (graspologic) + tree-sitter +
|
|
211
|
+
NetworkX + Leiden (graspologic) + tree-sitter + vis.js. Semantic extraction via Claude (Claude Code), GPT-4 (Codex), or whichever model your platform runs. No Neo4j required, no server, runs entirely locally.
|
|
170
212
|
|
|
171
213
|
<details>
|
|
172
214
|
<summary>Contributing</summary>
|
|
@@ -50,6 +50,11 @@ _PLATFORM_CONFIG: dict[str, dict] = {
|
|
|
50
50
|
"skill_dst": Path(".claw") / "skills" / "graphify" / "SKILL.md",
|
|
51
51
|
"claude_md": False,
|
|
52
52
|
},
|
|
53
|
+
"droid": {
|
|
54
|
+
"skill_file": "skill-droid.md",
|
|
55
|
+
"skill_dst": Path(".factory") / "skills" / "graphify" / "SKILL.md",
|
|
56
|
+
"claude_md": False,
|
|
57
|
+
},
|
|
53
58
|
}
|
|
54
59
|
|
|
55
60
|
|
|
@@ -107,6 +112,71 @@ Rules:
|
|
|
107
112
|
|
|
108
113
|
_CLAUDE_MD_MARKER = "## graphify"
|
|
109
114
|
|
|
115
|
+
# AGENTS.md section for Codex, OpenCode, and OpenClaw.
|
|
116
|
+
# All three platforms read AGENTS.md in the project root for persistent instructions.
|
|
117
|
+
_AGENTS_MD_SECTION = """\
|
|
118
|
+
## graphify
|
|
119
|
+
|
|
120
|
+
This project has a graphify knowledge graph at graphify-out/.
|
|
121
|
+
|
|
122
|
+
Rules:
|
|
123
|
+
- Before answering architecture or codebase questions, read graphify-out/GRAPH_REPORT.md for god nodes and community structure
|
|
124
|
+
- If graphify-out/wiki/index.md exists, navigate it instead of reading raw files
|
|
125
|
+
- After modifying code files in this session, run `python3 -c "from graphify.watch import _rebuild_code; from pathlib import Path; _rebuild_code(Path('.'))"` to keep the graph current
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
_AGENTS_MD_MARKER = "## graphify"
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _agents_install(project_dir: Path, platform: str) -> None:
|
|
132
|
+
"""Write the graphify section to the local AGENTS.md (Codex/OpenCode/OpenClaw)."""
|
|
133
|
+
target = (project_dir or Path(".")) / "AGENTS.md"
|
|
134
|
+
|
|
135
|
+
if target.exists():
|
|
136
|
+
content = target.read_text()
|
|
137
|
+
if _AGENTS_MD_MARKER in content:
|
|
138
|
+
print(f"graphify already configured in AGENTS.md")
|
|
139
|
+
return
|
|
140
|
+
new_content = content.rstrip() + "\n\n" + _AGENTS_MD_SECTION
|
|
141
|
+
else:
|
|
142
|
+
new_content = _AGENTS_MD_SECTION
|
|
143
|
+
|
|
144
|
+
target.write_text(new_content)
|
|
145
|
+
print(f"graphify section written to {target.resolve()}")
|
|
146
|
+
print()
|
|
147
|
+
print(f"{platform.capitalize()} will now check the knowledge graph before answering")
|
|
148
|
+
print("codebase questions and rebuild it after code changes.")
|
|
149
|
+
print()
|
|
150
|
+
print("Note: unlike Claude Code, there is no PreToolUse hook equivalent for")
|
|
151
|
+
print(f"{platform.capitalize()} — the AGENTS.md rules are the always-on mechanism.")
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _agents_uninstall(project_dir: Path) -> None:
|
|
155
|
+
"""Remove the graphify section from the local AGENTS.md."""
|
|
156
|
+
target = (project_dir or Path(".")) / "AGENTS.md"
|
|
157
|
+
|
|
158
|
+
if not target.exists():
|
|
159
|
+
print("No AGENTS.md found in current directory - nothing to do")
|
|
160
|
+
return
|
|
161
|
+
|
|
162
|
+
content = target.read_text()
|
|
163
|
+
if _AGENTS_MD_MARKER not in content:
|
|
164
|
+
print("graphify section not found in AGENTS.md - nothing to do")
|
|
165
|
+
return
|
|
166
|
+
|
|
167
|
+
cleaned = re.sub(
|
|
168
|
+
r"\n*## graphify\n.*?(?=\n## |\Z)",
|
|
169
|
+
"",
|
|
170
|
+
content,
|
|
171
|
+
flags=re.DOTALL,
|
|
172
|
+
).rstrip()
|
|
173
|
+
if cleaned:
|
|
174
|
+
target.write_text(cleaned + "\n")
|
|
175
|
+
print(f"graphify section removed from {target.resolve()}")
|
|
176
|
+
else:
|
|
177
|
+
target.unlink()
|
|
178
|
+
print(f"AGENTS.md was empty after removal - deleted {target.resolve()}")
|
|
179
|
+
|
|
110
180
|
|
|
111
181
|
def claude_install(project_dir: Path | None = None) -> None:
|
|
112
182
|
"""Write the graphify section to the local CLAUDE.md."""
|
|
@@ -211,13 +281,21 @@ def main() -> None:
|
|
|
211
281
|
print("Usage: graphify <command>")
|
|
212
282
|
print()
|
|
213
283
|
print("Commands:")
|
|
214
|
-
print(" install [--platform P] copy skill to platform config dir (claude|codex|opencode|claw)")
|
|
284
|
+
print(" install [--platform P] copy skill to platform config dir (claude|codex|opencode|claw|droid)")
|
|
215
285
|
print(" benchmark [graph.json] measure token reduction vs naive full-corpus approach")
|
|
216
|
-
print(" hook install install post-commit git
|
|
217
|
-
print(" hook uninstall remove
|
|
218
|
-
print(" hook status check if
|
|
219
|
-
print(" claude install write graphify section to
|
|
220
|
-
print(" claude uninstall remove graphify section from
|
|
286
|
+
print(" hook install install post-commit/post-checkout git hooks (all platforms)")
|
|
287
|
+
print(" hook uninstall remove git hooks")
|
|
288
|
+
print(" hook status check if git hooks are installed")
|
|
289
|
+
print(" claude install write graphify section to CLAUDE.md + PreToolUse hook (Claude Code)")
|
|
290
|
+
print(" claude uninstall remove graphify section from CLAUDE.md + PreToolUse hook")
|
|
291
|
+
print(" codex install write graphify section to AGENTS.md (Codex)")
|
|
292
|
+
print(" codex uninstall remove graphify section from AGENTS.md")
|
|
293
|
+
print(" opencode install write graphify section to AGENTS.md (OpenCode)")
|
|
294
|
+
print(" opencode uninstall remove graphify section from AGENTS.md")
|
|
295
|
+
print(" claw install write graphify section to AGENTS.md (OpenClaw)")
|
|
296
|
+
print(" claw uninstall remove graphify section from AGENTS.md")
|
|
297
|
+
print(" droid install write graphify section to AGENTS.md (Factory Droid)")
|
|
298
|
+
print(" droid uninstall remove graphify section from AGENTS.md")
|
|
221
299
|
print()
|
|
222
300
|
return
|
|
223
301
|
|
|
@@ -245,6 +323,15 @@ def main() -> None:
|
|
|
245
323
|
else:
|
|
246
324
|
print("Usage: graphify claude [install|uninstall]", file=sys.stderr)
|
|
247
325
|
sys.exit(1)
|
|
326
|
+
elif cmd in ("codex", "opencode", "claw", "droid"):
|
|
327
|
+
subcmd = sys.argv[2] if len(sys.argv) > 2 else ""
|
|
328
|
+
if subcmd == "install":
|
|
329
|
+
_agents_install(Path("."), cmd)
|
|
330
|
+
elif subcmd == "uninstall":
|
|
331
|
+
_agents_uninstall(Path("."))
|
|
332
|
+
else:
|
|
333
|
+
print(f"Usage: graphify {cmd} [install|uninstall]", file=sys.stderr)
|
|
334
|
+
sys.exit(1)
|
|
248
335
|
elif cmd == "hook":
|
|
249
336
|
from graphify.hooks import install as hook_install, uninstall as hook_uninstall, status as hook_status
|
|
250
337
|
subcmd = sys.argv[2] if len(sys.argv) > 2 else ""
|
|
@@ -16,12 +16,16 @@ def _is_file_node(G: nx.Graph, node_id: str) -> bool:
|
|
|
16
16
|
These are synthetic nodes created by the AST extractor and should be excluded
|
|
17
17
|
from god nodes, surprising connections, and knowledge gap reporting.
|
|
18
18
|
"""
|
|
19
|
-
|
|
19
|
+
attrs = G.nodes[node_id]
|
|
20
|
+
label = attrs.get("label", "")
|
|
20
21
|
if not label:
|
|
21
22
|
return False
|
|
22
|
-
# File-level hub: label
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
# File-level hub: label matches the actual source filename (not just any label ending in .py)
|
|
24
|
+
source_file = attrs.get("source_file", "")
|
|
25
|
+
if source_file:
|
|
26
|
+
from pathlib import Path as _Path
|
|
27
|
+
if label == _Path(source_file).name:
|
|
28
|
+
return True
|
|
25
29
|
# Method stub: AST extractor labels methods as '.method_name()'
|
|
26
30
|
if label.startswith(".") and label.endswith("()"):
|
|
27
31
|
return True
|
|
@@ -468,7 +472,7 @@ def graph_diff(G_old: nx.Graph, G_new: nx.Graph) -> dict:
|
|
|
468
472
|
]
|
|
469
473
|
|
|
470
474
|
def edge_key(G: nx.Graph, u: str, v: str, data: dict) -> tuple:
|
|
471
|
-
return (u, v, data.get("relation", ""))
|
|
475
|
+
return (min(u, v), max(u, v), data.get("relation", ""))
|
|
472
476
|
|
|
473
477
|
old_edge_keys = {
|
|
474
478
|
edge_key(G_old, u, v, d)
|
|
@@ -3,12 +3,18 @@ from __future__ import annotations
|
|
|
3
3
|
|
|
4
4
|
import hashlib
|
|
5
5
|
import json
|
|
6
|
+
import os
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
def file_hash(path: Path) -> str:
|
|
10
|
-
"""SHA256 of file contents
|
|
11
|
-
|
|
11
|
+
"""SHA256 of file contents + resolved path. Prevents cache collisions on identical content."""
|
|
12
|
+
p = Path(path)
|
|
13
|
+
h = hashlib.sha256()
|
|
14
|
+
h.update(p.read_bytes())
|
|
15
|
+
h.update(b"\x00")
|
|
16
|
+
h.update(str(p.resolve()).encode())
|
|
17
|
+
return h.hexdigest()
|
|
12
18
|
|
|
13
19
|
|
|
14
20
|
def cache_dir(root: Path = Path(".")) -> Path:
|
|
@@ -46,7 +52,13 @@ def save_cached(path: Path, result: dict, root: Path = Path(".")) -> None:
|
|
|
46
52
|
"""
|
|
47
53
|
h = file_hash(path)
|
|
48
54
|
entry = cache_dir(root) / f"{h}.json"
|
|
49
|
-
entry.
|
|
55
|
+
tmp = entry.with_suffix(".tmp")
|
|
56
|
+
try:
|
|
57
|
+
tmp.write_text(json.dumps(result))
|
|
58
|
+
os.replace(tmp, entry)
|
|
59
|
+
except Exception:
|
|
60
|
+
tmp.unlink(missing_ok=True)
|
|
61
|
+
raise
|
|
50
62
|
|
|
51
63
|
|
|
52
64
|
def cached_files(root: Path = Path(".")) -> set[str]:
|