Full release notes with details on each version: GitHub Releases
- Feat: CodeBuddy platform support.
graphify codebuddy installinstalls the graphify skill to~/.codebuddy/skills/graphify/SKILL.md, writes aCODEBUDDY.mdalways-on section, and registers Bash + Read|Glob PreToolUse hooks in.codebuddy/settings.jsonthat nudge the agent towardgraphify queryinstead of grepping raw files when a graph exists.graphify install --platform codebuddyandgraphify codebuddy uninstallalso supported. Thanks to @studyzy (#1136). - Fix:
graphify --updateno longer destructively collapses distinct same-named symbols across files. The skill's--updatemerge now passes re-extracted (changed) files toprune_sourcesalongside deleted files, so old nodes for changed files are pruned before fresh AST is inserted — no fuzzy reconciliation needed. Separately,dedup.pyPass 1 now skips nodes with an emptysource_fileso label-only merging across no-source-file nodes is prevented. The anti-shrink guard message now names fuzzy dedup as a possible cause rather than only blaming missing chunk files (#1178).
- Feat: Streamable HTTP transport for the MCP server.
python -m graphify.serve graph.json --transport http --port 8080 --api-key $SECRETserves the graph over the MCP Streamable HTTP transport (spec 2025-03-26) so a single shared process can serve the whole team. Flags:--host,--port,--api-key(envGRAPHIFY_API_KEY),--path,--json-response,--stateless,--session-timeout. Docker image included. stdio remains the default (#1143). - Feat: Salesforce Apex extractor.
.clsand.triggerfiles are now AST-extracted via regex (no tree-sitter grammar exists for Apex). Extracts classes, interfaces, enums, methods, triggers, and SOQL/DML edges (#1159). - Feat: Azure OpenAI Service backend.
--backend azurereadsAZURE_OPENAI_API_KEY+AZURE_OPENAI_ENDPOINTand auto-detects both. Uses the existingopenaipackage — no new dependency (#1107). - Feat: live PostgreSQL introspection.
graphify extract --postgres "postgresql://..."connects directly to a running database and maps tables, views, routines, and FK relations viainformation_schemain aSERIALIZABLE READ ONLYtransaction. Newgraphify[postgres]extra (psycopg3). Credentials are sanitized from error messages (#1103). - Feat: vision and PDF support in headless extract. Images now route through per-backend vision payloads (base64/data-URI for claude/openai, file path for claude-cli, bytes for bedrock) instead of producing garbage binary data. Non-vision backends get a text reference via
_strip_pixels. PDFs reuse pypdf. 5MB cap, 20-image chunk limit (#1110). - Fix:
graphify updatenow prunes symbols removed from files that still exist on disk. Previously, deleting a function left a ghost node in the graph until the source file itself was deleted. Every AST node is now stamped with_origin="ast"; on a full rebuild any stamped node absent from the fresh output is dropped (#1118). - Fix:
graphify pathandshortest_pathnow fire the exact-match bonus for multi-word queries. The per-token comparison never equalled a full multi-word label, so the exact bonus was silently skipped for queries like"AuthService"when the label contained punctuation or spaces. The full normalized query is now compared alongside each token (#1165). - Fix:
_is_sensitiveno longer flags topic-mentioning filenames as secrets.token-economics-of-recall.mdandpassword-policy-discussion.mdwere silently dropped. Generic keywords (token/secret/password) now only fire when the keyword ends the filename stem or the stem is ≤2 words; specific patterns (.env,.pem,id_rsa, etc.) remain unconditional (#1169). - Fix: git hooks no longer use
nohupto background the rebuild. Git for Windows' MSYS shell has nonohup, causing the post-commit/post-checkout hook to fail silently and the graph to go stale. Replaced with a cross-platform Python launcher usingDETACHED_PROCESS | CREATE_NEW_PROCESS_GROUPon Windows andstart_new_session=Trueon POSIX (#1161 / #1170). - Fix: post-commit and post-checkout hooks now respect an existing
.graphify_root. A scoped build (graphify src/) was silently expanded to the full repo on the next commit because the hook hardcodedPath('.'). The hook body now readsgraphify-out/.graphify_rootfirst (#1173). - Fix:
graphify affectednow forces a directed graph on load, matching the identical fix already applied inserve.pyand__main__.py. On undirected graphs ("directed": falsein graph.json) the traversal was direction-blind — missing true callers and reporting callees as affected (#1174). - Fix: Step 9 skill cleanup no longer aborts under fish/zsh on pure-code corpora. The
rm -f ... .graphify_chunk_*.jsonglob errored with "no matches found" when no chunk files existed, leaving other temp files on disk. Split intorm -ffor fixed filenames andfind -maxdepth 1 -deletefor the chunk glob (#1172). - Fix:
detect_incrementalno longer crashes on schema-drifted manifest files. A dict-valuedmtimeentry (from an older richer schema) is now coerced toNoneand the file is treated as new rather than raising a comparison error (#1163). - Fix: numpy pinned to
>=2.0only on Python 3.13+ in thesvgandallextras. numpy 1.26.4 ships nocp313wheel souv syncfell back to a source build requiring a C compiler (#1153 / #1154). - Fix: Codex platform skill now installs to
.codex/skills/graphify/(was.agents/skills/graphify/), aligning with where the hook already lives (#1160).
- Feat: install banner —
graphify installnow prints an amber knowledge-graph brain in the terminal (TTY-only, silent in CI/pipes, never raises). - Fix: Python
from pkg import submodpackage-form imports now resolve to a file-levelimports_fromedge to the submodule file when it exists on disk. Previously these imports produced zero edges, leaving test files as disconnected islands in the graph (up to 66% of test nodes in some corpora). The fix lives in the symbol-resolution post-pass which has filesystem access (#1146). - Fix: builtin type-annotation nodes (
str,int,bool,float,bytes,MagicMock,Mock,AsyncMock, etc.) no longer appear as graph nodes or accumulate edges. They were being created via the annotation walker whenever used as parameter or return types, inflating degree counts ~25% and displacing real abstractions from god-node rankings. A new_PYTHON_ANNOTATION_NOISEfilter suppresses them at extraction time;god_nodesalso filters them as a defense for pre-existing graphs (#1147). - Fix: AST/semantic ghost-duplicate nodes are now auto-merged at build time. When AST and semantic extraction produce different IDs for the same symbol (one with
source_location=L<n>, one without),build_from_jsondetects the pair by(source_file basename, label)and collapses the semantic ghost into the AST node, re-pointing all edges. Graphs built before this release can be cleaned up withgraphify extract . --force(#1145).
- Feat: Terraform/HCL support.
.tf,.tfvars, and.hclfiles are now AST-extracted viatree-sitter-hclinto a structured infrastructure dependency graph. Nodes: resources, data sources, modules, variables, outputs, providers, and locals. Edges:contains,references(interpolation), anddepends_on. Node IDs are directory-scoped for cross-file resolution. Requiresuv tool install "graphifyy[terraform]"(#1129). - Fix:
graphify extractno longer requires an LLM API key for code-only corpora. Backend resolution is now deferred until after file detection — a corpus with only code files (pure tree-sitter AST, zero LLM calls) runs fully offline. The key is only enforced when docs, PDFs, or images are present, or when--dedup-llmis passed (#1122). - Fix:
graphify kiro installnow correctly installs thereferences/sidecar and.graphify_versionstamp. The install was using a barewrite_textthat bypassed the shared helper, shippingSKILL.mdwith 8 deadreferences/*.mdpointers. Re-rungraphify kiro installto pick up the fix (#1142). - Fix:
GRAPHIFY_API_TIMEOUTnow applies toclaude-clisubprocess and Anthropic SDK backend, not just the HTTP client. Both subprocess paths previously hardcodedtimeout=600and ignored the env var and--api-timeoutflag (#1112). - Build: version floors added for
networkx>=3.4,datasketch>=1.6, andrapidfuzz>=3.0to prevent silent breakage from old installs resolving incompatible versions.
- Fix:
graphify hook installnow embeds the current interpreter (sys.executable) directly into the generated hook scripts. Previously, uv tool and pipx installs silently no-oped on git commit in GUI clients and CI runners where~/.local/binis not on PATH — the hook could not find the graphify launcher, fell through all detection probes, and exited 0 without rebuilding. The embedded path is sanitized through a filesystem-safe allowlist before substitution. If you already have hooks installed, re-rungraphify hook installto pick up the fix (#1127). - Fix: hook scripts now also probe
graphify-out/.graphify_pythonas a fallback interpreter source, covering Windows/Git Bash installs where the launcher is a binary with no parseable shebang, and the case where the pinned path goes stale after a reinstall. - Security: hook script hardening — the
_PINNED=assignment uses single quotes to prevent shell injection from a path containing metacharacters;nohup "$GRAPHIFY_PYTHON" -cis properly quoted to handle spaces; the fallback emits a loud stderr diagnostic instead of a bare silentexit 0. - Feat: query logging. Every
graphify query,graphify path,graphify explain, and MCPquery_graphcall is now appended to~/.cache/graphify-queries.login JSON Lines format (timestamp, kind, question, corpus path, nodes returned, result size, duration). Full subgraph responses are not stored by default. Control withGRAPHIFY_QUERY_LOG(path override),GRAPHIFY_QUERY_LOG_DISABLE=1(opt out),GRAPHIFY_QUERY_LOG_RESPONSES=1(store full response text) (#1128).
- Fix:
graphify install --project --platform antigravitynow writes Antigravity's always-on layer (.agents/rules/graphify.md+.agents/workflows/graphify.md), not just the skill. The project-scoped path went through the skill-only branch and skipped them, even though the project uninstall removes them. - Feat: close the Read-tool graph bypass. The
PreToolUsenudge previously only fired on Bash search (grep/rg/find); an agent answering a question by reading many source files through the nativeReadtool (orGlob) slipped past it. A newRead|Globhook nudges towardgraphify querywhengraphify-out/graph.jsonexists, only for a source/doc file outsidegraphify-out/, and never blocks (#1114). - Feat: add an
anthropicoptional extra (and include it in[all]) so theclaudebackend is installable like every other one:uv tool install "graphifyy[anthropic]". Previously it was the only backend with no extra, so a user withANTHROPIC_API_KEYset could not satisfy it without--with anthropic. The backend package-missing errors now point atuv tool install "graphifyy[<extra>]"(the isolated-venv path) rather than onlypip install.
- Feat: progressive-disclosure skill files. The per-host
SKILL.mdis now a lean core (~615 lines, down from the ~1156-line monolith, about 47% less always-loaded context) that carries the full default code-build pipeline inline and links to an on-demandreferences/sidecar (extraction-spec, query, update, exports, transcribe, github-and-merge, add-watch, hooks); an agent reads a reference only when that path is actually taken, so a normal build needs none. 18 hosts go progressive (claude, codex, opencode, kilo, copilot, claw, droid, trae, trae-cn, hermes, kiro, pi, antigravity, antigravity-windows, windows, kimi, amp, gemini); aider and devin stay monolithic by design. All 15 skill bodies + sidecars are generated from one source undertools/skillgen/, with CI guards (--check,--audit-coverage,--monolith-roundtrip,--always-on-roundtrip) proving the references are byte-identical slices of the old monolith so nothing is lost (#1121). - Fix:
graphify install --platform geminishipped aSKILL.mdwith 8 deadreferences/pointers. gemini installs claude's lean progressive core but the installer never copied claude's references sidecar; it now does, so every on-demand reference resolves (regression from the progressive-disclosure split). - Security (F1): a project-local
./.graphify/providers.json(which travels with a cloned or shared repo) is no longer loaded automatically, since a custom provider'sbase_urlis where your corpus and API key are sent. SetGRAPHIFY_ALLOW_LOCAL_PROVIDERS=1to opt in; the user's own~/.graphify/providers.jsonis still trusted. Non-http(s)base_urls are rejected on load and onprovider add, and plaintext-http egress warns. Behavior change: if you relied on an auto-loaded project-local providers file, set the opt-in env var. - Security (F2): untrusted office/PDF files are screened before parsing (on-disk size cap, plus a bounded streaming-decompression ceiling for
.docx/.xlsxzip containers) so a zip-bomb in a scanned corpus can no longer exhaust memory. - Security (F3):
OLLAMA_BASE_URLpointing at a link-local or cloud-metadata address (169.254.x,metadata.google.*, or any host that resolves to one) now fails closed with a clean error instead of sending the corpus there. Trusted LAN hosts still warn-and-allow. - Security (F5): the Fortran C-preprocessor step passes an absolute path so an attacker-named corpus file cannot be interpreted as a
cppoption.
- Feat: Kilo Code support —
graphify install --platform kiloinstalls a native skill (~/.config/kilo/skills/graphify/SKILL.md) and/graphifycommand, plus a.kilotool.execute.beforeplugin (mirroring the OpenCode integration). Existing.kilo/kilo.jsoncconfig is read but never rewritten — plugin registration goes tokilo.jsonso user comments are preserved (#512) - Feat: modernized Dart extractor — comment stripping,
part ofredirection, nested-generic-awareextends/with/implementsparsing, generic type-argument mapping, and generic call detection (#1098) - Fix:
uv tool install graphifyy/pip install graphifyyno longer fails to build on Linux/macOS —tree-sitter-dm(BYOND DreamMaker) ships only a Windows wheel, so on other platforms it compiled from source and aborted the entire install when a C toolchain orpython3-devheaders were missing. It is now an optional extra (graphifyy[dm], also in[all]) instead of a core dependency, so the default install needs no compiler (#1104).- Upgrade note: DreamMaker
.dm/.dmeusers must reinstall withgraphifyy[dm](or[all]) to keep AST extraction — onuv tool upgradethe now-optional grammar is removed..dmi/.dmm/.dmfparsing is unaffected (no tree-sitter dependency).
- Upgrade note: DreamMaker
- Fix: community IDs are now assigned by a total order (
(-size, sorted node IDs)) so an identical grouping always gets identical IDs across runs — previously the equal-sized small communities that dominate a sparse graph were numbered by the partitioner's (not seed-stable) enumeration order, making a per-node community diff report large spurious "churn" even though the actual grouping was reproducible (#1090 follow-up) - Fix:
graphify amp installnow writes the skill where Amp actually looks for it. It was landing in.amp/skills/graphify(project) and~/.amp/skills/graphify(user), neither of which Amp searches, so the skill never loaded. User-scope installs now go to~/.config/agents/skills/graphifyand project installs to.agents/skills/graphify, and a stale~/.amp/skills/graphifyfrom an older install is cleaned up on the next run.
- Feat: standalone CLI now auto-names communities with the configured backend instead of leaving
Community Nplaceholders — community labeling was previously an agent-only step (skill.md Step 5), so bare-CLI runs never got semantic names;cluster-onlynow auto-labels when no.graphify_labels.jsonexists, newgraphify label <path>subcommand (re)generates names on demand,--no-labelopts out,--backend=<name>overrides auto-detection; one batched LLM call with per-community placeholder fallback and graceful degradation on missing backend/API error; works with all built-in and custom OpenAI-compatible backends (#1097) - Fix: AST file-level node IDs now match the skill.md
{parent_dir}_{stem}spec — they were derived from the full relative path plus extension (match_script_pipeline_step_py) while semantic subagents usescript_pipeline_step, splitting every file into two disconnected ghost nodes; fixed at the single relative-path remap chokepoint so file nodes and all import/dependency edge endpoints (Python, TS, Lua, C, bash) convert together (#1033) - Fix: symbol-level node IDs for root-level files now match the spec too — the #1033 remap relativized file nodes but symbols still embedded the absolute parent-dir name (
<rootdir>_main_runvs specmain_run), splitting every top-level file's symbols into AST/semantic ghost pairs; the remap now canonicalizes symbol stems andraw_callscaller IDs, gated bysource_file(#1096) - Fix: TypeScript
interface A extends Band same-fileclass X extends Ynow produceinherits/implementsedges — the walker only inspectedclass_heritage(missing the interfaceextends_type_clausenode) and the resolver only consulted the import table (missing same-file bases); both gaps closed (#1095) - Fix:
graphify export obsidianno longer crashes withOSError ENAMETOOLONGon long node labels —to_obsidian/to_canvasnow cap filenames on UTF-8 bytes (not chars, so multibyte/CJK labels are handled) with an 8-char hash suffix on truncation to keep distinct long-prefix labels from colliding; also fixes the previously-uncapped_COMMUNITY_notes (#1094) - Fix:
graph.jsonis now deterministic across runs —detect()sorts file traversal lexicographically (os.walkorder is filesystem-dependent), which had made first-writer-wins node-ID decisions and Leiden community counts vary between identical runs (#1090) - Fix: Windows consoles no longer crash with
UnicodeEncodeErroron non-UTF-8 code pages —main()reconfigures stdout/stderr to UTF-8 at startup and→/—in print statements replaced with ASCII (#992)
- Feat:
find_import_cycles(G)inanalyze.pydetects file-level circular import dependencies — collapses symbol graph to file-level directed import graph, finds simple cycles via Johnson's algorithm, deduplicates rotations, renders## Import Cyclessection inGRAPH_REPORT.md(#961) - Feat: custom LLM provider registry —
graphify provider add/list/show/removeregisters any OpenAI-compatible endpoint (NVIDIA NIM, vLLM, OpenRouter, Together, LiteLLM) via~/.graphify/providers.json; custom providers auto-detected after built-ins indetect_backend()priority (#1084) - Fix:
extract_files_direct()no longer silently defaults to kimi (Moonshot AI) —backend=Nonenow callsdetect_backend()and raises a clearValueErrorif no key is configured, matching CLI behavior; README Privacy section updated with data-residency notes (#1086) - Fix:
pnpm-workspace.yamlwithpackages: - '.'no longer crashes withIndexError: tuple index out of rangeon Python 3.10 —Path.glob('.')replaced with[root]guard in_load_workspace_packages;GRAPHIFY_DEBUG=1env var added to_safe_extractfor full traceback on extraction errors (#1083) - Fix: anchored
.graphifyignorepatterns (leading/) no longer match the same directory name anywhere in the tree —_matches()in both_is_ignoredand_is_includednow gates basename/segment shortcuts onnot anchored; anchored patterns do exact anchor-relative path match only (#1087) - Docs: Filipino (fil-PH) README translation added (#1080)
- Fix: JS/TS
const/letinside arrow-function callbacks no longer emit phantom god-nodes — scope guard restricts_js_extra_walknode emission to program-level declarations only; applies uniformly to JS, TS, and TSX (#1077) - Fix: fenced code blocks in Markdown no longer emit orphan
codeblock_Nnodes — they had onlycontainsedges and no semantic meaning; fence-toggle still prevents inner content from being mis-parsed as headings (#1077) - Fix: Lua
require("pkg.sub")now resolves to the correct file node ID — dots converted to path separators, probes filesystem for.lua/.luau/init.luavariants up the directory tree (#1075) - Fix: Windows
claude-clibackend no longer raisesWinError 2— prefersclaude.cmdover bareclaudeto avoid PATHEXT.ps1resolution failure (#1072) - Fix: post-commit hook no longer silently drops
changed_pathswhen another rebuild holds the lock — lock-losers queue paths to a pending file; the lock-holder drains and merges on acquire (#1059) - Fix:
graphify install antigravityglobal install now writes to~/.gemini/config/skills/(per Antigravity docs) instead of the wrong~/.agents/; uninstall, version-stamp refresh, and project-scope install all updated to match (#1079) - Docs: README warns against
pip installon Mac/Windows due to Python env mismatch causingModuleNotFoundError;uv tool installrecommended as primary method (#1074)
- Feat: type-reference edges for ObjC, Julia, C, C++, Scala, Fortran, and PowerShell — extends cross-language semantic context work from #1015 to a second wave of languages; CI matrix now covers Python 3.10 with
faster-whisperversion guard (#1071) - Fix: claude-cli backend no longer loops on hollow streamed responses — handles all four documented failure modes (empty stream, no JSON, missing
result, emptyresult) with tests (#1063) - Fix:
callsedges no longer flip caller/callee when the same node pair appears in both directions in an undirected build — first-seen direction preserved on bidirectional collision (#1061) - Fix:
graphify-out/.graphify_pythonpath prefix was missing in 8 skill files (256 instances) causingcat: .graphify_python: No such file or directoryon every non-Claude-Code platform - Chore: all skill files now use uv-aware interpreter detection —
uv tool run graphifyy pythonpreferred over shebang parsing when uv is available
- Feat: type-reference edges for Swift, Kotlin, PHP, Rust, and Go —
referencesedges withparameter_type,return_type,generic_arg,field, andattributecontexts; inheritance split intoinherits(superclass) vsimplements(protocol/interface/trait) for all five languages (#1015) - Chore: CI switched from pip to uv (
astral-sh/setup-uv,uv sync,uv run pytest);uv.lockcommitted for reproducible installs; dev setup docs updated (#885)
- Feat: BYOND DreamMaker support —
.dm/.dmefiles extracted via tree-sitter-dm (type definitions, proc declarations,#includeedges, in-file call resolution,new /type()instantiation edges);.dmiPNG icon files parsed for icon-state nodes;.dmmmap files parsed for type-pathusesedges from the tile dictionary section;.dmfinterface files parsed for window/elem/control-type hierarchy (#884) - Feat:
graphify extract --mode deepflag enables richer semantic extraction using an extended system prompt; flag propagated through all four LLM backends (#1030)
- Fix:
graphify update(no--changedflag) no longer leaves ghost nodes from files deleted between runs — full re-extraction path now reconciles the existing graph against current disk state and evicts any node whosesource_fileno longer exists;_norm_source_fileused on both sides to guarantee path format consistency (#1007) - Fix:
graphify install --platform opencode --projectnow writesSKILL.mdto.opencode/skills/graphify/SKILL.md(discoverable by OpenCode) instead of the incorrect.config/opencode/skills/path; git-add hint updated accordingly (#1040) - Fix: post-commit hook no longer triggers rebuild when only
graphify-out/files were committed (avoids infinite dirty-tree loop when graph outputs are tracked in git);GRAPHIFY_SKIP_HOOK=1env var added for one-off skip; hook rebuild log now appends (>>) instead of overwriting (>) (#1018, #1037) - Fix: graph output is now byte-for-byte deterministic across runs — edges sorted by
(source, target, relation)inbuild_from_json;PYTHONHASHSEED=0exported in hook scripts to stabilize Louvain community ordering (#1010) - Feat: Amp (ampcode.com) platform support —
graphify amp install/uninstallinstalls the skill into.amp/skills/graphify/SKILL.md(#948) - Fix: query punctuation no longer breaks node matching —
"what calls extract?"correctly finds theextractnode;_search_tokenshelper strips punctuation from search terms in_query_terms,_score_nodes, and_find_node(#994, #978) - Fix: language built-in globals (
String,Number,Boolean,Object,Array, etc.) no longer accumulate spurious call edges — filtered at same-file and cross-file resolution in the AST extractor, eliminating god-node pollution from constructor-style calls (#916, #726) - Feat: SystemVerilog header files (
.svh) now extracted using the Verilog parser alongside.vand.sv(#1042) - Fix:
@property,@staticmethod,@classmethodmethods no longer produce orphaned nodes without a class-qualified ID —decorated_definitionis now treated as a transparent wrapper in the Python AST walker, preservingparent_class_nidthrough the decorator layer (#1050) - Fix: Pass 2 dedup no longer merges nodes with identical labels that live in different files — same-file partition enforced for the identical-label subcase so
foo()ina.pyandfoo()inb.pyare not collapsed into one node (#1046) - Fix:
graphify-out/memory/files are no longer silently excluded by.gitignorepattern matching — memory dir files now bypass the gitignore filter indetect.py, ensuring knowledge accumulated viagraphify rememberis always scanned (#1047)
- Fix: stale nodes persist after
graphify updatewhen files are deleted on Windows —deleted_pathsandevict_sourcesin_rebuild_codenow use.as_posix()for consistent forward-slash paths;_relativize_source_filescalled on the existing graph before eviction (not after);_relativize_source_filesitself now produces forward slashes (#1007) - Fix:
graphify extractstale-node pruning now also handles symlinked scan roots —prune_setexpansion usesPath(root).resolve()beforerelative_to()so symlinked roots produce correct relative paths (#1007) - Feat: MCP config extractor —
.mcp.json,mcp.json,mcp_servers.json,claude_desktop_config.jsonnow extracted into the knowledge graph; captures server nodes, npm/pip package refs, env var requirements; env values discarded to prevent secret leakage (#1034) - Fix:
cluster-onlyno longer drops community label alignment after re-clustering —remap_communities_to_previousnow applied in thecluster-onlypath, matching the behaviour ofgraphify update(#1028) - Fix: Dart child node IDs no longer embed absolute paths — switched from
_make_id(str(path), name)to_make_id(_file_stem(path), name), consistent with all other extractors; existing Dart graphs should be rebuilt with--force(#999) - Security: XML parsing in
extract_csprojandextract_lazarus_packagenow pre-screens for<!DOCTYPE/<!ENTITYdeclarations before callingET.fromstring, blocking billion-laughs DoS on malicious project files;extract_lpkalso gains the missing 2 MiB size cap
- Feat: .NET project file support —
.sln,.csproj,.fsproj,.vbproj,.razor,.cshtmlnow extracted; captures NuGet package refs, project-to-project dependencies, target frameworks, SDK attributes, Blazor/Razor directives (@using,@inject,@inherits,@model,@page), component refs, and@codeblock methods (#1025) - Feat: Chinese query segmentation — compound Chinese tokens (e.g.
页面路由) are split into meaningful words using jieba when installed, with character bigram fallback; original compound preserved alongside segments for exact-match; newpip install "graphifyy[chinese]"extra (#1026) - Fix: Wiki TypeError when
source_fileisNone—G.nodes[n].get("source_file") or ""replaces.get("source_file", ""), which did not handle explicitNonevalues (#1016) - Fix: Nested
.claude/worktrees/no longer indexed —_is_noise_dirnow accepts an optionalparentparam and skipsworktrees/directories nested inside dotted dirs like.claude/(#1023) - Fix:
backup_if_protectedno longer accumulates one folder per run — uses content-hash comparison to skip identical backups and overwrite in-place when content changes; one folder per day maximum - Feat: Devin CLI support —
graphify devin install/uninstallinstalls the skill into Devin's.devin/rules/directory (#1020) - Fix: TypeScript 5.0 array-form
extendsintsconfig.jsonnow handled —_read_tsconfig_aliasesnormalizesextendsto a list before iteration (#1017)
- Fix: post-commit hook now updates graph after delete-only commits — shrink-guard is bypassed when
changed_pathscontains explicit deletions, preventing stale nodes from accumulating indefinitely (#1000) - Fix:
graphify export(html/obsidian/wiki/svg/graphml/neo4j) no longer collapses to "Single community" when.graphify_analysis.jsonis absent — falls back to per-nodecommunityattribute already present ingraph.json(#1001) - Fix: Ukrainian README translation updated to v8 — all new sections, correct badges, 31 languages (#995)
- Feat: semantic context tags on
referencesedges for Python/JS/TS/C#/Java —parameter_type,return_type,generic_arg,attribute,field; C#/Java splitinherits/implements; dedup key now includes context (#996)- Breaking: Java
extendsedges are now emitted asinherits— queries filtering onrelation="extends"for Java nodes must be updated torelation="inherits"
- Breaking: Java
- Feat: constrained query expansion in skill — Step 0 extracts actual graph vocab and forces LLM to pick expansion tokens only from that set, preventing hallucinated expansions; Unicode regex fix captures Cyrillic/CJK labels (#998)
- Docs: Ukrainian README updated to v8 with all new sections, correct badges, YC badge, 31 language count (#995)
- Fix: Case-sensitive call resolution for Go, Rust, and Elixir — resolvers previously lowercased both the label index and the callee name, causing
Authorizeto matchauthorizeand produce phantom edges; Ruby/C#/Java/Kotlin/Scala/PHP use the same generic resolver which now splits into case-sensitive (all languages) and case-insensitive (PHP only, where function/class names are genuinely case-insensitive) dicts (#993) - Fix: Cross-language phantom
callsedges from semantic extraction dropped at graph-build time — INFERREDcallsedges whose source and target nodes belong to different language families (py/js/go/rs/jvm/c/cpp/rb/php/cs/swift/lua) are now discarded; skill.md prompt updated with an explicit anti-rule (#991)
- Fix: CJK/Unicode labels no longer silently stripped during dedup —
_norm()and_norm_label()now use Unicode-aware[\W_]+regex withcasefold()and NFKC normalization; previously道具処理クラスand any non-ASCII label collapsed to empty string and got falsely merged (#937) - Fix:
.ets(ArkTS/HarmonyOS) files now recognized as code and extracted via the TypeScript parser (#926) - Fix:
graphifynow exits non-zero when all semantic-extraction chunks fail — previously a silent empty graph was written with exit code 0, masking backend failures (#889) - Feat:
graphify install --projectinstalls the skill into the current repository (.claude/skills/,.agents/skills/, etc.) instead of the user home directory; per-platform subcommands support the same flag (#931) - Docs: Uzbek (uz-UZ) README translation (#982)
- Fix:
cluster-onlysubcommand crashed withFileNotFoundErrorwhengraphify-out/did not yet exist — output directory is now created before any write (#934) - Fix:
GRAPHIFY_MAX_OUTPUT_TOKENSenv var now respected for all OpenAI-compatible backends — previously the token limit was hardcoded, causing truncated responses on high-context queries (#973) - Fix: Swift extension nodes no longer duplicated across files —
_merge_swift_extensionsdeduplicates by canonical name before graph insertion (#969) - Fix: Non-Latin query terms (CJK, Arabic, Cyrillic, etc.) now preserved through query preprocessing — previous normalization stripped non-ASCII chars, making multi-lingual codebases unsearchable (#964)
- Feat: Multigraph runtime compatibility probe — emits a warning if a
MultiDiGraphis passed where aGraphis expected by any downstream consumer (analyze, cluster, wiki, export, report) (#956) - Feat: JS/TS barrel re-exports tracked as explicit
re_exportsgraph edges —export { X } from './mod'emits typed edges withcontext="re-export"andconfidence=EXTRACTED; file-levelimports_fromedges also emitted (#960) - Feat:
--affectedand--import-resolutionflags for thev8subcommand — impact analysis and cross-file import resolution exposed as first-class CLI options
- Fix:
--wikicrash when community node IDs are stale after dedup or re-extract — stale IDs are now silently dropped with a stderr warning; raises a clear error only if every ID is stale (#936) - Fix:
.gitignorepatterns now respected when no.graphifyignoreexists — previous behaviour silently ignored the project's gitignore, causing expected exclusions to be skipped (#945) - Feat:
--exclude <pattern>CLI flag to pass extra gitignore-style exclusion patterns at runtime without modifying.graphifyignore(#947) - Fix:
.worktrees/directory now skipped during scan — git worktree sibling checkouts inside.worktrees/were previously indexed as duplicate source (#947) - Security: NAT64 IPv6 addresses (
64:ff9b::/96) no longer false-positive as blocked reserved IPs — affects hosts likearxiv.orgon IPv6-only networks where the ISP uses RFC 6052 NAT64
- Fix: node ID collisions across same-named files in different directories — SQL extractor and Python import resolver now use directory-qualified stems (
dir_file_entity) instead of bare filename stems, preventing silent node merging on repos with duplicate filenames (#1A, #1B) - Perf: stat-based mtime fastpath for
file_hash— skips full SHA256 read when file size+mtime_ns unchanged, same trade-off as make; index flushed atomically via atexit - Fix: absolute
source_filepaths from semantic subagents no longer stored in graph —build_from_json,build, andbuild_mergeaccept arootparam and relativize paths at build time (#932) - Fix: failed semantic chunks no longer permanently freeze their files in the manifest — only files that appear in extraction output get
semantic_hashstamped; failed-chunk files keep emptysemantic_hashand are re-queued on next run (#933) - Feat:
graphify cache-check,graphify merge-chunks,graphify merge-semanticCLI subcommands expose cache and merge logic as library-callable commands for skill pipelines
- Security:
_is_sensitivenow correctly flags underscore-prefixed secret filenames (api_token.txt,oauth_token.json) —\bword boundary was treating_as a word char, so names likeapi_tokennever matched (#920) - Security:
_is_sensitivenow checks parent directories against a_SENSITIVE_DIRSblocklist (.ssh,.aws,.gcloud,secrets, etc.) so any file inside those dirs is skipped regardless of name; root-level files namedcredentialsorsecretsare no longer falsely flagged (#920) - Fix:
--wikiRelationships section was always empty —_cross_community_linksreadcommunityfrom node attributes (always None) instead of thecommunitiesdict;_god_node_articlehad the same bug and never linked to the owning community (#925) - Fix:
--watchnow respects.graphifyignore— the event handler was checking extensions before the ignore filter, so paths insidenode_modules/,.venv/, etc. triggered rebuilds (#928) - Fix:
graphify <path>now correctly dispatches tographify extract <path>— previously a bare path argument returned "unknown command" instead of starting extraction - Fix: skill fast path — if
graphify-out/graph.jsonalready exists and the request is a natural-language question, extraction steps are skipped entirely andgraphify queryruns immediately; previously the skill re-ran detect and hit the corpus-size gate on every question - Fix: large-corpus gate raised from 200 to 500 files;
detect()now returnsscan_rootso the skill correctly computes relative subdirectory breakdowns instead of showing absolute paths; flat repos with no subdirectories no longer ask the user to pick a subfolder that doesn't exist - Docs: clarify that code-only corpora skip the LLM semantic extraction pass entirely — AST handles code, Pass 3 is reserved for docs, papers, images, and transcripts (#836)
- Fix: LLM empty choices / None message guard — Gemini and other providers return
choices=[]on content-filtered HTTP 200 responses; now raises a clean error instead of crashing with IndexError (#924) - Fix: OpenCode skill removed invalid
general-purposeagent reference and headless-incompatible interactive halt (#911, closes #825) - Fix: Codex skill now uses graphify query/explain/path even when graph artifacts are dirty in worktree (#913, closes #860)
- Perf: precompute degrees once in surprise scoring — ~11x speedup per lookup on large graphs (#914)
- Fix: git hooks phantom directory on git < 2.31 — drop
--path-format=absolute, validate path contains no newlines, anchor relative paths on repo root (#907) - Fix:
save_manifestincremental data loss — seed from existing manifest before loop so untouched files aren't erased on partial runs (#917) - Fix: C++ class/struct inheritance edges missing — extract
base_class_clauseforclass_specifierandstruct_specifier(#915) - Fix: cohesion split threshold unreachable due to rounding —
cohesion_scorenow returns raw float, display rounds to 2dp (#919) - Fix: Rust cross-crate spurious INFERRED edges — skip
Type::method()scoped calls and common trait-method names from cross-file resolver (#908) - Feat:
--resolution Nforextractandcluster-only— control Leiden/Louvain community granularity (>1 = more smaller, <1 = fewer larger) (#919) - Feat:
--exclude-hubs Pforextractandcluster-only— exclude degree-percentile super-hubs from partitioning, reattach by majority-vote neighbour community (#919)
- Feat: DeepSeek backend support — set
DEEPSEEK_API_KEYand use--backend deepseek; default modeldeepseek-v4-flash
- Feat:
graphify prs— graph-aware PR dashboard: CI state, review decision, worktree mapping, and graph blast radius per PR;--triageranks your queue via any configured LLM backend (claude, kimi, openai, gemini, claude-cli, ollama — auto-detected);--conflictsshows PRs sharing graph communities with node labels;--worktreesmaps worktree paths to branches to open PRs; MCP toolslist_prs,get_pr_impact,triage_prsfor agent access
- Fix: query seed selection now uses IDF weighting — common terms like
errororhandlethat match dozens of nodes are down-weighted so a rare identifier likeFooBarServiceranks first and BFS expands from the right node (#897) - Fix: seed count is now dynamic — a dominant match (score gap >80% vs next candidate) gets one seed rather than always picking three, preventing noise nodes from consuming BFS slots alongside the target (#897)
- Fix: truncation message in
query_graphnow tells Claude what to do (callget_nodeor add acontext_filter) rather than just saying "truncated" (#897) - Fix: C++ class data members (
int x;,static const int MAX = 100;) now extracted as nodes withdefinesedges from the parent class — previously the field_declaration branch was a no-op due to a wrong child type guard (#898) - Fix: dedup Pass 1 now partitions same-label groups by source_file before merging — nodes with generic labels (
handle,init,run) from different files no longer collapse into artificial god nodes; cross-file matches are routed to Pass 2 fuzzy (#895) - Fix: C/C++
#include "path/to/file.h"edges now resolve the include path relative to the including file and use the full resolved path as the target node ID, matching what extraction creates for the included file — previously all include edges dangled with a basename-only ID (#899) - Fix:
exact_mergescounter in dedup now reports only merges actually performed rather than counting all same-label nodes across files (#895)
- Fix: cross-language INFERRED
calls/usesedges (e.g. Python → TypeScript) are suppressed in Surprising Connections — label-matching across language boundaries in monorepos is resolver pollution, not structural insight; all structural bonuses zeroed for these edges - Fix: code-to-doc INFERRED
calls/usesedges suppressed in Surprising Connections — the LLM seeing a symbol name in a README and emitting acallsedge is documentation cross-reference noise, not a real architectural connection (#890) - Fix: generic JSON key nodes (
name,id,type,start,end,key,value,data,items,title,description,version,properties) filtered from god_nodes — their degree is positional (every sibling record in the same JSON file references them), not architectural (#890) - Fix: Alembic migrations, Django migrations, and protobuf-generated files now have their module-level docstrings suppressed from rationale extraction — these are boilerplate headers, not design intent; function docstrings inside migration files are still captured
- Feat:
--follow-symlinksis now auto-detected — if symlinked children are present in the target directory, follow-symlinks is enabled automatically without requiring an explicit flag (#887) - Fix: install guidance now directs users to run
/graphify queryinteractively rather than readingGRAPH_REPORT.mdfirst; the report is a summary, not a starting point (#891)
- Fix:
.graphifyignoreparent-exclusion rule now correctly blocks files under an excluded directory even when a!negation exists elsewhere in the file — previously any negation pattern disabled directory pruning entirely (#882) - Fix: dedup no longer false-merges chip/model SKU variants like
ASR1603/ASR1605orM1/M1 Pro— Jaro-Winkler prefix bonus is now gated by_is_variant_pairand_short_label_blockedguards; real typos on short labels still merge (#878) - Docs: added
worked/rsl-siege-manager/— case study on a real-world Python + TypeScript monorepo (FastAPI backend, React/Vite frontend, Discord bot); covers god node behaviour with tests included, cross-language INFERRED edges, community cohesion, and Alembic migration noise (#881)
- Feat: Firebird SQL — trigger and stored procedure extraction via
CREATE TRIGGERand regex fallback; FK detection via global regex coveringREFERENCESandFOREIGN KEYclauses (#875) - Fix: SQL extraction regex fallback now decodes source as UTF-8 instead of latin-1, preventing non-ASCII identifier hash mismatches (#875)
- Fix:
--updatedeletion pruning now matches on full source file paths instead of basenames, preventing false node removal when different directories contain files with the same name (#876) - Fix:
--updatenow also prunes edges whosesource_fileattr points to deleted files, not just nodes (#876) - Fix: community label keys from
graph.json(stored as strings) are now coerced to int before lookup, fixing blank community names in GRAPH_REPORT.md and graph.html (#877)
- Fix: Windows skill temp files (chunk JSONs,
.graphify_python,.graphify_root) no longer pollute the project root — all written undergraphify-out/(#831) - Fix:
--updatewith deletions-only no longer errors when.graphify_extract.jsondoes not yet exist — creates an empty extraction file before merging (#876)
- Fix: Python interpreter detection for
uv toolandpipxinstalls on Windows —graphify installand all skill steps now find the correct executable (#831) - Fix: antigravity Windows skill path resolution (#831)
- Fix: dot directories (e.g.
.github/,.vscode/) are now indexed when explicitly included via.graphifyignore(#873) - Fix: MCP server hot-reloads the graph when
graph.jsonchanges on disk (#874)
- Feat: Bash extractor —
.shand.bashfiles now indexed via tree-sitter; extracts functions, cross-function calls,source/.imports resolved to real file paths, andexport/declarevariable declarations (#866) - Feat: JSON extractor —
.jsonfiles now indexed via tree-sitter; extracts key/valuecontainstree,dependencies/devDependenciesblocks asimportsedges,extendsedges (tsconfig, eslintrc), and$refreferences (#866) - Feat:
.sh,.bash,.jsonadded toCODE_EXTENSIONSindetect.pyso files are picked up during corpus scan (#866) - Feat: Mermaid callflow HTML auto-regenerates on every graph rebuild when
*-callflow.htmlexists ingraphify-out/— works with--watchandgraphify hook install - Fix:
coverage/,lcov-report/,visual-tests/,visual-test/,__snapshots__/,snapshots/,storybook-static/,dist-protected/added to_SKIP_DIRS— generated artefact dirs no longer appear in the corpus (#869, #870) - Fix:
graphify hook installnow works in git linked worktrees — usesgit rev-parse --git-path hooksinstead of constructing.git/hooks/directly (#865) - Fix: office sidecar files in
graphify-out/converted/are now checked against.graphifyignorebefore being added to the file list (#861) - Fix:
save_manifest()accepts akindparameter (ast,semantic,both) — incremental AST-onlygraphify updateno longer overwritessemantic_hashentries, preventing spurious full re-extracts on the next run (#857) - Fix: five paths in
skill-windows.mdStep B3 were missing thegraphify-out/prefix, causing chunk files to be written to the wrong directory (#862)
- Feat:
.astrofiles now extracted as code — frontmatter static imports, dynamic imports, and<script>block imports all produce edges; tsconfig path aliases resolved (#850, PR #852) - Fix:
.rebuild.lockno longer accumulates PIDs across rebuilds — now contains a single owning PID while running and is unlinked on release so downstream tooling polling for its absence unblocks promptly (#858, PR #859) - Docs: skill.md now clarifies that graphify does not read
ANTHROPIC_API_KEYor other provider keys during/graphifyskill runs — the host IDE session provides the LLM (PR #864)
- Fix:
graphify updateis now idempotent — graph.json and GRAPH_REPORT.md are only rewritten when content actually changes; topology comparison short-circuits clustering entirely on unchanged graphs, eliminating residual community-count drift (#824) - Fix: community IDs are now stable across rebuilds — Leiden/Louvain receive deterministically sorted input and a fixed random seed; greedy overlap remapper preserves existing IDs so hand-edited
.graphify_labels.jsonlabels don't drift onto wrong communities (#824) - Fix:
--no-clusterflag added tographify update— writes raw AST graph without clustering, consistent withgraphify extract --no-cluster(#824) - Fix:
graphify update --no-clusternow writes"links"key matching the schema of the full clustered path; previously wrote"edges", causing schema toggle on every mode switch - Fix:
.graphify_labels.jsonwas rewritten on every rebuild even when nothing changed; now only written when outputs actually change - Fix: shrink-check (refuse overwrite when new graph has fewer nodes) was duplicated across two code paths; unified into a single
_check_shrink()helper - Fix: node ID format in skill.md corrected to
{parent_dir}_{filename_stem}_{entity}— the old filename-only format caused ghost-duplicate nodes when AST and semantic extractors disagreed on the stem; top-level files use just the filename stem; existing graphs with ghost duplicates can be cleaned up withgraphify extract --force - Fix: safer JSON serialization in clustering sort keys (
default=str) prevents crashes when edge attributes contain non-serializable values - Docs: added Prerequisites, optional extras table, environment variables reference, troubleshooting, and dev setup to README (#833)
- Fix:
graphify pathandgraphify explainnow render arrow direction correctly —-->for caller→callee,<--for callee←caller; previously the graph was loaded undirected so every hop printed-->regardless of stored direction (#849, #853) - Fix: MCP
shortest_pathandget_neighborstools had the same reversed-arrow bug; now fixed inserve.pyalongside the CLI commands (#849, #853) - Fix:
graphify extract --backend bedrockwas rejected by the CLI guard even whenAWS_PROFILE/AWS_REGION/AWS_DEFAULT_REGION/AWS_ACCESS_KEY_IDwere set — boto3 session auth was never reached (#846) - Fix: BFS/DFS query traversal now skips expanding high-degree hub nodes (threshold:
max(50, p99_degree)) as transit — hubs can still be destinations but no longer produce semantically meaningless 2-hop paths likeClassA → View → ClassBin Android/Spring corpora (#830) - Fix:
--updatemanifest shrink — after an incremental run,manifest.jsonwas overwritten with only the changed-file subset, causing the next--updateto re-flag the entire unchanged corpus as new; Step 9 now persists the full corpus viaall_filesfallback (#837) - Fix:
file_typeenum aligned acrossskill.mdandllm.py(both now enumerate all six values:code,document,paper,image,rationale,concept); synonym mapper inbuild.pysilently coerces known LLM-emitted synonyms (pattern→concept,markdown→document,tool→code, etc.) before validation (#840) - Fix: Fortran test fixture renamed
sample.F90→sample_preprocessed.F90to avoid case-collision withsample.f90on macOS case-insensitive filesystems (credit: @FatahChan, #823)
- Fix: all
read_text()/write_text()calls inskill.mdandskill-windows.mdnow specifyencoding="utf-8"— bare calls defaulted to the system codepage on Chinese-locale Windows, silently mojibaking node labels and Markdown content on--update(#832) - Fix:
json.dumpsin skill pipeline now usesensure_ascii=Falseso Chinese/CJK characters are stored as-is rather than\uXXXXescaped (#832) - Fix: Step 1 install fallback in skill now prefers
uv tool install --upgrade graphifyyoverpipwhen uv is on PATH — pip was installing to the wrong environment when graphify was originally installed viauv tool(#831) - Fix:
_score_nodesinserve.pynow uses three-tier precedence (exact 1000 / prefix 100 / substring 1) instead of flat substring scoring —graphify path "Foo" "FooBar"no longer returns 0 hops when both labels substring-match the same node (#828) - Fix:
graphify pathand MCP_tool_shortest_pathnow emit a clear error when source and target resolve to the same node, instead of silently returning 0 hops (#828) - Fix:
file_hashincache.pynow normalises path keys via.as_posix().lower()— Windows junction/case variants of the same file now hash identically, fixingsave_semantic_cachealways reporting "Cached 0 files" on subsequent--updateruns (#826) - Fix:
check_semantic_cachenow applies the same absolute-path normalization assave_semantic_cacheso relativesource_filepaths resolve consistently on both sides (#826) - Fix:
_AGENTS_MD_SECTIONnow includes the/graphifyskill trigger instruction — all 7 AGENTS.md platforms (OpenCode, Codex, Aider, Trae, Hermes, OpenClaw, Factory Droid) now correctly invoke the skill tool when the user types/graphify(#827)
- Fix:
-h/--help/-?in any position now stops execution — previouslygraphify cursor install --helpsilently installed into Cursor;graphify benchmark --helpcrashed with FileNotFoundError (#821) - Fix:
--version,-v, andgraphify versionnow print the installed version and exit (#818) - Fix:
GRAPHIFY_OLLAMA_NUM_CTX=<invalid>no longer falls back to hardcoded 131072 (which exhausted VRAM) — it now falls through to the auto-derived value and prints a warning (#820) - Fix: when
GRAPHIFY_OLLAMA_NUM_CTXis set smaller than the estimated chunk size, graphify now warns explicitly that Ollama will silently truncate the prompt and suggests a corrected--token-budget(#820)
- Fix:
_make_idand_normalize_idnow apply NFKC Unicode normalization before ID generation -- composed/decomposed forms of the same character (e.g.étyped vs pasted from a PDF) now produce the same node ID; switched from.lower()to.casefold()for correct Turkish/German/Greek case folding; both functions are now byte-for-byte equivalent (#811) - Fix: non-ASCII identifiers (CJK, Cyrillic, Arabic, accented Latin) are no longer collapsed to a bare file stem --
[^\w]+withre.UNICODEreplaces the old[^a-zA-Z0-9]+so Unicode word chars are preserved as part of the ID (#811) - Fix: dedup edge remap uses explicit key-presence check instead of
orso empty-stringsourceis not silently swapped forfrom; stalefrom/tokeys are now popped before the edge is emitted so they can't leak intograph.jsonedge attributes (#803) - Fix:
--updatemerge now callsbuild_merge()directly instead of an inline NetworkX round-trip that re-introduced the direction-flip bug from #760; dict merge ordering fixed so explicitsource/targetalways win over stale attrs; hyperedges pulled fromG.graph(merged) rather than just the new extraction (#801) - Fix: subagent chunk files are now written to an absolute path (
CHUNK_PATHinjected at dispatch time fromgraphify-out/.graphify_root) so the Write tool doesn't lose chunks to an undefined working directory (#808) - Fix: skill version mismatch warning is now suppressed during
hook-check(runs on every editor tool use and must be silent) and routed to stderr for all other commands
- Fix: Ollama
num_ctxnow derived from actual chunk size instead of hardcoded 131072 -- over-allocating 128k KV-cache slots for small chunks exhausted VRAM by chunk 4 on large models; formula ismin(input_tokens + output_cap + 2000, 131072)so--token-budget 8192gets ~26k instead of 131072 (#798) - Fix: hollow-response warning now mentions VRAM pressure and
GRAPHIFY_OLLAMA_NUM_CTX/GRAPHIFY_OLLAMA_KEEP_ALIVEenv vars as tuning knobs (#798) - Feat:
graphify export callflow-html-- generates a self-contained Mermaid architecture/call-flow HTML page fromgraphify-out/graph.json, grouped by community with interactive zoom/pan diagrams, call detail tables, and graph report highlights (#797) - Feat: callflow HTML auto-regenerates on every
--watchrebuild and post-commit hook if the file already exists -- opt-in by existence, zero config (#800)
- Fix:
graphify explainandgraphify pathno longer crash onMultiGraphinputs -- newedge_data()/edge_datas()helpers inbuild.pyhandle both simple and multi-graphs; all 8 production call sites and 30 skill-file inline heredocs updated (#796) - Fix: hollow Ollama responses (0 tokens / empty string) now trigger adaptive retry bisection instead of silently dropping the chunk --
_response_is_hollow()detects empty/null/whitespace content and parsed results with no nodes/edges, then rewritesfinish_reason="length"to route into the existing bisection path (#792) - Fix: post-commit hook no longer spawns unbounded parallel rebuilds -- per-repo
fcntl.flocknon-blocking lock in_rebuild_code;changed_pathswired from hook through to AST extractor; stale nodes evicted on deletion;GRAPHIFY_REBUILD_TIMEOUTwatchdog; Darwin-aware memory cap (#791) - Fix: Antigravity install now writes to
.agents/(plural) -- corrected in platform config, paths, workflow body, and help text (#453) - Fix: Antigravity rules file now includes
trigger: always_onYAML frontmatter so Antigravity recognises it (#785) - Feat:
graphify extractgains--max-workers,--token-budget,--max-concurrency,--api-timeoutflags; hard 8-worker AST cap removed; explicit HTTP timeout on OpenAI client (default 600s,GRAPHIFY_API_TIMEOUT); ollama API key gate skipped for loopback URLs (#792) - Feat: Pascal/Delphi extraction now works without
tree-sitter-pascal-- regex fallback covers unit/program/library headers, uses clauses, class/interface inheritance, method declarations, and intra-file calls (#781) - Feat:
/graphify --helpnow prints the Usage block and stops without running pipeline steps (all 12 skill files) (#795)
- Fix: context-window-exceeded API errors now trigger automatic retry with bisected file chunks -- exponential bisection up to 6 levels deep; covers
"context_length_exceeded","maximum context length", and"too_large"across OpenAI-compat backends (#789) - Fix: Windows pipeline unblocked --
print_benchmark()falls back to ASCII box-drawing on cp1252 consoles;ProcessPoolExecutorBrokenProcessPoolcaught and falls back to sequential extraction when caller lacksif __name__ == "__main__":guard; Windows skill file (skill-windows.md) rewrites allpython -c "..."blocks as PowerShell heredocs to fix quote-escaping failures (#788) - Fix: reversed
callsedges after--update--build_merge()now reads the saved JSON directly instead of round-tripping through NetworkXnode_link_graph(), which was silently reversing edge direction on reload (#760) - Fix: atomic SKILL.md install -- temp-file +
os.replace()pattern prevents half-installed empty skill directories that looked valid but contained no file; version-stamp guard and warning added for missing installs (#725) - Feat:
graphify uninstalltop-level command -- removes graphify skill files from all platforms in one shot;--purgeflag also deletesgraphify-out/ - Feat: SQL
ALTER TABLEFK extraction --ADD CONSTRAINT ... FOREIGN KEYandADD FOREIGN KEYDDL statements now emitreferencesedges; schema-qualified table names (schema.table) correctly resolved (#779)
- Fix:
.tsxfiles now uselanguage_tsxgrammar for JSX-aware parsing -- previouslylanguage_typescriptwas used, silently dropping all JSX-specific nodes (#766) - Fix:
edgeskey in saved graph JSON now normalised tolinksbefore loading -- preventsKeyError: 'links'on graphs written by older NetworkX versions inquery,path,explain, and serve (#768) - Fix: Google Workspace
gws exportdrops unsupportedresourceKeyquery param -- Drive API requires it as an HTTP header; sending it as a query param was a silent no-op (#772) - Security: eleven hardening fixes -- Cypher escape strips C0 control chars and
\n/\r; YAML frontmatter escapes U+2028, U+2029, tabs, and C0; MCPsanitize_labelapplied to all LLM-derived fields; C preprocessor blocked from#includeexfiltration via-nostdinc -I /dev/null; merge-driver 50 MB file size cap and 100k node cap;detect_backend()places Ollama last so paid API keys take precedence over ambientOLLAMA_BASE_URL; Neo4j--passwordreads fromNEO4J_PASSWORDenv var by default; hooks exception handling narrowed to(configparser.Error, OSError) - Refactor: skill YAML descriptions rewritten to be trigger-oriented (#774)
- Refactor: generated
CLAUDE.md/AGENTS.md/GEMINI.mdtemplates strengthened withALWAYS/NEVER/IF ... EXISTSgraph-first directives (#775)
- Feat: TypeScript extraction parity -- interface, enum, type alias, and module-level const nodes extracted; new_expression emits calls edges; parity with Java/C# class_types (#708)
- Feat: Quarto (
.qmd) file support -- routed through existing Markdown extractor; Quarto executable code blocks (```{python}) extracted as code nodes (#761) - Feat: optional Google Workspace shortcut export for headless extraction --
graphify extract ./docs --google-workspaceconverts.gdoc,.gsheet, and.gslidesfiles into Markdown sidecars with thegwsCLI before semantic extraction; account email pseudonymized via SHA256 hash;[google]extra adds Sheets table rendering support (#752) - Fix: Google Workspace exports now run
gwsfrom the sidecar output directory with a relative-opath, matchinggwspath validation and avoiding failures when extracting a corpus outside the current working directory. - Feat: AWS Bedrock backend --
graphify extract ./docs --backend bedrock; credentials via standard AWS provider chain (AWS_PROFILE, AWS_REGION, IAM roles, SSO); model via GRAPHIFY_BEDROCK_MODEL (default anthropic.claude-3-5-sonnet-20241022-v2:0);[bedrock]extra adds boto3 (#757)
- Fix: CommonJS
require()imports now extracted from JS/TS --const { foo } = require('./mod'),const m = require('./mod'), andconst x = require('./mod').yall emit EXTRACTEDimports_from(and per-symbolimports) edges. Previously CJS-only Node.js codebases produced AST graphs missing every import edge, which downgraded all cross-file calls to INFERRED. - Fix: cross-file
callsedges are now promoted from INFERRED to EXTRACTED when the caller's file has an explicitimportsorimports_fromedge to the callee. Previously every cross-file call was unconditionally INFERRED, even when a top-of-fileimport/requireproved the binding. On a 92-file CJS Node.js corpus this promoted 88% of cross-file calls (104 of 118) to EXTRACTED. - Feat: Gemini and OpenAI backends --
graphify extract ./docs --backend gemini(GEMINI_API_KEY / GOOGLE_API_KEY) or--backend openai(OPENAI_API_KEY);[gemini]and[openai]extras added (#735) - Feat: Groovy and Spock support --
.groovyand.gradleextracted via tree-sitter-groovy; Spock spec files (def "feature"()syntax) handled via regex fallback (#732) - Feat: Luau support --
.luau(Roblox Luau) added to code extraction using the Lua tree-sitter parser (#745) - Feat: Markdown structural extraction -- headings, fenced code blocks, and nesting hierarchy extracted as graph nodes from
.mdand.mdxfiles with zero new dependencies (#711) - Fix:
collect_files()extension set now auto-syncs with_DISPATCH-- previously 18 extensions (.sql,.vue,.svelte,.jsx,.ex,.jl, etc.) were silently skipped in skill-mode extraction (#711) - Fix:
detect_incrementalnow forwardsfollow_symlinkstodetect()-- symlinked subtrees no longer vanish on--updateruns (#736) - Fix: TS bare-path /
.svelte.ts/.svelte.js/index.tsdirectory / multi-dot imports now resolve correctly -- previously these produced phantom edges dropped at merge time (#717, #716) - Fix:
cluster-onlynow loads and saves.graphify_labels.json-- human-readable community labels survive re-clustering instead of resetting to "Community N" (#744) - Fix:
graphify export wikinow fails fast with exit 1 if.graphify_analysis.jsonis missing -- prevents silent deletion of existing wiki articles (#746) - Fix:
to_wiki()now raises before the cleanup loop whencommunitiesis empty -- second safety layer against wiki data loss (#746) - Fix: Ollama import error message now says "Ollama" not "Kimi" and points to
pip install openai;[ollama]extras group added (#750) - Security: hooks.py path execution now validates scripts are within the repo root -- closes supply-chain attack vector where a malicious commit could redirect hook execution (#747)
- Feat: Ollama backend for headless extraction --
graphify extract ./docs --backend ollama; auto-detected whenOLLAMA_BASE_URLis set; defaults toqwen2.5-coder:7b; zero cost ($0.00); sentinel API key handles OpenAI client auth requirement (#729) - Feat: Cross-project global graph at
~/.graphify/global.json--graphify global add/remove/list/pathto register multiple project graphs with<repo>::<id>prefixed node IDs, preventing silent collisions; hash-based skip avoids re-ingesting unchanged graphs (#729) - Feat:
graphify extract --global --as <tag>flag -- after building a project graph, auto-registers it into the global graph in one step (#729) - Feat:
merge-graphsnow prefix-relabels each input graph before composing, preventing silent node ID collisions when two projects share entity names (#729) - Fix:
deduplicate_entitiesraisesValueErrorif called with nodes spanning multiple repos (cross-project dedup disabled by design -- per-project graphs are deduplicated in isolation) (#729) - Fix:
detect_incremental()now accepts and forwardsfollow_symlinkstodetect(). Without this,--updateruns silently miss any files reached through a symlinked sub-tree (e.g.state_of_truth/symlinking to a directory outside the corpus root), even when the original full run had detected them. Previously the flag was ondetect()andcollect_files()only. (#736)
- Fix:
cluster-onlynow accepts--graph <path>to specify a non-default graph.json location; positional path and flags can appear in any order (#724) - Fix:
_is_sensitive()no longer drops legitimate source files — word boundaries on the keyword pattern prevent false positives liketokenizer.py,password_verification.py,SecretManager.java(#718) - Fix:
graphify extract --backend claude/kimiraises defaultmax_tokensfrom 8192 → 16384, eliminating the truncation-then-recursive-split cascade on dense doc corpora; respectsGRAPHIFY_MAX_OUTPUT_TOKENSenv var (#730) - Fix:
--updateprune message now clearly distinguishes "N nodes pruned from M deleted files" from "M deletions detected but graph already clean — no drift" (#539) - Fix:
extract_svelte()stub nodes now carry the resolved import path assource_fileinstead of the importer's path, preventing metadata corruption after merge (#712) - Fix:
extract_svelte()now catches staticimport X from './foo.svelte'via a dedicated regex pass over<script>block content — previously tree-sitter's JS parser silently dropped all static imports in.sveltefiles (#713) - Fix:
graphify extract(full rebuild path) now savesmanifest.jsonon every successful run, not only on--update; prevents stale-manifest drift on subsequent incremental runs (#538) - Fix:
graphify antigravity installnow writes to.agent/(no trailing s) matching Antigravity's actual config paths (#704) - Fix: Pi skill YAML frontmatter description simplified to avoid "nested mappings" parse error on Pi startup (#737)
- Fix:
--dedup-llmflag now correctly threads LLM backend through todeduplicate_entitiesin both fresh and incremental extract paths; fresh extract path now also runs dedup (previously calledbuild_from_jsondirectly, bypassing dedup entirely)
- Feat:
graphify extractnow runs incrementally - auto-detects priormanifest.jsonand re-extracts only changed/new files; semantic results cached by content hash so unchanged docs cost zero LLM tokens on repeat runs (#698) - Feat: Entity deduplication pipeline runs on every build - entropy gate + MinHash/LSH blocking + Jaro-Winkler verification + same-community boost collapses near-duplicate entities (typos, spacing, plurals) before clustering
- Feat:
--dedup-llmflag forgraphify extract- optional LLM tiebreaker for ambiguous entity pairs (~$0.01 for 10k-node graphs), off by default - Fix:
graphify hook installrebuild now preserves human-readable community labels from.graphify_labels.jsoninstead of resetting to generic "Community N" names on every commit (#705) - Fix:
graphify install --platform gemininow works correctly (#706) - Deps:
datasketchandrapidfuzzadded as base dependencies
- Fix:
_read_tsconfig_aliases()now parses JSONC — handles//line comments,/* */block comments, and trailing commas that every TypeScript framework starter generates; warns to stderr on parse failure instead of silently returning{}(#700) - Fix:
extract_svelte()regex fallback now captures aliased dynamic imports ($lib/...,$partials/...,@/...) and uses correct_make_id(str(path))scheme so edges survive intograph.jsoninstead of being dropped as phantom nodes (#701)
- Feat:
graphify extract <path>— headless full-pipeline extraction for CI; runs AST extraction on code files and semantic LLM extraction on docs/papers/images without Claude Code in the loop; supports--backend kimi|claude,--out DIR,--no-cluster; auto-detects backend fromMOONSHOT_API_KEY/ANTHROPIC_API_KEY; docs-only corpora (issue #698) work cleanly - Fix: export/query/path/explain CLI subcommands added in 0.7.2 now ship with integration tests
- Fix: skill.md reduced from 63KB to 47KB by replacing Python heredocs with CLI calls (#696)
- Feat: Fortran support - extracts modules, subroutines, functions, programs,
useimports, andcalledges from.f,.F,.f90,.F90,.f95,.F95,.f03,.F03,.f08,.F08files; names are lowercased for case-insensitive matching (#694)
- Fix: Obsidian export - community labels with
.,&,(,)now produce valid Obsidian tags; only[a-zA-Z0-9_\-/]characters survive, preventing broken Dataview queries (#690) - Fix:
_load_tsconfig_aliases()now follows tsconfigextendschains - SvelteKit, Nuxt, and NestJS path aliases defined in extended configs are no longer silently dropped (#691) - Fix:
.sveltefiles now get a regex pass over the template layer after JS AST extraction -{#await import('./X.svelte')}markup-level dynamic imports are captured as edges (#692) - Fix: recursion limit raised to 10,000 at extract entry points (main process + each worker) with a
_safe_extractwrapper that skips pathological files with a clear warning instead of crashing the whole run (#695)
Multi-dev busy-repo support: four gaps that caused merge conflicts, stale graphs, and silent cache misses in team workflows.
- Feat:
graphify hook installnow also configures a git merge driver forgraphify-out/graph.json— union-merges two graph.json files so git never produces conflict markers in the knowledge graph; writes.gitattributesand registersgraphify merge-driverin.git/config - Feat:
graphify merge-driver <base> <current> <other>subcommand — takes two graph.json variants and writes their node/edge union back to<current>; always exits 0 so merge never blocks - Feat: Leiden community detection now seeded (
seed=42when supported) for deterministic community IDs across parallel rebuilds — reduces JSON diff churn in multi-dev repos - Feat:
graph.jsonnow embedsbuilt_at_commit(git HEAD) at write time;GRAPH_REPORT.mdsurfaces the commit hash and a freshness check hint - Fix:
file_hashis now content-only (path removed from hash) — renamed files reuse their cache entry instead of re-extracting; cachedsource_filefields are updated to the new path on load - Fix: watch mode mixed-batch handling — commits with both code and non-code files now rebuild code immediately AND write
needs_updateflag; previously code changes were silently dropped in mixed batches
- Fix:
source_filepath separators normalized to forward slashes at graph ingestion — same physical file emitted with backslashes (Windows AST extractor) and forward slashes (semantic subagents) now merges into one node instead of splitting into two disconnected components (#683) - Fix: two-phase cohesion re-clustering — communities with cohesion < 0.05 and ≥ 50 nodes are re-split, preventing doc-hub nodes (e.g.
CLAUDE.md) from merging unrelated subsystems into one giant community (#683) - Fix: VS Code Copilot instructions rewritten to be prescriptive — agent's first tool call must read
GRAPH_REPORT.md, explicit trigger list, narrow allowlist for raw source reads (#688) - Feat:
GRAPHIFY_OUTenv var overrides the output directory — accepts a relative name or absolute path, wires throughcache.py,watch.py, and the CLI; useful for sharing one graph across multiple git worktrees (#686) - Fix:
graphify antigravity installnow auto-updates stale rules and workflow files on re-run instead of silently skipping them (#652) - Docs: README simplified — less dense, plain language; technical pipeline details moved to
docs/how-it-works.md
- Fix:
.graphifyignorenegation patterns (!src/**) now work correctly — when any!pattern is present, directory pruning is deferred to per-file checks so negated files inside ignored directories are reached (#676) - Fix: Antigravity slash command
/graphifynow appears in the command dropdown — workflow file now includes YAML frontmatter withname: graphifyrequired for Antigravity discovery (#678) - Fix: Gemini CLI BeforeTool hook replaced
[ -f ... ] && echo(bash-only) with cross-platformpython -cusingjson.dumps— fixes hook failure on Windows CMD and Git Bash (#681) - Fix: Codex hook-check exits silently — resolves
additionalContextrejection on Codex Desktop PreToolUse (#651) - Fix:
graphify install --platform codexnow writes absolute path tographifyexecutable — fixes PATH resolution in VS Code extension on Windows (#651) - Fix: thin communities (fewer than 3 concept nodes) are now omitted from the Communities section in
GRAPH_REPORT.mdby default; report header shows(N total, M thin omitted)and Knowledge Gaps collapses thin communities to one summary line (#664)
- Feat:
graphify tree— self-contained D3 v7 collapsible-tree HTML view ofgraph.json; expand/collapse controls, depth-based colours, hover inspector; XSS-safe (#557) - Feat: token-aware chunking with split-and-retry on truncation (#625)
- Feat: cross-language edge context filters in MCP
query_graphtool (#573) - Feat: dynamic
import()extraction for JS/TS (#579) - Fix:
save_semantic_cachecrashed withIsADirectoryErrorwhen a node'ssource_filewas a directory path —p.exists()→p.is_file()(#655) - Fix:
sanitize_label(None)raisedTypeErrorcrashingto_htmlon graphs with nullsource_filerationale nodes — return""early (#656) - Fix: chunk-extraction prompt omitted
rationalefrom validfile_typevalues — model hallucinatedconcepton every doc/paper run; explicit merge step added to all skill variants (#657) - Fix:
cost.jsonalways reported 0 tokens — chunk JSONs have placeholder zeros; orchestrator now globs and sums real token counts before merging (#658)
- Fix:
skill-windows.mdrewritten from PowerShell to bash — Claude Code on Windows uses git-bash so PowerShell syntax ($null,$LASTEXITCODE,Select-Object,& (Get-Content ...),Remove-Item) caused exit code 49 failures; now mirrorsskill.mdstructure withpythonadded as fallback afterpython3for Windows Conda (#39) - Fix: wiki
to_wiki()now clears stale articles before regenerating, preventing orphan .md accumulation (#558) - Fix:
_safe_filename()in wiki.py now strips Windows-reserved characters (< > : " / \ | ? *) and caps length at 200 chars (#594) - Fix: rationale-node leakage in cross-file INFERRED call resolution — rationale nodes now excluded from name lookup; edge direction (
calls,rationale_for) preserved correctly at JSON export (#576) - Feat:
.graphifyincludehidden path allowlist — opt specific hidden dirs into traversal (e.g..hermes/plans/**/*.md) (#583) - Feat:
--no-vizflag wired incluster-only;GRAPHIFY_VIZ_NODE_LIMITenv var overrides 5000-node HTML threshold (#565) - Fix: stray colon SyntaxError in
skill-trae.md--cluster-onlyblock (#603) - Docs: skill INFERRED confidence score guidance changed to discrete rubric (0.55/0.65/0.75/0.85/0.95) backed by calibration data (#546)
- Docs: skill
--updateprune output clarified — splits no-drift vs drift cases (#544) - Docs: skill
--updatemerge step now callssave_manifestto prevent deleted files reappearing (#545) - Feat:
graphify tree— self-contained D3 v7 collapsible-tree HTML view ofgraph.json; expand/collapse controls, depth-based colours, hover inspector; XSS-safe viahtml.escape()and_js_safe()(#557)
- Fix: Kotlin call-walker now accepts both
simple_identifierandidentifiernode types — PyPI'stree_sitter_kotlingrammar usesidentifierwhile older forks usesimple_identifier, causing zerocallsedges to be emitted (#659) - Feat: community sidebar now uses checkbox-based multi-select instead of show/hide buttons — supports indeterminate "select all" state (#647)
- Feat:
graphify update --forceandGRAPHIFY_FORCE=1env var — bypass the node-count safety check after refactors that legitimately shrink the graph (#639) - Fix: Codex PreToolUse hook on Windows — replaced
python3 -c "..."inline command (fails on Conda where onlypythonexists, and breaks PowerShell JSON parsing) withgraphify hook-check, a new shell-agnostic subcommand. Re-rungraphify codex installto regenerate the hook (#651, #522)
- Fix: Codex PreToolUse hook failed on Windows —
[ -f ]is bash-only and crashes oncmd.exe; replaced with a cross-platform Python one-liner (pathlib.Path.exists()) (#651)
- Fix: incremental rebuild (
graphify update, post-commit hook) dropped INFERRED/AMBIGUOUS semantic nodes extracted from code files — node preservation now filters by ID membership in the new AST output instead offile_type, so LLM-extracted call/data-flow edges survive code-only rebuilds (#653) - Fix: post-commit and post-checkout hooks blocked
git commitfor the full rebuild duration (hours on large repos) — rebuilds now detach vianohup & disown, git returns in ~100ms, log written to~/.cache/graphify-rebuild.log(#650) - Fix: cross-file INFERRED
callsresolution used a last-write-wins name map, causing common short names (log,execute,find) to accumulate hundreds of spurious edges and dominate god_nodes ranking — resolution now skips any callee name that matches 2+ candidates (ambiguous, no import evidence to pick the right target) (#543) - Fix:
cluster-onlycommand crashed on graphs with >5000 nodes due to unguardedto_htmlcall — now wrapped in try/except ValueError matching the watch/hook path (#541)
- Fix: Kimi K2.6 reasoning mode consumed entire token budget leaving
contentempty — thinking now disabled on Moonshot calls so graphs actually populate (#623) - Fix:
graphify update/graphify watchnever persisted the manifest, so every subsequent--updatere-extracted all files — manifest now saved after each rebuild (#621) - Fix: inline comments in
.graphifyignore(e.g.vendor/ # legacy) now stripped correctly — whitespace +#suffix is treated as a comment,path#hash.pypreserved (#605) - Fix:
graphify query "FunctionName"now returns the exact matching node first instead of high-degree hub modules hijacking the output — 100-point exact-match bonus + seeds render before BFS expansion (#638) - Fix: concurrent AST extractors raced on a shared
.tmpcache file — each writer now gets a unique tempfile viamkstemp, eliminating cache corruption under parallel extraction (#589) - Fix:
_clone_repobranch names starting with-could be interpreted as git flags — validation added,--separator inserted before positional args (#589) - Fix: replaced
html2text(GPL-3.0) withmarkdownify(MIT) — removes the only copyleft dependency from a MIT project (#586) - Fix:
--updatere-extracted files whose mtime was bumped by sync tools (Obsidian, Nextcloud) without content changes — manifest now stores content hash alongside mtime; mtime bump triggers an MD5 check before re-extraction (#593) - Feat: R language support —
.rfiles classified as code and processed via LLM semantic extraction (#617) - Feat: extensionless shell scripts now detected via shebang (
#!/bin/bash,#!/usr/bin/env python3, etc.) and included as code (#619) - Fix: cross-language INFERRED
callsedges (e.g. Python→TypeScript name collision) no longer appear as top surprising connections in GRAPH_REPORT.md (#630) - Fix:
cluster-onlyCLI silently flipped directed graphs to undirected —directedflag now read from graph.json and preserved through re-clustering (#590) - Fix: Windows UNC / extended-length paths (
\\?\C:\...) now normalize to consistent cache keys (#629) - Fix:
.graphifyignorenegation patterns (!src/lib/secrets.ts) now work — full last-match-wins evaluation with!un-ignore support (#628)
- Fix:
.graphifyignorediscovery now uses correct gitignore semantics — outer rules are loaded first so inner (closer) rules always win via last-match-wins, matching standard gitignore behavior (#643) - Fix: without a VCS root,
.graphifyignorediscovery is now hermetic to the scan folder — no leakage across sibling projects in a shared workspace (#643) - Fix: anchored patterns (leading
/) in a parent.graphifyignorenow correctly apply only relative to their own directory, not the scan root (#643) - Fix: trailing spaces in patterns are now handled per gitignore spec — unescaped trailing spaces are stripped,
vendor\(escaped) is preserved (#643)
- Feat: SQL AST extractor —
.sqlfiles now processed deterministically via tree-sitter. Extracts tables, views, functions/procedures, foreign key references, and FROM/JOIN reads_from edges. No LLM needed. Requirespip install 'graphifyy[sql]'(#349) - Feat:
xlsx_extract_structure()utility — extracts sheet names, named tables, and column headers from .xlsx files as structural nodes
- Feat: YAML/YML files now indexed for semantic extraction — Kubernetes, Kustomize, Helm, and any YAML corpus now picked up automatically (#633)
- Fix:
NameError: name '_os' is not definedcrash aftergraphify update— this was fixed in v5 branch but not released to PyPI (#618, #612)
- Feat: Kimi K2.6 backend —
pip install 'graphifyy[kimi]'+MOONSHOT_API_KEYroutes semantic extraction through Kimi K2.6. 3-6x richer relation extraction at ~3x lower cost. Claude remains default; Kimi is opt-in. - Fix: phantom god nodes (#598) — member-call callees (
this.logger.log()→log) no longer cross-file resolved. Go package-qualified calls (pkg.Func()) correctly preserved. Affects JS/TS, Go, Rust, Swift, Kotlin, Scala, PHP, C++, C#, Zig, Elixir. - Fix:
conceptfile_type no longer triggers validation warnings (#601) - Fix:
graphify updateremembers scan root viagraphify-out/.graphify_root— no path argument needed on subsequent runs - Fix: Kimi K2.6 temperature 400 error — temperature param is now skipped for Kimi backends (model enforces its own fixed value) (#610)
- Fix: community labels deleted in Step 9 cleanup —
.graphify_labels.jsonis now preserved so wiki/obsidian/HTML retain human-readable names after re-cluster (#608) - Fix:
NameError: name '_os' is not definedingraphify updateKimi tip (#612) - Fix:
SyntaxWarningin__main__.pyfor shell glob pattern with backslash escapes - Fix: Python upper bound removed —
requires-python = ">=3.10"now supports Python 3.14+ (#607)
- Fix: SSRF DNS rebinding —
safe_fetchnow patchessocket.getaddrinfofor the full request duration (#591) - Fix: yt-dlp SSRF bypass —
download_audionow callsvalidate_urlbefore handing URL to yt-dlp (#592)
- Fix: cache namespace — AST and semantic entries now live in
cache/ast/andcache/semantic/subdirectories; flat entries read as migration fallback
- Fix: PreToolUse hook now matches on
Bashinstead ofGlob|Grepfor Claude Code v2.1.117+
- Fix: node ID collision for same-named files in different directories
- Fix:
source_filepaths relativized before return sograph.jsonis portable - Fix: desync guard —
to_json()returns bool; report only written on successful JSON write - Feat: TypeScript
@/path aliases resolved viatsconfig.json - Feat: Show All / Hide All buttons in HTML community panel
- Feat:
graphify clone <github-url>— clone and graph any public repo - Feat:
graphify merge-graphs— combine multiplegraph.jsonoutputs into one cross-repo graph - Feat:
CLAUDE_CONFIG_DIRsupport ingraphify install - Feat: shrink guard —
to_json()refuses to overwrite with a smaller graph - Feat:
build_merge()for safe incremental updates - Feat: duplicate node deduplication via
deduplicate_by_label() - Fix:
graphify-out/excluded from source scanning
- Fix: stale skill version warning persists after running
graphify installwhen multiple platforms were previously installed —graphify installnow refreshes.graphify_versionin all other known skill directories so the warning clears across the board (#178) - Fix:
.htmlfiles silently skipped during detection — added.htmltoDOC_EXTENSIONS; HTML pages, docs, and web project content now indexed correctly (#260) - Fix:
_rebuild_code(watch/update/hook) fails entirely on graphs > 5000 nodes becauseto_htmlraisesValueError— wrapped in its own try/except sograph.jsonandGRAPH_REPORT.mdalways land; stalegraph.htmlfrom a previous smaller run is removed (#432) - Fix: Go stdlib imports (e.g.
"context") producedimports_fromedges pointing at local files of the same basename — Go import node IDs now prefixedgo_pkg_using the full import path, eliminating false cycle-dependency pairs (#431)
- Fix: AST cache written to
src/graphify-out/cache/instead of project root when all code files share a common prefix likesrc/—extract()now called with explicitcache_root=watch_pathin_rebuild_codeandcache_root=Path('.')in the Codex skill AST step (#429) - Fix:
.mdxfiles silently skipped during detection — added.mdxtoDOC_EXTENSIONSindetect.py; MDX-based corpora (Next.js, Docusaurus, Astro) now indexed correctly (#428)
- Fix:
graphify cluster-onlycrashed withKeyError: 'total_files'inreport.py— cluster-only skips detection so the stats dict was empty; now passes awarningkey so the report skips the file-stats section (#422) - Fix:
/graphify --updatedropped all existing graph nodes — the merge block built a correct in-memoryG_existingbut never wrote it back to.graphify_extract.json, so Step 4 rebuilt from the new-extraction-only file; merged result is now serialized back before Step 4 runs (#423)
- Fix: JS/MJS
imports_fromedges were silently dropped for files that use../subdir/file.mjsstyle imports —Path.parent / rawleft..segments unnormalized, so the generated target ID didn't match the actual file node ID. Fixed withos.path.normpath(#414) - Fix:
graphify update .andgraphify cluster-onlynow generategraph.htmlalongsidegraph.jsonandGRAPH_REPORT.md— previously only the skill generated the interactive HTML (#418)
- Fix: AST and semantic extraction no longer produce mismatched node IDs —
build_from_jsonnow normalises IDs before dropping edges, so edges survive when the LLM generates slightly different casing or punctuation than the AST extractor (#390) - Fix: cross-file call resolution extended to Go, Rust, Zig, PowerShell, and Elixir — unresolved callees are now saved as
raw_callsand resolved globally in a post-pass, matching existing behaviour for Python, Swift, Java, C#, Kotlin, Scala, Ruby, and PHP (#298) - Fix: Windows
graphify-out/graphify-outnesting bug —cache_dirand_rebuild_codein watch.py now call.resolve()on the root path, preventing a nested output directory when graphify is run from a subdirectory (#410) - Fix:
graphify hook installnow respectscore.hooksPathgit config (used by Husky and similar tools) — hooks are written to the configured path instead of always.git/hooks(#401) - Fix: Kiro skill YAML frontmatter —
descriptionvalue is now quoted and colons replaced with dashes, preventing a parse error in Kiro's YAML loader (#385) - Docs: added Windows PATH tip (
%APPDATA%\Python\PythonXY\Scripts) and macOS pipx tip (pipx ensurepath) to the install section (#413) - Docs: added team workflow section — committing
graphify-out/,.graphifyignoreusage, and recommended.gitignoreadditions (#369)
- Fix: graphify watch crashed on all platforms with NameError because import sys was missing from watch.py (#386, #394)
- Fix: .mjs files were detected but produced 0 nodes — added .mjs to the AST extractor dispatch table (#387)
- Fix: llm.py excluded from the published wheel (local benchmarking file, not part of the public API) (#391)
- Feat: VS Code Copilot Chat support —
graphify vscode installinstalls a Python-only skill (works on Windows PowerShell) and writes.github/copilot-instructions.mdfor always-on graph context (#206) - Fix: OpenCode plugin path used backslashes on Windows causing duplicate entries in
opencode.json— now uses forward slashes via.as_posix()(#378) - Fix: Gemini CLI on Windows now installs skill to
~/.agents/skills/(higher priority) instead of~/.gemini/skills/(#368) - Fix:
.mjsand.ejsfiles now recognised by the AST extractor as JavaScript (#365, #372) - Fix:
god_nodes()field renamed fromedgestodegreefor clarity — updated in report, wiki, serve, and all tests (#375) - Fix: macOS
graphify watchnow usesPollingObserverby default to avoid missed events with FSEvents (#373)
- Fix: cross-file call edges now emitted for all languages (Swift, Go, Rust, Java, C#, Kotlin, Scala, Ruby, PHP, and others) — previously only Python had cross-file resolution; unresolved call sites are now saved per file and resolved against a global label map in a post-pass (#348)
- Fix: PHP extractor now handles
scoped_call_expression(static method calls likeHelper::format()) andclass_constant_access_expression(enum/constant references likeStatus::ACTIVE) — both were silently dropped before (#230, #232) - Fix:
--wikiflag now runsto_wiki()as Step 6b in the skill pipeline before the cleanup step — community labels are available and the wiki is written tographify-out/wiki/(#229, #354) - Fix:
graphify install --platform opencodenow also installs the.opencode/plugins/graphify.jsplugin, matching whatgraphify opencode installdoes (#356) - Fix:
extract()accepts explicitcache_rootparameter so subdirectory runs no longer write cache to<subdir>/graphify-out/cache/(#350) - Fix:
os.replacein cache writer falls back toshutil.copy2onPermissionError(Windows WinError 5) (#287) - Fix:
graphify updateexits with code 1 on rebuild failure instead of silently returning (#287) - Fix:
CLAUDE.md, Cursor, and Antigravity templates now usegraphify update .instead of hardcodedpython3 -cinvocation (#287) - Fix:
skill-kiro.mdadded topyproject.tomlpackage-data —graphify kiro installwas failing on fresh pip installs (#352) - Fix:
betweenness_centralityinsuggest_questionsusesk=100approximate sampling for graphs over 1000 nodes;edge_betweenness_centralityreturns early for graphs over 5000 nodes (#341)
- Add: Verilog/SystemVerilog support —
.vand.svfiles extracted via tree-sitter-verilog (modules, functions, tasks, package imports, module instantiations withinstantiatesedges) (#325) - Fix: hyperedge polygons render correctly on HiDPI/Retina displays —
afterDrawingcallback ctx is now used directly (already in network coordinate space), removing the double-applied transform and incorrectcanvas.width/2DPR anchor (#334) - Fix: AGENTS.md and GEMINI.md rebuild rule now uses
graphify update .instead of hardcodedpython3 -c "..."— correct Python is resolved through the graphify binary, no more interpreter mismatches in Nix/pipx/uv environments (#324) - Fix:
graphify queryandgraphify explainno longer crash withAttributeErrorwhen a node haslabel: null— all.get("label", "")calls guarded withor ""to handle explicit null values (#323)
- Add: Kiro IDE/CLI support —
graphify kiro installwrites.kiro/skills/graphify/SKILL.md(invoked via/graphify) and.kiro/steering/graphify.md(inclusion: always— always-on context before every conversation) (#319, #321) - Fix: cache
file_hash()now uses the path relative to project root instead of the resolved absolute path — cache entries are now portable across machines, CI runners, and different checkout directories (#311)
- Fix:
graphify queryno longer crashes withValueErroron MultiGraph graphs —G.edges[u, v]replaced withG[u][v]+ MultiGraph guard (#305) - Fix:
graphify queryno longer crashes withAttributeError: 'NoneType' has no attribute 'lower'when a node has a nullsource_file(#307) - Fix: MCP server launched from a different directory now correctly derives the
graphify-outbase from the absolute path provided, instead of CWD (#309) - Fix:
.graphifyignorepatterns from a parent directory now fire correctly when graphify is run on a subfolder — patterns are matched against paths relative to both the scan root and the.graphifyignore's anchor directory (#303)
- Fix:
graphify install --platform cursorno longer crashes — passesPath(".")to_cursor_install(#281) - Fix:
_agents_uninstallnow only removes the OpenCode plugin when uninstalling theopencodeplatform — other platforms were incorrectly having their OpenCode plugin stripped (#276) - Fix: misleading comment in query
--graphpath handler removed (#278) - Fix:
skill-codex.md—wait→wait_agent(correct Codex tool name) (#273) - Add:
svg = ["matplotlib"]optional extra in pyproject.toml;matplotlibadded to[all]extra (#288) - Fix:
graspologicdependency now haspython_version < '3.13'env marker inleidenandallextras — prevents install failures on Python 3.13+ (#290) - Add: Dart/Flutter support —
.dartfiles extracted via regex (classes, mixins, functions, imports); added toCODE_EXTENSIONS(#292) - Add:
norm_labelfield written at build time into_json()for diacritic-insensitive search;_score_nodesand_find_nodeinserve.pyusenorm_labelwith Unicode NFKD normalization fallback (#293) - Add: Hermes Agent platform support —
graphify hermes installwrites skill to~/.hermes/skills/graphify/SKILL.mdand AGENTS.md (#251) - Add: PHP extractor now captures static property access (
Foo::$bar) asuses_static_propedges (#234) - Add: PHP extractor now captures
config()helper calls asuses_configedges pointing to the first config key segment (#236) - Add: PHP extractor now captures service container bindings (
bind,singleton,scoped,instance) asbound_toedges (#238) - Add: PHP extractor now captures
$listen/$subscribeevent listener arrays aslistened_byedges (#240) - Add:
prune_dangling_edges()utility inexport.py— removes edges whose source/target is not in the node set (#294) - Fix: Antigravity install injects YAML frontmatter into skill file for native tool discovery; rules now include MCP navigation hint; prints MCP config snippet (#268)
- Fix: Windows hook tests now use platform-aware assertions instead of POSIX executable bit checks (#279)
- Add: CLI commands
path,explain,add,watch,update,cluster-onlynow work as bare terminal commands (not just AI skill invocations) — documented in--helpoutput (#277)
- Fix: platform skill files (aider, codex, opencode, claw, droid, copilot, windows) no longer contain Claude-specific language — references to "Claude" as the AI model replaced with platform-agnostic wording (#272)
- Fix:
watchsemantic edge preservation was always empty —graph.jsonuseslinkskey but code readedges(#269) - Fix:
graphify claw installnow writes to.openclaw/(correct OpenClaw directory) instead of.claw/(#208) - Add: Blade template support —
@include,<livewire:>components, andwire:clickbindings extracted from.blade.phpfiles (#242) - Docs: WSL/Linux MCP setup note — package name is
graphifyy, use.venv/bin/python3in.mcp.json(#250)
- Add: Google Antigravity support —
graphify antigravity installwrites.agent/rules/graphify.md(always-on rules) and.agent/workflows/graphify.md(/graphifyslash command) (#203, #199, #53)
- Fix: MCP server no longer crashes with
ValidationErroron blank lines sent between JSON messages by some clients (#201)
- Fix:
watchnow preserves INFERRED/AMBIGUOUS edges (code↔doc rationale links) across rebuilds — previously all cross-type edges were dropped (#261) - Fix: Codex hook no longer emits
permissionDecision:allowwhich codex-cli 0.120.0 rejects (#249) - Fix: Common lockfiles (
package-lock.json,yarn.lock,Cargo.lock, etc.) are now skipped during detection, preventing token drain on large JS/Rust/Python projects (#266)
- Fix: JS/TS relative imports now resolve to full-path node IDs — previously all
imports_fromedges were silently dropped on large TypeScript codebases (#256) - Fix: Python relative imports (
from .foo import bar) now resolve correctly to full-path node IDs (#256) - Fix:
watch --rebuild_codenow merges fresh AST with existing semantic nodes from docs/papers instead of overwriting them (#253) - Fix: Windows hooks now fall back to
pythonifpython3is not found; exits cleanly if neither has graphify installed (#244) - Fix:
surprising_connections/suggest_questionsno longer crash withKeyErroron stale_src/_tgtedge hints after node merges (#226) - Add:
.vueand.sveltefiles now recognized as code and included in extraction (#254)
- Fix: same-basename files in different directories produced colliding node IDs — now uses full path (#211)
- Fix: edges using
from/tokeys instead ofsource/targetwere silently dropped (#216) - Fix: empty graphs (no edges) crashed
to_htmlwithZeroDivisionError(#217) - Fix: post-commit hook skipped
.tsx,.jsx, and other valid code extensions due to stale allowlist (#222) - Fix: NetworkX ≤3.1 serialises edges as
links— now accepted alongsideedges(#212) - Fix: version warning fired during
install/uninstalland duplicated on shared paths (#220) - Fix: all file IO now uses
encoding="utf-8"— prevents crashes on Windows with CJK or emoji labels; hook writes usenewline="\n"to prevent CRLF shebang breakage (#204) - Fix: Obsidian export — node labels ending in
.mdproduced.md.mdfilenames;GRAPH_REPORT.mdnow links to community hub files so vault stays in one connected component (#221)
- Fix:
collect_files()inextract.pynow respects.graphifyignore— previously ignored patterns, causing thousands of unwanted files (e.g.node_modules/) to be scanned (#188) - Fix: skill.md Step B2 now explicitly requires
subagent_type="general-purpose"— usingExploretype silently dropped extraction results since it is read-only and cannot write chunk files (#195) - Fix: Step B3 now warns when chunk files are missing from disk instead of silently skipping them
- Branch: v4 — video and audio corpus support
- Add: drop
.mp4,.mp3,.wav,.mov,.webm,.m4a,.ogg,.mkv,.avi,.m4vfiles into any corpus and graphify transcribes them locally with faster-whisper before extraction - Add: YouTube and URL download via yt-dlp —
/graphify add https://youtube.com/...downloads audio-only and feeds it through the same Whisper pipeline - Add: domain-aware Whisper prompts — the coding agent reads god nodes from the corpus and writes a one-sentence domain hint for Whisper itself, no separate API call
- Add:
graphify-out/transcripts/cache — transcripts cached by filename; YouTube URLs cached by hash so re-runs skip already-transcribed files - Requires:
pip install 'graphifyy[video]'for faster-whisper and yt-dlp
- Add: video and audio corpus support — drop
.mp4,.mp3,.wav,.mov,.webm,.m4a,.ogg,.mkv,.avi,.m4vfiles into any corpus and graphify transcribes them with faster-whisper before extraction - Add: YouTube and URL video download — pass a YouTube link (or any video URL) to
/graphify add <url>and yt-dlp downloads audio-only, which is then transcribed and added to the corpus automatically - Add: domain-aware Whisper prompts — god nodes from non-video files are used to build a one-sentence domain hint for Whisper via a cheap Haiku call, improving transcript accuracy on technical content
- Add:
graphify-out/transcripts/cache — transcripts are cached by filename so re-runs skip already-transcribed files; URLs cached by hash - Requires:
pip install 'graphifyy[video]'for faster-whisper + yt-dlp
- Fix: hook installers (Claude Code, Codex, Gemini CLI) now always remove and reinstall the hook on re-run — users upgrading from old versions no longer get stuck with a broken hook format (#182)
- Fix: rationale node labels no longer contain bare
\rcharacters on Windows/WSL CRLF files — breaks Obsidian export was silently producing invalid filenames (#176) - Fix:
skill-windows.mdnow includes--wiki,--obsidian-dir, and--directedwhich were missing vs the main skill (#177)
- Fix: graphify install --platform gemini now also copies the skill file to ~/.gemini/skills/graphify/SKILL.md so the /graphify trigger works in Gemini CLI (#174)
- Fix: MCP server no longer uses a circular path validation when loading a graph outside cwd — now validates the path exists and ends in
.jsoninstead of checking containment within its own parent directory (security fix)
- Fix:
graphify install --platform gemininow routes togemini_install()instead of erroring —geminiwas missing from_PLATFORM_CONFIG(#171) - Fix:
graphify install --platform cursornow routes to_cursor_install()the same way (#171) - Fix:
serve.pyvalidate_graph_pathnow passesbase=Path(graph_path).resolve().parentso MCP server works when graph is outside cwd (#170) - Fix: MCP
call_tool()handler now wraps dispatch in try/except — exceptions in tool handlers return graceful error strings instead of crashing the stdio loop (#163) - Fix:
_load_graphifyignorenow walks parent directories up to the.gitboundary, matching.gitignorediscovery behavior — subdirectory scans now inherit root ignore patterns (#168) - Add: Aider platform support —
graphify install --platform aidercopies skill to~/.aider/graphify/SKILL.md;graphify aider install/uninstallwrites AGENTS.md rules (#74) - Add: GitHub Copilot CLI platform support —
graphify install --platform copilotcopies skill to~/.copilot/skills/graphify/SKILL.md;graphify copilot install/uninstallfor skill management (#134) - Add:
--directedflag —build_from_json()andbuild()now acceptdirected=Trueto produce aDiGraphpreserving edge direction (source→target);cluster()converts to undirected internally for Leiden;graph_diffedge key handles directed graphs correctly (#125) - Add: Frontmatter-aware cache for Markdown files —
.mdfiles hash only the body below YAML frontmatter, so metadata-only changes (reviewed, status, tags) no longer invalidate the cache (#131)
- Fix:
graphify codex install(and opencode) no longer exits early whenAGENTS.mdalready has the graphify section — partial installs with a missing.codex/hooks.jsoncan now recover on re-run (#153)
- Add: Gemini CLI support —
graphify gemini installwrites aGEMINI.mdsection and aBeforeToolhook in.gemini/settings.jsonthat fires before file-read tool calls (#105) - Add: sponsor nudge at pipeline completion — all skill files now print a one-line sponsor link after a fresh build, not on
--updateruns
- Add: Cursor support —
graphify cursor installwrites.cursor/rules/graphify.mdcwithalwaysApply: trueso the graph context is always included;graphify cursor uninstallremoves it (#137) - Fix:
_rebuild_code()KeyError —detected[FileType.CODE]corrected todetected['files']['code']matchingdetect()'s actual return shape; was silently breaking git hooks on every commit (#148) - Fix:
to_json()crash on NetworkX 3.2.x —node_link_data(G, edges="links")now falls back tonode_link_data(G)on older NetworkX, same shim already used fornode_link_graph(#149) - Fix: README clarifies
graphifyyis the only official PyPI package — othergraphify*packages are not affiliated (#129)
- Fix: Codex PreToolUse hook now places
systemMessageat the top level of the output JSON instead of insidehookSpecificOutput— matches the strict schema enforced by codex-cli 0.118.0+ which usesadditionalProperties: false(#138) - Fix: git hooks now use
#!/bin/shinstead of#!/bin/bash— Git for Windows shipssh.exenotbash, so hooks were silently skipped on Windows (#140)
- Fix: XSS in interactive HTML graph — node labels, file types, community names, source files, and edge relations now HTML-escaped before
innerHTMLinjection; neighbor linkonclickusesJSON.stringifyinstead of raw string interpolation - Add: OpenCode
tool.execute.beforeplugin —graphify opencode installnow writes.opencode/plugins/graphify.jsand registers it inopencode.json, firing the graph reminder before bash calls (equivalent to Claude Code's PreToolUse hook) (#71) - Fix: AST-resolved call edges now carry
confidence=EXTRACTED, weight=1.0instead of INFERRED/0.8 — tree-sitter call resolution is deterministic, not probabilistic (#127) - Fix:
tree-sitter>=0.23.0now pinned in dependencies and_check_tree_sitter_version()guard added — stale environments now get a clearRuntimeErrorwith upgrade instructions instead of a crypticTypeErrordeep in the AST pipeline (#89)
- Fix: install step now tries plain
pip installbefore falling back to--break-system-packages— Homebrew and PEP 668 managed environments no longer risk environment corruption (#126)
- Fix:
--watchmode now respects.graphifyignore—_rebuild_codewas callingcollect_files()directly instead ofdetect(), bypassing ignore patterns (#120) - Fix: Codex PreToolUse hook now uses
systemMessageinstead ofadditionalContext— Codex does not supportadditionalContextand was returning an error (#121) - Fix: Trae link corrected from
trae.comtotrae.aiin README, README.zh-CN.md, README.ja-JP.md, README.ko-KR.md (#122) - Docs: Korean README added (README.ko-KR.md) (#112)
- Refactor:
save_query_resultinline Python blocks in all 6 skill files replaced withgraphify save-resultCLI command — shorter, maintainable, less tokens for LLM (#114) - Add:
graphify save-resultCLI subcommand — saves Q&A results to memory dir without inline Python - Fix: HTML graph click detection now uses hover-tracking (
hoveredNodeId) — more reliable than vis.js click params on small/dense nodes (#82) - Fix:
mkdir -p graphify-outnow runs before writing.graphify_pythoninskill.md— prevents write failure on first run;.graphify_pythonno longer deleted in Step 9 cleanup across all skill files so follow-up commands keep their interpreter (#93) - Fix:
skill-trae.mdadded topyproject.tomlpackage-data — Trae users no longer hitModuleNotFoundErrorafterpip install(#102) - Fix:
analyze.pyandwatch.pynow import extension sets fromdetect.pyinstead of local copies — Swift, Lua, Zig, PowerShell, Elixir, JSX, Julia, Objective-C files no longer misclassified as documents (#109) - Refactor: dead
build_graph()function removed fromcluster.py(#109)
- Add: Julia (.jl) support — modules, structs, abstract types, functions, short functions, using/import, call edges, inherits edges via tree-sitter-julia (#98)
- Fix: Semantic extraction chunks now group files by directory so related artifacts land in the same chunk, reducing missed cross-chunk relationships (#65)
- Fix:
tree-sitter>=0.21now pinned in dependencies — prevents silent empty AST output when older tree-sitter is installed with newer language bindings (#52) - Add: Progress output every 100 files during AST extraction so large projects don't appear to hang (#52)
- Fix:
graphify query,serve, andbenchmarknow work on NetworkX < 3.4 — version-safe shim fornode_link_graph()at all call sites (#95) - Fix:
.jsxfiles now detected and extracted via the JS extractor — added toCODE_EXTENSIONSand_DISPATCH(#94) - Fix:
.graphify_pythonno longer deleted in Step 9 cleanup across all 6 skill files — pipx users no longer hitModuleNotFoundErroron follow-up commands (#92)
- Feat: Trae and Trae CN platform support (
graphify install --platform trae/trae-cn) - Fix:
skill-droid.mdwas missing from PyPI package data — Factory Droid users couldn't install the skill - Fix: XSS in HTML legend — community labels now HTML-escaped before
innerHTMLinjection - Fix: Shebang allowlist validation in
hooks.pyand all 6 skill files — prevents metacharacter injection from malicious binaries - Fix:
louvain_communities()kwargs now inspected at runtime for cross-version NetworkX compatibility - Fix: pipx installs now detected correctly in git hooks (reads shebang from graphify binary)
- Fix: graspologic ANSI escape codes no longer corrupt PowerShell 5.1 scroll buffer
- Docs: Japanese README added
- Docs:
graph.json+ LLM workflow example added to README - Docs: Codex PreToolUse hook now documented in platform table
- Fix:
graphify codex installnow also writes a PreToolUse hook to.codex/hooks.jsonso the graph reminder fires before every Bash tool call (#86) - Fix:
--updatenow prunes ghost nodes from deleted files before merging new extraction (#51)
- Fix: PreToolUse hook now outputs
additionalContextJSON so Claude actually sees the graph reminder before Glob/Grep calls (#83) - Fix: Go AST method receivers and type declarations now use package directory scope, eliminating disconnected duplicate type nodes across files in the same package (#85)
- Fix: PDFs inside Xcode asset catalogs (
.imageset,.xcassets) are no longer misclassified as academic papers (#52) - Fix:
_resolve_cross_file_importsis now guarded withif py_pathsand wrapped in try/except so a Python parser crash can't abort extraction for non-Python files (#52) - Fix: Skill intermediate files (
.graphify_*.json) now live ingraphify-out/instead of project root, preventing git pollution (#81)
- Fix:
sanitize_labelwas double-encoding HTML entities in the interactive graph (&lt;instead of<) — removedhtml.escape()fromsanitize_label; callers that inject directly into HTML now callhtml.escape()themselves (#66) - Fix:
--wikiflag missing fromskill.mdusage table (#55)
- Fix: Louvain fallback hangs indefinitely on large sparse graphs — added
max_level=10, threshold=1e-4to prevent infinite loops while preserving community quality (#48)
- Fix: Windows UnicodeEncodeError during
graphify install— replaced arrow character with->in all print statements (#47) - Add: skill version staleness check — warns when installed skill is older than the current package, across all platforms (#46)
- Add:
follow_symlinksparameter todetect()andcollect_files()— opt-in symlink following with circular symlink cycle detection (#33) - Fix:
watch.pynow usescollect_files()instead of manual rglob loop for consistency - Docs: Codex uses
$graphify .not/graphify .(#36) - Test: 5 new symlink tests (367 total)
- Add: C# inheritance and interface implementation extraction —
base_listnow emitsinheritsedges for both simple (identifier) and generic (generic_name) base types (#45) - Add:
graphify query "<question>"CLI command — BFS/DFS traversal ofgraph.jsonwithout needing Claude Code skill (--dfs,--budget N,--graph <path>flags) - Test: 2 new C# inheritance tests (362 total)
- Add: Objective-C support (
.m,.mm) —@interface,@implementation,@protocol, method declarations,#importdirectives, message-expression call edges - Add:
--obsidian-dir <path>flag — write Obsidian vault to a custom directory instead ofgraphify-out/obsidian - Fix: semantic cache was only saving 4/17 files — relative paths from subagents now resolved against corpus root before existence check
- Fix: 75 validation warnings per run for
file_type: "rationale"— added"rationale"toVALID_FILE_TYPES - Test: 6 Objective-C tests;
.m/.mmadded totest_collect_files_from_dirsupported set (360 total)
- Add: multi-platform support — Codex (
skill-codex.md), OpenCode (skill-opencode.md), OpenClaw (skill-claw.md) - Add:
graphify install --platform <codex|opencode|claw>routes skill to correct config directory - Add:
graphify codex install/opencode install/claw install— writes AGENTS.md for always-on graph-first behaviour - Add:
graphify claude uninstall/codex uninstall/opencode uninstall/claw uninstall - Add: MIT license
- Fix:
build()was silently dropping hyperedges when merging multiple extractions - Refactor:
extract.py2527 → 1588 lines — replaced 12 copy-pasted language extractors withLanguageConfigdataclass +_extract_generic() - Docs: clustering is graph-topology-based (no embeddings) — explained in README
- Docs: all missing flags documented (
--cluster-only,--no-viz,--neo4j-push,query --dfs,query --budget,add --author,add --contributor)
- Add:
graphify claude install— writes graphify section to local CLAUDE.md + PreToolUse hook in.claude/settings.json - Add:
graphify claude uninstall— removes section and hook - Add:
graphify hook install— installs post-commit and post-checkout git hooks (platform-agnostic) - Add:
graphify hook uninstall/hook status - Add:
graphify benchmarkCLI command - Fix: node deduplication documented at all three layers
- Fix: follow-up questions now check for wiki first (graphify-out/wiki/index.md) before falling back to graph.json
- Fix: --update now auto-regenerates wiki if graphify-out/wiki/ exists
- Fix: community articles show truncation notice ("... and N more nodes") when > 25 nodes
- UX: pipeline completion message now lists all available flags and commands so users know what graphify can do
- Add:
--wikiflag — generates Wikipedia-style agent-crawlable wiki from the graph (index.md + community articles + god node articles) - Add:
graphify/wiki.pymodule withto_wiki()— cross-community wikilinks, cohesion scores, audit trail, navigation footer - Add: 14 wiki tests (245 total)
- Fix: follow-up question example code now correctly splits node labels by
_to extract verb prefixes (previous version useddef/fnprefix matching which always returned zero results)
- Fix: follow-up questions after pipeline now answered from graph.json, not by re-exploring the directory (was 25 tool calls / 1m30s; now instant)
- Skill: added "Answering Follow-up Questions" section with graph query patterns
- Perf: semantic extraction chunks 12-15 → 20-25 files (fewer subagent round trips)
- Perf: code-only corpora skip semantic dispatch entirely (AST handles it)
- Perf: print timing estimate before extraction so the wait feels intentional
- Fix: 5 skill gaps - --graphml in Usage table, --update manifest timing, query/path/explain graph existence check, --no-viz clarity
- Refactor: dead imports removed (shutil, sys, inline os); _node_community_map() helper replaces 8 copy-pasted dict comprehensions; to_html() split into _html_styles() + _html_script(); serve.py call_tool() if/elif chain replaced with dispatch table
- Test: end-to-end pipeline integration test (detect → extract → build → cluster → analyze → report → export)
- Replace pyvis with custom vis.js HTML renderer - node size by degree, click-to-inspect panel with clickable neighbors, search box, community filter, physics clustering
- HTML graph generated by default on every run (no flag needed)
- Token reduction benchmark auto-runs after every pipeline on corpora over 5,000 words
- Fix: 292 edge warnings per run eliminated - stdlib/external edges now silently skipped
- Fix:
build()cross-extraction edges were silently dropped - now merged before assembly - Fix:
pip install graphify→pip install graphifyyin skill Step 1 (critical install bug) - Add:
--graphmlflag implemented in skill pipeline (was documented but not wired up) - Remove: pyvis dependency, dead lib/ folder, misplaced eval reports from tests/
- Add: 5 HTML renderer tests (223 total)
- Fix:
pyproject.tomlstructure -requires-pythonanddependencieswere incorrectly placed under[project.urls] - Add: GitHub repository and issues URLs to PyPI page
- Add:
keywordsfor PyPI search discoverability - Docs: README clarifies Claude Code requirement, temporary PyPI name, worked examples footnote
- Add: CI badge to README (GitHub Actions, Python 3.10 + 3.12)
- Add: ARCHITECTURE.md - pipeline overview, module table, extraction schema, how to add a language
- Add: SECURITY.md - threat model, mitigations, vulnerability reporting
- Add:
worked/directory with eval reports (karpathy-repos 71.5x benchmark, httpx, mixed-corpus) - Fix: pytest not found in CI - added explicit
pip install pyteststep - Fix: README test count (163 → 212), language table, worked examples links
- Docs: README reframed as Claude Code skill; Karpathy problem → graphify answer framing
Initial release.
- 13-language AST extraction via tree-sitter (Python, JS, TS, Go, Rust, Java, C, C++, Ruby, C#, Kotlin, Scala, PHP)
- Leiden community detection via graspologic with oversized community splitting
- SHA256 semantic cache - warm re-runs skip unchanged files
- MCP stdio server -
query_graph,get_node,get_neighbors,shortest_path,god_nodes - Memory feedback loop - Q&A results saved to
graphify-out/memory/, extracted on--update - Obsidian vault export with wikilinks, community tags, Canvas layout
- Security module - URL validation, safe fetch with size cap, path guards, label sanitisation
graphify installCLI - copies skill to~/.claude/skills/and registers inCLAUDE.md- Parallel subagent extraction for docs, papers, and images