Skip to content

Releases: Graphify-Labs/graphify

graphify 0.9.97

Choose a tag to compare

@safishamsi safishamsi released this 27 Oct 18:15

0.9.97 (2026-10-27)

  • Security: rationale redaction credential redaction for rationale labels moves to a single pre-cache choke point (_redact_rationale_labels inside _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 example ghp_...), Slack xoxe- 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.2 in the mcp extra, 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/no are no longer folded to booleans (a workflow on: block is extracted, not turned into a True node) (#4784, #4785, thanks @jaimemartinez).
  • Fix: razor a component's @implements interfaces are extracted as implements edges 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 a provider = aws.west reference resolves to it instead of dangling; a local literally named provider is no longer misread (#4819, thanks @ayushcodes10).
  • Fix: cobol paragraphs that follow a nested END PROGRAM reattach to the enclosing program instead of sticking to the nested one, via a program stack (#4824, thanks @ayushcodes10).
  • Fix: blade a wire:click directive binds the bare method name: dotted modifiers (wire:click.prevent="submit") are matched, call arguments are trimmed from the name (deleteItem(5) binds deleteItem), and a $-prefixed magic action mints no fabricated edge (#4823, thanks @ayushcodes10).
  • Fix: pascal a record is recognised as a type with its own methods in the regex fallback (the default path without the optional pascal extra), matching the tree-sitter path; operator members are extracted too (#4825, thanks @ayushcodes10).
  • Fix: vbnet an Operator declaration is extracted as an operator-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 call resolves 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 now graphify 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-chained module ... and ... or class ... 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 task method is modeled like a function one (its own node, method edge 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 relation is dropped instead of persisted, on both the build and the raw --no-cluster write paths, and alias folding (relationship to relation) 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.glob rejects (a ** component or an absolute pattern) is skipped with a warning instead of crashing the whole extract run (#4681, #4687, thanks @Deepjyoti-Sarmah).
  • Fix: report a community hub [[wikilink]] is slugged through the same export._obsidian_safe_stem the 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/getting are dropped from query terms (like the existing work/works), so a framework hub labelled "Get" is not pulled in as a BFS seed by an exact-match bonus; node lookups for a literal Get still resolve (#4686, thanks @AndresDiagoM).

graphify 0.9.96

Choose a tag to compare

@safishamsi safishamsi released this 26 Oct 15:18

0.9.96 (2026-10-25)

  • Security: deps the Pillow floor is raised to >=13.0.0 on Python 3.11+ (staying at >=12.3.0 on 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 imports and calls) instead of only the first edge (#4731, thanks @rudycelekli).
  • Fix: build a hyperedge whose members are given under the members/node_ids aliases has its numeric member ids coerced to strings like the canonical nodes list, 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 the EXTRACTED enum, 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 than max_completion_tokens (which it ignores), so responses are no longer silently uncapped (#4739, #4753, thanks @Ethereal49; reported by @snapp-kenya).
  • Fix: extract XAML codebehind (*.xaml to *.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/namespace no 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 extract records each run's token usage to graphify-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) so new 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/ and bin/ 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 real src/bin stays (#4742, thanks @Great-Peace).
  • Fix: watch each watch rebuild is bounded by GRAPHIFY_REBUILD_TIMEOUT (default 600s, 0 disables), with a thread-Timer fallback where SIGALRM is unavailable or watch() runs off the main thread (a SIGALRM arm there raises ValueError and 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_file sentinel like other languages, instead of a node that fails validation (#4725, #4728, thanks @madanlalit; reported by @alopezradicle).
  • Fix: rust a use is scoped to the crate it names, so use serde_json::Value no longer resolves to a same-named type in another crate; a named pub use re-export is followed and a manifest-less binding stays INFERRED (#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 update with 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

Choose a tag to compare

@safishamsi safishamsi released this 23 Oct 17:59

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-named mkstemp/mkdtemp file created with O_EXCL and restrictive mode instead of a predictable *.tmp name, 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 = B alias is extracted as a type node (tree-sitter parses it as a type_alias, not a type_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; or typedef 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 type alias and a union item are extracted as type nodes (a union's fields reference their types like a struct), so references resolve instead of minting stubs; an impl-associated type is 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 tree on 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 a FileNotFoundError; 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.json dependency'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 relabelled name@range (#4569, #4572, thanks @Deepjyoti-Sarmah; reported by @BiSide).
  • Feature: yaml .yaml/.yml files are now extracted structurally (a file node plus contains edges to keys) and classified as code rather than documents, so Helm charts, Kubernetes manifests, and CI pipelines contribute nodes to a code-only or --update run instead of nothing, matching how .json is 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 uses safe_load so 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_id defined in both a.py and b.py) is no longer promoted to EXTRACTED; the edge is still emitted for connectivity but stays INFERRED, so a symbol that was never imported is not falsely certified. A real symbol import (from a import _make_id) still resolves EXTRACTED (#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 two hooks.py from 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 .m binds 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 stray graphify-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_ENUM declarations are extracted as enums with their cases, the same as NS_ENUM/NS_OPTIONS; the AST cache schema is bumped so the first build after upgrading re-extracts (#4705, thanks @Jvxoq).
  • Fix: sql a CREATE TABLE whose column default the SQL grammar cannot parse (for example MySQL/MariaDB DEFAULT 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

Choose a tag to compare

@safishamsi safishamsi released this 22 Oct 16:19

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_url rejects a fetched URL that has no hostname (http:///path), a non-numeric, out-of-range, or zero port, or embedded user: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.xml contributes 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() where x has 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, so new X() resolves to the required declaration; a real const 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.h yields 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 Host header ([::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 --help lists every accepted --platform value (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 emits reads_from/writes_to edges 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 GO batch separator (a client command, not a terminator) ends the statement, so a statement after a GO with no trailing ; parses on its own instead of merging into one malformed node; a GO inside a string, comment, or column name is left alone (#4651, #4652, thanks @Deepjyoti-Sarmah).
  • Fix: sql a table referenced before its CREATE TABLE is 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.Orders vs sales.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 redis where only Cache.redis exists) 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 false references edge; a qualified Class.method or Class::method mention still resolves (#4609, #4617, thanks @nothariharan; reported by @saad-siddique).
  • Fix: mcp the get_node and get_neighbors tools, and the explain command, 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_file and source_location name 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_empty and 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

Choose a tag to compare

@safishamsi safishamsi released this 20 Oct 16:29

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 typealias declaration 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 delegate declaration is extracted, so references resolve to it instead of a sourceless stub; built-in Func<>/Action<> stay external (#4552, #4556, thanks @rajatnagda45).
  • Fix: Swift macro declarations 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 use rooted at a sibling mod (for example use item::Thing;) now reaches its declaration, while an external use 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 .graphifyrc is 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 typedef is extracted as a type alias on its own line, including the legacy typedef R name(args) form, instead of a bogus variable of type typedef; a field or parameter typed by the alias resolves to it rather than minting a sourceless typedef stub (#4582, thanks @madhusudanpatnaik).
  • Fix: Python a module.func() call resolves to the module child named exactly func, even when a same-key sibling (for example a FuncSchema class beside a func_schema function) 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/.cu file no longer mint sourceless god nodes; the kernel function still extracts and a <<<...>>> launch still resolves (#4550, #4554, thanks @rajatnagda45).
  • Fix: extract a .h header containing extern "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 example release/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 StatusContext state 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 --version and --help no 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, matching explain and path; 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 --update re-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

Choose a tag to compare

@safishamsi safishamsi released this 16 Oct 17:57

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.field is typed from an assignment in any method, including static and accessors (#4473, #4482, thanks @FolatheDuckofDuckingburg).
  • Fix: JS a workspace package whose exports points only into dist/ falls back to src/ (#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, super calls 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 .git is treated as a VCS root, so a stray home-dir .git no 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 --update path 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 -c block no longer run a command mid-step (#4461, #4462, thanks @Deepjyoti-Sarmah).
  • Fix: skill Pi dispatches semantic subagents to the native delegate agent (#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.26 so a fresh install cannot pull the ABI-incompatible 0.26 grammar (#4044, thanks @safishamsi).

0.9.91

Choose a tag to compare

@safishamsi safishamsi released this 14 Oct 22:17

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_stats no longer hangs under a stdio host on Windows (and no longer silently drops its built-at-commit staleness line): _git_head closes the git child's stdin so git does not block on the JSON-RPC pipe (#4440, #4441, thanks @bercedev).
  • Fix: Rust a use crate::…::Name edge 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_call edges (#4448, #4457, thanks @bercedev).
  • Fix: extract a module symbol whose id spells a sibling file's id (a const sql beside x.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 derived num_ctx actually reaches the server and large prompts are no longer silently truncated; a server without /api/chat falls 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 readlink returned, fixing a false failure on Windows (#4435, #4442, thanks @bercedev).

v0.9.90

Choose a tag to compare

@safishamsi safishamsi released this 13 Oct 22:17

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# foreach loop 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 separate Box[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_file was 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.md beside docs/protocol.md and docs/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.json sidecar, so the tracked .graphify_labels.json holds 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 install now also installs a post-merge hook 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

Choose a tag to compare

@safishamsi safishamsi released this 13 Oct 10:43

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 add against 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_ENUM and NS_OPTIONS declarations 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-guard before Pi's tool calls and also loads under Oh My Pi, so the hook-guard policy reaches Pi; install/uninstall delegates to pi install/pi remove and 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 .js import now resolves to a .tsx source when no real .js file exists, matching TypeScript's NodeNext resolution; a real .js still 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

Choose a tag to compare

@safishamsi safishamsi released this 12 Oct 22:19

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, new or 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", STM32 Core/Src to Core/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/.deleter decorator 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 sourceless self stub (#4381, #4386, thanks @rajatnagda45).
  • Fix: Swift a Self type annotation no longer mints a sourceless self stub (#4382, #4387, thanks @rajatnagda45).
  • Fix: Go generic type parameters ([T any]) in signatures, struct fields and interface methods no longer mint sourceless t/r stubs (#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 $PSScriptRoot paths 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/utils and @scope-b/utils stay distinct and lodash/fp/map collapses onto one lodash node (#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.md and b/x.md (both minting a bare x) 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 update on 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/uninstall now removes only graphify's own hook entries (keyed on the hook-guard/hook-check command, 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 --seed starts 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).