This release includes breaking changes for platform teams planning a safe upgrade.
✓ No known CVEs patched in this version
Topics
+5 more
Affected surfaces
ReleasePort's take
Light signalQuery logging in graphify is now opt‑in (off by default). Several correctness bugs across extraction, incremental updates, and reference resolution have been fixed.
Why it matters: With query logging disabled by default, operators avoid unintended log bloat; bugfixes eliminate silent node eviction, stale report counts, and dangling function references affecting accuracy of analysis pipelines.
Summary
AI summaryQuery logging is now opt‑in and several correctness issues across extraction, incremental update, and query resolution have been fixed.
Changes in this release
| Type | Severity | Summary | CVE |
|---|---|---|---|
| Feature | Low |
Cross‑file Bash execution edges are added for `bash x.sh` and `./x.sh`. Cross‑file Bash execution edges are added for `bash x.sh` and `./x.sh`. Source: llm_adapter@2026-07-13 Confidence: high |
— |
| Feature | Low |
Ruby `.rake` files are now extracted and participate in Ruby cross‑file resolution. Ruby `.rake` files are now extracted and participate in Ruby cross‑file resolution. Source: llm_adapter@2026-07-13 Confidence: high |
— |
| Bugfix | Medium |
Markdown files no longer duplicate into two nodes on incremental updates. Markdown files no longer duplicate into two nodes on incremental updates. Source: llm_adapter@2026-07-13 Confidence: high |
— |
| Bugfix | Medium |
Incremental `graphify update` no longer silently evicts nodes for ignored but present files. Incremental `graphify update` no longer silently evicts nodes for ignored but present files. Source: llm_adapter@2026-07-13 Confidence: high |
— |
| Bugfix | Medium |
`build_merge` no longer deletes fresh nodes when the same file is listed in `prune_sources`. `build_merge` no longer deletes fresh nodes when the same file is listed in `prune_sources`. Source: llm_adapter@2026-07-13 Confidence: high |
— |
| Bugfix | Medium |
`graphify path` resolves endpoints by full token match instead of top‑scored node. `graphify path` resolves endpoints by full token match instead of top‑scored node. Source: llm_adapter@2026-07-13 Confidence: high |
— |
| Bugfix | Medium |
Query log is now opt-in (off by default). Query log is now opt-in (off by default). Source: llm_adapter@2026-07-13 Confidence: low |
— |
| Bugfix | Low |
Report's "Suggested Questions" count now matches "Knowledge Gaps" count. Report's "Suggested Questions" count now matches "Knowledge Gaps" count. Source: llm_adapter@2026-07-13 Confidence: high |
— |
| Bugfix | Low |
Cross‑module function references resolve to definitions instead of dangling stubs. Cross‑module function references resolve to definitions instead of dangling stubs. Source: llm_adapter@2026-07-13 Confidence: high |
— |
Full changelog
Maintenance release: a batch of correctness and privacy fixes across extraction, incremental update, and query. No breaking changes.
Highlights:
- Query log is now opt-in (off by default) — no more undocumented plaintext record of your queries in
~/.cache(#1797). - Incremental
graphify updateno longer silently evicts nodes for files that are merely newly-ignored but still on disk (#1795), andbuild_mergeno longer drops a re-extracted file passed inprune_sources(#1796). - Markdown files no longer split into duplicate document nodes across the quick-scan and semantic passes (#1799).
- New language coverage: Ruby
.rakefiles (#1784) and cross-file Bash script execution edges (#1756).
Fixes
-
Fix: the query log is now opt-in (off by default) (#1797, thanks @adam-pond-agent).
querylogwrote everyquery/path/explainquestion and corpus path (and full responses ifGRAPHIFY_QUERY_LOG_RESPONSES) to a default-on, unbounded, fail-silent plaintext file at~/.cache/graphify-queries.log— outside any repo's .gitignore/retention, and undocumented, which contradicts graphify's on-device / no-telemetry posture. Logging is now OFF unless you opt in withGRAPHIFY_QUERY_LOG_ENABLE=1(default path) orGRAPHIFY_QUERY_LOG=<path>;GRAPHIFY_QUERY_LOG_DISABLE=1still forces it off. All the query-log env vars are now documented in the README. -
Fix: a markdown file that went through semantic extraction is no longer duplicated into two disconnected nodes on later
graphify update(#1799, thanks @jerp86). The semantic pass mints<slug>_docwhile the markdown quick-scan mints the bare<slug>, so the file's edges split across two twins (a docs->code path query would dead-end on the bare half; centrality and communities split too).build_from_jsonnow merges the bare quick-scan node into the semantic_docnode when both share the samesource_fileand arefile_type: document, consolidating their edges/hyperedges onto one node. Gated so an unrelated code symbolfooandfoo_docnever merge. -
Fix: incremental
graphify updateno longer silently evicts nodes for a file that left the scan corpus but still exists on disk (#1795, thanks @CJNA)._reconcile_existing_graphread "source absent from the collected corpus" as "deleted", but that's also what an ignore-rule/filter change looks like (e.g. an upgrade that starts honoring.gitignore) — in one 27k-node graph the first rebuild after such an upgrade mass-evicted 655 nodes whose files were present the whole time. Eviction now fails closed: a corpus-absent source is only evicted whenPath(identity).exists()is False (true deletion), otherwise its nodes/edges/hyperedges are preserved and a loud line reports how many were kept and why. True deletions and renames evict as before; a fullextract --forcestill purges deliberate exclusions. -
Fix:
build_mergeno longer silently deletes a re-extracted file's fresh nodes when that file is also passed inprune_sources(#1796, thanks @erichkusuki). A file present innew_chunksis being replaced, not deleted, so it's now excluded from the prune set — "replace" wins over a contradictory "delete" of the same source. Previously, following the old edit-workflow (pass the changed file inprune_sources) deleted the just-built concept whenever an edit kept a node's label. Genuine deletions (a file inprune_sourcesbut notnew_chunks) still prune. -
Fix:
graphify pathresolves each endpoint to the first candidate whose label contains every query token, instead of blindly taking the top-scored node (#1785, thanks @CJNA)._score_nodes' full-query bonus only fires when the query equals/prefixes a label, so a query that is a token subset of the intended label ("Reject-everything judge"vs"Degenerate Reject-Everything Judge") got no bonus and a node prefix-matching one rare token could outscore it — anchoring the path on an unrelated, often disconnected node and yielding a false "No path found". When the top candidate already full-matches (the common case) the pick is unchanged. Applied to both thepathCLI and the MCP shortest-path tool; the close-runner-up ambiguity warning now fires only when the score head is what was actually picked. -
Fix: the report's "Suggested Questions" weakly-connected-node count now matches its "Knowledge Gaps" count (#1768, thanks @balloon72).
suggest_questions()omitted thefile_type != "rationale"filter thatreport.py's Knowledge Gaps section applies, so the sameGRAPH_REPORT.mdshowed two different numbers for the same concept (e.g. 757 vs 245), making a healthy graph look like it had a major documentation gap. Both computations now use the same filter. -
Fix: Bash scripts that run each other by execution now get a cross-file edge (#1756, thanks @balloon72).
extract_bashonly linkedsource x.sh/. x.sh; the two most common forms —bash x.shand./x.sh— produced no edge, so execution topology was missing. They now emit acallsedge (contextscript_invocation) to the invoked script's entry node when the target resolves to a real file on disk (script runnersbash/sh/zsh/ksh/dashand bare./x.sh), skipping missing or shadowed targets. -
Fix: Ruby
.rakefiles are now extracted and participate in Ruby cross-file resolution like.rb(#1784, thanks @krishnateja7)..rakeis plain Ruby but the extension was gated out of seven places (classification, extractor dispatch, the language-name/family maps, theruby_member_callsresolver's suffix set, both.rb-suffix filters inruby_resolution.py, and the build repo-tag map), so every rake task was skipped and its calls were invisible. All seven now include.rake;Widget.tallyfrom a.raketask resolves to its.rbdefinition. -
Fix: cross-module references to a function now resolve to its definition instead of dangling on a name-only stub (#1781, thanks @EmilNyg).
_rewire_unique_stub_nodesgated merge targets through_is_type_like_definition, which rejects any label ending in)— so function/method defs could never absorb their reference stubs, and "who references this function" returned nothing on the definition node while a sourceless stub held all the edges. Top-level function defs are now eligible rewire targets when the label match is globally unique, gated by a language-family match with the referrers (a Pythonget_dbreference can't bind to a unique Goget_db()) and excluding stubs used as a supertype (inherits/implements/extends— you don't inherit from a function). Types are unchanged.
Install
uv tool install --upgrade graphifyy # or: pipx upgrade graphifyy
Weekly OSS security release digest.
The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.
No spam, unsubscribe anytime.
Share this release
About graphify
AI coding assistant skill (Claude Code, Codex, OpenCode, Cursor, Gemini CLI, OpenClaw, Factory Droid, Trae). Turn any folder of code, docs, papers, images, videos, or YouTube links into a queryable knowledge graph
Beta — feedback welcome: [email protected]