Repository navigation
Releases: Graphify-Labs/graphify
Release list
graphify 0.9.97
0.9.97 (2026-10-27)
- Security: rationale redaction credential redaction for rationale labels moves to a single pre-cache choke point (
_redact_rationale_labelsinside_safe_extract), so no extractor can skip it, and it now covers more leak shapes: URL userinfo with an empty user or with//@in the password, PEM private-key bodies, tokens glued to surrounding text by_(for exampleghp_...), Slackxoxe-refresh tokens, short JWTs, and Common Lisp docstrings that previously built labels without redacting. Benign strings (hashes,sk-prose, URLs without userinfo) are left alone (#4647, thanks @0xkaushik-ai). - Security: deps anyio is floored to
>=4.14.2in themcpextra, above CVE-2026-63374 (an IDNA 2003 vs 2008 hostname-validation bypass that let a MITM on a non-ASCII domain present a cert for a different ASCII host, CVSS 9.3). anyio is only a transitive dependency and the lockfile already resolves 4.15.1, so this is a floor to stop a future re-resolution from regressing. - Fix: markdown ATX headings parse per CommonMark: a trailing run of
#is not part of the heading text (## Setup ##is "Setup"), up to three spaces of indent are allowed (four is an indented code block), and a hash-only line like## ##mints no node (#4790, #4791, thanks @jaimemartinez). - Fix: markdown fenced code blocks are tracked by CommonMark rules (backtick and tilde fences, info strings, matching close length), so a line that looks like a heading inside a fence no longer leaks as structure, and a heading after a
~~~block that contains a```line is no longer lost (#4787, #4788, thanks @jaimemartinez). - Fix: yaml structural extraction reads the composed node tree, so keys carry their written spelling and their own source line instead of all landing on line 1, and YAML 1.1 bare keys like
on/off/yes/noare no longer folded to booleans (a workflowon:block is extracted, not turned into aTruenode) (#4784, #4785, thanks @jaimemartinez). - Fix: razor a component's
@implementsinterfaces are extracted asimplementsedges instead of being silently dropped (#4820, thanks @ayushcodes10). - Fix: terraform an aliased provider block gets its own alias-qualified node (so two
provider "aws"blocks no longer collapse into one and lose attributes), and aprovider = aws.westreference resolves to it instead of dangling; alocalliterally namedprovideris no longer misread (#4819, thanks @ayushcodes10). - Fix: cobol paragraphs that follow a nested
END PROGRAMreattach to the enclosing program instead of sticking to the nested one, via a program stack (#4824, thanks @ayushcodes10). - Fix: blade a
wire:clickdirective binds the bare method name: dotted modifiers (wire:click.prevent="submit") are matched, call arguments are trimmed from the name (deleteItem(5)bindsdeleteItem), and a$-prefixed magic action mints no fabricated edge (#4823, thanks @ayushcodes10). - Fix: pascal a
recordis recognised as a type with its own methods in the regex fallback (the default path without the optionalpascalextra), matching the tree-sitter path;operatormembers are extracted too (#4825, thanks @ayushcodes10). - Fix: vbnet an
Operatordeclaration is extracted as anoperator-kind member of its class and its body is walked for calls, so a helper call inside an operator no longer vanishes (#4821, thanks @ayushcodes10). - Fix: fortran a
callresolves to the subroutine it actually names instead of a target salted with the calling file's name (which never resolved), using the extractor's own cross-file stub idiom (#4795, thanks @ayushcodes10). - Fix: cli
graphify query --help/-h(and nowgraphify explain --help/-h) with nothing else prints usage instead of running a literal query for the text "--help"; a longer question that merely contains "--help" as a substring still runs as a query (#4830, thanks @curl-man). - Fix: js a nested (inner) function no longer leaks into the file-wide name map, so a call elsewhere in the file binds to the top-level function of that name rather than an inner one it cannot see; recursion, shadowing and sibling scopes resolve correctly (ports the Python scope scheme to JS/TS) (#4767, thanks @smngvlkz).
- Fix: ocaml every binding in an
and-chainedmodule ... and ...orclass ... and ...is extracted, not just the first, so later bindings are no longer silently dropped; each carries its own source line (#4822, thanks @ayushcodes10). - Fix: verilog a SystemVerilog class
taskmethod is modeled like afunctionone (its own node,methodedge and parameter-type references), and a task-local variable no longer leaks as a false field reference on the class (#4774, thanks @ayushcodes10). - Fix: build an edge with no
relationis dropped instead of persisted, on both the build and the raw--no-clusterwrite paths, and alias folding (relationshiptorelation) runs before the check (#4810, thanks @legendteddy; reproducer also filed as #4826 by @sunhouy). - Fix: build the shrink guard counts a saved document-mention node that folds into its AST file twin on reload as present, not lost, so a cluster-only write is no longer refused when nothing was actually lost (#4778, #4779, thanks @AndresDiagoM).
- Fix: detect a linked git worktree whose main checkout resolves inside the scan root is pruned, so a sibling worktree no longer gets indexed as a second full copy of the repo (#4683, #4833, thanks @barlowa124; duplicate work in #4685 by @AndresDiagoM).
- Fix: resolution an inline comment in a pnpm-workspace glob is stripped per YAML rules, and a glob that
Path.globrejects (a**component or an absolute pattern) is skipped with a warning instead of crashing the wholeextractrun (#4681, #4687, thanks @Deepjyoti-Sarmah). - Fix: report a community hub
[[wikilink]]is slugged through the sameexport._obsidian_safe_stemthe export uses, so the link matches the file the export actually writes instead of dangling (#4696, thanks @ayushcodes10). - Fix: wiki a community relabelled only by letter case keeps its article instead of having the sweep delete the file the run just wrote; on a case-sensitive filesystem the stale lower-case twin is unlinked rather than renamed over the fresh file (which would silently restore the old body) (#4508, #4798, thanks @dupeisen).
- Fix: query filler verbs
get/gets/got/gettingare dropped from query terms (like the existingwork/works), so a framework hub labelled "Get" is not pulled in as a BFS seed by an exact-match bonus; node lookups for a literalGetstill resolve (#4686, thanks @AndresDiagoM).
graphify 0.9.96
0.9.96 (2026-10-25)
- Security: deps the Pillow floor is raised to
>=13.0.0on Python 3.11+ (staying at>=12.3.0on 3.10, which Pillow 13 no longer supports) and pypdf to>=6.19.0, and the lockfile is refreshed to patched versions of transitive dependencies (pyjwt, cryptography, certifi, urllib3, anyio, fsspec, soupsieve, virtualenv). This clears the bulk of the open Dependabot advisories; the Pillow image-parsing CVEs are only patched upstream for Python 3.11+, so a 3.10 install keeps the newest 3.10-compatible Pillow. - Fix: llm a chunk that failed before returning a response no longer has its files reported as model omissions; the warning distinguishes a failed chunk from a genuine omission, and both are still re-dispatched (#3616, #4752, thanks @jaimemartinez; reported by @GREYGROUPJP).
- Fix: watch a Markdown file that
detect()classifies as a paper (arXiv markers, an Abstract) is included in the watch quick-scan rebuild instead of contributing zero nodes; a paper that already has a semantic layer is still excluded from the AST quick-scan (#4750, #4751, thanks @jaimemartinez; reported by @yeochul-jeon). - Fix: prs every unfinished CheckRun status (
WAITING,REQUESTED,PENDING, ...) counts as pending CI, so a PR gated on a deployment-protection job is no longer read as ready (#4730, thanks @rudycelekli). - Fix: export an Obsidian note lists every parallel relation between two nodes (for example both
importsandcalls) instead of only the first edge (#4731, thanks @rudycelekli). - Fix: build a hyperedge whose members are given under the
members/node_idsaliases has its numeric member ids coerced to strings like the canonicalnodeslist, so the hyperedge is no longer dropped (#4732, thanks @rudycelekli). - Fix: llm a code node whose confidence is written in a different case (
extracted/Extracted) is still evidence-checked before it folds to theEXTRACTEDenum, so an un-verified node is not presented as solid (#4733, thanks @rudycelekli). - Fix: python a member call binds to the method it actually spells rather than a case/underscore-folded twin (
run()no longer resolves to_run()); a lone folded method still resolves, and a genuine collision fails closed (#4734, thanks @rudycelekli). - Fix: zig a call no longer crosses between a method and a same-named free function; a bare call binds the free function and a receiver call binds the method (#4755, thanks @ayushcodes10).
- Fix: dart an unnamed
extension on T { }declaration is detected and extracted (the name is optional), so its members attach to the extended type (#4741, thanks @ayushcodes10). - Fix: llm the DeepSeek backend sends its output cap as
max_tokens(which DeepSeek honours) rather thanmax_completion_tokens(which it ignores), so responses are no longer silently uncapped (#4739, #4753, thanks @Ethereal49; reported by @snapp-kenya). - Fix: extract XAML codebehind (
*.xamlto*.xaml.cs) resolves deterministically regardless of directory iteration order, so a graph built on a case-sensitive filesystem is stable (#4747, thanks @anishraja04). - Fix: extract the AST cache hit rate is reported over the file total, not the uncached set, so a warm run no longer prints a misleading "100% uncached" line (#4740, #4746, thanks @Deepjyoti-Sarmah; reported by @lavaxun).
- Fix: dedup a node id legitimately shared by two files as a
module/namespaceno longer prints a spurious "minted by two different files" warning (#4756, thanks @idachev). - Fix: python the member-call resolver binds only Python callers to Python targets, so a same-named class in another language is no longer mis-bound as a call (#4757, thanks @idachev).
- Fix: cli the PreToolUse hook reminders are worded as facts rather than imperatives, so the agent's tool-result stream no longer reads them as prompt injection and ignores them (#2202, #4764, thanks @smngvlkz).
- Fix: llm the Ollama context window is sized from an estimate that counts non-Latin characters as whole tokens and from the real system-prompt length, so a non-English or long prompt is no longer silently truncated (#4414, #4761, thanks @smngvlkz).
- Fix: cli
graphify extractrecords each run's token usage tographify-out/cost.json(the same ledger the skill writes), so a standalone extract refresh updates the cost history (#1769, #4765, thanks @smngvlkz). - Fix: ts chained TypeScript decorators (
@(Link().toMany())) are recovered as a decorator reference, and a lossy-parse warning names the real error region (#4711, #4715, thanks @Deepjyoti-Sarmah). - Fix: js a
const X = require('pkg')binding for an external package keeps its node (with the package as source) sonew X()still resolves, while a require of a corpus-local file still folds to the required module (#4688, #4702, thanks @ayushcodes10). - Fix: detect generated MSBuild
obj/andbin/output is pruned only when build evidence is present (restore/runtime markers nearby), so a C# project scanned after a build no longer ingests generated sources while a realsrc/binstays (#4742, thanks @Great-Peace). - Fix: watch each watch rebuild is bounded by
GRAPHIFY_REBUILD_TIMEOUT(default 600s,0disables), with a thread-Timer fallback whereSIGALRMis unavailable orwatch()runs off the main thread (aSIGALRMarm there raisesValueErrorand would tear the watcher down before the rebuild ran), so a hung rebuild no longer stalls the watcher (#2173, #4724, thanks @danieldutu). - Fix: robot each duplicate test-case name gets its own node (salted by line), so two tests with the same name are kept distinct (#4697, thanks @ayushcodes10).
- Fix: vbnet external namespaces and types emit a sourceless stub carrying an empty
source_filesentinel like other languages, instead of a node that fails validation (#4725, #4728, thanks @madanlalit; reported by @alopezradicle). - Fix: rust a
useis scoped to the crate it names, souse serde_json::Valueno longer resolves to a same-named type in another crate; a namedpub usere-export is followed and a manifest-less binding staysINFERRED(#4699, #4712, thanks @Deepjyoti-Sarmah). - Fix: python a call through a field injected from a constructor parameter, or through a local typed by a method's return annotation, resolves to the target method (
INFERRED); it requires a single unambiguous producer and class (#4726, thanks @keny11300). - Fix: dedup an LLM-marked cross-document reference stub that collides with its real definition is namespaced instead of silently dropped, so neither node is lost (#4738, #4743, thanks @SinghAman21; reported by @snapp-kenya).
- Perf: update a
graphify updatewith no relevant input change skips the detect/extract/build pipeline and leaves the outputs untouched, keyed on the scan file-set, config,.graphifyrc, extractor epoch, and an output-completeness stamp; a scanned file with no manifest row (including one whose extraction previously failed) still forces a full rebuild so a later fix is never skipped (#4740, #4748, thanks @Deepjyoti-Sarmah; reported by @lavaxun).
graphify 0.9.95
Twenty-one community pull requests. A security pass on install: the skill-install writes go through randomly-named temp files instead of predictable ones, so a pre-planted symlink can no longer redirect a write. Extraction: Python, Go, C++ and Rust explicit type aliases (and Rust union items) are extracted as type nodes so references resolve instead of minting sourceless stubs, each C# method overload gets its own node bound by argument count, and a package.json dependency's manifest entry links to the node that references it. Plus a one-root-per-repo tree on merged graphs, extended-length cache paths on Windows, and binary media no longer counted as text. The AST cache schema is bumped, so the first build after upgrading re-extracts.
- Fix: security the skill install stages every write (version stamp,
SKILL.md, references) through a randomly-namedmkstemp/mkdtempfile created withO_EXCLand restrictive mode instead of a predictable*.tmpname, so a local attacker who pre-creates a symlink at that path can no longer redirect the write to clobber an arbitrary file; the final move stays atomic (#4513, thanks @Mahdifotohi). - Fix: python an explicit module-level type alias (
X: TypeAlias = ...,type X = ...,NewType) is extracted as a type node, so a field or parameter typed by the alias resolves to it instead of minting a sourceless stub; an implicit assignment, a local alias, or a re-export is left alone (#4578, thanks @madhusudanpatnaik). - Fix: go a
type A = Balias is extracted as a type node (tree-sitter parses it as atype_alias, not atype_spec), so references resolve to it; a re-export (type Field = pkg.Field) mints no node (#4579, thanks @madhusudanpatnaik). - Fix: cpp a namespace-scope
using A = B;ortypedef B A;alias is extracted as a type node so references resolve; a member alias inside a class and a same-name re-export are excluded (#4580, thanks @madhusudanpatnaik). - Fix: rust a
typealias and aunionitem are extracted as type nodes (a union's fields reference their types like a struct), so references resolve instead of minting stubs; an impl-associatedtypeis excluded (#4581, Refs #4285, thanks @madhusudanpatnaik; reported by @jonatasbcardio-boop). - Fix: csharp each method overload gets its own node and source location instead of collapsing to one, and a call binds to the overload matching its argument count, across in-file, receiver-typed, bare-name cross-file, partial-class, and interface-dispatch resolution; a non-overloaded method keeps its id (#4584, #4591, thanks @Mpasha17; reported by @TerraVenil).
- Fix: tree
graphify export treeon a merged multi-repo graph gives each repo its own root (keyed by the repo tag) instead of conflating same-path files from different repos; untagged nodes are not counted as a repo (#4524, #4525, thanks @AromalBiju1). - Fix: cache AST cache entries are read and written through Windows extended-length (
\\?\) paths, so a deep cache path over the 260-character limit no longer fails extraction with aFileNotFoundError; a no-op off Windows (#4542, thanks @omsenjalia). - Fix: detect a binary media file (an image or audio/video) is no longer read and counted as text toward the corpus word total; an SVG stays counted as the XML text it is (#4548, thanks @kalkaran).
- Fix: json_config a
package.jsondependency's manifest entry links (declares) to the ref node that importing code resolves to, so the manifest entry and its importers share one node instead of being orphaned; the entry is relabelledname@range(#4569, #4572, thanks @Deepjyoti-Sarmah; reported by @BiSide). - Feature: yaml
.yaml/.ymlfiles are now extracted structurally (a file node pluscontainsedges to keys) and classified as code rather than documents, so Helm charts, Kubernetes manifests, and CI pipelines contribute nodes to a code-only or--updaterun instead of nothing, matching how.jsonis handled. Multi-document streams (---separators) are walked per document; a data array, an OpenAPI/Swagger spec, a JSON-schema-in-YAML, and a flat data bundle are skipped so data-heavy YAML does not mint orphan nodes; parsing usessafe_loadso a!!python/...tag never executes; output is bounded (1 MiB, 500 pairs, depth 6). The AST cache schema is bumped, so the first build after upgrading re-extracts (#2214, #4706, thanks @nothariharan; reported by @dchavezf). - Fix: extract a bare call that resolves to a same-named symbol only because the caller imported that symbol's module (
from b import other, then a call to a_make_iddefined in botha.pyandb.py) is no longer promoted toEXTRACTED; the edge is still emitted for connectivity but staysINFERRED, so a symbol that was never imported is not falsely certified. A real symbol import (from a import _make_id) still resolvesEXTRACTED(#2945, #4707, thanks @nothariharan; reported by @TotalUnitManagement). - Fix: security the SSRF guard blocks a host that resolves to a multicast address (
224.0.0.0/4,ff00::/8), closing a gap alongside the existing private/reserved/loopback/link-local checks (#4708, thanks @Dextheking1). - Fix: security the Obsidian export sanitizes a node's file-type and confidence before emitting them as frontmatter
tags, so a crafted value cannot break out of the YAML list into a sibling key, matching how community tags are already sanitized (#4709, thanks @Dextheking1). - Fix: security the Google Workspace shortcut sidecar escapes a file id or url through full YAML double-quoted-scalar escaping (tab, C0/DEL controls, and the Unicode line breaks U+2028/U+2029/U+0085), so a hostile shortcut file cannot inject frontmatter keys (#4710, thanks @Dextheking1).
- Fix: affected
graphify affected <path>resolves a path whose file-node label was disambiguated by the shared-basename suffix pass (for example twohooks.pyfrom different directories), reusing the canonical file-label predicate instead of a bare basename match (#4698, #4713, thanks @Deepjyoti-Sarmah; reported by @karsan8119). - Fix: build a raw (
--no-cluster) build resolves an import endpoint through the same old-stem alias index the clustered build uses, and mints an external stub only after resolution, so the raw graph no longer freezes an import onto a stub when the clustered graph resolves it (#4670, #4676, thanks @nothariharan; reported by @xiongjianxu). - Fix: cross-repo an Objective-C class declared in one repo's header and implemented in another repo's
.mbinds a member call to the implementation, the cross-repo analog of the same-repo split-dir fix; two same-named classes that both define the selector stay ambiguous (#4690, #4691, thanks @xiongjianxu). - Fix: hooks the rebuild hook runs from the checkout's top level (derived from the git common dir, falling back to
--show-toplevel), so a straygraphify-out/in a subdirectory can no longer root the rebuild at the wrong place and walk an enormous tree (#3258, #4689, thanks @jaimemartinez; reported by @dsfaccini). - Fix: objc
NS_CLOSED_ENUMdeclarations are extracted as enums with their cases, the same asNS_ENUM/NS_OPTIONS; the AST cache schema is bumped so the first build after upgrading re-extracts (#4705, thanks @Jvxoq). - Fix: sql a
CREATE TABLEwhose column default the SQL grammar cannot parse (for example MySQL/MariaDBDEFAULT current_timestamp()) is recovered from the ERROR node instead of being dropped, so the table and its foreign-key references still resolve; the AST cache schema is bumped (#4613, #4677, thanks @08raviyadav; reported by @AirRunner).
graphify 0.9.94
Nineteen community pull requests. A security pass on ingestion: a fetched URL with no hostname, with a malformed or zero port, or with embedded user:pass@ credentials is now rejected before the request leaves, on the first fetch and on every redirect, and a text capture no longer follows a dangling symlink out of the corpus. Extraction and resolution: a Maven POM contributes only its own dependencies, a JS/TS member call on an untyped receiver stops guessing a same-named method in the same file, a CommonJS require binding no longer shadows the class the required file exports, and Objective-C category node ids stay repo-relative instead of embedding the absolute checkout path. SQL gets its own pass: T-SQL bracketed names are unbracketed, a GO batch separator ends the statement, cross-file table stubs fold onto their real definition, and a procedure emits reads_from/writes_to edges. Plus a markdown bare method only links when its class is cited, the MCP node lookup refuses a substring near-miss instead of answering with an unrelated node, a cross-repo edge points at the call site, Objective-C calls resolve across a split header/impl, an incremental build stops re-queuing files an extractor declined by design, a quoted Codex hook command for install paths with spaces, an IPv6 bracketed-Host serve fix, and a complete, drift-guarded --platform list in --help. The AST cache schema is bumped, so the first build after upgrading re-extracts.
- Fix: security
validate_urlrejects a fetched URL that has no hostname (http:///path), a non-numeric, out-of-range, or zero port, or embeddeduser:pass@credentials, before the request is made and again on every redirect, so a malformed or credential-bearing URL is no longer fetched or persisted into the graph; a normal@in a path or query and a valid high port still pass (#4643, #4644, #4645, thanks @cellrishi-code). - Fix: manifest a Maven
pom.xmlcontributes only its own<dependencies>(including those under<profiles>), not the version pins under<dependencyManagement>or a build plugin's own<dependencies>, so a parent or BOM POM no longer emits dependency edges it only manages (#4596, thanks @jayhemnani9910). - Fix: js a member call on an untyped receiver (
x.foo()wherexhas no known type) is deferred to receiver-typed resolution instead of binding to a same-named method elsewhere in the file, so a spurious self-loop or cross-call edge is no longer emitted;this.foo(), a typed receiver, and a locally instantiated receiver still resolve (#4598, #4605, thanks @ayushcodes10; reported by @SaschaAndresGrimm). - Fix: js a CommonJS
const X = require('./m')binding no longer mints a module-scope node that shadows the class the required file exports, sonew X()resolves to the required declaration; a realconst x = factory()binding still keeps its node (#4621, #4634, thanks @lab1207; reported by @sub4biz). - Fix: extract an Objective-C category's class and method node ids stay repo-relative instead of embedding the absolute checkout path, so a category file like
Foo+Cat.hyields portable ids that match across machines and merge cleanly; two same-named categories in different directories stay distinct (#4666, #4642, thanks @madhusudanpatnaik; reported by @xiongjianxu). - Fix: codex the generated Codex PreToolUse hook command quotes the graphify executable path, so an install under a path containing a space no longer builds a broken hook command, matching the existing Claude and Gemini hooks (#4662, thanks @supercell02).
- Fix: serve an IPv6 HTTP bind accepts its own bracketed
Hostheader ([::1]:port), so a server bound to an IPv6 loopback no longer refuses every request with a 421 (#4656, thanks @zydo). - Fix: ingest a text capture never writes through an existing entry: the free-path search uses
lstat, so a name that is a dangling symlink is treated as occupied and the capture is diverted instead of following the link and writing outside the corpus (#4657, thanks @zydo). - Fix: cli
graphify --helplists every accepted--platformvalue (it had omitted amp, copilot, kilo, kimi, and antigravity-windows); the list is derived from the same source as the install usage so the two cannot drift, with a guard test (#4655, thanks @zydo). - Fix: sql T-SQL bracketed identifiers (
[dbo].[Orders]) are unbracketed so a name matches across styles, and a stored procedure's body emitsreads_from/writes_toedges for the tables it reads and writes; aliases, variables, temp tables, strings, and comments never become targets (#4635, #4649, thanks @Deepjyoti-Sarmah; reported by @RuVl). - Fix: sql a
GObatch separator (a client command, not a terminator) ends the statement, so a statement after aGOwith no trailing;parses on its own instead of merging into one malformed node; aGOinside a string, comment, or column name is left alone (#4651, #4652, thanks @Deepjyoti-Sarmah). - Fix: sql a table referenced before its
CREATE TABLEis seen folds onto the real definition instead of staying a separate stub, and a schema-qualified name binds correctly, while two genuinely different tables in different schemas (dbo.Ordersvssales.Orders) stay distinct and a SQL stub no longer binds to a same-named class in another language (#4653, #4654, thanks @Deepjyoti-Sarmah). - Fix: markdown a bare method name in prose (for example
rediswhere onlyCache.redisexists) only links to the method when the owning class is cited in the same document, so a plain word is no longer turned into a falsereferencesedge; a qualifiedClass.methodorClass::methodmention still resolves (#4609, #4617, thanks @nothariharan; reported by @saad-siddique). - Fix: mcp the
get_nodeandget_neighborstools, and theexplaincommand, refuse a substring-only near-miss with candidate suggestions instead of returning an unrelated node as the answer; an exact or prefix match still resolves (#3917, #4618, thanks @nothariharan; reported by @Alexandre-Aktisea). - Fix: cross-repo a cross-repo call edge points at the real call site rather than the caller's header declaration, so the edge's
source_fileandsource_locationname the line that makes the call (#4668, #4669, thanks @xiongjianxu). - Fix: extract an incremental build no longer re-queues, on every run, a code file an extractor declined by design (for example a virtual-workspace manifest); the file is marked
ast_emptyand left alone, while a genuinely failed or transiently empty extraction is still retried (#2543, #4672, thanks @xiongjianxu). - Fix: objc a member call resolves when a class is split across a header and an implementation in different directories, binding the selector to its single definition; two unrelated same-named classes that both define the selector stay ambiguous and get no edge (#4673, #4674, thanks @xiongjianxu).
graphify 0.9.93
Twenty-two community pull requests. Extraction: a reference to a Kotlin type alias, C# delegate, Swift macro, Dart typedef, Python module function or Rust sibling-module use now resolves to its real declaration instead of minting a sourceless stub; Metal/CUDA GPU qualifiers no longer mint god nodes; extern "C" headers route to the C++ extractor; an extensionless script with a versioned-interpreter shebang is classified; and Obsidian vault-relative wikilinks resolve. Plus a credential-redaction pass on rationale labels, a node-confidence fold, a truncated-reply label decode, a .graphifyrc BOM fix, a GraphML multigraph export fix, two-repo file disambiguation in explain and path, a PDF-read warning, no skill writes on --version/--help, two PR-tooling fixes (slashed default branch, legacy CI statuses), and a skill partly-read-file recovery so a long file a subagent only skimmed is retried on the next --update instead of silently kept half-read. The AST cache schema is bumped, so the first build after upgrading re-extracts.
- Fix: Kotlin a
typealiasdeclaration is extracted, so a field or parameter typed as the alias resolves to it instead of minting a sourceless cross-file stub (#4553, #4557, thanks @rajatnagda45). - Fix: C# a
delegatedeclaration is extracted, so references resolve to it instead of a sourceless stub; built-inFunc<>/Action<>stay external (#4552, #4556, thanks @rajatnagda45). - Fix: Swift
macrodeclarations are extracted and a freestanding#macro(...)call resolves to the declaration; an unknown or standard-library macro stays unresolved rather than minting a stub (#4551, #4555, thanks @rajatnagda45). - Fix: Rust a
userooted at a siblingmod(for exampleuse item::Thing;) now reaches its declaration, while an externaluse serde::...still does not hijack a same-named local type (#4564, #4567, thanks @Deepjyoti-Sarmah; reported by @almothafar-maf). - Fix: build a node's drifted or legacy confidence is folded onto the enum the same way edges and hyperedges already are, so a node no longer reaches graph.json with an unnormalized confidence (#4529, #4531, thanks @rudycelekli; reported by @grazenN).
- Fix: llm community labels salvaged from a truncated reply are JSON-decoded, so an escaped label (
\",\n,\uXXXX, surrogate pairs) is no longer kept with literal backslash escapes (#4537, thanks @rudycelekli). - Fix: rcfile
.graphifyrcis read as utf-8-sig, so a file saved with a UTF-8 BOM no longer drops its first key (#4538, thanks @rudycelekli). - Fix: Dart a
typedefis extracted as a type alias on its own line, including the legacytypedef R name(args)form, instead of a bogus variable of typetypedef; a field or parameter typed by the alias resolves to it rather than minting a sourcelesstypedefstub (#4582, thanks @madhusudanpatnaik). - Fix: Python a
module.func()call resolves to the module child named exactlyfunc, even when a same-key sibling (for example aFuncSchemaclass beside afunc_schemafunction) previously made the lookup ambiguous and dropped the edge; it never binds to a same-named child of an unrelated module (#4577, thanks @madhusudanpatnaik). - Fix: C++ Metal and CUDA GPU address/execution-space qualifiers (
kernel,device,constant,__global__,__device__, ...) in a.metal/.cufile no longer mint sourceless god nodes; the kernel function still extracts and a<<<...>>>launch still resolves (#4550, #4554, thanks @rajatnagda45). - Fix: extract a
.hheader containingextern "C"is routed to the C++ extractor, so a C-API header the C grammar rejects extracts its symbols instead of nothing (#4526, thanks @bekzodibragimov2004-design). - Fix: extract credential-shaped text (API keys, tokens, Bearer tokens, private-key headers,
user:pass@URLs) in a comment or docstring that becomes a rationale label is redacted before it reaches graph.json, the viz or exports; ordinary identifiers such as git SHAs and UUIDs are left intact (#4566, thanks @0xkaushik-ai). - Fix: export GraphML export of a graph loaded as a MultiGraph (a graph with parallel edges, after #4500) no longer crashes with an empty output; parallel edges are written with distinct keys and round-trip through
read_graphml(#4536, thanks @rudycelekli). - Fix: prs the default branch is derived by stripping only the
refs/remotes/origin/prefix, so a branch name that contains a slash (for examplerelease/2.x) is kept whole and PRs against it are no longer all dropped as wrong-base (#4534, thanks @rudycelekli). - Fix: prs CI classification now reads legacy commit-status
StatusContextstate in addition to check-run conclusions, so a PR whose only signal is an external status (Jenkins, CircleCI) is classified correctly, with a failing status taking precedence (#4533, thanks @rudycelekli). - Fix: detect an extensionless script whose shebang names a versioned interpreter (
#!/usr/bin/env python3.11,#!/bin/bash5,ruby3.2, ...) is now classified to its language instead of being skipped (#4535, thanks @rudycelekli). - Fix: detect when a PDF cannot be read (corrupt, encrypted, or a missing optional dependency) graphify prints a one-time warning naming the file instead of silently returning empty text, so a failed read is distinguishable from a text-less PDF (#4527, thanks @rudycelekli; reported by @grazenN).
- Fix: markdown an Obsidian
[[wikilink]]whose target begins with one of the scan root's own folder names (a vault-relative path) now resolves to the real page instead of a ghost node, restoring intra-vault connectivity (#4559, thanks @bercedev; reported by @CryptoRMac4). - Fix: explain / path two same-path files from different repos in a merged graph are kept distinct: an ambiguous name names each repo and the retry hint points at the full node id, instead of conflating them as one file (#4512, thanks @Deepjyoti-Sarmah; reported by @kaka-in-home).
- Fix: cli
graphify --versionand--helpno longer rewrite or back up an installed skill file; only a real command refreshes skills (the staleness warning still prints) (#4545, thanks @bercedev; reported by @EmanuelFaria). - Fix: query a bare name that is the exact name of several nodes (for example a
.nonce()method in two files) is refused with the candidates listed and the ambiguous exit code, matchingexplainandpath; a keyword that only prefix- or substring-matches labels still runs a normal search (#4511, #4517, thanks @shivampal46011; reported by @kaka-in-home). - Fix: skill a long file a subagent only partly read is no longer a silent, permanent loss. On the skill extraction path each chunk now self-reports the lines it covered; a file whose reported coverage falls short of its real length is written to
.graphify_partial.txt, cached as partial (which the loader treats as a miss) and left unstamped in the manifest, so the next--updatere-dispatches it and replace-on-re-extract swaps the half-read node set for a complete one. This mirrors the library path's truncated-reply recovery (#933, #1950); the already-extracted nodes are kept, and a file no subagent reported is not falsely flagged (#3987, #2225, thanks @nothariharan; reported by @Ryanm218).
0.9.92
Twenty-three community pull requests: call-resolution and id-collision fixes across JS/TS, Python, Go, Rust and Solidity; graph round-trip, dedup and confidence-folding fixes; skill code-only-update and dispatch fixes; and LLM/Ollama and detection fixes. The AST cache schema is bumped, so the first build after upgrading re-extracts.
- Fix: JS/TS class members differing only by
_,$or#are kept as separate nodes (#4475, #4479, thanks @Mpasha17). - Fix: TypeScript
this.fieldis typed from an assignment in any method, includingstaticand accessors (#4473, #4482, thanks @FolatheDuckofDuckingburg). - Fix: JS a workspace package whose
exportspoints only intodist/falls back tosrc/(#4485, #4489, thanks @bercedev). - Fix: JS a dangling barrel-named import edge is dropped once the import resolves through the barrel (#4486, #4488, thanks @bercedev).
- Fix: Python module-level class ids colliding with a function or class are salted apart (#2810, #4467, thanks @hementhu).
- Feature: Python a member call on a pytest fixture parameter is typed from the fixture's returned class (#4332, #4333, thanks @rohit-jsfreaky).
- Fix: Go / Rust same-file declarations differing only by case are kept as separate nodes (#4468, thanks @abdulsamie10).
- Feature: Solidity inherited calls,
supercalls and modifiers resolve through C3 linearization (#4379, #4384, thanks @rohit-jsfreaky). - Fix: MCP parallel edges are preserved through the graph.json round-trip and query output (#4500, #4503, thanks @rtmalikian).
- Fix: dedup a node with a source_file beats a sourceless namesake in collision rank (#4492, #4496, thanks @ayushcodes10).
- Fix: build model-drifted string confidences fold to a valid value before validation and dedup (#4495, #4501, thanks @ayushcodes10).
- Fix: extractors the in-flight scan root is shared via the extractors base module, restoring the one-way import direction (#3666, #3758, thanks @abhay-codes07).
- Fix: detect only a valid
.gitis treated as a VCS root, so a stray home-dir.gitno longer leaks its .gitignore (#4444, #4464, thanks @Mpasha17). - Fix: hooks post-merge rebuilds on real merges, and a new post-rewrite hook rebuilds after cherry-pick/rebase/
pull --rebase(#4463, #4476; #4490, #4491, thanks @Deepjyoti-Sarmah). - Fix: skill the code-only
--updatepath materializes the extraction before the merge across all hosts (#4447, #4313, thanks @vibhanshu-mishra; aider/devin #4456, thanks @Deepjyoti-Sarmah). - Fix: skill stray backticks inside a double-quoted
-cblock no longer run a command mid-step (#4461, #4462, thanks @Deepjyoti-Sarmah). - Fix: skill Pi dispatches semantic subagents to the native
delegateagent (#4494, #4502, thanks @bercedev). - Fix: skill the agent pushes to the exact Neo4j/FalkorDB URI supplied, not a localhost example (#4349, thanks @vibhanshu-mishra).
- Fix: llm the extraction prompt pins source_file to the dispatched file (#3377, #2270, #4487, thanks @cornwe19).
- Feature: llm opt-in backend selection via
GRAPHIFY_BACKEND, a disable switch, and an honest auto-detect (#4361, #4376, thanks @nothariharan). - Fix: deps cap
tree-sitter-dm <0.26so a fresh install cannot pull the ABI-incompatible 0.26 grammar (#4044, thanks @safishamsi).
0.9.91
Eight community pull requests: a Windows MCP-stdio hang fix, Rust/JS/TS/extract call-resolution and id-collision fixes, an Ollama context-size fix, and a clustering label-retention fix. The AST cache schema is bumped, so the first build after upgrading re-extracts.
- Fix: MCP
graph_statsno longer hangs under a stdio host on Windows (and no longer silently drops its built-at-commit staleness line):_git_headcloses the git child's stdin so git does not block on the JSON-RPC pipe (#4440, #4441, thanks @bercedev). - Fix: Rust a
use crate::…::Nameedge now lands on the declaration it imports rather than a bare name-folded target (#4439, #4443, thanks @bercedev). - Fix: JS/TS a file-scope callback's own parameters are now shadowed, so a bare parameter passed on as a call argument no longer mints phantom cross-bundle
indirect_calledges (#4448, #4457, thanks @bercedev). - Fix: extract a module symbol whose id spells a sibling file's id (a
const sqlbesidex.sql) is kept on its own node instead of being merged onto the sibling's file node and dropped (#4449, #4452, thanks @Deepjyoti-Sarmah). - Fix: TypeScript a class field's receiver type is now scoped to its own class and bases, so
this.field.method()resolves to the right class when two classes share a field name (#4294, #4297, thanks @rohit-jsfreaky). - Fix: Ollama extraction and labeling requests now go to Ollama's native
/api/chat, so the derivednum_ctxactually reaches the server and large prompts are no longer silently truncated; a server without/api/chatfalls back to the OpenAI-compatible endpoint (#4413, #4414, thanks @smngvlkz). - Fix: cluster a community keeps its curated or LLM label across a rebuild when its membership still overlaps the previous community by a strict majority (#2298, #4451, thanks @SrijanSriv).
- Test: ingest the skip-existing symlink test now compares the link target against what
readlinkreturned, fixing a false failure on Windows (#4435, #4442, thanks @bercedev).
v0.9.90
0.9.90 (2026-10-13)
Fourteen community pull requests: C# call-resolution and id-collision fixes, Python/Go/dedup correctness, a hub-label sidecar, a post-merge heal hook, and query/build fixes. The AST cache schema is bumped, so the first build after upgrading re-extracts.
- Fix: C# a nameless member-call receiver (
run.Sequence.Apply(),Make().Apply()) no longer mis-binds to the caller's own same-named method; every C# member call defers and resolves only through a typed receiver (#4422, thanks @nixvideojuego-ui). - Fix: C#
new X()no longer binds to a method that shares the type's name, same-file or cross-file; a real same-named type still wins (#4428, thanks @nixvideojuego-ui). - Feature: C#
foreachloop variables are now typed from the collection's element type (arrays, known sequences, dictionary.Keys/.Values), so calls on the loop variable resolve; untypable iterables stay unresolved (#4423, thanks @nixvideojuego-ui). - Fix: C# node ids now keep names that differ only by a leading/trailing
_or by case apart (Action/_Action,Load/load,Token/TOKEN), in both ids and member-call resolution keys, instead of collapsing one onto the other (#4415, #4416, thanks @JensD-git). - Fix: C# colliding ids are salted before the partial-class merge, so a partial half keeps its members and an unrelated node sharing a half's id is no longer deleted (#4411, #4412, thanks @JensD-git).
- Fix: Go a generic receiver type (
func (b *Box[T]) ...) is normalized before building its id, so a generic type's methods attach to the type node instead of a separateBox[T]node (#4438, thanks @Goodkamalpandey). - Fix: Python a module member call (
mod.func()) now resolves when the caller is a method or nested function, by walking the enclosing scopes to the file node instead of reading only the immediate parent (#2447, #4437, thanks @SrijanSriv). - Fix: an edge between two surviving nodes is no longer dropped just because its own
source_filewas not dispatched this run; it is kept as long as both endpoints are kept nodes (#2276, #4436, thanks @SrijanSriv). - Fix: dedup keeps a dropped-folder document next to a top-level file that mints the same id (
protocol.mdbesidedocs/protocol.mdanddocs/firmware/protocol.md), path-qualifying the siblings instead of collapsing and losing one; a genuine reference still collapses onto the named file (#4281, #4410, thanks @Deepjyoti-Sarmah). - Fix: Jinja templates (
.j2,.jinja,.jinja2) are now classified as documents instead of being dropped from the graph (#3427, #3455, thanks @nikhilsaxena04). - Fix: build source-less placeholder nodes orphaned by a re-extraction that drops their edges are now swept on a normal (non-prune) incremental build, not just under prune; the sweep removes only code placeholders and external stubs and spares disk-isolated, fresh-isolated, and hyperedge-member nodes (#4399, thanks @Mpasha17).
- Fix: query the fallback traversal now retains relationships among the visited nodes (seed-to-seed edges, cycles, cross-links, and parallel relations), via the induced subgraph, instead of printing only tree edges (#4314, #4315, thanks @vibhanshu-mishra).
- Feature: watch hub-fallback community labels now go to a
.graphify_labels.pending.jsonsidecar, so the tracked.graphify_labels.jsonholds only curated (manual/LLM) names; a promoted name drops from the sidecar and an emptied sidecar is removed (#3334, #3551, thanks @ayushcodes10). - Feature: hooks
graphify hook installnow also installs apost-mergehook that runs an unscoped background rebuild after a merge, healing a symbol the graph.json union merge driver resurrected on one side (which nothing else would re-extract), so the phantom node no longer persists (#2418, #3556, thanks @ayushcodes10).
v0.9.89
0.9.89 (2026-10-13)
Sixteen community pull requests: cross-repo member-call resolution (Go, PHP, TypeScript, Kotlin, Objective-C), generic/template type-parameter cleanup (Kotlin, Scala, C++, Swift), an Objective-C enum extractor, interface-dispatch fan-out, a native Pi guard extension, and several resolution/ingest fixes. The AST cache schema is bumped, so the first build after upgrading re-extracts.
- Feature: cross-repo member calls now finish across a repository boundary for Go, PHP, TypeScript/JS, Kotlin and Objective-C: a call whose receiver type is declared in another repo is parked by name during the single-repo build and bound on
merge-graphs/global addagainst a unique same-named exported type, fail-closed on ambiguity (#3152, #3388, #3393, #3385, #3387, #3389, #3391, #3395, thanks @xiongjianxu). - Fix: Go a package's type whose methods span several files now folds into one node instead of fragmenting under
_disambiguate_colliding_node_ids, so single-definition guards and receiver typing work (#3399, #3400, thanks @xiongjianxu). - Fix: Kotlin / Scala / C++ / Swift generic and template type parameters (
class Box<T>,[T],template<typename T>,struct Stack<Element>) no longer mint sourceless stub god-nodes; a real same-named type is still referenced (#4406, #4407, #4408, #4409, thanks @rajatnagda45). - Feature: Objective-C
NS_ENUMandNS_OPTIONSdeclarations are now extracted as an enum type plus its members, with the macro forms validated and malformed macros rejected fail-closed (#4400, #4401, thanks @oleksii-tumanov). - Feature: dispatch an interface member now links to every implementer, not just one, so a DI chain through a multi-implementer interface resolves; the fan-out is gated to genuine implementers with a correct method match (#3800, #4396, thanks @Goodkamalpandey).
- Feature: Pi a native Pi guard extension now runs
graphify hook-guardbefore Pi's tool calls and also loads under Oh My Pi, so the hook-guard policy reaches Pi; install/uninstall delegates topi install/pi removeand the guard fails open (#4378, thanks @andrebrait). - Feature: hook a firing read/search nudge now shows the graph nodes behind the nudged call and tightens its wording, so agents act on it instead of treating it as noise; the graph read piggybacks on the already-bounded nudge and is injection-safe and size-capped (#4368, thanks @andrebrait).
- Fix: resolution a
.jsimport now resolves to a.tsxsource when no real.jsfile exists, matching TypeScript's NodeNext resolution; a real.jsstill wins (#3486, #4395, thanks @DevChiniwala). - Fix: distinct downloaded binary captures (PDFs/images) whose URLs collide to one filename are now kept under numbered names instead of silently overwriting each other, matching the markdown path's de-dup (#4393, #4394, thanks @oleksii-tumanov).
v0.9.88
0.9.88 (2026-10-12)
Twenty community pull requests: language-extraction and call-resolution fixes (Java, C/C++, Python, Swift, Go, PowerShell, C#, JS/EJS), dedup/shrink-guard hardening, and query/graph.html ergonomics. The AST cache schema is bumped, so the first build after upgrading re-extracts.
- Feature: Java a call on a chained,
newor cast receiver (factory.builder().size(3).build(),new Builder().size(1),((Builder) o).build()) now resolves through the declared return types on the method chain, binding only on a single unambiguous target (#4306, #4307, thanks @rohit-jsfreaky). - Fix: Java a bare call or field receiver inherited from a supertype in another file now resolves to the nearest declaring supertype (class wins over an interface default; a tie binds nothing), instead of dangling (#4304, #4305, thanks @rohit-jsfreaky).
- Fix: C/C++ a quoted cross-directory include (
#include "../lib/foo.h", STM32Core/SrctoCore/Inc) now resolves to the right header by a unique longest-shared-directory-prefix match, fail-closed on ties and never guessing for./,../, absolute or angle-bracket includes (#4354, #4392, thanks @hopstreax). - Fix: Python a
@name.setter/.getter/.deleterdecorator no longer mints a sourceless stub node (#4380, #4385, thanks @rajatnagda45). - Fix: Python a
Self(PEP 673) type annotation (-> Self,: Self,typing.Self) no longer mints a sourcelessselfstub (#4381, #4386, thanks @rajatnagda45). - Fix: Swift a
Selftype annotation no longer mints a sourcelessselfstub (#4382, #4387, thanks @rajatnagda45). - Fix: Go generic type parameters (
[T any]) in signatures, struct fields and interface methods no longer mint sourcelesst/rstubs (#4383, #4388, thanks @rajatnagda45). - Fix: Python a class type-hinted before it is defined (a forward reference) no longer mints a bare stub that collides with and swallows the file node (#4334, #4343, thanks @Mpasha17).
- Fix: C# extraction now recovers members declared after a verbatim interpolated string that ends in an escaped quote (
$@"a""{e}"""), instead of silently dropping the rest of the file; the fix masks only the offending bytes and discards the rewrite unless it re-parses clean (#3376, #3612, thanks @rohit-jsfreaky). - Fix: PowerShell dot-sourced includes with quoted or
$PSScriptRootpaths now emit import edges, and script-scope commands (outside any function) are now collected as calls (#4356, #4369, thanks @FabioRueda). - Fix: JS/TS a bare or scoped external import is now anchored to the package name rather than the path leaf, so
@scope-a/utilsand@scope-b/utilsstay distinct andlodash/fp/mapcollapses onto onelodashnode (#3084, #3092, thanks @rohit-jsfreaky). - Feature: EJS (
.ejs) templates now have an extractor: scriptlet functions/classes, require/import edges, dynamic imports, and<%- include('partial') %>composition edges, instead of a single top-level parse error (#3811, #4338, thanks @nothariharan). - Fix: serve a dotted Python query (
pkg.mod.func,pkg.mod:func) now resolves to the symbol by module path, fail-closed on a same-file ambiguity, without regressing bare-name lookups (#4366, #4367, thanks @Mpasha17). - Fix: dedup now path-qualifies semantic ids that dropped the directory, so
a/x.mdandb/x.md(both minting a barex) stay distinct instead of collapsing and losing one node; a reference to the bare id from a third file is left unresolved with a warning rather than guessed (#4281, #4362, thanks @Deepjyoti-Sarmah). - Fix: a semantic node that dedup legitimately folded into its AST twin is now exempt from the shrink guard, so
graphify updateon a graph that had an LLM semantic ghost is no longer wrongly write-blocked; the exemption is scoped to a strict_origin=="ast"twin at the same path and label, so a genuine partial-build loss is still refused. LLM node/edge field aliases (file/filepath,relationship) are folded, with the canonical field always winning (#4389, #4391, thanks @AndresDiagoM). - Fix: install
graphify install/uninstallnow removes only graphify's own hook entries (keyed on thehook-guard/hook-checkcommand, not a loose "graphify" substring), keeping co-located user hooks and other commands in the same group, and routes uninstall through a backup (#4359, #4373, thanks @nothariharan). - Fix: install CLAUDE.md, AGENTS.md and sibling files now keep their original line endings (CRLF or LF) across install and uninstall, instead of being normalized to the platform default (#4360, #4372, thanks @nothariharan).
- Fix: wiki index rows now link to their own article when two communities or god-nodes share a label, instead of both pointing at the first-registered slug and orphaning the second article (#3032, #3033, #3095, thanks @rohit-jsfreaky).
- Feature: query
--seedstarts the traversal at given nodes (ids, labels, callable names or paths) so an external ranker can choose the start set; unresolved seeds are reported and skipped, and an all-unresolved set fails closed rather than falling back to keyword seeds (#4293, #4289, thanks @devkancheti4-design). - Feature: graph.html the sidebar now shows a hover tooltip with the full (truncated) legend/search/neighbor name and the legend node count; user text is written via
textContent, preserving the embedded-JSON escaping (#4286, #4291, thanks @Hassannzidan).