Skip to content

v0.10.0

Choose a tag to compare

@github-actions github-actions released this 26 Jun 07:41

[0.10.0] - 2026-06-26

Breaking Changes

  • The public Subgraph type now exposes entryNodes instead of roots, matching the project terminology for Entry Nodes.
  • Database access interfaces now use Access Model names, so TypeScript users should import AgentAccessModel, MaintenanceAccessModel, ResolutionAccessModel, and StatusAccessModel from the new access-model module.
  • ZCodeGraph now uses a private zcodegraph namespace for new project indexes and MCP server configs: project data lives in .zcodegraph/zcodegraph.db, and installers write the MCP server key zcodegraph. Existing .codegraph/ indexes are no longer opened as initialized projects; run zcodegraph init to build a fresh index in the new namespace.
  • zcodegraph init is now the clean initialization command and always builds the initial index; the historical -i / --index flag has been removed.
  • Index engine selection now uses explicit --engine flags only; ZCODEGRAPH_INDEX_ENGINE is no longer supported and now points users to zcodegraph index --engine typescript.

Security

  • Closed a path-traversal hole where a symbolic link inside an indexed project that pointed outside the project root could make CodeGraph serve that out-of-root file's contents (for example a file under your home directory) to the AI agent. CodeGraph now resolves symlinks when validating file access and refuses to read anything whose real location is outside the project, while still allowing symlinks that stay within it. Thanks @sulthonzh. (#527)
  • CodeGraph now indexes Spring configuration files (application.properties / application.yml) by key only, and never includes their values in codegraph_explore or codegraph_node output. Previously a secret committed to one of these files — a database password, API key, or connection string with embedded credentials — could be surfaced to an AI agent that asked about nearby code, even though the agent never opened the file. The configuration keys are still indexed, so reference and impact analysis are unaffected; an agent that genuinely needs a value reads the file itself. Shopify Liquid {% schema %} blocks are likewise indexed by name only. (#383)

New Features

  • rust-hybrid profile output now includes shadow semantic replay diagnostics for direct named TypeScript and JavaScript imports, helping audit resolver migration without changing indexed results. (#521)
  • rust-hybrid profile output now labels the LowerName, QualifiedName, and FileNodes candidate-fact protocol shapes with their ownership status and semantic boundary, making resolver migration work easier to audit without changing indexed results. (#520)
  • rust-hybrid indexing now owns baseline Python extraction by default, so ordinary Python files are indexed by the Rust path instead of being appended through same-language TypeScript fallback. (#485, #486, #487)
  • rust-hybrid indexing now understands repo-local TypeScript config inheritance for module resolution, including inherited paths aliases, rootDirs, and safer package-map behavior for classic module resolution. (#447, #448, #449)
  • rust-hybrid indexing now follows repo-local package exports and imports condition order more closely, including types, CommonJS require, and configured custom conditions. (#451, #452, #453)
  • rust-hybrid indexing now resolves extensionless repo-local imports through modern TypeScript source extensions such as .mts and .cts, while keeping config/data files out of graph-edge candidates. (#455, #456, #457)
  • rust-hybrid indexing now resolves explicit JavaScript runtime extensions to matching TypeScript source files, so imports like ./thing.js can link to thing.ts or thing.tsx when that is how the project is authored. (#446)
  • Programmatic SDK full indexing now uses the same rust-hybrid default as the CLI, while still offering explicit typescript and rust engine choices for compatibility and debugging. (#263)
  • zcodegraph_explore now handles Gin-style METHOD /path route questions more directly, surfacing the matched route and handler in one response for first-user Go projects. (#281)
  • The first-user rust-hybrid release path now has refreshed pre-release docs, troubleshooting, smoke evidence, and README-backed Agent Sufficiency validation for TypeScript/JavaScript and Go.
  • rust-hybrid indexing now safely falls back to the TypeScript indexer for individual Rust-owned files that hit a Rust parse gap, marks the run as degraded, and records privacy-preserving diagnostics for replayable bug reports. (#257)
  • The Rust indexing profiler now breaks reference resolution into database, name-matching, import, framework, and other timing buckets, so large-repo bottlenecks can be targeted with evidence. (#87)
  • The experimental Rust indexer now accepts more modern TypeScript syntax used in large VS Code sources, including import-type queries and contextual keyword identifiers. (#88)
  • Phase 4 readiness work now records profile, memory, package-safety, and large VS Code sufficiency evidence for experimental Rust indexing, with a continue opt-in decision while follow-up blockers are addressed. (#83)
  • New Rust indexing profiler script reports source scanning, parsing/extraction, SQLite writing, TypeScript finalization, and subprocess handoff timings as JSON, making the experimental Rust path easier to compare across local runs. (#66)
  • The experimental Rust indexing path now batches SQLite writes in one transaction, reducing write overhead while preserving the TypeScript indexer as the default. (#67)
  • zcodegraph index now has an experimental opt-in Rust indexing engine path for the first JavaScript/TypeScript migration slice; the TypeScript indexer remains the default while the Rust core proves out parity, performance, memory, safe SQLite handoff, JS/TS/JSX/TSX indexing, graph-resolution, semantic-parity, CLI/MCP integration, benchmark, agent-sufficiency, and packaging-readiness gates. (#50, #51, #52, #53, #54, #55, #56, #57, #58, #59)
  • New zcodegraph upgrade command updates CodeGraph to the latest release in place — it detects how you installed (the standalone install.sh / install.ps1 bundle, npm, or npx) and does the right thing for each, on macOS, Linux, and Windows. Use zcodegraph upgrade --check to see whether an update is available without installing, or zcodegraph upgrade <version> to move to a specific version. After upgrading it reminds you to re-index your projects so they pick up the newer engine's improvements. (#679)
  • zcodegraph status now flags when a project's index was built by an older engine than the one you're running and recommends re-indexing (also surfaced in zcodegraph status --json), so you know when a zcodegraph index -f or zcodegraph sync will add coverage a newer release introduced.
  • Cross-file impact and blast-radius coverage now spans all 22 supported languages and 14 web frameworks, each validated on a real-world repo — see the new coverage table in the README. This release ships the cross-file resolution behind it, including Lua and Luau require, Shopify OS 2.0 Liquid section templates, Delphi form code-behind, Rust cross-module calls and Rocket route macros, Swift Fluent relationships, and the SvelteKit / Nuxt / Vapor / Axum route conventions. The residual everywhere is genuine static-analysis frontiers (runtime dispatch, reflection / DI, framework-convention entry points), never hidden.
  • C# types are now tracked by their namespace-qualified name. Same-named types in different namespaces — a domain entity and a DTO both called CatalogBrand, say — are told apart instead of collapsing into one arbitrary match, so a reference resolves to the right one and impact no longer conflates them. (C#)
  • ASP.NET Razor (.cshtml) and Blazor (.razor) markup are now parsed for code relationships. A @model / @inherits / @inject directive links the view to the C# view-model, base type, or service it names; a Blazor <MyComponent/> tag (plus @typeof(...) and generic TItem="..." arguments) links to the component class; and the C# inside @code { } / @functions { } / @{ } blocks is analyzed too, so services and types used in component logic are linked. A view-model, component, or service referenced only from markup is no longer reported as having no dependents, and editing it surfaces the views that use it. (ASP.NET, Blazor)
  • A Razor/Blazor type reference now resolves through the component's @using namespaces — including the folder's cascading _Imports.razor — so a simple name that exists in several namespaces lands on the right one. A @model / <MyComponent> / @code reference to CatalogBrand resolves to the @using'd DTO (BlazorShared.Models.CatalogBrand) rather than a same-named domain entity. (ASP.NET, Blazor)
  • zcodegraph status --json now also reports the running CLI version, the index directory (indexPath), and a lastIndexed timestamp (ISO-8601, or null when nothing's indexed yet), so CI and scripts can pin the CLI version and check index freshness from a single command. A matching CodeGraph.getLastIndexedAt() library method exposes the same freshness check without shelling out. Thanks @12122J and @eddieran. (#329)

Fixes

  • rust-hybrid indexing now batches more candidate lookups during reference resolution, reducing default indexing time on TypeScript-heavy projects without changing indexed results or fallback behavior. (#491)
  • rust-hybrid indexing now completes sparse-checkout projects when a planned non-Rust-owned fallback file is missing, and reports the missing fallback coverage as degraded diagnostics instead of failing the whole run. (#482, #483, #484)
  • rust-hybrid indexing now reuses Rust parser instances by source language during extraction, reducing repeated parser setup work without changing indexed results or fallback behavior. (#292)
  • rust-hybrid indexing now writes Rust-extracted source facts in a single bulk transaction, reducing large-project indexing overhead without changing indexed results or fallback behavior. (#288)
  • rust-hybrid now handles TypeScript import("...") type queries used in as assertions and function-type returns, avoiding unnecessary TypeScript fallback on valid project files. (#282)
  • Degraded rust-hybrid runs now separate recovered fallback warnings from unrecovered parse errors in the CLI summary and error log, so users can tell when the graph is still usable. (#283)
  • Unsupported Node.js version warnings now point to the current ZCodeGraph repository instead of the historical project URL. (#285)
  • zcodegraph_explore now keeps self-query Flow sections on the named path for planner and indexing questions, avoiding fuzzy fallback matches that could show unrelated helper paths instead of the requested symbols. (#48)
  • zcodegraph_explore now seeds a concrete Java REST-to-transport action slice for broad flow questions, so a single answer includes route dispatch, handler preparation, local client execution, and transport action execution evidence instead of forcing repeated follow-up explores. (#47)
  • zcodegraph_explore now keeps polymorphic Java implementation families together when answering broad implementation questions, so Elasticsearch Engine queries include the base type, write-capable engines, read-only engines, and relevant plugin engines without pulling in test-only subclasses. (#46)
  • zcodegraph_explore now keeps Java allocation services and allocator implementations in scope for broad shard-allocation questions, so "How does shard rebalancing and allocation work?" surfaces the service and concrete shard allocator evidence. (#45)
  • zcodegraph_explore now keeps Java-style action/request/response families together for broad operation questions, so "How does bulk indexing work?" surfaces the bulk action, request, and response instead of unrelated one-word matches. (#44)
  • zcodegraph_explore now shows the exact callback registration line for synthesized callback edges, so React-style observer flows such as Scene.onUpdate(this.triggerRender) can be explained without opening the wiring file. (#43)
  • Local install helpers, git sync hooks, upgrade guidance, and evaluation scripts now consistently look for the zcodegraph command and .zcodegraph project index, so renamed installs no longer appear missing under the old codegraph name.
  • Grammar loading is now covered by a regression test that keeps WASM grammars loading one at a time, preventing Node 20+ external-scanner races that could make TypeScript, TSX, C#, Swift, Kotlin, Dart, and similar languages fail to index. (#40)
  • Pascal/Delphi support is now documented with the full set of supported source and form extensions, including .dfm and .fmx form files. (#41)
  • C/C++ headers with complex declarations are now covered by a regression test so skipped empty-name symbols cannot leave dangling graph edges that abort indexing with a foreign-key error. (#42)
  • Documentation and CLI help now consistently use ZCodeGraph for the product and API/package shorthand, CodeGraph only for existing code identifiers, and zcodegraph for commands, MCP tools, index paths, database files, and MCP server keys.
  • The shared background server no longer logs a scary-looking [error] … undefined line on every session start. Attaching to the shared daemon is normal, healthy behavior, but the informational message was being surfaced by MCP hosts (Claude Code and others) as an error; it's now silent by default — set CODEGRAPH_MCP_LOG_ATTACH=1 to surface it when debugging daemon attach. Thanks @mturac. (#618)
  • On Windows, CodeGraph's background processes no longer pile up without bound and saturate CPU over a long session. When the editor or agent that launched CodeGraph exited, its helper process couldn't tell its parent had gone — Windows reports process lineage differently than macOS and Linux — so the helper kept running, the shared background server never saw the client disconnect, and its idle timer never fired to shut it down. CodeGraph now detects parent-process exit directly on Windows, so helpers and the idle background server wind down promptly, the same as they already did on macOS and Linux. (#692, #576, #680)
  • The shared background server has two further safeguards against ever lingering: it now drops a client the moment it detects that client's process is gone (even if the disconnect arrived uncleanly — a force-quit or a dropped connection that never closed the socket), and it won't stay running indefinitely with clients attached but no activity. Together these guarantee it always winds down, on every platform. (#692)
  • A session no longer loses CodeGraph when the shared background server is restarted out from under it — for example when your MCP host (opencode and others) stops and restarts the server as you open another session. Previously the affected session's connection died silently and any request in flight at that moment hung; now CodeGraph keeps that session working by serving it locally, so the tools stay available without restarting the session. (#662)
  • React Native native→JS events now connect through the common sendEvent(context, "X", body) wrapper. Many libraries (react-native-device-info and others) wrap the event emitter behind a helper whose .emit(eventName, …) takes a variable, so the matcher — which looked for .emit("literal", …) — missed it; the literal event name actually lives in the wrapper call. Now a native method that fires sendEvent(…, "batteryLevelChanged", …) links to the JS addListener('batteryLevelChanged', …) handler, so editing the native emitter surfaces the JS subscriber. (React Native)
  • React Native / Expo cross-language bridges are more complete and more precise. An Expo Module method declared with a generic type — Android's AsyncFunction<Float>("getBatteryLevelAsync") — is now indexed (the <Float> used to defeat the matcher, so every Android Expo method was dropped and a JS call resolved only to the iOS Swift impl). The iOS and Android implementations of the same JS-visible method — both Expo Modules and classic NativeModules (@ReactMethod on Android, the matching method on iOS) — are now linked to each other, so a JS call that resolves to one platform still reaches the other and editing either platform's native code surfaces the JS caller. And a Type.member static read in native code (e.g. Android's BatteryManager.EXTRA_LEVEL) no longer falsely links to a coincidentally same-named class in another language (a web BatteryManager) — type references stay within a language family, while genuine cross-language bridges (config→code, JS↔native calls) are unaffected. (React Native, Expo)
  • A TypeScript/JavaScript reference or import no longer gets mis-linked to a same-named class in a native language. In a React Native / Expo repo that has both a TypeScript TestRunner type and a Kotlin TestRunner class, a TS reference to TestRunner — or an import React sitting next to a Swift React — used to resolve onto the native symbol (the component resolver matched any same-named class regardless of language, and import statements weren't language-checked at all). References and imports now stay within their language family, so they land on the right symbol while genuine cross-language bridges (JS↔native calls, config→code) are untouched. A C/C++ #include "Foo.h" likewise no longer resolves to a same-named header from another platform (an iOS Objective-C Foo.h). (React Native, Expo, TypeScript, C/C++)
  • Native includes and Kotlin Multiplatform imports now resolve to the correct file in multi-platform projects. A C/C++ #include "Foo.h" now resolves to the header in the including file's own directory first (the C quoted-include rule), so when a module ships a same-named header per platform (a Windows, an Apple, and an Android Foo.h side by side) the local one correctly shows its dependents instead of an arbitrary other-platform header looking like the dependency. And a Kotlin Multiplatform expect declaration is no longer reported as having no dependents: a commonMain import now resolves to the commonMain expect (matched within the importing source set) rather than being absorbed by one platform's actual. (C/C++, Kotlin)
  • zcodegraph affected now reports the tests and files that actually depend on your changes. It used to follow only import statements — but those never cross file boundaries in CodeGraph's graph — so it returned no affected tests for any change, in every language. It now traces the real cross-file usage graph (calls, references, instantiations, and class extends / implements), so git diff --name-only | zcodegraph affected surfaces the test files that exercise the changed code. Circular-dependency detection, which had the same blind spot, now works too.
  • Blast radius, callers, and zcodegraph affected now recognize far more of the dependencies that were already in your code. A symbol now counts as a dependency whether it's called, used only in a type annotation inside a function body (const items: Foo[] = []), imported and placed in a registry array or passed as an argument, used as a JSX component, simply re-exported from a barrel (export { X } from './x'), or pulled in as a namespace (import * as ns from '@/x') — including through tsconfig path aliases like @/. Previously only called, instantiated, or signature-typed symbols created a cross-file link, so a file that used a dependency in any other way could look like it depended on nothing — and the file that defined a widely-used symbol could look like nothing depended on it. The graph still indexes exactly the same symbols; it just connects the ones that were already there. (TypeScript/JavaScript)
  • The same completeness fix now applies to Python: a name brought in with from module import X is recorded as a dependency on that module even when X is only stored in a list/dict, passed as an argument, used as a decorator, or re-exported through an __init__.py. Previously Python linked only imports that were called or instantiated, so a module consumed purely by value — or only re-exported — looked like nothing depended on it.
  • Rust impact and zcodegraph affected now connect far more of the module graph. Struct literals (Widget { n: 1 }) are recorded as instantiations; a use / pub use brings its item into the dependency graph — so a pub use re-export hub (a mod.rs re-exporting its submodules) depends on the modules it re-exports — resolved by Rust module path (crate::/self::/super::), so a re-export of a common name like read links to the right module instead of a same-named symbol elsewhere; and trait dispatch reaches implementations — a struct whose methods cover a trait's is treated as implementing it, and a call through &dyn Trait resolves to the concrete method. Previously a Rust type linked only when called or used in a type position, so structs built by literal, modules surfaced only through pub use, and trait-only implementations looked like they had no dependents. (#584 for Rust traits)
  • Rust cross-module function calls now resolve to the right file. A call to a sibling submodule's function — users::router(), the common router-assembly / handler-registration pattern where mod users; makes users a child of the current module — is now resolved relative to the current module, not only the crate root. Deeper module-path calls (database::profiles::find() — the db.run(|c| …) data-access shape) now resolve too; these were being discarded before resolution even ran, because the path's leaf function name was never checked. Previously such a call linked to nothing, so a module reached only as module::path::function() looked like it had no dependents; a web app wired this way (Axum, Rocket, and similar) now surfaces its handler and data-access modules' real callers. (Rust)
  • Rocket route handlers now connect to where they're mounted. A handler registered in a routes![a::b::handler, …] or catchers![…] macro used to be invisible — the macro body is a raw token tree, so the handler looked like it had no caller (Rocket mounts it at runtime) and its file showed no dependents. The handler paths are now read out of the macro and linked to the mount/register call, so editing a Rocket handler surfaces its route registration and a routes module is no longer reported as unused. (Rust, Rocket)
  • SvelteKit pages now connect to their server load functions. SvelteKit wires a +page.server.js / +page.js load (and form actions) to the sibling +page.svelte's data by file path, with no import between them — so editing a load previously showed no impact on the page it feeds. Each page is now linked to the load/actions in its own route directory (and likewise for +layout), so editing a loader surfaces the page that renders its data, and tracing a page reaches its server-side data source. (Svelte, SvelteKit)
  • Nuxt nested components are now connected to where they're used. Nuxt auto-imports a component in a subdirectory by a directory-prefixed name — components/media/Card.vue is used in templates as <MediaCard/> — but it was tracked by its file name (Card), so the usage didn't resolve and the component looked unused. PascalCase component tags (<MediaCard>, <NavBar>) in a .vue template are now matched, falling back to the Nuxt directory-prefixed name, so editing a nested component surfaces every page and component that renders it. (Vue, Nuxt)
  • Lua and Luau require calls now connect to their module files. A dotted module path (require("telescope.config")telescope/config.lua or .../config/init.lua) and a Roblox/Luau instance-path require (require(script.Parent.Signal) → the Signal module) now link to the file they load, so editing a module surfaces every file that requires it. Previously requires resolved to nothing, so a Lua/Luau module looked like it had no dependents. (Lua, Luau)
  • Shopify OS 2.0 sections now connect to the JSON templates that use them. Modern Shopify themes define templates as JSON (templates/*.json, plus section groups sections/*.json) that list sections by type rather than with a {% section %} Liquid tag, so a section used only from a JSON template was reported as having no dependents. Those JSON files are now read and each section type is linked to its sections/<type>.liquid, so editing a section surfaces the templates that render it. (Liquid, Shopify)
  • Delphi form definitions now connect to their code-behind units. A .dfm (VCL) or .fmx (FireMonkey) form is owned by its same-named .pas unit through the {$R *.dfm} directive rather than a uses clause, so a form file used only as a definition was reported as having no dependents. The unit is now linked to its form, so editing a form surfaces the unit that owns it. (Pascal/Delphi)
  • Swift property wrappers and attributes are now connected. A @Argument / @Published / @State / custom @propertyWrapper on a property — and attributes on types, methods, and functions (@objc, @MainActor, …) — now record a dependency on the wrapper/attribute type. Previously these were dropped entirely (Swift attributes parse differently from other languages, and stored properties weren't being inspected), so the wrapper type looked unused and the file using it depended on nothing — a big gap for SwiftUI and argument-parser-style code.
  • Swift Fluent relationship models are no longer orphaned. A type referenced only through a property-wrapper argument@Siblings(through: AcronymCategoryPivot.self, …), the many-to-many pivot/join model — now records a dependency on that type. Previously only the wrapper itself (Siblings) and the property's declared type were captured, so a pivot model reached solely through the relationship looked like nothing depended on it and editing it surfaced no impact. (Swift, Vapor/Fluent)
  • Java annotations are now connected. Annotation definitions (@interface Foo) are indexed as types, and every @Foo usage on a class, method, or field is recorded as a dependency on it. Previously neither side was captured — annotation usages were dropped (they live inside the declaration's modifiers) and @interface types weren't indexed at all — so annotation-driven code (Spring @GetMapping, JPA @Entity, Gson @SerializedName, …) showed the annotation as having no users and the annotated class as not depending on it.
  • Kotlin Multiplatform expect/actual declarations are now connected. A platform implementation — actual fun, actual class, or an actual typealias in a jvm / native / js / wasm source set — is linked to the common expect declaration it fulfills (including the common case of an expect class fulfilled by an actual typealias). Previously a caller in common code resolved to the expect declaration, so every platform actual looked like it had no dependents and editing one showed an empty blast radius; now changing a platform implementation surfaces the common API and everything that uses it. (Kotlin)
  • Scala impact and zcodegraph affected now connect the type graph that typeclass-style code is built on. A parameterized supertype (trait Monoid[A] extends Semigroup[A] with Serializable) now links to each parent; a type used in a val/def signature, as a type argument, or as a context bound (def f[A: Monoid]) — including the trailing implicit parameter list ((implicit M: Monoid[A])) where typeclass instances are passed — now records a dependency; and new T[...] { … } counts as an instantiation. Previously Scala linked only plain calls and bare, non-generic supertypes, so a trait extended with type parameters, used as a type, or required as an implicit looked like nothing depended on it — which on a typeclass-heavy codebase (cats, algebra) was most of the graph. (Scala)
  • PHP impact and zcodegraph affected now understand namespaces and use imports. Classes are tracked by their namespaced name, so the many same-named classes a framework defines (Laravel has 7+ Factory interfaces, several Dispatchers, across namespaces) are told apart instead of collapsing into one arbitrary match. A use App\Contracts\Cache\Factory; now records a dependency on exactly that class — so a contract or interface that's imported and constructor-injected (the dependency-injection pattern) is no longer reported as having no dependents — and parameter, property, and return type-hints are recorded too. Previously PHP ignored namespaces entirely and linked only calls, new, and inheritance. (PHP)
  • Objective-C impact and zcodegraph affected are dramatically more complete. Four gaps are fixed: a single-argument message ([cache storeImage:key] — the most common call form) now matches its storeImage: method instead of dropping the colon; a class-message receiver ([SDImageCache sharedCache], [[Foo alloc] init]) now records a dependency on the class, whose @interface lives in the header; #import "Foo.h" now resolves to the header file, so a header is no longer reported as having no dependents; and class-method message calls now resolve through the receiver type. Together these took typical libraries from a third-to-half of their files showing real dependents to ~90%. (Objective-C)
  • A type referenced only through a static member or enum value now records a dependency. Reading an enum value (MediaKind.video), a static constant (Colors.red, JsonScope.EMPTY_DOCUMENT), or a class constant (Foo::BAR) now links to the type — previously only method calls and new did, so a type or enum used purely by value (enum-heavy APIs, constants classes — a very common pattern) looked like nothing depended on it. Applies to Java, C#, Kotlin, Swift, Scala, Dart, PHP, and C++.
  • Dart impact and zcodegraph affected now follow mixins and method type annotations. A with mixin — Dart's core composition mechanism, which Flutter is built on — now records a dependency, so editing a mixin surfaces every class that mixes it in (the whole with clause used to be dropped, and a class declared with M alone even lost its real superclass link). And types used in a method's parameters or return value now link to their definition, so a class or enum referenced only as a type — not constructed or called — is no longer reported as having no dependents. (Dart)
  • C++ free functions are now indexed under their real name. A function written with a qualified-type parameter (std::string TableFileName(const std::string& dbname)) or an auto … -> std::string trailing return type was mistakenly named after that type (string), so calls to it never resolved, codegraph_node couldn't find it by name, and the file defining it looked like nothing depended on it. The function now keeps its real name, so cross-file calls, callers, and blast radius work — a meaningful gain for any namespaced C++ codebase (this is how most free functions in a library look). (C++)
  • Ruby impact and zcodegraph affected now follow mixins and requires. include, extend, and prepend of a module — Ruby's primary composition mechanism (ActiveSupport concerns, Comparable, Enumerable) — now record a dependency on that module, so editing a concern surfaces every class that mixes it in; previously these were read as a call to a method named include, so a module whose methods are exercised only by application code looked like nothing depended on it. And require "lib/foo" / require_relative "../foo" now link to the required file, so a file pulled in only by a require (config-loaded components, gems that don't autoload) is no longer reported as having no dependents. Together these took a typical gem from ~71% of its files showing real dependents to ~100%. (Ruby)
  • C# record types are now indexed. record, record class, and record struct declarations (everywhere in modern C# — DTOs, value objects, CQRS messages, MediatR notifications) were previously skipped entirely, so every reference, generic type argument (IEnumerable<MyRecord>), and new MyRecord(...) pointed at nothing and the file defining a record looked like it had no callers or dependents. (#237)
  • C# is now parsed with an up-to-date grammar that understands C# 12 primary constructors. A class or struct written as class OrderService(IRepo repo, [FromKeyedServices("primary")] ICache cache) { … } is now indexed reliably — previously the constructor parameter list confused the parser and could drop the whole class (and all of its methods) from the index, most often exactly when a parameter carried an attribute, as in the ASP.NET keyed-dependency-injection pattern. The primary-constructor parameters are also recorded as dependencies, so the services a type is constructed with show up in its blast radius and "who depends on this contract" answers. Method return types, base types, and members all continue to resolve, and #if-guarded members in multi-targeting code keep parsing correctly. (#237)
  • Go interfaces now connect to their implementations. Go has no implements keyword — a type satisfies an interface just by having the right methods — so CodeGraph now infers that link: a struct whose methods cover an interface's method set is treated as implementing it, and a call through the interface (API.Marshal(...)) reaches every concrete implementation. This means a type used only via an interface (the common plugin/strategy pattern — e.g. JSON-codec or renderer implementations selected at runtime) is no longer reported as having no callers or no dependents, and impact now flows from an interface method to the implementations behind it. (#584)
  • Go now records cross-package struct creation. A composite literal like render.XML{...} or pkga.Widget{...} — including ones registered in a package-level var registry = map[string]R{...} — now links to the package that defines the type. Cross-package function calls and type references already resolved; this closes struct instantiation, so a package whose types are only constructed elsewhere (a common pattern for interface implementations) is no longer reported as having no dependents. Go type conversions such as (*Wrapped)(x) now link to the converted-to type as well.
  • Python now follows whole-module imports — from . import certs then certs.where(), or from pkg import sub then sub.run(). Calls and attribute access through an imported submodule now resolve to that submodule, and importing a module is recorded as a dependency on it even when the member you use is itself re-exported from a third-party package. This also fixed Python relative-import path resolution generally (from .sub.mod import x), so zcodegraph affected and impact see the real module graph of a package.
  • Python now also links a whole-module absolute import (import conduit.apps.signals) to that module's file, not just from x import y. A module imported by its dotted path — common in package setup and side-effect imports — is no longer reported as having no dependents. Standard-library imports (import os) correctly create no edge. (Python)
  • Python from package import submodule now links to that submodule's file, resolved through the import's package so it lands on the right one when same-named modules exist in sibling packages (the FastAPI / Django router-aggregator pattern: from app.api.routes import authentication with an unrelated authentication.py elsewhere). So a route/handler module pulled in only by an aggregator is no longer reported as having no dependents. (Python)
  • Python now records the actual call edge for a function invoked through an imported module — from pkg import module (or import pkg.module) followed by module.func(), a common testing and namespacing pattern. Previously only the module-level dependency was tracked, so codegraph_callers, codegraph_callees, and impact on the target function came back empty even though the import itself resolved. (#578) (Python)
  • Django include('app.urls') now records a dependency from the project URLconf onto the included app's urls.py, so an app's routes module is no longer reported as having no dependents and editing it surfaces the project that mounts it. (Django)
  • A chained method call (builder.Services.AddCoreServices(...)) now resolves to its definition. Previously only a single-segment receiver (obj.method()) resolved, so a call through a property/member chain — very common for C# extension methods like ASP.NET dependency-injection registration (AddCoreServices/AddWebServices) and Guard clauses — found no definition. (C#, and any language with chained calls)
  • A renamed default import (import articlesController from './article.controller' where the module does export default router) now records a dependency on the imported module. Previously only named imports linked, so a module consumed only through a default import — the standard Express/NestJS route-controller pattern — looked like nothing depended on it. External packages (import React from 'react') still create no edge. (TypeScript/JavaScript)
  • The background file watcher no longer exhausts your machine's file-descriptor budget. On macOS it previously kept one open file handle per watched file, so on a large project the running MCP server could pile up tens of thousands of handles and blow past the system-wide limit — at which point unrelated apps (your shell, editor, Docker, browser) started failing with "too many open files" until the codegraph process was killed. The watcher now uses a single recursive watch on macOS and Windows, and bounded per-directory watches on Linux, so its cost stays flat no matter how large the project is. (#644, #496, #555, #628, #579)
  • Indexing a project with very symbol-dense files (tens of thousands of functions or methods in a single file) no longer runs out of memory. The step that links dynamic call relationships used to load every function and method into memory at once, which could exhaust the heap and abort indexing with "JavaScript heap out of memory" on large or generated codebases; it now streams them, so memory stays flat no matter how many symbols the project has. (#610)
  • Indexing a very large repository no longer aborts during its first sync with a "too many SQL variables" error. (#540)
  • Files under directories with non-ASCII names (for example CJK characters) are no longer silently skipped during indexing. (#541)
  • The .zcodegraph/ index folder no longer clutters git status: its generated ignore file now excludes everything in the folder except itself, so the database, daemon.pid, sockets, and logs stop showing up as untracked changes. (#492, #484)
  • SAP HANA .xsjs / .xsjslib files are now indexed as JavaScript. (#556)
  • TypeScript .mts and .cts module files are now indexed instead of being skipped. (#366)
  • JavaScript modules that wrap their code in an anonymous function — AMD/RequireJS, NetSuite SuiteScript, IIFE bundles — now have their inner functions and calls indexed, instead of the file coming up nearly empty. (#528)
  • Go methods declared on generic types (e.g. func (s *Stack[T]) Push(...)) are now correctly attached to their type, so callers, callees, and impact include them. (#583)
  • Go methods now attach to their receiver type even when declared in a different file from the type itself — the idiomatic split where type User struct{…} lives in one file and func (u *User) Save() in another. Previously a cross-file method was orphaned from its struct, so the type's member list, callers/callees, and impact missed it; as a knock-on, a struct whose interface-satisfying methods are spread across files now also links to the interfaces it implements. (#583)
  • Asking what a symbol impacts no longer drags in every unrelated sibling method of its class — impact now follows real dependencies instead of the structural "contains" relationship, keeping the result focused on what actually depends on the symbol. (#536)
  • CodeGraph's MCP server now answers an agent's resources/list and prompts/list probes with an empty list instead of an error, clearing the -32601 messages some clients (opencode, Codex) logged on connect. (#621)
  • Svelte and Vue components used through a barrel file — export { default as Button } from './Button.svelte' re-exported from an index.ts and imported elsewhere — are no longer falsely reported as having 0 callers. CodeGraph now follows the default re-export all the way to the component and resolves the imports that .svelte / .vue files themselves use, so codegraph_callers and codegraph_impact see every place a component is used. This also covers components imported from another package in a workspace/monorepo (@scope/ui/widgets) and bare directory imports (import { x } from './'). Previously a live component consumed only through a barrel looked like dead code. Thanks @nakisen. (#629)
  • Components used in a Vue Single-File Component's <template><MyButton />, or the kebab-case <my-button /> — are now indexed as usages, so codegraph_callers and codegraph_impact include components that appear only in another component's markup (including through a barrel re-export). Previously only a Vue component's <script> block was analyzed, so template-only usages were invisible. (#629)