Skip to content

Commit cdabc21

Browse files
committed
release-v1.2.0
1 parent e89436b commit cdabc21

130 files changed

Lines changed: 12717 additions & 1413 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/CLAUDE.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# graphify
2+
- **graphify** (`.claude/skills/graphify/SKILL.md`) - any input to knowledge graph. Trigger: `/graphify`
3+
When the user types `/graphify`, use the installed graphify skill or instructions before doing anything else.

.claude/settings.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"hooks": {
3+
"PreToolUse": [
4+
{
5+
"matcher": "Bash|Grep",
6+
"hooks": [
7+
{
8+
"type": "command",
9+
"command": "/home/saldev/.local/bin/graphify hook-guard search"
10+
}
11+
]
12+
},
13+
{
14+
"matcher": "Read|Glob",
15+
"hooks": [
16+
{
17+
"type": "command",
18+
"command": "/home/saldev/.local/bin/graphify hook-guard read"
19+
}
20+
]
21+
}
22+
]
23+
}
24+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
0.9.29

.claude/skills/graphify/SKILL.md

Lines changed: 702 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# graphify reference: add a URL and watch a folder
2+
3+
Load this when the user ran `/graphify add <url>` or passed `--watch`. Neither is part of the default build.
4+
5+
## For /graphify add
6+
7+
Fetch a URL and add it to the corpus, then update the graph.
8+
9+
```bash
10+
$(cat graphify-out/.graphify_python) -c "
11+
import sys
12+
from graphify.ingest import ingest
13+
from pathlib import Path
14+
15+
try:
16+
out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR')
17+
print(f'Saved to {out}')
18+
except ValueError as e:
19+
print(f'error: {e}', file=sys.stderr)
20+
sys.exit(1)
21+
except RuntimeError as e:
22+
print(f'error: {e}', file=sys.stderr)
23+
sys.exit(1)
24+
"
25+
```
26+
27+
Replace `URL` with the actual URL, `AUTHOR` with the user's name if provided, `CONTRIBUTOR` likewise. If the command exits with an error, tell the user what went wrong - do not silently continue. After a successful save, automatically run the `--update` pipeline on `./raw` to merge the new file into the existing graph.
28+
29+
Supported URL types (auto-detected):
30+
- YouTube / any video URL → audio downloaded via yt-dlp, transcribed to `.txt` on next run (requires `pip install 'graphifyy[video]'`)
31+
- Twitter/X → fetched via oEmbed, saved as `.md` with tweet text and author
32+
- arXiv → abstract + metadata saved as `.md`
33+
- PDF → downloaded as `.pdf`
34+
- Images (.png/.jpg/.webp) → downloaded, Claude vision extracts on next run
35+
- Any webpage → converted to markdown via html2text
36+
37+
---
38+
39+
## For --watch
40+
41+
Start a background watcher that monitors a folder and auto-updates the graph when files change.
42+
43+
```bash
44+
$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3
45+
```
46+
47+
Replace INPUT_PATH with the folder to watch. Behavior depends on what changed:
48+
49+
- **Code files only (.py, .ts, .go, etc.):** re-runs AST extraction + rebuild + cluster immediately, no LLM needed. `graph.json` and `GRAPH_REPORT.md` are updated automatically.
50+
- **Docs, papers, or images:** writes a `graphify-out/needs_update` flag and prints a notification to run `/graphify --update` (LLM semantic re-extraction required).
51+
52+
Debounce (default 3s): waits until file activity stops before triggering, so a wave of parallel agent writes doesn't trigger a rebuild per file.
53+
54+
Press Ctrl+C to stop.
55+
56+
For agentic workflows: run `--watch` in a background terminal. Code changes from agent waves are picked up automatically between waves. If agents are also writing docs or notes, you'll need a manual `/graphify --update` after those waves.
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# graphify reference: extra exports and benchmark
2+
3+
Load this when the user passed one of the export flags (`--wiki`, `--neo4j`, `--neo4j-push`, `--falkordb`, `--falkordb-push`, `--svg`, `--graphml`, `--mcp`), or when the corpus is large enough for the token-reduction benchmark. Each step runs only for its own flag.
4+
5+
### Step 6b - Wiki (only if --wiki flag)
6+
7+
**Only run this step if `--wiki` was explicitly given in the original command.**
8+
9+
Run this before Step 9 (cleanup) so `.graphify_labels.json` is still available.
10+
11+
```bash
12+
graphify export wiki
13+
```
14+
15+
### Step 7 - Neo4j export (only if --neo4j or --neo4j-push flag)
16+
17+
**If `--neo4j`** - generate a Cypher file for manual import:
18+
19+
```bash
20+
graphify export neo4j
21+
```
22+
23+
**If `--neo4j-push <uri>`** - push directly to a running Neo4j instance. Ask the user for credentials if not provided:
24+
25+
```bash
26+
graphify export neo4j --push bolt://localhost:7687 --user neo4j --password PASSWORD
27+
```
28+
29+
Default URI is `bolt://localhost:7687`, default user is `neo4j`. Uses MERGE - safe to re-run without creating duplicates.
30+
31+
### Step 7a - FalkorDB export (only if --falkordb or --falkordb-push flag)
32+
33+
**If `--falkordb`** - generate a Cypher file. The statements are OpenCypher, but FalkorDB's `GRAPH.QUERY` runs one statement at a time (no bulk script import like Neo4j's `cypher-shell`), so prefer `--falkordb-push` to load a graph. Use this only when you want the portable `cypher.txt` artifact:
34+
35+
```bash
36+
graphify export falkordb
37+
```
38+
39+
**If `--falkordb-push <uri>`** - push directly to a running FalkorDB instance. Credentials are optional; ask the user only if the instance requires auth:
40+
41+
```bash
42+
graphify export falkordb --push falkordb://localhost:6379
43+
```
44+
45+
Default URI is `falkordb://localhost:6379` (the scheme is informational - `redis://` or a bare `host:port` work too), auth is optional, and the target graph defaults to `graphify`. Uses MERGE - safe to re-run without creating duplicates.
46+
47+
### Step 7b - SVG export (only if --svg flag)
48+
49+
```bash
50+
graphify export svg
51+
```
52+
53+
### Step 7c - GraphML export (only if --graphml flag)
54+
55+
```bash
56+
graphify export graphml
57+
```
58+
59+
### Step 7d - MCP server (only if --mcp flag)
60+
61+
```bash
62+
$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json
63+
```
64+
65+
This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live.
66+
67+
To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desktop can't run `$(...)`, and under `uv tool install` the system `python3` can't import graphify — so set `command` to the **absolute interpreter path** printed by `cat graphify-out/.graphify_python`:
68+
```json
69+
{
70+
"mcpServers": {
71+
"graphify": {
72+
"command": "<absolute path from: cat graphify-out/.graphify_python>",
73+
"args": ["-m", "graphify.serve", "/absolute/path/to/graphify-out/graph.json"]
74+
}
75+
}
76+
}
77+
```
78+
79+
### Step 8 - Token reduction benchmark (only if total_words > 5000)
80+
81+
If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run:
82+
83+
```bash
84+
graphify benchmark
85+
```
86+
87+
Print the output directly in chat. If `total_words <= 5000`, skip silently - the graph value is structural clarity, not token compression, for small corpora.
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# graphify reference: extraction subagent prompt
2+
3+
Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH).
4+
5+
```
6+
You are a graphify extraction subagent. Read the files listed and extract a knowledge graph fragment.
7+
Output ONLY valid JSON matching the schema below - no explanation, no markdown fences, no preamble.
8+
9+
Files (chunk CHUNK_NUM of TOTAL_CHUNKS):
10+
FILE_LIST
11+
12+
Rules:
13+
- EXTRACTED: relationship explicit in source (import, call, citation, "see §3.2")
14+
- INFERRED: reasonable inference (shared data structure, implied dependency)
15+
- AMBIGUOUS: uncertain - flag for review, do not omit
16+
17+
Code files: focus on semantic edges AST cannot find (call relationships, shared data, arch patterns).
18+
Do not re-extract imports - AST already has those.
19+
Doc/paper files: extract named concepts, entities, citations. For rationale (WHY decisions were made, trade-offs, design intent): store as a `rationale` attribute on the relevant concept node — do NOT create a separate rationale node or fragment node. Only create a node for something that is itself a named entity or concept. Use `file_type:"rationale"` for concept-like nodes (ideas, principles, mechanisms, design patterns). `file_type` MUST be one of exactly these six values: `code`, `document`, `paper`, `image`, `rationale`, `concept`. Any other value is invalid and will be rejected.
20+
Code files: when adding `calls` edges, source MUST be the caller (the function/class doing the calling), target MUST be the callee. Never reverse this direction. `calls` edges MUST stay within one language: a Python function cannot `calls` a JS/TS/Go/Rust/Java symbol and vice versa — cross-language call edges are phantom artifacts, never emit them.
21+
Image files: use vision to understand what the image IS - do not just OCR.
22+
UI screenshot: layout patterns, design decisions, key elements, purpose.
23+
Chart: metric, trend/insight, data source.
24+
Tweet/post: claim as node, author, concepts mentioned.
25+
Diagram: components and connections.
26+
Research figure: what it demonstrates, method, result.
27+
Handwritten/whiteboard: ideas and arrows, mark uncertain readings AMBIGUOUS.
28+
29+
DEEP_MODE (if --mode deep was given): be aggressive with INFERRED edges - indirect deps,
30+
shared assumptions, latent couplings. Mark uncertain ones AMBIGUOUS instead of omitting.
31+
32+
Semantic similarity: if two concepts in this chunk solve the same problem or represent the same idea without any structural link (no import, no call, no citation), add a `semantically_similar_to` edge marked INFERRED with a confidence_score reflecting how similar they are (0.6-0.95). Examples:
33+
- Two functions that both validate user input but never call each other
34+
- A class in code and a concept in a paper that describe the same algorithm
35+
- Two error types that handle the same failure mode differently
36+
Only add these when the similarity is genuinely non-obvious and cross-cutting. Do not add them for trivially similar things.
37+
38+
Hyperedges: if 3 or more nodes clearly participate together in a shared concept, flow, or pattern that is not captured by pairwise edges alone, add a hyperedge to a top-level `hyperedges` array. Examples:
39+
- All classes that implement a common protocol or interface
40+
- All functions in an authentication flow (even if they don't all call each other)
41+
- All concepts from a paper section that form one coherent idea
42+
Use sparingly — only when the group relationship adds information beyond the pairwise edges. Maximum 3 hyperedges per chunk.
43+
44+
If a file has YAML frontmatter (--- ... ---), copy source_url, captured_at, author,
45+
contributor onto every node from that file.
46+
47+
confidence_score is REQUIRED on every edge - never omit it, never use 0.5 as a default:
48+
- EXTRACTED edges: confidence_score = 1.0 always
49+
- INFERRED edges: pick exactly ONE value from this set — never 0.5:
50+
0.95 direct structural evidence (shared data structure, named cross-file reference).
51+
0.85 strong inference (clear functional alignment, no direct symbol link).
52+
0.75 reasonable inference (shared problem domain + similar shape, requires interpretation).
53+
0.65 weak inference (thematically related, no shape evidence).
54+
0.55 speculative but plausible (surface-level co-occurrence only).
55+
Models follow discrete rubrics better than continuous ranges; the bimodal
56+
distribution observed in production (>50% at 0.5, >40% at 0.85+) shows the
57+
range guidance is being collapsed to a binary. If no value above fits, mark
58+
the edge AMBIGUOUS rather than picking 0.4 or below.
59+
- AMBIGUOUS edges: 0.1-0.3
60+
61+
Node ID format: lowercase, only `[a-z0-9_]`, no dots or slashes. Format: `{stem}_{entity}` where stem is the **full repo-relative path with the extension dropped**, every path segment kept and joined with `_` (each segment lowercased with non-alphanumeric chars replaced by `_`), and entity is the symbol name similarly normalized. Use every directory level, not just the immediate parent — this keeps same-named files in different directories distinct. Examples: `src/auth/session.py` + `ValidateToken` → `src_auth_session_validatetoken`; `lib/utils/helpers.py` + `parse_url` → `lib_utils_helpers_parse_url`; `tests/test_foo.py` + `_helper` → `tests_test_foo_helper`; `docs/v1/api/README.md` + `getUser` → `docs_v1_api_readme_getuser`. Top-level files (no parent dir, e.g. `setup.py`) use just the filename stem: `setup_my_func`. This must match the ID the AST extractor generates — using just the filename (e.g., `session_validatetoken`) or only the immediate parent (e.g., `auth_session_validatetoken`) will create orphan ghost-duplicate nodes. If you are re-extracting a project built under the old immediate-parent format, the user should run `graphify extract --force` to rebuild cleanly. CRITICAL: never append chunk numbers, sequence numbers, or any suffix to an ID (no `_c1`, `_c2`, `_chunk2`, etc.). IDs must be deterministic from the label alone — the same entity must always produce the same ID regardless of which chunk processes it.
62+
63+
Generate the extraction JSON matching this schema exactly:
64+
{"nodes":[{"id":"auth_session_validatetoken","label":"Human Readable Name","file_type":"code|document|paper|image|rationale|concept","source_file":"<FILE_LIST path verbatim>","source_location":null,"source_url":null,"captured_at":null,"author":null,"contributor":null}],"edges":[{"source":"node_id","target":"node_id","relation":"calls|implements|references|cites|conceptually_related_to|shares_data_with|semantically_similar_to|rationale_for","confidence":"EXTRACTED|INFERRED|AMBIGUOUS","confidence_score":1.0,"source_file":"<FILE_LIST path verbatim>","source_location":null,"weight":1.0}],"hyperedges":[{"id":"snake_case_id","label":"Human Readable Label","nodes":["node_id1","node_id2","node_id3"],"relation":"participate_in|implement|form","confidence":"EXTRACTED|INFERRED","confidence_score":0.75,"source_file":"<FILE_LIST path verbatim>"}],"input_tokens":0,"output_tokens":0}
65+
66+
source_file RULE (every node, edge, and hyperedge): set source_file to the path of the originating file EXACTLY as it appears in FILE_LIST — verbatim and absolute. Do NOT shorten to a basename, do NOT re-relativize, do NOT strip any directory prefix, and do NOT change separators (the engine canonicalizes separators and relativizes against the build root downstream). Copy the FILE_LIST entry character-for-character. This keeps the full build and incremental --update on the same base, so build_merge's replace-on-re-extract matches the existing node instead of accumulating a duplicate.
67+
68+
Then write the JSON to disk using the Write tool at this exact absolute path (no relative paths — Write resolves relative paths against an undefined cwd and the file will be silently lost):
69+
CHUNK_PATH
70+
```
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# graphify reference: GitHub clone and cross-repo merge
2+
3+
Load this when the user passed one or more `https://github.com/...` URLs, or named several local subfolders to merge into one graph.
4+
5+
### Step 0 - Clone GitHub repo(s) (only if a GitHub URL was given)
6+
7+
**Single repo:**
8+
```bash
9+
LOCAL_PATH=$(graphify clone <github-url> [--branch <branch>])
10+
# Use LOCAL_PATH as the target for all subsequent steps
11+
```
12+
13+
**Multiple repos (cross-repo graph):**
14+
```bash
15+
# Clone each repo, run the full pipeline on each, then merge
16+
graphify clone <url1> # → ~/.graphify/repos/<owner1>/<repo1>
17+
graphify clone <url2> # → ~/.graphify/repos/<owner2>/<repo2>
18+
# Run /graphify on each local path to produce their graph.json files
19+
# Then merge:
20+
graphify merge-graphs \
21+
~/.graphify/repos/<owner1>/<repo1>/graphify-out/graph.json \
22+
~/.graphify/repos/<owner2>/<repo2>/graphify-out/graph.json \
23+
--out graphify-out/cross-repo-graph.json
24+
```
25+
26+
Graphify clones into `~/.graphify/repos/<owner>/<repo>` and reuses existing clones on repeat runs. Each node in the merged graph carries a `repo` attribute so you can filter by origin.
27+
28+
**Multiple local subfolders (monorepo or multi-service layout):**
29+
30+
The skill pipeline writes all intermediate and final outputs to `graphify-out/` in the current working directory. Running the skill on each subfolder separately will clobber the same output dir. Instead, use the CLI directly for each subfolder — it places `graphify-out/` *inside* the scanned path:
31+
32+
```bash
33+
graphify extract ./core/ # → ./core/graphify-out/graph.json
34+
graphify extract ./service/ # → ./service/graphify-out/graph.json
35+
graphify extract ./platform/ # → ./platform/graphify-out/graph.json
36+
# Add --backend gemini|kimi|openai|deepseek|claude-cli depending on which API key you have set
37+
38+
# Then merge at the project root:
39+
graphify merge-graphs \
40+
./core/graphify-out/graph.json \
41+
./service/graphify-out/graph.json \
42+
./platform/graphify-out/graph.json \
43+
--out graphify-out/graph.json
44+
```
45+
46+
Once `graphify-out/graph.json` exists, the fast path above takes over: any codebase question runs `graphify query` directly on the merged graph — no re-extraction, no size gate.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# graphify reference: commit hook and native CLAUDE.md integration
2+
3+
Load this when the user asked to install the post-commit hook or wire graphify into a project's CLAUDE.md.
4+
5+
## For git commit hook
6+
7+
Install a post-commit hook that auto-rebuilds the graph after every commit. No background process needed - triggers once per commit, works with any editor.
8+
9+
```bash
10+
graphify hook install # install
11+
graphify hook uninstall # remove
12+
graphify hook status # check
13+
```
14+
15+
After every `git commit`, the hook detects which code files changed (via `git diff HEAD~1`), re-runs AST extraction on those files, and rebuilds `graph.json` and `GRAPH_REPORT.md`. Doc/image changes are ignored by the hook - run `/graphify --update` manually for those.
16+
17+
If a post-commit hook already exists, graphify appends to it rather than replacing it.
18+
19+
---
20+
21+
## For native CLAUDE.md integration
22+
23+
Run once per project to make graphify always-on in Claude Code sessions:
24+
25+
```bash
26+
graphify claude install
27+
```
28+
29+
This writes a `## graphify` section to the local `CLAUDE.md` that instructs Claude to check the graph before answering codebase questions and rebuild it after code changes. No manual `/graphify` needed in future sessions.
30+
31+
```bash
32+
graphify claude uninstall # remove the section
33+
```

0 commit comments

Comments
 (0)