v0.9.96
Graphify-Labs/graphifyv0.9.96Oct 26, 2026by safishamsi
Upgrading?
Release notes summary
Graphify 0.9.96 is a maintenance and security release that raises dependency floors for Pillow and pypdf and refreshes transitive dependencies to address Dependabot advisories. It also delivers a broad set of correctness fixes across LLM handling, watch mode, PR CI status, exports, deduplication, and multiple language extractors, plus performance improvements for update and watch workflows.
Key Highlights
- Security dependency updates: Pillow >=13.0.0 on Python 3.11+ (>=12.3.0 on 3.10), pypdf >=6.19.0, and refreshed transitive dependencies.
- LLM and watch fixes improve failed-chunk reporting, DeepSeek token caps, Ollama context sizing, and paper detection during watch quick scans.
- Language extractor fixes for Python, TypeScript, JavaScript, Rust, Zig, Dart, VB.NET, XAML, and robot tests improve binding and node extraction correctness.
- Performance: graphify update skips the pipeline when no relevant inputs changed, and watch rebuilds are bounded by GRAPHIFY_REBUILD_TIMEOUT.
- CLI/export fixes include cost ledger recording for graphify extract, complete Obsidian parallel relations, and clearer PreToolUse hook reminders.
Breaking Changes
- Minimum dependency versions changed: Pillow is now >=13.0.0 on Python 3.11+ (still >=12.3.0 on Python 3.10) and pypdf is now >=6.19.0, which may require dependency updates.
New Features
- Configurable watch rebuild timeout via GRAPHIFY_REBUILD_TIMEOUT (default 600s; 0 disables).
- No-op graphify update runs skip detect/extract/build when scan inputs, config, .graphifyrc, extractor epoch, and output completeness are unchanged.
- graphify extract records per-run token usage to graphify-out/cost.json.
- Improved extractor support for unnamed Dart extensions, chained TypeScript decorators, external JavaScript require bindings, scoped Rust use declarations, and Python member-call resolution.
- Obsidian export now lists every parallel relation between two nodes instead of only the first edge.
Full Release Notes
## 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).
Related Repositories
A collective list of free APIs
The agent that grows with you
A feature-rich command-line audio/video downloader
Python tool for converting files and office documents to Markdown.
AutoGPT is the vision of accessible AI for everyone, to use and to build on. Our mission is to provide the tools, so that you can focus on what matters.