What's new
Every release, straight from GitHub, newest first.
- v0.9.35Aug 6, 2026
v0.9.35
Correctness release: revives the merge shrink guard, fixes prune/eviction on absolute paths and newly-ignored files, stops a Java external-annotation conflation, and makes callflow and query direction/relation aware.
- Fix: the
build_merge#479 shrink guard is no longer effectively dead (#2497, thanks @sortakool). It read the post-replace node count, so a broken partial re-extract could silently destroy nodes without tripping the guard, and the guard was skipped entirely underprune_sources. The guard now diffs the on-disk baseline by node identity and refuses any loss from a source that was neither re-extracted nor pruned this run (active even underprune_sources, skipped only underdedup), and reports how many nodes a re-extract replaced. - Fix:
build_merge/merge_raw_extractionprune_sourcesnow prunes correctly when given absolute paths under a non-standard layout, deriving the scan root by suffix-matching stored source paths, and warns (instead of reporting "already clean") when a prune matches nothing (#2446, thanks @AI-invest). - Fix:
graphify updatenow removes newly-ignored files from an existing graph (#2495, thanks @alisson-acioli). A file added to.graphifyignore/--exclude(or a skip rule) is evicted even though it still exists on disk;.gitignore-driven eviction applies on an explicit fullupdate. Files that merely changed are still preserved, and a file that leaves the corpus without matching any live ignore rule stays (fail-closed, #1795). - Fix: a Java local class and a same-named external annotation (e.g. a local
class Componentand Spring's@Component) no longer collapse into one node (#2504, thanks @te7ina-honey). The Java type resolver now runs before the unique-label stub rewire and parks an imported-but-external type on its fully-qualified name, and cross-file import resolution checks the package. In-corpus annotation resolution is unchanged. - Fix:
graphify callflownow respects edge direction, so the caller/callee columns are correct (#2508, thanks @Tomaskobel). The call-flow HTML loads the graph directed and recovers direction from the stored_src/_tgtmarkers (consistent with thepathfix), and indirect calls are counted. - Fix: relational-intent verbs in a
query("calls", "uses", "extends", ...) no longer seat spurious seeds (#2507, thanks @filipechagas). Such a verb is excluded from the per-term seed guarantee, so a decoy matching only the verb no longer becomes a traversal root, while a verb that is a genuine symbol name can still be seeded on merit.
- Fix: the
- v0.9.34Aug 5, 2026
v0.9.34
Correctness release: a C# receiver-typing regression fix, direction-respecting shortest paths, and a set of hyperedge merge/load integrity fixes.
- Fix: C# receiver typing no longer drops a true call when a same-named variable is declared untypeably elsewhere in the method (#2472, thanks @JensD-git). Receiver types are now tracked per lexical declaration scope and resolved by the call's position, so a typed
staticlocal-function parameter keeps resolving even when anout varreuses the name in the enclosing body. This fixes a regression from 0.9.32 (#2346). Cross-method independence (#2299) and field-conflict poisoning are unchanged; anout varreceiver itself remains untyped. - Fix:
graphify path(and the MCPshortest_pathtool) now respect edge direction by default instead of running on an undirected view, so a returned path no longer traverses edges backwards (#2487, thanks @luliaz0601). Direction is recovered from the stored_src/_tgtmarkers. Pass--undirected(CLI) orundirected=true(MCP) to search ignoring direction; when no directed path exists the command says so instead of silently returning a reversed one. - Fix: semantic extraction no longer aborts at merge with a
TypeErrorwhen a hyperedge carries dict-shaped members (#2486, thanks @adminwat). Members are normalized to ids (or dropped with a warning) so a malformed hyperedge can no longer destroy a completed extraction. - Fix:
graphify merge-graphsno longer drops hyperedges (#2484, thanks @sortakool, and @oleksii-tumanov for the approach in #1691). Hyperedge member ids and ids are now relabeled with the per-repo prefix, both inputs' hyperedges are unioned instead of one clobbering the other, and they are written to both the top-level and nested slots. - Fix:
build_from_jsonnow reads hyperedges from both the top-level and nestedgraphslots, so label and re-cluster runs no longer silently empty a graph's hyperedge set (#2485, thanks @sortakool); a full validation wipeout is now reported loudly. - Fix: the skill flow now passes the curated community labels to
to_json, sograph.jsonships withcommunity_nameon nodes instead of dropping it (#2490, thanks @PapiScholz).
- Fix: C# receiver typing no longer drops a true call when a same-named variable is declared untypeably elsewhere in the method (#2472, thanks @JensD-git). Receiver types are now tracked per lexical declaration scope and resolved by the call's position, so a typed
- v0.9.33Aug 5, 2026
v0.9.33
Data-integrity release: fixes a C# partial-class regression from 0.9.32, stops incremental rebuilds from dropping cross-file call edges, and stops extract from silently losing a file when a worker crashes.
- Fix: the C#
partial classmerge (#2332) no longer conflates two same-named classes that live in different assemblies (#2411, thanks @JensD-git). The merge now keys on assembly (nearest ancestor directory containing a.csproj/.fsproj/.vbproj) in addition to namespace and name, so genuine partial halves within one project still merge while same-name types in separate projects stay distinct. A corpus with no project file keeps merging by namespace and name as before. - Fix:
graphify updateno longer drops member-call andindirect_calledges from a changed file into an unchanged target (#2437, #2438, thanks @aryanbonigala). Incremental re-resolution now sees the unchanged corpus (its nodes,contains/methodedges, and the_callablemarkers, which now persist tograph.jsonlike_origin), so cross-file calls survive an incremental rebuild while edges to a genuinely removed target are still evicted. - Fix:
graphify extractno longer silently substitutes an empty result when a worker crashes (#2444, #2445, thanks @Baziar). ABrokenProcessPoolnow triggers the sequential fallback instead of being swallowed per future, a failed worker file is retried sequentially rather than merged as empty, and a whole-pass AST failure on a fresh build exits non-zero instead of writing a zero-node graph (use--allow-partialto opt into a best-effort partial graph). graphify installnow prints a one-time pointer to the hosted platform (early access is open free before the public v1 launch) after the setup summary.
- Fix: the C#
- v0.9.32Aug 1, 2026
v0.9.32
Correctness release: a tier-aware merge that stops incremental/rebuild from dropping a file's other layer, plus a batch of language-resolution and CLI fixes.
- Fix: incremental extraction and
_rebuild_codeno longer drop a file's other tier (#2333, #2334, #2336). Merge is now tier-aware (an AST re-extract replaces only AST nodes and keeps the semantic layer, and vice versa), the_originprovenance marker is backfilled on load so old graphs self-heal, and the full-rebuild drop is scoped to sources actually regenerated. - Fix:
graphify updatepreserves the graph'sdirectedflag instead of rebuilding it undirected (#2342, thanks @Rishet11). - Fix: a numeric or otherwise non-string node id from an LLM fragment no longer aborts the build with a TypeError (#2326, thanks @Rishet11).
- Fix:
graphify queryrenders every edge between visited nodes, not just the traversal-tree edges (#2323, thanks @Rishet11). - Fix:
graphify updatewritesmanifest.jsonto the target'sgraphify-outinstead of the current working directory (#2316, thanks @Rishet11). - Fix: a real Python package named
coverage/is no longer silently dropped; the prune is gated on coverage-report artefacts (#2339, thanks @Manoj21k). - Fix: a custom
GRAPHIFY_OUTname no longer prunes every same-named directory in the tree (#2273, thanks @oleksii-tumanov). - Fix: C# member calls resolve for receivers declared inline via
out var,is,case, and switch-arm patterns (#2346, thanks @JensD-git), and members of apartial classsplit across files now attach to one merged class node (#2332). - Fix: members of a Kotlin anonymous object (
object : Foo { ... }) are now extracted, with theirimplementsandcallsedges (#2347). - Fix: Ruby mixins declared with compact/nested syntax now resolve, and a qualified external mixin can no longer fabricate a phantom hub (#2302, thanks @FolatheDuckofDuckingburg).
module Foo::Barandmodule Foo; module Barcanonicalize to the same label;extend ActiveSupport::Concernno longer binds to a local module namedConcern; a genuine in-corpusinclude Foo::Concernstill resolves. - Perf: dedup drops an O(nodes x components) scan in remap construction (#2328, thanks @stupidprogrammer4), with identical results.
- Fix: incremental extraction and
- v0.9.31Jul 30, 2026
v0.9.31
Full notes ↗Resolution-accuracy fixes, an MCP SDK compatibility widening, and community extractor fixes.
MCP
- The MCP server is now dual-compatible with the
mcpSDK 1.x and 2.x, lifting themcp<2cap from 0.9.30 tomcp>=1,<3(#2308, thanks @NiSHoW)._build_serverbinds the same handlers via the 1.x decorator API or the 2.xon_*constructor callbacks at runtime, and adaptsTool.inputSchema,Resource.uri, and the droppedAnyUrlre-export. Verified with full stdio handshakes under mcp 1.29 and 2.0.
Resolution / graph accuracy
- C# member calls on a typed receiver no longer drop true
callsedges when the same local name is reused across methods (#2299, thanks @JensD-git). Receiver typing is now per-method (mirroring the Java resolver) instead of per-file, so an untypablevar x = ...in one method can't delete a typed-parameter call edge in another. - SQL cross-file table references (e.g. a prisma migration referencing a table created in an earlier one) resolve to the real table node instead of leaking an absolute-path id and losing the foreign key (#2324). References mint a sourceless stub that collapses onto the real definition, and identifiers are normalized so
"public"."users"matchespublic.users. graphify pathandexplainno longer print reversed hops (#2309): they recover edge direction from the stored_src/_tgtmarkers instead of the persisted endpoint order.export const X = <scalar>now emits a graph node, so a named import of a scalar export is no longer left dangling (#2266, thanks @oleksii-tumanov).- Go predeclared functions (
make,len,append, ...) no longer fabricate call edges to same-named user symbols (#2313, thanks @PathGao); the filter is scoped to Go bare-identifier callees. graphify explainrefuses and lists candidates when a name matches symbols in more than one file, instead of silently resolving to an arbitrary one (#2233, thanks @0bLoM).
- The MCP server is now dual-compatible with the
- v0.9.30Jul 29, 2026
v0.9.30
Full notes ↗Fixes a fresh-install failure of the MCP server, plus node-id portability, cache, bedrock, and merge-graphs fixes.
Install
- Pin
mcpbelow 2.0 so a freshgraphifyy[mcp]/graphifyy[all]install works again (#2277, #2279, #2291).mcp2.0.0 dropped themcp.types.AnyUrlre-export and theServerdecorator-registration API thatgraphify/serve.pyuses, so an unpinned resolve brokegraphify-mcpon every new install with anImportError. Themcpandallextras now requiremcp>=1,<2(resolving to 1.29.0) andstarlette>=1.3.1,<2. Porting to the mcp 2.x API is tracked in #2308.
Node-id portability
- TypeScript
.tsxfiles no longer leak absolute-path / machine-slug ids into edge endpoints (#2262). The symbol-resolution pass parsed.tsxwith the plain TypeScript grammar; JSX misparsed, nested handlers floated to top level, andcallsedges were emitted from an absolute-stem source with no node..tsxnow uses the TSX grammar, acallsedge is never emitted from an unowned source, and a general backstop canonicalizes any node-less absolute-derived endpoint. - A warm AST-cache hit after a corpus move or clone no longer replays node ids minted under the original root (#2257, thanks @Kaushik2003). Cached ids are stored root-relative and re-anchored on read.
Backends / graph ops
- The Bedrock backend reads the first text block of a Converse response instead of block 0, so reasoning-capable models no longer parse to zero nodes (#2287, thanks @zhiyanliu).
- Pin
- v0.9.29Jul 28, 2026
v0.9.29
Full notes ↗Portability, hook-safety, and resolution-accuracy fixes.
Node-id portability
- Absolute-path / machine-slug node ids no longer leak into edge endpoints (#2231, #2243). Module-top-level
indirect_callsources, bashsource/script-invocation targets, and other producers that minted an id from an absolute path are now canonicalized to the root-relative node id by a general backstop, sograph.jsonlink endpoints are portable across machines and clones.
Hook safety
- The post-commit hook no longer overwrites an existing
graph.jsonit merely failed to read (#2251). If the existing graph is over the size cap or unparseable, the rebuild refuses to write (matching the CLI) instead of replacing it with a code-only extraction; the--no-clusterwrite is now atomic with a protected-graph backup. - The post-commit hook launcher no longer pops a focus-stealing console window on Windows (#2253, thanks @hopstreax).
Resolution / extraction
- False
indirect_calledges from JS/TS closure arguments are gone (#2241, thanks @Yyunozor): a closure parameter now shadows outer names, sorows.map(r => ...)no longer bindsrto a corpus-wide callable of the same name.
- Absolute-path / machine-slug node ids no longer leak into edge endpoints (#2231, #2243). Module-top-level
- v0.9.28Jul 27, 2026
v0.9.28
Fixes for incremental extraction correctness, graph loading, uninstall scoping, macOS paths, and Swift extraction.
Incremental extraction
- Incremental runs no longer drop cross-file edges whose target file wasn't in the batch (#2211, #2213). Python relative imports and markdown reference links emitted absolute-path target ids without the stamp the incremental canonicalization needs, so a re-extracted file's imports/references dangled or vanished. Both now canonicalize to the root-relative node.
- Incremental extraction no longer prunes alive files as "deleted" (#2210). The stale-source check compared paths with a raw string test (no Unicode NFC) and pruned non-matches without a liveness check, so macOS NFD paths and legacy basename spellings lost their nodes. It now compares NFC on both sides and is fail-closed.
--updateon macOS no longer re-extracts everything when the corpus path or a filename contains non-ASCII characters (#2221, thanks @SyedFahad7). Manifest keys are NFC-normalized.- Incremental rebuilds no longer reuse stale community labels, and a graph that outgrows the visualization cap now keeps an aggregated view instead of deleting
graph.html(#2218, thanks @bobspryn).
Other fixes
graphify benchmark, the graph merge-driver, and the call-flow HTML export no longer crash or silently fail on a--no-clustergraph.json(#2212), which stores edges underedgesrather thanlinks.claude/gemini/codebuddyuninstall no longer delete the user-global skill when called with aproject_dir(#2215); this also fixesgraphify uninstall --projectdeleting the global codebuddy skill.- Swift computed and observed properties (
var body: some View { ... },get/set,willSet/didSet) now emit graph nodes, so SwiftUI views are no longer erased (#2181, thanks @ozdemirsarman).
- v0.9.27Jul 26, 2026
v0.9.27
Full notes ↗A large maintenance release: install-safety fixes, node-identity/canonicalization fixes, cross-file resolution improvements, and a batch of community contributions.
Install and data safety
claude/gemini/codex/codebuddy installno longer overwrite a settings/hooks file they cannot parse (#2167). On any JSON parse error they used to fall back to an empty config and rewrite the whole file, destroying the user's settings (most often triggered by a UTF-8 BOM). They now readutf-8-sig, refuse to modify a non-JSON-object file, and back up to<name>.graphify-bakbefore any write.- Incremental
extract --no-clusterno longer overwrites the full graph with just the changed files (#2169). It now merges the existing graph forward with the same replace/prune semantics as the clustered path and canonicalizes cross-file edge targets. - Running the test suite no longer touches the developer's real
~/.claude/~/.gemini/~/.codebuddy/~/.copilot(#2168).
Node identity and caching
stat-index.jsonis stored with root-relative keys (re-anchored on load, mirroringmanifest.json) and pruned of deleted-file entries, so a moved or cloned corpus keeps its cache hits instead of re-extracting everything (#2199).- JavaScript/TypeScript regex-rescued imports (Svelte/Astro/Vue) no longer create ghost target nodes with absolute-path ids (#2195).
- Cross-file
conceptnodes with identical normalized labels now merge, matching the behavior already applied to near-identical labels (#2182). - Absolute
source_filepaths (for example from a Windows scan) no longer break node identity (#2197), andbuild_from_jsonfolds legacy field aliases (name/path/type/confidence_score) so alias-carrying nodes stop entering the graph invisible and unmergeable (#2194).
- v0.9.26Jul 24, 2026
v0.9.26
Maintenance release. Correctness fixes across Python call-graph inference, the git hook (Windows), and bash source resolution.
Fixes
graphify query/explainno longer fabricateindirect_calledges to class definitions (#2137, thanks @Rishet11). Passing a class as a value (select(Model),db.get(Model, id),except (ErrorA, ErrorB),getattr(obj, "Name", 0)) produced a false inferred call edge; classes are now excluded fromindirect_callin both the intra-file and cross-file paths, while direct instantiation still emits itscallsedge.- The post-commit hook's interpreter allowlist now accepts Windows backslash paths (#2126, thanks @Rishet11). The shell
caseglob silently emptied any interpreter path containing a backslash, so the hook failed on Windows uv/venv installs. Both allowlist sites use a verified character class that admits backslashes while still rejecting shell metacharacters. - The hook rebuild timeout is now armed on Windows (#2148, thanks @Rishet11). It relied on
signal.SIGALRM, which does not exist on Windows, soGRAPHIFY_REBUILD_TIMEOUTwas a silent no-op and a hung rebuild ran unbounded. Athreading.Timerfallback now terminates a runaway rebuild where SIGALRM is unavailable; the Unix path is unchanged. - Bash calls into functions defined in a
sourced file now getcallsedges (#2141, thanks @HerenderKumar). Resolution was gated on same-file definitions, so a call to a sourced-library function looked like an external command and produced no edge. Bothsource fileand. fileare handled; resolution is in-corpus and single-match only, so a genuine external command still fabricates nothing. - Bash
sourceedges built from a variable path now resolve (#2079, thanks @HerenderKumar).source "${BENCH_DIR}/lib/x.sh"baked the unexpanded${VAR}into a dead node id; the leading expansion is stripped and the literal suffix resolved against the script's directory, emitted as INFERRED only when it resolves to a real file. Calls into a${VAR}-sourced library resolve too. - Ignore files saved with a UTF-8 BOM are now honored (#2163).
.gitignore/.graphifyignore/info/excludewere read asutf-8, so a leading BOM stayed on the first line and silently dropped the first pattern. The ignore read sites now useutf-8-sig, matching git.
- v0.9.25Jul 22, 2026
v0.9.25
Maintenance release: a license change to Apache 2.0 and a dead-code removal.
License
- graphify is now licensed under the Apache License, Version 2.0 (previously MIT). Apache 2.0 adds an explicit patent grant, a patent-retaliation clause, and explicit inbound-contribution terms. Contributions made before the relicensing were submitted under MIT and remain available under those terms; the original MIT text is retained in
LICENSE-MITand referenced fromNOTICE.
Removed
.graphifyincludehandling is gone (#2112). The file had been non-functional since dot directories became indexed by default (#873): its loader and matchers had no consumers, sodetectparsed the file on every run and then discarded the result, making a.graphifyincludea silent no-op. The dead loader and matchers are deleted, a leftover.graphifyincludeno longer appears in theunclassifiedlist, anddetectprints a one-time note when one is present at the scan root. To re-include ignored paths, use!negation patterns in.graphifyignore.
- graphify is now licensed under the Apache License, Version 2.0 (previously MIT). Apache 2.0 adds an explicit patent grant, a patent-retaliation clause, and explicit inbound-contribution terms. Contributions made before the relicensing were submitted under MIT and remain available under those terms; the original MIT text is retained in
- v0.9.24Jul 22, 2026
v0.9.24
Full notes ↗Maintenance release. Correctness fixes across extraction, dedup, query rendering, and the sensitive-file filter, plus a hang fix in the .NET/XAML path.
Fixes
- The XAML code-behind
.csscan is now bounded and prunes noise directories, so it can no longer hang. A standalone extraction on a.xamlunder a large or shared parent (a temp dir, a big monorepo) could resolve the project root to a broad ancestor and recursively scan the whole tree. It now walks withnode_modules/.venv/.git/dot-dir pruning and a directory cap: a real project scans fully, a runaway root degrades to a fast partial scan. - The sensitive-file filter no longer silently drops topic docs and real source (#2106). Prose files whose slug merely ends in a keyword (
privacy-tokens.md) and real source likeservice_account.pywere dropped with no trace, while some genuine secrets (.npmrc,.pypirc,.git-credentials, case variants) were missed. The filter is now stricter on real secrets and no longer loses legitimate files, and bothgraphify extractand the skill flow now name the skipped files instead of only a count. callsedges now resolve through an aliased Python import (#2082, thanks @Yyunozor).from pkg import mod as aliasrecorded the import but dropped every downstreamalias.func()call, so the callee looked like dead code.deduppreserves a node's attributes when two exact-ID records from the same source file collapse (#2091, thanks @Synvoya). Non-conflicting attributes are retained deterministically, records from different files stay isolated, and a dropped record can never stamp a false origin onto the survivor.- The
claude-clibackend now reads the CLI's structured-output channel instead of free-form prose (#2076, thanks @Yyunozor), which had parsed to zero nodes and bisected forever on newer Claude Code. graphify explainon a high-degree node groups the cut connections by file instead of a bare... and N more(#2009, thanks @Yyunozor).graphify queryand MCPquery_graphno longer printcallsedges backwards (#2080, thanks @Yyunozor); the renderer recovers the stored direction from the edge.
Features
- The XAML code-behind
Full release history: github.com/Graphify-Labs/graphify/releases ↗