Skip to content
Changelog

What shipped.

Every release, straight from the repository, newest first. Nothing is written twice: this is the note that went out with the tag.

Releases
  • v0.9.87

    Oct 12, 2026

    v0.9.87

    0.9.87 (2026-10-12)

    Eighteen community pull requests: language-extraction fixes (PHP, C#, Python, TypeScript, Julia), retrieval and watch hardening, and skill/benchmark correctness.

    • Fix: PHP a Class::method() static call now resolves to the called method rather than binding to the class node, and no longer stalls at INFERRED confidence for a same-namespace call that needs no use import. self/static/parent and lowercase class receivers route through the PHP resolver, fail-closed on any ambiguous or off-corpus receiver (#3872, #3874, thanks @rikurunico).
    • Fix: C# nested and generic partial types now merge by their full type path (Outer\1.Inner), so a two-file nested partial is unified while FooandFoo<T>` stay distinct; a cross-file unqualified call binds to the caller's own merged type when it is the single own-type candidate, and a sourceless placeholder base is dropped when a real same-named base exists on the partial (#4363, #4364, thanks @JensD-git). (The AST cache schema is bumped, so the first build after upgrading re-extracts.)
    • Feature: Python a read of a @property (obj.prop, including x.prop += v) now links to the property's getter, instead of being dropped as a bare attribute access (#4337, thanks @rohit-jsfreaky). (The AST cache schema is bumped, so the first build after upgrading re-extracts.)
    • Fix: TypeScript a public call c.name() reaches a #name-labeled node only when the class declares a public name, and a public call keeps its edge when foo and #foo share one node (#4298, thanks @rohit-jsfreaky).
    • Fix: Julia parametric and module-qualified functor (callable-struct) types are named by their type rather than the variable, and never fall back to the variable binding (#4351, thanks @ayarodionov).
    • Fix: C# a var is typed from the called method's return type, so downstream member calls on it resolve (#4266, #4268, thanks @Mpasha17).
    • Fix: graphify affected <PR> now scopes graph impact to the requested PR instead of the repository default branch, and PR default-branch detection is isolated under test (#3829, thanks @hopstreax).
    • Fix: update refuses to drop a saved semantic node id when the node total grows (treating it as an incomplete re-extract), while still letting a removed import stub go; export keeps an integer node id that is still in the graph (#4115, thanks @SrijanSriv).
    • Fix: the MCP query_graph seed order no longer lets a weak match on an early-alphabet term lead a specific term's exact match: the per-term guaranteed seeds (#1445) are ordered by match strength (#4357, #4358, thanks @devkancheti4-design).
    • Fix: the update skill stamps _origin on the semantic tier so an AST-only update cannot delete semantic nodes it did not re-extract (#2843, #3110, thanks @abhay-codes07).
    The full note
  • v0.9.86

    Oct 11, 2026

    v0.9.86

    Eighteen community pull requests: language-extraction fixes, safety and determinism hardening, and CLI/query ergonomics.

    • Safety: graphify uninstall --purge now refuses to delete the project (or home, or a filesystem root) when GRAPHIFY_OUT is empty or ., instead of silently removing the working tree (#4329, thanks @Hassannzidan).
    • Fix: Julia now extracts return-typed, qualified (Base.show), operator (Base.:+) and functor (callable-struct) methods, and resolves broadcast (f.(xs)) and pipe (x |> f) calls (#4310, thanks @ayarodionov).
    • Fix: Rust grouped use declarations (use a::{b, c::d}) now expand into one import binding per name, instead of a single edge to the common prefix (#4135, thanks @krishhgg). (The AST cache schema is bumped, so the first build after upgrading re-extracts.)
    • Fix: Scala 3 class Foo derives Bar now links the class to each derived typeclass (#2048, #4173, thanks @Mpasha17).
    • Fix: Codex semantic chunks are no longer clobbered by the shared B3 merge (each chunk is written to its own file, matching the other hosts), so semantic nodes/edges survive (#4311, #4312, thanks @vibhanshu-mishra).
    • Fix: affected <Symbol> now also walks callers of the supertype member that an overriding method overrides, so a change to an override surfaces users of the base contract (#4330, #4331, thanks @rohit-jsfreaky).
    • Fix: dedup keeps combining marks in label normalization, so distinct Indic-script words no longer collapse to one node (#4317, #4318, thanks @Suraj370).
    • Fix: dedup ranks a relative source_file against the scan root rather than the CWD, so building from a subdirectory no longer strands an extension-renamed node's edges on the survivor (#4281, #4326, thanks @Deepjyoti-Sarmah).
    • Fix: the global (cross-repo) graph preserves stored edge direction on global add, so path and other direction-aware readers no longer follow reversed arcs (#4066, #4138, thanks @e4c5).
    • Fix: graphify now respects git's global ignore file (core.excludesFile), with git-faithful precedence and ~/XDG expansion (#4335, #4339, thanks @smngvlkz).
    • Fix: null token counts from a backend are coerced to 0 across all backends, instead of crashing a chunk with a TypeError (#4325, #4340, thanks @rtmalikian).
    • Feature: built-in Ollama requests accept a sampling seed for reproducible extraction (#4168, thanks @oleksii-tumanov).
    The full note
  • v0.9.85

    Oct 10, 2026

    v0.9.85

    A language-extraction and tooling batch: six extractor/exporter fixes picked from open issues, plus fourteen community pull requests.

    • Fix: Julia functions with a where clause (long and short form) and parametric type definitions (struct Box{T}, abstract type Shape{T}, struct Sq{T} <: Shape{T}) are now extracted. The name sat inside a where_expression / parametrized_type_expression wrapper that the name lookup skipped, so the whole method/type was dropped; a declared type parameter (value::T) no longer leaks as a phantom field-type node (#4126, #4128).
    • Fix: Fortran a named generic interface now gets a callable node and a dispatches_to edge to each listed module procedure, so a call to the generic name resolves instead of dangling; unnamed and operator/assignment interfaces are unaffected (#4141, #4142, thanks @rajatnagda45).
    • Fix: Elixir defdelegate is now extracted as a function definition, so the delegated function appears and same-module calls to it resolve (#4132).
    • Fix: Scala 3 given ... with instance methods are scoped to the given instead of leaking to file scope (where they collided with the same-named trait type); an anonymous given Show[Int] with keeps its members under a synthesized name (#4130).
    • Fix: graph.html a node label containing an unclosed <!-- then <script can no longer break out of the embedded data script and blank the page; every < in the embedded JSON is escaped (#4124).
    • Fix: the incomplete-extraction message now explains a pure semantic omission (a smaller --token-budget is the lever) instead of always blaming truncation (#4101, #4280, thanks @ayushcodes10).
    • Fix: TypeScript export type * star re-exports no longer trip a spurious syntax-error flag that skewed the health report (#3942, #4303, thanks @ayushcodes10).
    • Fix: Rust a cross-file reference to a type with impl blocks in other files now binds to the single declaration instead of a sourceless stub, fail-closed (#4283, #4284, thanks @Alin1233).
    • Fix: distinct files that mint the same node id after the extension is dropped (x.py vs x.html) are kept as separate nodes instead of collapsing and losing one (#4281, #4282, thanks @bitwizard25).
    • Fix: the git hook now updates the graph for files whose names contain non-ASCII characters (core.quotePath=false plus C-quote decoding) (#4278, #4279, thanks @smngvlkz).
    • Fix: watch the rebuild lock no longer unlinks on release while a waiter holds it, closing a race that let two rebuilds run at once (POSIX) (#4273, #4277, thanks @ayushcodes10).
    • Fix: an unanchored ignore pattern is now matched against the entry name only (so * no longer crosses / and negations behave like git) (#4242, #4251, thanks @Yyunozor).
    The full note
  • v0.9.84

    Oct 10, 2026

    v0.9.84

    A correctness batch picked directly from open issues, plus an OpenCode plugin fix.

    • Fix: PowerShell functions (and classes/enums) defined inside a file-scope begin {} / process {} / end {} block are now extracted. These blocks parse as pseudo-commands rather than named blocks, so the walker returned before descending and dropped everything inside — the common [CmdletBinding()] advanced-function layout (#4270).
    • Fix: R every backtick-quoted binding now gets a collision-free id. A partially-symbolic name like `%foo%` (or an S3 method `[.cls`, or a dotted `my.op`) normalized to the same id as an ordinary identifier and was silently dropped on merge; such names now use the reserved operator namespace (#4253). (The separate infinite-loop reported in that issue was already fixed in 0.9.83.)
    • Fix: graphify path and the MCP shortest_path tool now fail closed on a file::symbol endpoint whose file defines no such symbol, instead of falling back to scoring the bare name and answering from a same-named symbol in another file; the refusal lists the files that do define it (#4264).
    • Fix: OpenCode the plugin now loads on OpenCode 2 (a default export with setup()) while keeping the v1 server() hook, and graphify install refreshes an already-installed v1-only copy, so the graph tools appear again for users upgraded past the v1 plugin contract (#3554, #3732, thanks @bercedev).
    • Fix: Python a bare import logging is no longer captured by a loose same-named module (scripts/logging.py) in a non-package directory — it resolves to the stdlib module. Guarded by a vendored, deterministic stdlib-name set across the module resolver, the sibling-repoint pass, and the build-time stem-alias index; a deliberate package shadow (logging/__init__.py) still resolves (#4261).
    • Fix: Python a qualified external annotation (httpx.Response) no longer binds to an unrelated private local class (_Response). The stub-rewire match key now preserves underscores, so _Response and Response are distinct identifiers (#4269).
    • Fix: C# an external type the corpus references but never declares (List<T>, System.Type, Unity's VisualElement) now gets one shared, name-keyed placeholder instead of a separate per-file stub (a_cs_list, b_cs_list), so a query returns one node and the files sharing the type connect through it (#4247).
    • Internal: added regression coverage locking in cross-module binding of a singly-defined type through re-export chains and the unique-stub rewire; the reported failure (#4262) no longer reproduces on this line.
  • v0.9.83

    Oct 9, 2026

    v0.9.83

    A C# resolution and determinism batch, plus Windows test-suite fixes.

    • Fix: C# a generic and a non-generic type of the same name (Effect vs Effect<T>) now get distinct node ids (arity folded into the id), so they no longer collapse into one node and Effect<T> : Effect no longer produces an inherits self-loop (#4255, #4249, thanks @ayushcodes10).
    • Fix: C# a call through a member chain (a.b.C()), element access (xs[i].M()), or inside a constructor body now resolves to the right method, fail-closed to a single declared type per hop (collection element types only for T[]/List<T>), instead of being dropped (#4258, #4246, thanks @Mpasha17).
    • Fix: C# a bare call whose name matches an enum member (Delegate(t) next to a Delegate case) no longer binds to the enum member; case members are excluded from both the per-file and cross-file call-resolution maps, fail-closed (#4254, #4245, thanks @ayushcodes10).
    • Fix: C# a static factory that constructs its own type keeps its method membership edge — an undirected collapse previously let the reverse calls edge overwrite it, hiding the member from every type walk (#4256, #4248, thanks @Mpasha17).
    • Fix: an unqualified call in Java/C#/Scala/C++ binds to the method on the caller's own class chain (own class, then in-file bases, then enclosing classes) instead of the last same-named method declared anywhere in the file; fail-closed on a tie, with free functions and constructors still resolving (#4252, thanks @Yyunozor).
    • Fix: an unresolved re-export target id is now portable — it is minted in a dedicated namespace with a hash over the repo-relative path instead of the absolute checkout path, so a clone produces the same graph (#4257, thanks @andan0).
    • Fix: graphify's own skill runbook now reuses the persisted scan options (excludes and the gitignore flag) a prior build wrote, so a skill-driven update no longer drops opted-in files or re-adds explicitly excluded ones versus a CLI rebuild (#4250, #4240, thanks @deepanshupal).
    • Fix: the test suite passes on Windows — _atomic_replace refuses a read-only destination there instead of silently clobbering it (nt-only guard, no POSIX change), plus encoding, path-shape, and non-regular-file test guards (#4260, thanks @SoloDrex52).
    • Fix: C# nested types imported with using static now resolve (using static Demo.Layer; reaching Layer.Inner), fail-closed on ambiguity, complementing the enclosing-namespace resolution also in this release (#4235, #4216, thanks @hopstreax).
    • Fix: the AST cache directory is now namespaced by the installed tree-sitter grammar versions (...-g<fingerprint>), so upgrading a grammar within the same graphify release no longer serves stale or ABI-incompatible cached ASTs for unchanged files (#4239, #4236, thanks @nothariharan).
  • v0.9.82

    Oct 9, 2026

    v0.9.82

    • Feature: after graphify extract builds a graph, the CLI prints a short one-time pointer to Graphify Cloud (faster indexing, fewer tokens, cross-repo search, PR review, and an always-current view of your SDLC at app.graphify.com). It is shown only in an interactive terminal, once per project, and can be turned off with GRAPHIFY_NO_TIPS or GRAPHIFY_NO_CTA; CI, piped output, and the AI-assistant pipeline never see it.
    • Fix: Rust an in-file call now binds to the type that actually names it rather than any same-named function — Type::new() / Self::f() / self.f() resolve through the owning impl (unique-owner only, fail-closed), instead of mis-binding to an unrelated fn with the same last segment (#4238, #4237, thanks @rohit-jsfreaky).
    • Fix: SVG export strips XML-illegal control characters from node and legend labels, so a label carrying e.g. an ANSI escape no longer produces a malformed graph.svg; valid whitespace and Unicode are preserved, and node identity is unchanged (#4244, thanks @Yyunozor).
  • v0.9.81

    Oct 8, 2026

    v0.9.81

    A large resolution-accuracy and determinism batch across Python, TypeScript, C#, Elixir, and PHP, plus analysis-quality fixes and a portability regression guard.

    • Fix: Python nested class identities are now qualified by their enclosing class, so class Outer: class Inner no longer collides with a different Outer2: Inner into one node (and their methods no longer collapse together) (#4228, thanks @xiehuanyi).
    • Feature: Python self/cls/super() calls now resolve to a base-class method defined in another file, fail-closed on multiple/opaque/out-of-corpus bases, with super(Cls, obj) forms excluded (#4222, #4221, thanks @rohit-jsfreaky).
    • Fix: Python typed-receiver resolution finds a nested function's file by climbing to the real file node, so a self.x.m()/annotated-local call inside a nested def now resolves instead of failing the visibility check (#4227, #4226, thanks @rohit-jsfreaky).
    • Fix: Python an absolute import (from werkzeug.wrappers import Request) no longer resolves onto a local same-named module (wrappers.py), which had rewired a class to inherit from itself; a same-named module in another package still resolves (#4225, #4224, thanks @rohit-jsfreaky).
    • Feature: TypeScript this.field receivers are typed from class field declarations (not only constructor-injected parameters), so a service's this.repo.find() resolves; fail-closed on static/array/union/generic field types (#4231, #4230, thanks @rohit-jsfreaky).
    • Fix: TypeScript a call on a receiver whose type name is declared in several files resolves to the one the caller actually imports, and a public call never binds to a #private method of the same name (#4233, #4232, thanks @rohit-jsfreaky).
    • Fix: C# types declared in an enclosing namespace now resolve from a nested namespace (Demo.Inner referencing a type in Demo), innermost-wins, additive over the existing scope resolution (#4204, #4196, thanks @hopstreax).
    • Fix: Elixir qualified and aliased remote calls (App.Accounts.get_user, alias App.Accounts; Accounts.get_user) resolve to the right module's function, and a member call never mis-binds to a same-named local; cross-file targets link only to the single corpus module that defines the function (#4213, #4206, thanks @Mpasha17).
    • Fix: Elixir keyword-form definition bodies (def f(x), do: g(x)) now have their calls extracted, not only the do/end block form (#4210, #4207, thanks @rtmalikian).
    • Fix: PHP 8.5 (void) casts and a cast applied to a match expression are parsed via a fail-safe pre-processing pass, so calls behind them are no longer dropped to a syntax error (#4211, #4202, thanks @Mpasha17).
    • Fix: plain AST declarations (TS type aliases, enum members, JSON keys) whose only edge is the structural contains from their file are no longer flagged as weakly-connected knowledge gaps in the analysis output and GRAPH_REPORT.md (#4212, #4205, thanks @nothariharan).
    • Fix: low-confidence AMBIGUOUS edges are scaled down before community detection (on a copy, leaving the real graph untouched) so they no longer fuse independent clusters, and ambiguous suggested questions move to a separate low-confidence section; GRAPHIFY_AMBIGUOUS_SCALE=1.0 restores the prior behavior (#4214, #4199, thanks @JunoLee1).
    The full note
  • v0.9.80

    Oct 7, 2026

    v0.9.80

    More clone-identical determinism, a large MCP retrieval speedup, and a batch of extractor and resolution fixes.

    • Fix: more node ids and manifest keys stop leaking the local checkout path or OS username, so a clone keeps producing the same graph — a re-clone no longer keeps a previous checkout's absolute manifest keys (#4175, thanks @SrijanSriv), an AST cache hit whose import target has since been deleted is re-extracted instead of replaying the stale absolute-path id (#4185, #4184, thanks @rohit-jsfreaky), and --no-cluster graph.json no longer ships extract()'s run-only absolute source paths or undeclared/dangling endpoints (#4189, #4183, thanks @rohit-jsfreaky).
    • Fix: cross-drive scans no longer abort on a syntax-error warning — the remaining unguarded os.path.relpath in the partial-extraction warning path falls back to a portable display path on Windows cross-drive files, completing the 0.9.78 #4106 fix (#4149, thanks @xiehuanyi).
    • Fix: an external import stub whose last referencing edge is gone is dropped on incremental rebuild instead of lingering as a zero-degree ghost a fresh build never has (#4181, thanks @rohit-jsfreaky).
    • Fix: Python self.<attr>.<method>() calls now resolve through the attribute's constructor/annotation type to the owning class, fail-closed on ambiguity (#4176, #2860, thanks @Mpasha17).
    • Fix: Python obj.method() on a local or parameter whose class is known from an annotation (c: Client, including Optional/union/string forms) or a constructor/with binding now resolves to the owning class's method, fail-closed to a single in-file-or-imported class that owns it (#4198, thanks @rohit-jsfreaky).
    • Fix: Python imports under if TYPE_CHECKING: are marked type-only so they no longer form impossible runtime import cycles (#4179, #3159, thanks @Yyunozor).
    • Fix: Java methods and the calls inside anonymous class bodies (new Runnable() { public void run() {...} }) are now captured, mirroring the Kotlin object-literal handling (#4140, thanks @rajatnagda45).
    • Fix: markdown links to file names containing spaces or percent-encoding ([x](<My Note.md>), [x](My%20Note.md)) resolve to the real file instead of a ghost target; wikilinks stay verbatim and external links stay excluded (#4178, thanks @Yyunozor).
    • Fix: a re_exports edge is kept for both files whose ids collide after separator normalization (a-b/x.ts and a/b/x.ts), removing an order-dependent dropped edge (#4143, thanks @Cintu07).
    • Fix: the Windows graphify console script now uses the multi-core extraction pool instead of silently falling back to single-core, since a non-file __main__.__file__ no longer disables it (#4187, #4186, thanks @rohit-jsfreaky).
    • Perf: the MCP server builds the traversal view and shortest-path graphs once per loaded graph instead of rebuilding them on every call, keyed to the existing graph cache (~1.6x on query_graph, up to ~300x on shortest_path); the two cached path graphs add a bounded, LRU-capped memory cost (#4192, #4191, thanks @rohit-jsfreaky).
    • Perf: the extraction id-remap and call tie-break resolve and parse each path once per run instead of recomputing it for every node and candidate (tens of thousands of redundant Path.resolve() calls eliminated), with byte-identical graph.json output (#4195, thanks @rohit-jsfreaky).
    The full note
  • v0.9.79

    Oct 6, 2026

    v0.9.79

    • Fix: incremental graphify update and watch no longer re-cluster and re-render on every run after an unchanged rebuild. The schema_version/graphify_version metadata added to graph.json in 0.9.78 (#4167) was being counted as a topology change by the watch unchanged-topology check, since the freshly-built candidate graph carries no such metadata; it is now excluded from the comparison.
  • v0.9.78

    Oct 6, 2026

    v0.9.78

    A determinism and portability batch: node ids no longer leak the checkout path, OS username, or line endings into graph.json, so a clone produces the same graph everywhere. Plus encoding, C#, PowerShell, C++, and watch-reconcile correctness fixes.

    • Fix: node ids no longer embed the local checkout path or OS username for unresolved targets — a missing require('./x') (#4155, #4154), a missing Python relative import from .absent import x (#4157, #4156), and a .dmf element keyed on its window (#4153, #4152) now mint portable, clone-identical ids; all three thanks @rohit-jsfreaky.
    • Fix: C# namespace scope ids are keyed on row/column instead of byte offset, so a CRLF checkout no longer writes different scope_chain metadata than an LF one (#4165, #4164, thanks @rohit-jsfreaky).
    • Fix: R symbol-only bindings (operators like `%||%`) no longer collapse onto the file node and spin resolve_local forever; they get a stable, collision-free id (#4171, #4162, thanks @xiehuanyi).
    • Fix: source files are decoded before parsing — a UTF-16 file no longer yields zero nodes and a cp1252 name like CaféOrder is no longer truncated; valid UTF-8 files are byte-for-byte unchanged, non-UTF-8 falls back deterministically (#4146, #4145, thanks @rohit-jsfreaky).
    • Fix: C# calls through a cast or an interface-typed property now resolve — ((IStore)x).Save(), (x as IStore).Save(), and a shadowed IStore Store => ...; Store.Save() bind to the interface's own method instead of being dropped or mis-bound to the concrete class (#4172, #3797, thanks @Mpasha17).
    • Fix: PowerShell member calls bind by receiver owner rather than method name alone — $this.M() resolves to the enclosing class and [Type]::M() to a single unambiguous local class, fixing a same-name-method mis-bind; value, cast, dynamic, duplicate, and external receivers stay fail-closed (#4163, #4158, thanks @oleksii-tumanov).
    • Fix: C++ classes behind module export macros (class MYLIB_EXPORT Foo : Base {}) are preserved — the ALL-CAPS macro is blanked before parsing (byte-length and newline preserving) so tree-sitter no longer error-recovers over the class and drops it (#3661, #3648, thanks @nikhilsaxena04).
    • Fix: incremental graphify update keeps placeholder nodes for never-scanned referenced files, so an unchanged referrer's cross-file edges to an unresolved import or a .csproj/.sln reference are no longer dropped as if the target were deleted; genuinely deleted files are still reaped (#4161, #4160, thanks @rohit-jsfreaky).
    • Fix: graph_diff keeps edge direction, so a reversed edge (a→b becomes b→a) is reported as a change instead of cancelling out to "no changes"; the diff now loads the previous graph through the direction-preserving reader (#4170, #4067, thanks @Mpasha17).
    • Perf: the watch reconcile pass computes each stored source path's identity once per update instead of recomputing it for every node, edge, and hyperedge, cutting reconcile on graphify's own repo from 10.2s to 2.7s with graph.json byte-identical (#4151, #4150, thanks @rohit-jsfreaky).
    • Feature: graph.json now carries schema_version and graphify_version metadata for downstream consumers, written additively so existing readers and older graphs are unaffected (#4167, #3638, thanks @smngvlkz).
  • v0.9.77

    Oct 5, 2026

    v0.9.77

    More community language-structure coverage, two reload/incremental correctness fixes, and a batch of extractor tests.

    • Feature: four more language extractors gained type coverage from @rajatnagda45 — Solidity enum values link via case_of instead of contains (#4090), PowerShell enum members likewise (which also stops a member named like a type binding as a constructor) (#4092), Objective-C C-style enum and typedef enum declarations are extracted with their members (#4096), and a SQL trigger is linked to the function it executes with an executes edge (#4094).
    • Feature: Scala class-level context bounds (class C[A: Ordering]) now resolve to references edges, mirroring the method-level handling from 0.9.75 (#4085, #4080, thanks @Mpasha17).
    • Fix: Astro files terminate a trailing // comment in one <script> block so it no longer swallows the next block on the same line; byte offsets and line numbers are preserved (#4083, #4072, thanks @Sourya-Prabaharan).
    • Fix: a zero-byte source file keeps its node but no longer claims a line-1 source location, so an empty __init__.py is still a real module without a misleading anchor (#4086, #4041, thanks @Mpasha17).
    • Fix: PHP calls to a method whose name collides with a cross-language builtin ($this->list(), $this->open()) now resolve against the caller's own class instead of being dropped, while non-$this receivers and bare construct names stay fail-closed (#4119, refines #3975 and #3381, thanks @xiehuanyi).
    • Fix: JavaScript methods attached to an exported object (res.format = function () {...}; module.exports = res) are now extracted as nodes, so calls inside them resolve across CommonJS/ESM module boundaries (#4121, #3778, thanks @harshaygadekar).
    • Fix: incremental graphify update on a subfolder no longer false-reports files in sibling folders as deleted; a shared single manifest now anchors stored paths to its base and scopes deletion detection to the scanned root (#4118, #3785, thanks @harshaygadekar).
    • Fix: reloading a saved graph.json preserves stored edge direction across the HTML, Cypher, Neo4j, FalkorDB, and Obsidian-canvas exporters, the watch HTML re-render, and the merge driver, instead of reversing edges whose target precedes their source in the node list (#4088, #4066, thanks @e4c5).
    • Fix: PowerShell method calls are now recorded — $this.Method() and [Type]::Method() resolve to the method node by name, keyed only on method-labelled targets so a free function sharing the name is never bound, and unresolved names stay fail-closed (#3995, thanks @rajatnagda45).
    • Fix: Rust anonymous constants (const _: () = assert!(...)) no longer collapse onto the file node and emit a self-loop; the anonymous item is skipped while named consts and statics keep their nodes (#4108, #4064, thanks @xiehuanyi).
    • Fix: a cleanly-parsed source file on a different drive from the scan root no longer aborts the whole extraction on Windows; the symbol-free-file warning falls back to an absolute display path instead of raising (#4106, #4059, thanks @xiehuanyi).
    • Fix: --no-dedup now also disables the same-file ghost-merge pass in build_from_json, so two distinct non-AST nodes sharing a (source_file, label) are preserved when dedup is turned off; AST reconciliation and the default dedup path are unchanged (#4122, #4019, thanks @xiehuanyi).
    The full note
  • v0.9.76

    Oct 4, 2026

    v0.9.76

    More language-structure coverage, resolution/dedup correctness, and a security fix for the git-hook installer.

    • Feature: four more language extractors gained type coverage from @rajatnagda45 — Zig tagged-union variants (union(enum)) emit a node per variant with a case_of edge (#4050), C++ union specifiers are extracted as class-like type nodes with their members (#4052), VB.NET enum members link via case_of instead of contains (which also stops a member named like a type binding as a constructor) (#4054), and Pascal enumerated types and their values are extracted (#4056).
    • Feature: three Scala type-reference fixes shipped together earlier in the day are followed here by @Faisal-Fayaz's extractor hardening — graphify now stops walking JSON Schema files as config manifests, keyed on a $schema declaration plus a structural marker ($defs/definitions/$id) so real manifests that merely reference a schema are unaffected (#4048, #2255).
    • Fix: Elixir import/use call scoping is now per-module rather than per-file, so an unqualified call in one module no longer resolves against another module's imports in the same file (#4058, refines #4015).
    • Fix: track calls to external Python modules — a module.func() call to a plainly-imported dependency now records a calls edge to that module, fail-closed (receiver-shadowing and non-unique bindings are skipped, builtins and unresolved locals are never fabricated) (#4043, #3793, thanks @oleksii-tumanov).
    • Fix: Svelte files now feed only their <script> blocks to the AST pass (masking the template and style, preserving line numbers), so the markup no longer produces a parse error that dropped every symbol (#3984, #3928, thanks @Agnik47).
    • Fix: PHP language constructs (isset, empty, list, eval, ...) no longer bind as calls to a user method that happens to share the name (#3975, #3830, thanks @Cintu07).
    • Fix: an unresolved base class whose only same-named definition lives in another language is kept unresolved instead of binding across languages; same-language cross-file inheritance still resolves (#4068, thanks @SrijanSriv).
    • Fix: unstamped document nodes with the same heading in different files are no longer merged together during dedup; same-file document twins still merge (#4065, thanks @SrijanSriv).
    • Fix: graphify path and the MCP shortest_path tool resolve a path::symbol or raw node-id endpoint to the exact node before falling back to fuzzy scoring, and refuse an ambiguous endpoint instead of silently picking one (#3935, #3913, thanks @bercedev).
    • Fix: cross-repo resolver confidence scores are snapped to the canonical INFERRED rubric (a label-only change; no edge is added, dropped, or reclassified) (#4046, #4045, thanks @DeepanshuPal).
    • Fix: graphify no longer indexes its own installed skill folders and whole-written rule/hook files when scanning a project, keyed on the exact install locations so a user's own graphify-named folder is not skipped (#4062, #4057, thanks @Mpasha17).
    • Fix: the suggested questions in the analysis output are diversified across signal types with a round-robin, so one category no longer crowds out the others (#3972, #3849, thanks @azizur100389).
    • Security: graphify hook install refuses a core.hooksPath that resolves outside the repository (resolving both sides, symlink-safe), falling back to the in-repo .git/hooks instead of writing an executable outside the checkout; legitimate in-repo custom hook paths, linked worktrees, and submodules still work (#3919, #3869, CWE-22, thanks @nothariharan).
    The full note

Every release on GitHub

Try Graphify now.

Try for free