All notable changes to CodeGraph are documented here. Each entry also ships as
a GitHub Release tagged
vX.Y.Z, which is where most people will look.
This project follows Keep a Changelog and adheres to Semantic Versioning.
- Impact and blast-radius analysis for TypeScript, JavaScript, Go, Python, Rust, Ruby, C, Java, C#, PHP, Scala, Kotlin, Swift, Dart, and Pascal/Delphi now understands the readers of a constant. When you change a file-scope, package-level, module-level, or class-level constant — a config object, a lookup table, a shared constant — the other symbols in that file that read it now show up as affected, where before they were invisible (impact only followed calls, imports, and inheritance, so a constant's consumers looked like "nothing depends on this"). This makes
codegraph impact, and the impact trail incodegraph_explore/codegraph_node, catch the "change this table, break its readers" class of change. It's on by default and adds no nodes to your graph; bundled/minified files and ambiguously-shadowed names are skipped to keep results precise. SetCODEGRAPH_VALUE_REFS=0to turn it off. - C file-scope constants and globals —
static constscalars, pointer/array lookup tables, and shared mutable globals — are now recognized as symbols in their own right. They previously weren't extracted at all, so they never appeared in search or carried any dependents; now they show up incodegraph searchand participate in impact analysis (see above), so changing a C lookup table surfaces the same-file functions that read it. - Java
static finalconstants, C#const/static readonlyconstants, Scalaobjectvals, and Kotlin top-level /object/companion objectvals are now classified as constants rather than generic fields, so they participate in the constant-reader impact analysis above — change apublic static finaltable, aconst string, a Scalaobject Config { val Timeout = … }, or a Kotlincompanion object { const val … }and the methods that read it now show up as affected. (Per-object Javafinal/ C#readonly/ Scala & Kotlinclassinstance properties are unchanged.) Kotlin constants were previously not indexed as their own symbols at all, so they now also appear incodegraph search. - Swift top-level
lets andstatic letconstants (including those namespaced in anenum/struct, the common Swift pattern) are now indexed as constants and participate in the constant-reader impact analysis above — change astatic let defaultRetryLimitor anenum Constants { static let … }and the same-file code that reads it shows up as affected. Computed properties and per-instancelets are not treated as constants. - Dart top-level
const/finaland classstatic const/static finalconstants are now indexed as constants and participate in the constant-reader impact analysis above. Instance fields,vars, and locals are not treated as constants. (Generated Dart code with the standard.g.dart/.freezed.dart/.pb.dartsuffixes is already skipped.)
codegraph indexnow rebuilds the full graph from scratch, so it produces the same result as a freshcodegraph initinstead of reporting "0 nodes, 0 edges" and looking like it wiped your index. Previously, re-runningindexon an unchanged project skipped every file (their contents hadn't changed) and showed an empty-looking summary; it now clears and re-indexes for an honest, complete rebuild every time. Usecodegraph syncfor fast incremental updates between full rebuilds. Thanks @Arc-univer. (#874)- The file watcher that auto-syncs the graph now fails cleanly when live watching can no longer be trusted, instead of looking healthy while the index quietly goes stale. If the operating system runs out of file-watch resources, or another process holds the write lock far longer than a normal save, CodeGraph now disables auto-sync once — with a single clear message telling you to run
codegraph sync(or rely on the git sync hooks) to refresh — rather than retrying forever or repeating the same error on a loop. And while auto-sync is disabled, CodeGraph's tool responses (andcodegraph status) now say so plainly, so your AI agent knows to read files directly instead of trusting a frozen index. This mostly matters for long-running MCP/daemon sessions, which could otherwise keep serving stale results while appearing to work. Thanks @thismilktea. (#876) - On Linux, hitting the kernel's inotify watch limit on a large project no longer silently leaves half the tree unwatched. CodeGraph now tells you once — naming the exact setting to raise (
fs.inotify.max_user_watches, e.g.sudo sysctl fs.inotify.max_user_watches=1048576) — and keeps live-watching the directories it could register whilecodegraph sync(or the git sync hooks) covers the rest. (#876)
1.0.1 - 2026-06-13
- New
codegraph daemoncommand (aliasdaemons) — an interactive manager for the background daemons. It shows what's running (your current project's daemon first, pre-selected), and you arrow-key to one and press enter to stop it, or pick "Stop all". Previously the only way to shut a daemon down was to hunt for its pid andkillit by hand. (#845) - Checking your installed version is now easy to reach however you guess at it:
codegraph version,codegraph -v, andcodegraph -versionall print it, alongside the existingcodegraph --version. (#864) - The CodeGraph MCP server now self-heals if its main thread ever locks up. A lightweight watchdog notices when the process has stopped responding and stops it so a fresh one starts on your next request — it can no longer sit pinned at 100% CPU with no way to recover. Tune the detection window with
CODEGRAPH_WATCHDOG_TIMEOUT_MS, or turn it off entirely withCODEGRAPH_NO_WATCHDOG=1. (#850)
- Git worktrees nested inside your project — like the
.claude/worktrees/that Claude Code creates — are no longer indexed as duplicate copies of your whole codebase. CodeGraph deliberately indexes genuine embedded repos (a real second project checked out inside yours), but a worktree is just another working view of a repo it already indexed, so each one was multiplying every symbol — one report went from ~1,850 files to over 24,000, with search andexploreflooded by stale duplicates. CodeGraph now recognizes worktrees and skips them, while still indexing real embedded repos and submodules. Thanks @tphakala. (#848) - Running
codegraph serve --mcpby hand no longer just hangs in silence. That command is the MCP server your AI agent starts for itself — not a step you run directly — and in a terminal it used to sit there waiting for input that never comes, looking broken. It now recognizes when a person runs it and explains what to do instead (codegraph status,codegraph daemon), and it's been dropped from the command listing so it stops looking like something you need to launch. - Cross-file static method calls like
ClassName.staticMethod()now resolve correctly. CodeGraph was linking the call to the class instead of the method (and recording it as a construction), socallersandimpactfor a static method came back empty — a real blind spot in TypeScript and JavaScript codebases that lean on static utility classes (Python and other languages with the same call shape benefit too). The call now links to the method itself. Thanks @contextFlow-lab. (#825) codegraph affectednow accepts./-prefixed and absolute file paths, not just bare project-relative ones. Passing./src/x.tsor an absolute path — common when the file list comes from another tool — used to silently match nothing and report no affected tests. Thanks @contextFlow-lab. (#825)- The CodeGraph MCP server no longer risks getting stuck at 100% CPU after an unexpected internal error. Previously such an error was logged but the process was left running in a broken state, where it could spin a CPU core indefinitely and had to be killed by hand. The server now logs the error and exits cleanly, so a fresh one starts on the next request. Thanks @songhlc. (#850)
- CodeGraph no longer indexes your entire home directory by accident. Running the installer — or
codegraph init/codegraph index— from your home folder or a filesystem root would index everything underneath it (caches,Library, every other project), producing a multi-gigabyte index and constant file-watching churn. CodeGraph now refuses these roots and points you at a specific project instead; pass--forceif you genuinely mean to. (Combined with the macOS file-descriptor fix already in 1.0.0, this closes the report of a runaway watcher exhausting the system file limit.) Thanks @ligson. (#845)
1.0.0 - 2026-06-12
- 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 incodegraph_exploreorcodegraph_nodeoutput. 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)
-
CodeGraph now indexes R (
.R/.r) — functions in every assignment form (name <- function(...),name = function(...), nested definitions), S4 / Reference / R6 classes with their methods,setGeneric/setMethodgenerics, top-level variables and constants,library()/require()imports,source()file references, and call edges — including calls inside tidyverse pipe chains. Statistical and research codebases get the full explore / impact / callers surface. (#828) (R) -
Workspaces holding multiple git repositories now index as a whole. Running
codegraph initat the root of a directory that contains several independent git repos — including the common "super-repo" layout where the parent repo's.gitignorehides the child repos to keepgit statusquiet — now indexes every nested project into one graph, with each child repo's own.gitignorerespected.codegraph syncand live file watching pick up changes inside the nested repos too (previously change detection only consulted the parent repo, so edits in child repos were invisible until a full re-index). Git repositories insidenode_modules(npm git-dependencies) remain excluded. (#514) -
codegraph_explorenow explains where a flow ends instead of going silent. When the symbols you ask about don't connect statically — because the code dispatches through a runtime mechanism like a computed call (handlers[action.type](...)), Python'sgetattr, a command/mediator bus (sender.Send(new DeleteCommand(...))), reflection, ornew Proxy— explore now announces the exact dispatch site (file and line) where the static path stops, and when the dispatch key is visible in the source it shortlists the likely runtime targets (for example pointing a MediatR command straight at itsHandler.Handlemethod). Detection is deterministic and runs only when a flow fails to connect; fully connected flows are unchanged, and nothing about indexing or the graph itself changes. Relatedly, a custom event bus whose emit and handler connect through a single synthesized hop now shows that hop explicitly (with the registration site) — it previously rendered nothing because the connection was "too short" for the flow section. (#687) -
Anonymous usage telemetry, documented field-by-field and easy to turn off. CodeGraph now collects a small set of anonymous usage statistics — which commands and MCP tools get used, which languages get indexed, which agents connect — so language and agent support work goes where real usage is. Never any code, file paths, file or symbol names, search queries, or IP addresses; usage aggregates locally into daily totals before anything is sent, and the ingest endpoint is public, auditable code in the repository that enforces the documented field list. The installer asks up front with a visible default-on toggle (and never re-asks); everywhere else a one-line notice prints before the first send. Disable any time with
codegraph telemetry off,CODEGRAPH_TELEMETRY=0, or the cross-toolDO_NOT_TRACK=1standard — off means off: nothing is recorded, nothing is sent, and buffered data is deleted.TELEMETRY.mddocuments every field. -
Subagents and non-MCP agents can now reach CodeGraph. Two new CLI commands —
codegraph explore "<symbols or question>"andcodegraph node <symbol-or-file>— print exactly what the matching MCP tools return (relevant symbols' source + call paths; one symbol's source + callers; file reads with line numbers), so any agent with a shell can use the graph. Andcodegraph installnow writes a small marker-fenced CodeGraph section into each agent's instructions file (CLAUDE.md/AGENTS.md/GEMINI.md) pointing at both surfaces — that file is what Task-tool subagents actually see, where the MCP server's own guidance only reaches the main agent. Measured on a delegated code-exploration task: subagents went from almost never using CodeGraph (~1 in 9 runs) to using it in every run, including runs with zero grep/file-reading fallback. The section is small, survives your own content, upgrades cleanly from the old long block, andcodegraph uninstallremoves it. Thanks @liuyao37511. (#704) -
The MCP tool list is now a focused default of four —
codegraph_explore,codegraph_node,codegraph_search, andcodegraph_callers. The other four (codegraph_callees,codegraph_impact,codegraph_files,codegraph_status) remain fully functional — the CLI and library API are unchanged, andCODEGRAPH_MCP_TOOLSre-enables any of them — but they're no longer listed to agents by default: measured agent behavior shows they're never or rarely picked, and the information they carry already arrives inline on the tools agents do use (explore's blast-radius section, node's dependents note, a symbol's own body as its callee list). A leaner list saves context tokens every session and steers agents to the right tool by presence alone. -
CodeGraph now goes quiet instead of failing loudly in unindexed projects. When an AI agent's session starts in a workspace that has no CodeGraph index, the MCP server now announces itself as inactive with a short note and lists no tools at all — instead of presenting the full toolset and erroring on every call, which taught agents to distrust CodeGraph even where it works. Querying another project that isn't indexed likewise returns clear guidance (use your regular tools for that codebase; the user can run
codegraph initthere to enable CodeGraph) instead of an error, and genuine internal errors now tell the agent to retry once rather than give up on CodeGraph entirely. Indexing stays your decision — agents are told not to run it themselves. (#769) -
Astro projects are now indexed.
.astrofiles previously weren't parsed at all — on a typical Astro site that left most of the codebase invisible to search, impact, andcodegraph_explore. CodeGraph now extracts the TypeScript frontmatter (functions, imports,getStaticPaths, …) and client-side<script>blocks, captures function calls and<Component>usages in template markup so cross-component dependencies trace end-to-end, resolves theAstroglobal andastro:*module imports as framework-provided, and mapssrc/pages/file-based routing to route nodes (.astropages and.tsendpoints, including[param]and[...rest]dynamic segments, with underscore-prefixed files correctly excluded). Validated on two real-world Astro sites with 93% measured cross-file coverage and every page mapping to its route. Thanks @xingwangzhe. (#768) (Astro) -
Same-named symbols across a monorepo's apps are no longer conflated. In a NestJS-style workspace with one
UserServiceper app,codegraph_callers,codegraph_callees, andcodegraph_impactnow report one section per distinct definition — each app's callers and blast radius under its own file-labeled heading — instead of a single merged list, and accept afileargument to focus exactly the definition you mean (likecodegraph_nodealready did). Impact in particular no longer overstates a change's blast radius by merging unrelated same-named classes. Thanks @Igorgro. (#764) -
Fixed a related source of cross-package wrong edges: PascalCase type references from plain
.tsfiles were being resolved as React components, which could link a file's own type alias to an arbitrary same-named class in another package (on one large monorepo this produced over a thousand wrong cross-package reference edges; 96% are now gone, and the remainder are genuine shared-model imports). Component resolution now applies only to references from JSX-capable files and never guesses between multiple candidates without a positional signal. The Svelte and Vue component resolvers had the same arbitrary-pick flaw (Vue resolved the first same-named.vuefile found anywhere in the tree) and now follow the same rule: same-directory first, otherwise only an unambiguous name resolves. Re-index a project to benefit. (#764) (TypeScript, React, Svelte, Vue) -
TypeScript and JavaScript class fields are now reported as properties instead of methods. A plain field like
public fonts: Fonts;previously extracted as a method, misrepresenting class shape and letting calls to same-named functions resolve to data fields (a boolean field namedisArraywas soaking upArray.isArray(...)call edges). Fields holding arrow functions or function expressions (onClick = () => {…}, including wrapped ones likeonScroll = throttle(() => {…})) correctly remain methods and their bodies are still analyzed. Field initializers are analyzed too, sohistory = createHistory()records its call — and JavaScript class fields, which previously produced no symbol at all, now appear in the graph. Re-index a project to benefit. (#808) (TypeScript, JavaScript) -
Callback registration through
thisnow resolves precisely in TypeScript and JavaScript:window.addEventListener("online", this.onOfflineStatusToggle)or an API object like{ mutateElement: this.mutateElement }produces a reference edge to the enclosing class's own method — never a same-named method on an unrelated class, and never a data field. Builds on the callback-registration support below. (#808) (TypeScript, JavaScript) -
Callback-registration coverage deepened across four more shapes: a
this.<member>registration whose method lives on a base class now resolves through the inheritance chain (bus.on("submit", this.handleSubmit)in a subclass links to the parent'shandleSubmit); Java and Kotlin method references to other classes (Handlers::onMessage,OtherClass::handle) resolve across files, withthis::andsuper::scoped to the defining class and references through a variable deliberately left out; and Swift bare callback names now match only the enclosing type's methods (implicitself), eliminating a class of wrong edges where a parameter likerequestlinked to a same-named method on an unrelated type. (Java, Kotlin, Swift, TypeScript, JavaScript) -
PHP string and array callables now register: a string passed to a callable-taking core function (
usort($items, 'cmp_items'),array_map('absint', …),call_user_func,spl_autoload_register, …) links to that function — including across files — and the array forms[$this, 'method']and[Foo::class, 'method']link to the named method (the$thisform resolves through the class and its parents). Strings passed to arbitrary functions are deliberately ignored: only known callable positions are trusted. Validated on WordPress core (+556 edges, every sampled edge a genuine registration). (PHP) -
Ruby lifecycle-hook symbols now register:
before_action :authenticate,after_save :reindex,around_create,validate :check,rescue_from(…, with: :handler)and friends link the symbol to the method it names — on the class itself or inherited from a parent (before_action :authenticatein a controller resolves toApplicationController's method).validates(plural) is excluded since its symbols name attributes, not methods. Validated on rails/rails (+385 edges, every sampled edge genuine). (Ruby) -
Method references to a type that needed no import now resolve: Java/Kotlin same-package references (
.concatMapMaybe(Maybe::just, …)), Kotlin companion-object members (KtHandlers::handle), and cross-file C++ member pointers (&TestSuite::RunSetUpTestSuite). Resolution stays anchored to the named type, so a same-named member on a different class never matches. (Java, Kotlin, C++) -
CodeGraph now sees where a function is registered as a callback, not just where it's called. A function name passed as an argument (
signal(SIGINT, handler),qsort(…, compare),addEventListener(…, onBlur)), assigned to a function pointer or field (ops->recv_cb = my_cb,OnClick := Handler), or placed in a struct initializer or handler table ({ .recv_cb = my_cb },{ "get", getCommand }) now produces a reference edge from the registration site to the function — socodegraph_callersandcodegraph_impactsurface callback wiring that previously looked like dead code. Works across all supported languages, including the language-specific forms: C/C++&fn, JavaClass::method, Kotlin::fn, Swift#selector, Objective-C@selector, Rubymethod(:fn), Scala eta-expansion, and Delphi/Pascal@HandlerandOnClick := Handlerevent wiring. Callers output labels these "via callback registration". Resolution is deliberately conservative: an ambiguous name produces no edge rather than a wrong one. Re-index a project to benefit. Thanks @zmcrazy. (#756) -
The
codegraph_nodeMCP tool can now read a whole source file like the built-in Read tool — only faster, served from the index. Pass a file path with no symbol and it returns that file's current source with line numbers (the same<n>⇥<line>shape Read produces, so an assistant can edit straight from it), narrowable withoffset/limitexactly like Read, plus a one-line note of which files depend on it (the file's blast radius). Use it anywhere you'd reach for Read on an indexed source file. PasssymbolsOnly: truefor just the file's structure. Configuration/data files (.yml/.properties) are summarized by key only, never dumped, so secrets in them are never surfaced. The agent-facing guidance was also retuned so assistants reach for codegraph while implementing a change (not only when answering questions), since one codegraph call returns the same bytes plus the blast radius, faster than re-reading the file. -
New
codegraph upgradecommand updates CodeGraph to the latest release in place — it detects how you installed (the standaloneinstall.sh/install.ps1bundle, npm, or npx) and does the right thing for each, on macOS, Linux, and Windows. Usecodegraph upgrade --checkto see whether an update is available without installing, orcodegraph 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) -
codegraph statusnow flags when a project's index was built by an older engine than the one you're running and recommends re-indexing (also surfaced incodegraph status --json), so you know when acodegraph index -forcodegraph syncwill 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#
record structandreadonly record structdeclarations now index with the correctstructkind, and positional one-liner records (public record struct Money(decimal Amount);) index reliably in every form — previously a bodiless value-type record could be skipped entirely and could halt extraction of the declarations following it in the same file. (#831) (C#) -
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/@injectdirective links the view to the C# view-model, base type, or service it names; a Blazor<MyComponent/>tag (plus@typeof(...)and genericTItem="..."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
@usingnamespaces — including the folder's cascading_Imports.razor— so a simple name that exists in several namespaces lands on the right one. A@model/<MyComponent>/@codereference toCatalogBrandresolves to the@using'd DTO (BlazorShared.Models.CatalogBrand) rather than a same-named domain entity. (ASP.NET, Blazor) -
codegraph status --jsonnow also reports the running CLIversion, the index directory (indexPath), and alastIndexedtimestamp (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 matchingCodeGraph.getLastIndexedAt()library method exposes the same freshness check without shelling out. Thanks @12122J and @eddieran. (#329) -
TypeScript service/RPC contracts defined as a tuple of generic types —
type MyServiceList = [Service<'query_apply_record', …>, Service<'apply_confirm', …>]— now index each entry's string-literal name as a searchable symbol. Previously these names existed only as type arguments, socodegraph query query_apply_recordfound nothing even though the names are the app's primary API surface. The pattern is common in typed RPC / BFF clients and mock servers where the types are the source of truth for a runtime proxy object. Utility types (Pick,Omit,Record) and route paths are deliberately left out to avoid noise. Thanks @jiezhiyong. (#634) (TypeScript) -
New
CODEGRAPH_DIRenvironment variable sets the per-project index directory name (default.codegraph). This lets one working tree hold two independent indexes — most usefully when you open the same checkout from both Windows and WSL, which can't safely share a single.codegraph/: the background-server lock and the SQLite database are tied to the OS that wrote them, and SQLite locking across the WSL2/Windows filesystem boundary is unreliable. SetCODEGRAPH_DIR=.codegraph-winon the Windows side, leave WSL on the default, and each keeps its own index in the same folder without clobbering the other. CodeGraph also skips any sibling.codegraph-*directory when indexing and watching, so neither environment trips over the other's data. Thanks @rrtt2323. (#636)
- opencode on Windows now finds CodeGraph. The installer wrote opencode's global MCP entry to
%APPDATA%\opencode\, but opencode reads its config from~/.config/opencode/on every platform (honoringXDG_CONFIG_HOME), so the entry was invisible to it. Installs now write where opencode actually looks, andcodegraph install/codegraph uninstallboth clean a stale CodeGraph entry out of the old%APPDATA%location — other servers and comments in that file are left untouched. Thanks @fucknoobhanzo for the report and @WodenJay for the first patch. (#535) - The
codegraph_searchtool'skind: "type"filter — a value its own schema advertises — silently matched nothing; it now correctly finds type aliases. Thecodegraph_exploretool's parameter guidance also no longer suggests runningcodegraph_searchfirst, which contradicted explore's call-it-first design and cost agents an extra round-trip. - Symbols defined in Svelte and Vue
<script>blocks were reported one line below where they actually are — a function on line 3 was reported at line 4 — which offset every script-block symbol's location in search,codegraph_node, and explore output. Line numbers now match the file exactly. Re-index a project to benefit. (Svelte, Vue) - Doc comments are now captured for exported,
const-assigned, and decorated declarations, and the documentation a symbol carries is now clean across every supported language. Previously a comment aboveexport class X,export const fn = () => …, a plainconst fn = () => …, or a decorated Pythondef/class(@app.route(...),@dataclass) was dropped entirely — only comments directly above a plain declaration were kept. CodeGraph now finds the comment through theexport/const/ decorator wrapper. Comment-marker cleanup was also rounded out for every language CodeGraph supports: Rust/Swift/Kotlin doc lines (///,//!), Python/Ruby/shell#, Lua/Luau (--and--[[ ]]), and Pascal ({ }and(* *)) no longer leave stray markers in the stored text — validated end-to-end across all 19 code languages plus Svelte/Vue<script>blocks. (#780). Thanks @caleb-kaiser. - Go method calls made through a chained factory function now resolve to the correct type. A call like
New().Method()used to drop the receiver, so the chained method attached to a same-named method on an unrelated type — or didn't resolve. CodeGraph now captures Go return types (a pointer*Fooresolves toFoo, and a multi-return(*Foo, error)to its first result), infers the chained receiver's type from what the factory function returns, and resolves the method on it — including methods promoted from an embedded struct — creating the edge only when the type or an embedded type genuinely has the method. Existing Go indexes should be re-indexed (codegraph index -f) to benefit. (#750) (Go) - Scala method calls made through a companion-object factory, a fluent chain, or a case-class
applynow resolve to the correct type. A call likeFoo.create().bar()orBuilder(cfg).bar()used to drop the receiver, so the chained method silently attached to a same-named method on an unrelated type — most often mis-attributing a standard-libraryOption/Iterator.map/.flatMap/.foreachonto your own same-named class. CodeGraph now captures Scala return types (a genericList[Foo]resolves to its containerList, a qualifiedpkg.FootoFoo), infers the chained receiver's type from what the inner call returns or constructs, and resolves the method on it — including methods inherited from a trait the type extends — creating the edge only when that type or one of its traits genuinely has the method (so a wrong inference produces no edge instead of a misleading one). Existing Scala indexes should be re-indexed (codegraph index -f) to benefit. (#750) (Scala) - Rust method calls made through a chained associated function now resolve to the correct type. A call like
Foo::new().bar()orFoo::with(cfg).build()used to drop the receiver, so the chained method silently attached to a same-named method on an unrelated type — or didn't resolve. CodeGraph now captures Rust return types (-> Selfresolves to the implementing type), infers the chained receiver's type from what the associated function returns, and resolves the method on it — including methods provided by a trait the type implements (via the newimpl Trait for Typerelationships) — creating the edge only when the type or one of its traits genuinely has the method. Existing Rust indexes should be re-indexed (codegraph index -f) to benefit. (#750) (Rust) - Dart method calls made through a static factory, a factory or named constructor, or a fluent chain now resolve to the correct type. A call like
Foo.create().bar()used to drop the receiver, so the chained method silently attached to a same-named method on an unrelated type — most often mis-attributing a standard-libraryOption/Iterator.map/.whereonto your own same-named class. CodeGraph now indexes Dart factory and named constructors (factory Foo.create(),Foo.named()) as first-class members so calls to them resolve, captures Dart return types (a genericList<Foo>resolves to its containerList), infers the chained receiver's type from what the inner call returns or constructs, and resolves the method on it — including methods inherited from a superclass or mixin — creating the edge only when that type genuinely has the method. Plain construction (Foo(...)) is still recorded as instantiation. Existing Dart indexes should be re-indexed (codegraph index -f) to benefit. (#750) (Dart) - Objective-C methods called through a chained message send now resolve to the correct class. A call like
[[Foo create] doIt]used to drop the receiver, sodoItsilently attached to a same-named method on an unrelated class — most often a test helper or stdlib class. CodeGraph now captures Objective-C method return types and infers the chained receiver's type from what the inner message returns. For the ubiquitous[[X alloc] init]and singleton ([[X sharedInstance] …]) patterns — where the factory returnsinstancetype— the receiver is the classXitself, so the chained method resolves onX(including methods inherited from a superclass), creating the edge only when the class genuinely has the method. Existing Objective-C indexes should be re-indexed (codegraph index -f) to benefit. (#750) (Objective-C) - Pascal/Delphi methods called through a chained factory call now resolve to the correct class. A call like
TFoo.GetInstance().DoIt()used to drop the receiver, soDoItsilently attached to a same-named method on an unrelated class. CodeGraph now captures Pascal return types and infers the chained receiver's type from what the factory function returns — resolving to the declared type (including an interface return likeIFoo), and for a constructor (TFoo.Create().…) or a typecast (TFoo(x).…) to the classTFooitself, since both yield aTFoo. The edge is created only when that type genuinely has the method (so a wrong inference produces no edge). Existing Pascal/Delphi indexes should be re-indexed (codegraph index -f) to benefit. (#750) (Pascal/Delphi) - Pascal/Delphi paren-less method calls are now tracked. Pascal lets a no-argument method or procedure drop its parentheses (
Obj.Free;,List.Clear;,TFoo.GetInstance.DoIt;), which previously weren't recorded as calls at all — so callers, impact, and trace missed them. CodeGraph now extracts these, scoped to statement position so a field or property access (which looks identical) is never mistaken for a call. On a real Delphi codebase this added ~1,100 previously-missing call edges with no false positives. Existing Pascal/Delphi indexes should be re-indexed (codegraph index -f) to benefit. (Pascal/Delphi) - Pascal/Delphi calls inside a standalone procedure or function (one with no
interfacedeclaration, defined only in theimplementationsection) are now attributed to that routine instead of the whole file. Previously such a routine had no symbol of its own, so everything it called was lumped under the unit —codegraph_callersreturned the file, and impact couldn't tell which routine was responsible. These routines are now indexed and their calls attributed correctly. Existing Pascal/Delphi indexes should be re-indexed (codegraph index -f) to benefit. (Pascal/Delphi) - Chained method calls now resolve when the chained method is inherited from a superclass or declared on an interface/protocol the receiver's type conforms to — for example a call on a sealed-subclass instance (
Either.Right(x).combine(...)) that invokes a method defined on its parent type. Previously these chains found no caller edge even though the factory's type was known, so the call was invisible to callers, impact, and trace. CodeGraph now walks the type's supertypes (itsextends/implementsrelationships) to find the method, creating the edge only when a supertype genuinely declares it (so a wrong inference still produces no edge). This makes Java, Kotlin, and C# factory and fluent chains more complete. Existing indexes should be re-indexed (codegraph index -f) to benefit. (#750) - Swift method calls made through a static factory, fluent chain, or constructor now resolve to the correct class. A call like
Foo.make().draw()orFoo().draw()used to drop the receiver, so the chained method silently attached to a same-named method on an unrelated class — or didn't resolve at all. CodeGraph now captures Swift return types and infers the chained receiver's type from what the inner call returns (or the constructed type), creating the edge only when that class genuinely has the method (so a wrong inference produces no edge instead of a misleading one). Existing Swift indexes should be re-indexed (codegraph index -f) to benefit. (#750) (Swift) - C# method calls made through a static factory or fluent chain now resolve to the correct class. A call like
Foo.Create().Bar()orJObject.Parse(s).Property(...)used to lose the receiver's type, so the chained method didn't resolve and the call was invisible to callers/impact/trace. CodeGraph now captures C# return types and infers the chained receiver's type from what the inner call returns, creating the edge only when that class genuinely has the method (so a wrong inference produces no edge). Existing C# indexes should be re-indexed (codegraph index -f) to benefit. (#750) (C#) - Kotlin method calls made through a companion-object factory or fluent chain now resolve to the correct class. A call like
Foo.getInstance().bar()orConfig.create(opts).build()used to drop the receiver entirely, so the chained method silently attached to a same-named method on an unrelated class — or didn't resolve at all — corrupting callers, impact, and trace. CodeGraph now captures Kotlin return types and infers the chained receiver's type from what the inner call returns, creating the edge only when that class genuinely has the method (so a wrong inference produces no edge instead of a misleading one). Existing Kotlin indexes should be re-indexed (codegraph index -f) to benefit. (#750) (Kotlin) - Java method calls made through a static factory or fluent chain now resolve to the correct class. A call like
Foo.getInstance().bar()orConfig.create(opts).build()used to lose the receiver's type, so when two classes had a same-named method the call silently attached to whichever was indexed first — or didn't resolve at all — corrupting callers, impact, and trace. CodeGraph now captures Java return types and infers the chained receiver's type from what the inner call returns, creating the edge only when that class genuinely has the method (so a wrong inference produces no edge instead of a misleading one). Covers factories and fluent builders that take arguments (hashKeys().arrayListValues()), including builders that return a nested type. Existing Java indexes should be re-indexed (codegraph index -f) to benefit. (#750) (Java) - PHP: a method called through a chained static factory —
Cls::for($x)->method(...), the canonical Laravel per-credential / per-tenant client idiom — now records a caller edge. Previously the receiver type (whatfor()returns) was never recovered, socodegraph_callersreturned nothing for the method and the call was invisible tocodegraph_impact. CodeGraph now captures PHP return types —: self/: staticresolve to the declaring class,: SomeClassto that class — and resolves the chained method on the factory's result, creating the edge only when that class actually has the method (so a wrong inference produces no edge). Existing PHP indexes should be re-indexed (codegraph index -f) to benefit. Thanks @cvanderlinden. (#608) (PHP) - Search relevance: including the project name in a query (a user naturally writes
MyApp backend routes) no longer buries the part of the codebase the query is actually about. The project name lexically matches whatever stack embeds it — aMyAppFrontend/directory, aMyAppAppclass — and it was over-weighted two ways: a single PascalCase word was scored once per sub-token (my/app/myapp), so one concept boosted that path several times over; and the name carried full path / disambiguation weight even though it names the whole repo, not any symbol. Now path relevance counts each query word once, and a word matching the project name (derived fromgo.mod,package.json, or the repo directory) is dropped from path scoring and fromcodegraph_explore's type-disambiguation bias — unless it's the only term, so a bare project-name search still works. In a mixed-stack repo, a backend question now surfaces the backend even with the project name in the query. Thanks @MiNuo1. (#720) - Go: a function called only from inside an anonymous closure — a cobra
RunE: func(…) {…}handler, a goroutine literal, or a callback closure stored in a package-levelvar— now shows its real caller. Previously the call leaked to the file node, socodegraph_callersandcodegraph_impactreported such a function as having no meaningful caller; the call is now attributed to the enclosing declaration, so editing the function surfaces the closures that use it. Existing Go indexes should be re-indexed (codegraph index -f) to benefit. Thanks @Cyclone1070. (#693) (Go) - Indexing no longer aborts when a
.gitignorecontains non-UTF-8 bytes or an unparseable pattern. A.gitignoretransparently encrypted in place by corporate DLP / endpoint-security software (a common enterprise scenario) — or one with a stray pattern the matcher can't compile (\[, producing "Unterminated character class") — used to crash the entiresync/indexwith a screen of garbled bytes and never name the offending file, leavingFiles: 0 / Nodes: 0. CodeGraph now skips a.gitignorethat isn't valid UTF-8 text whole, drops only the individual unparseable patterns from a text one, and logs a warning naming the file — indexing continues either way. Thanks @zhanghang-9527. (#682) - C++ method calls made through a singleton, factory, or chained getter now resolve to the correct class. A call like
Foo::instance().bar(),WidgetFactory::create().draw(),openSession()->run(), or the same stored in anautolocal first, used to lose the receiver's type — so when two classes had a same-named method the call silently attached to whichever was indexed first (or didn't resolve at all), corrupting callers, impact, and trace. CodeGraph now infers the receiver's type from what the inner call returns (capturing C++ return types for the first time) and creates the edge only when that class genuinely has the method, so a wrong guess produces no edge instead of a misleading one. Covers singletons and self-returning accessors, factories that return a different type, free-function factories,make_unique/make_shared/new/ direct construction, and single-level member chains. Existing C/C++ indexes should be re-indexed (codegraph index -f) to benefit. Thanks @stabey. (#645) (C/C++) - The shared background server no longer logs a scary-looking
[error] … undefinedline 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 — setCODEGRAPH_MCP_LOG_ATTACH=1to 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 MCP server now shuts down cleanly when its editor/agent connection drops abruptly, instead of risking an orphaned process that pins a CPU core. Editors talk to a stdio MCP server over a socket; if that socket failed with an error rather than closing cleanly — which can happen when the editor window is reloaded or the launching process is killed — the server didn't treat it as a disconnect and could be left running. CodeGraph now treats any failure of its input stream as a shutdown signal and tears the stream down, so an orphaned server exits promptly. (#799)
- 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 firessendEvent(…, "batteryLevelChanged", …)links to the JSaddListener('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 (@ReactMethodon 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 aType.memberstatic read in native code (e.g. Android'sBatteryManager.EXTRA_LEVEL) no longer falsely links to a coincidentally same-named class in another language (a webBatteryManager) — 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
TestRunnertype and a KotlinTestRunnerclass, a TS reference toTestRunner— or animport Reactsitting next to a SwiftReact— 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-CFoo.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 AndroidFoo.hside by side) the local one correctly shows its dependents instead of an arbitrary other-platform header looking like the dependency. And a Kotlin Multiplatformexpectdeclaration is no longer reported as having no dependents: acommonMainimport now resolves to thecommonMainexpect(matched within the importing source set) rather than being absorbed by one platform'sactual. (C/C++, Kotlin) codegraph affectednow reports the tests and files that actually depend on your changes. It used to follow onlyimportstatements — 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 classextends/implements), sogit diff --name-only | codegraph affectedsurfaces the test files that exercise the changed code. Circular-dependency detection, which had the same blind spot, now works too.- Blast radius, callers, and
codegraph affectednow 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 Xis recorded as a dependency on that module even whenXis 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. codegraph_callers(and thecallerscommand) now lists the places a class is instantiated, not just where it's imported. Constructing a class —Foo(...)in Python,new Foo()elsewhere — is calling its constructor, so asking who calls a class now returns the construction sites, andcodegraph_callees/ trace cross the instantiation the same way. Previously a class's instantiation sites were invisible tocallers, so "what breaks if I change this class?" could come back empty even when the constructor was called from many places. Works on your existing index — no re-index needed. (#774)- Rust impact and
codegraph affectednow connect far more of the module graph. Struct literals (Widget { n: 1 }) are recorded as instantiations; ause/pub usebrings its item into the dependency graph — so apub usere-export hub (amod.rsre-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 likereadlinks 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 Traitresolves 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 throughpub 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 wheremod users;makesusersa 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()— thedb.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 asmodule::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, …]orcatchers![…]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 themount/registercall, 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
loadfunctions. SvelteKit wires a+page.server.js/+page.jsload(and formactions) to the sibling+page.svelte'sdataby file path, with no import between them — so editing aloadpreviously showed no impact on the page it feeds. Each page is now linked to theload/actionsin 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.vueis 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.vuetemplate 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
requirecalls now connect to their module files. A dotted module path (require("telescope.config")→telescope/config.luaor.../config/init.lua) and a Roblox/Luau instance-path require (require(script.Parent.Signal)→ theSignalmodule) 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 groupssections/*.json) that list sections bytyperather 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 sectiontypeis linked to itssections/<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.pasunit through the{$R *.dfm}directive rather than ausesclause, 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@propertyWrapperon 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@Foousage 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@interfacetypes 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/actualdeclarations are now connected. A platform implementation —actual fun,actual class, or anactual typealiasin ajvm/native/js/wasmsource set — is linked to the commonexpectdeclaration it fulfills (including the common case of anexpect classfulfilled by anactual typealias). Previously a caller in common code resolved to theexpectdeclaration, so every platformactuallooked 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
codegraph affectednow 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 aval/defsignature, 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; andnew 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
codegraph affectednow understand namespaces anduseimports. Classes are tracked by their namespaced name, so the many same-named classes a framework defines (Laravel has 7+Factoryinterfaces, severalDispatchers, across namespaces) are told apart instead of collapsing into one arbitrary match. Ause 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
codegraph affectedare dramatically more complete. Four gaps are fixed: a single-argument message ([cache storeImage:key]— the most common call form) now matches itsstoreImage:method instead of dropping the colon; a class-message receiver ([SDImageCache sharedCache],[[Foo alloc] init]) now records a dependency on the class, whose@interfacelives 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 andnewdid, 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
codegraph affectednow follow mixins and method type annotations. Awithmixin — 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 wholewithclause used to be dropped, and a class declaredwith Malone 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 anauto … -> std::stringtrailing return type was mistakenly named after that type (string), so calls to it never resolved,codegraph_nodecouldn'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
codegraph affectednow follow mixins andrequires.include,extend, andprependof 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 namedinclude, so a module whose methods are exercised only by application code looked like nothing depended on it. Andrequire "lib/foo"/require_relative "../foo"now link to the required file, so a file pulled in only by arequire(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#
recordtypes are now indexed.record,record class, andrecord structdeclarations (everywhere in modern C# — DTOs, value objects, CQRS messages, MediatR notifications) were previously skipped entirely, so every reference, generic type argument (IEnumerable<MyRecord>), andnew 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
implementskeyword — 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{...}orpkga.Widget{...}— including ones registered in a package-levelvar 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 certsthencerts.where(), orfrom pkg import subthensub.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), socodegraph affectedand 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 justfrom 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 submodulenow 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 authenticationwith an unrelatedauthentication.pyelsewhere). 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(orimport pkg.module) followed bymodule.func(), a common testing and namespacing pattern. Previously only the module-level dependency was tracked, socodegraph_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'surls.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 doesexport 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
.codegraph/index folder no longer cluttersgit 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) - Projects initialized by an older version now get that fix automatically: a
.codegraph/.gitignorewritten before this change — which listed only the database, cache, and logs and so let the daemon'sdaemon.pidget committed — is upgraded in place the next time you run any CodeGraph command. A.gitignoreyou've customized yourself is left untouched. (#788) - SAP HANA
.xsjs/.xsjslibfiles are now indexed as JavaScript. (#556) - TypeScript
.mtsand.ctsmodule 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
typeitself — the idiomatic split wheretype User struct{…}lives in one file andfunc (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/listandprompts/listprobes with an empty list instead of an error, clearing the-32601messages 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 anindex.tsand 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/.vuefiles themselves use, socodegraph_callersandcodegraph_impactsee 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, socodegraph_callersandcodegraph_impactinclude 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) - PHP:
include/require/include_once/require_onceof a static path now create a file→file dependency edge, socodegraph_callersandcodegraph_impactfollow includes in procedural / script-style PHP codebases — previously only namespaceusestatements became dependency edges. Dynamic includes (include $var,require __DIR__ . '/x') are skipped. Thanks @atahan150 (#660).
0.9.9 - 2026-06-02
codegraph_exploreis now the primary tool, and one call is usually all an agent needs: it returns the verbatim source of the symbols relevant to your question (a plain question works as the query — you no longer need exact symbol names), grouped by file and Read-equivalent, so the agent answers without falling back to read/grep. The narrowercodegraph_contextandcodegraph_tracetools were removed in favor of it — explore already surfaces the call flow among the symbols you name (the job trace did), so there's one obvious tool to reach for instead of three.codegraph_explorenow includes a compact "Blast radius" for the symbols you're looking at — who depends on each (just the locations, not their source) and which test files cover it — so before editing, the agent can see what else to update and which tests to run, without a separate impact lookup. Symbols nothing depends on are skipped, so it stays short.- Functions defined inside a store or handler object — the actions in a Zustand
create((set, get) => ({ … }))store, and the same shape in Redux, Pinia, MobX, or any exported handler/route map — are now indexed as real symbols. Previously they existed only as object properties, so looking one up by name or asking who calls it returned "not found" and the agent had to read the whole store file to follow the flow; nowcodegraph_node,codegraph_callers, andcodegraph_exploreresolve them directly — including calls made throughuseStore.getState().fetchUser()or a destructuredconst { fetchUser } = useStore.getState(). codegraph_explorenow surfaces the right definition when a method name is overloaded across types. Asking about, say,DataRequest'staskandvalidateused to return a same-named method from an unrelated file (or an abstract base stub) and bury the one you meant; explore now recognizes the type you named in the query and leads with that type's own overloads, in full.
- Search ranking no longer lets a common word in your request hijack the results: asking about, say, a "flat object" screen used to surface an unrelated constant that merely happened to be named the same, because the exact-name match outweighed everything else. Ranking now weighs how well each result is corroborated by the rest of your request, so the symbols you actually meant come first (this improves
codegraph_explore's results). codegraph_nodenow returns every definition when a name is ambiguous — an overloaded method, or the same method name on different types — instead of returning one (sometimes the wrong one) with a note listing the rest. Asking for such a symbol now hands back all of the matching definitions with their source in a single call, so the agent stops having to read the file by hand to find the specific overload it wanted (common in Swift, Go, Java, and C#). For a heavily-overloaded name (apoll/validatewith dozens of definitions), passfile(and/orline) — e.g. thefile:lineshown in a trail — to get that exact definition's body. Large overload sets show the most relevant ones in full and list the remainder by location.codegraph_explorenever returns half a method anymore: when output runs up against its size budget it drops whole methods or whole files (and lists what it dropped, so you can ask for them in another call) instead of cutting off a method body partway. A truncated method was the one case that still sent the agent to read the file for the rest — so the source explore returns is now always complete and usable as-is.
0.9.8 - 2026-06-01
codegraph initnow builds the initial index by default — you no longer need the-i/--indexflag (it's still accepted, so existing commands and scripts keep working). (#483)- Go: Gin middleware chains now connect end-to-end in
codegraph_traceandcodegraph_explore— following a request reaches the middleware and route handlers registered via.Use()/.GET()instead of dead-ending where the framework dispatches the chain dynamically. codegraph_explorenow sizes its response to the answer instead of the file count: it shows the mechanism and the exact methods you asked about in full — even when they're buried deep in a large file — while collapsing the redundant interchangeable implementations of an interface (an HTTP interceptor chain, a query-compiler family) down to signatures. Fewer tokens for a more complete answer, so on the flows that used to occasionally cost more than plain grep/read it's now clearly cheaper — and the win holds across small, medium, and large codebases. Distinct, non-interchangeable code is shown in full as before. Disable withCODEGRAPH_ADAPTIVE_EXPLORE=0.- Swift deferred-validation flows (and similar "handler array" patterns) now connect end-to-end in
codegraph_traceandcodegraph_explore— following a request's lifecycle reaches the validators registered with.validate { … }instead of dead-ending where the framework runs them by iterating a stored list of closures. Any pattern where closures are appended to a collection and later invoked by looping over it is now traced. codegraph_explorenow spells out the dynamic-dispatch relationships of the symbols you ask about — e.g. "the closures registered here are run bydidCompleteTask" — so the indirect hops you'd otherwise grep to reconstruct are listed alongside the call flow.codegraph_exploreanswers multi-phase questions that span a large "god file" far more completely. For a flow like "build, send, and validate a request" — where one big file holds the build chain and the validate logic lives in others — it now keeps every method on the flow path in full, collapses the file's off-path methods to one-line signatures, and guarantees each phase's defining file is shown (instead of truncating at a fixed size and dropping whichever phase came last, which sent you to read it by hand). Incidental files that merely name-drop the flow are still trimmed, so the response stays focused on the code that answers the question.- CodeGraph is usable as an embedded library again:
require("@colbymchenry/codegraph")andimportnow resolve the programmatic API — theCodeGraphclass plus building blocks likeDatabaseConnection,QueryBuilder,initGrammars, andFileLock— so you can drive the graph directly from your own app (for example an Electron process) instead of only through the CLI or MCP server. Embedding runs on your own runtime, so it needs Node 22.5+ for the built-in SQLite. (#354)
codegraph_tracenow resolves an overloaded symbol name to its real implementation instead of an empty protocol/delegate stub. Tracing a flow through a heavily-overloaded API (common in Swift, Java, C#, and Go) could land on an unrelated no-op method that happened to share the name and report "no path"; it now picks the substantive definition the flow actually runs through.- CodeGraph's MCP server now answers an agent's opening handshake the instant it launches instead of blocking while the index loads, so a fresh session's very first tool call no longer occasionally races a server that's still warming up and falls back to grep/read. The first question in a new session now reliably goes through CodeGraph.
- Indexing a project that contains only config-style files (YAML, Twig, or
.properties) no longer misleadingly reports "No files found to index" — these files are tracked at the file level and are now counted as indexed. Thanks @luojiyin1987 (#357).
0.9.7 - 2026-05-28
- Go: gRPC interface stubs now connect to their hand-written implementation, so callers, callees, impact, and trace land on the real method instead of an empty generated stub.
- Generated files (protobuf, gRPC stubs, mocks, build output) now rank last in search, trace, and explore, so results land on your real implementation instead of an auto-generated placeholder.
- When
codegraph_tracecan't find a static path (a dynamic-dispatch break), it now inlines both endpoints' source, callers, and callees in one response, so the agent gets the full picture without a flurry of follow-up calls. - Trace now picks the right endpoints in large multi-module repos by preferring symbols that share a directory, instead of grabbing an arbitrary same-named symbol from an unrelated module.
- Test files are now deprioritized in
codegraph_explore(Go, Ruby, JS/TS, Java/Kotlin/Scala), so the explore budget goes to your real implementation source. - Small projects (under ~500 files) now resolve flow questions in fewer MCP calls, with a leaner tool surface and tuned context and explore output sized for the project.
codegraph_contextnow auto-traces flow questions like "how does X reach Y" or "trace the path from A to B", splicing the trace into the response so you don't need a separatecodegraph_tracecall.codegraph_contextnow inlines a URL-to-handler routing table and the source of your main routes file for routing questions on small projects, so you don't have to go readroutes.rborweb.phpyourself.codegraph_contextsearch now boosts results in the directory of a project's core framework file, so a small same-named extension file no longer outranks the actual framework core.- Interface-to-implementation linking now works for C#, TypeScript, JavaScript, Swift, and Scala (previously Java/Kotlin only), so investigating an interface method surfaces its concrete implementations.
- MCP tool descriptions are now shorter, trimming per-session overhead while keeping the steering guidance.
- Java and Kotlin imports now resolve by fully-qualified name, so same-name classes in different packages are told apart correctly in multi-module Spring and Android codebases, including across the Java/Kotlin interop boundary.
- Java and C# anonymous classes (
new T() { ... }) and their overridden methods are now indexed as real class nodes, so an agent sees those hidden overrides in its trail without a Read. - The installer no longer writes a duplicate
## CodeGraphinstructions block into your agent's instructions file (CLAUDE.md,AGENTS.md,GEMINI.md, Cursor's.cursor/rules/codegraph.mdc, or Kiro's steering doc) — the MCP server is now the single source of truth, and re-runningcodegraph installorcodegraph uninstallstrips a block a previous version left behind (#529). If you added your own notes inside theCODEGRAPH_START/CODEGRAPH_ENDmarkers, move them outside the markers first, since the whole marked block is removed.
- MCP tools no longer return results for files that were deleted while no server was running — the first query of a session now waits for the catch-up sync, so you get the correct index instead of stale rows.
- Windows: black console windows no longer flash on every file save or MCP reconnect (#485, #510, #530).
codegraph indexandinit -inow report the true edge count in their summary, instead of undercounting by missing resolution and synthesizer edges.
0.9.6 - 2026-05-27
- Enterprise Spring and MyBatis flows now trace end-to-end: MyBatis XML mappers are indexed and linked to their Java mapper interfaces, Spring
@Valueand@ConfigurationPropertiesreferences resolve to the matching keys in yourapplication.yml/.propertiesconfig (including relaxed kebab/camel/snake binding), and field-injected concrete beans likethis.field.method()resolve through to their implementation (#389). - Gemini CLI (and the rebranded Antigravity CLI) plus the Antigravity IDE are now supported by
codegraph install, detected and configured out of the box with sibling settings and MCP servers preserved across re-installs (#399). - Kiro (CLI and IDE) is now supported by
codegraph installon macOS, Linux, and Windows, with its own steering file so it loads CodeGraph guidance naturally (#385).
- C/C++: bare
#include "header.h"directives now connect to the real header file instead of a phantom import, so includes show up as true file-to-file edges; system and stdlib headers are filtered out so they don't false-resolve (#453). - Java/Kotlin: imports now disambiguate same-name classes across modules using the fully-qualified import path, so callers, callees, and trace land on the right class in multi-module projects instead of guessing by file proximity (#314).
- TypeScript:
typealiases with object shapes (including function-typed members and intersection types) now surface their members in the graph, so a call likehandle.stop()resolves to the alias member instead of an unrelated look-alike class in a sibling directory (#359). - C#: parameter, return, property, and field types now produce reference edges, so callers and callees on a DTO or service type return real results instead of nothing (#381).
- Go: cross-package qualified calls like
pkg.Func()now resolve to the right package by reading yourgo.mod, so callers, callees, impact, and trace return complete results on Go monorepos instead of almost nothing (#388). codegraph_filesnow returns the whole project when an agent passes a root-ish path like/,.,./,"", or a Windows-style\, and subdirectory filters like/src,./src, andsrc\componentsall resolve correctly instead of returning "No files found" (#426).- The file watcher no longer marks edited files as fresh when another process holds the index lock, so the per-file staleness signal stays accurate until the edit is actually indexed (#449).
- TypeScript/JavaScript: calls inside top-level variable initializers (
const token = getToken()) and inside inline object-literal methods are no longer dropped, so they show up in callers as expected, including in Vue single-file components (#425). - Watch sync no longer aborts with a
FOREIGN KEY constraint failederror in a long-running daemon; a stale lookup now drops a single edge instead of failing the whole sync (#455). - Hermes:
codegraph install --target hermesno longer corrupts~/.hermes/config.yaml, correctly handling PyYAML's block-style lists and re-installing cleanly even on an already-corrupted file (#456). - NestJS: route prefixes from
RouterModule.register([...])(including nestedchildren) now propagate to controller routes, so a route shows up at its full path likeGET /admin/usersinstead ofGET /(#459). - C++: callers now resolve through typed member pointers such as
m_alg->Processing(), including out-of-line method definitions and the common case of two classes sharing a method name (#445, #454).
0.9.5 - 2026-05-25
- Running multiple AI agents in the same project no longer multiplies the cost: two Claude Code windows, a worktree agent, or parallel sub-agents now share one background daemon per project with a single file watcher, SQLite connection, and tree-sitter warm-up instead of N independent copies (#411).
- The daemon runs detached so it outlives any single session, meaning closing one editor or terminal never severs the others; it lingers briefly after the last client disconnects so back-to-back sessions skip the startup cost, then exits and cleans up after itself. Tune the idle wait with
CODEGRAPH_DAEMON_IDLE_TIMEOUT_MS(default five minutes). - Set
CODEGRAPH_NO_DAEMON=1to opt out and get one independent server per client, handy for debugging or sandboxes that disallow local sockets; the daemon is also version-pinned, so upgrading CodeGraph never mixes versions over the connection. - CodeGraph responses now tell the agent which files are pending re-index: when the watcher has seen edits since the last sync, tool responses add a warning banner naming the stale files and their state so the agent reads just those directly while trusting the rest, with zero cost when nothing is pending (#403).
CODEGRAPH_WATCH_DEBOUNCE_MSlets you tune the file-watcher quiet window (default 2000ms) for workspaces with bursty writes like format-on-save chains or large generated outputs, without touching your agent's command line (#403).- Objective-C indexing:
.m,.mm, and content-sniffed.hfiles now parse with full structural extraction, including full multi-part selectors, properties, imports, and superclass/protocol relationships, so trace, callers, and callees work across iOS codebases (#165). - Mixed iOS, React Native, and Expo projects now trace end-to-end across language boundaries: Swift to Objective-C auto-bridging, the React Native legacy bridge and TurboModules, native-to-JS event channels, Expo Modules, and Fabric/Codegen view components are all bridged so flows connect through gaps that static parsing alone can't follow (#401).
- TypeScript: types used only in an interface's property or method signatures now produce references edges, so impact and callers on a type include every consumer that imports it just for an interface shape (#432).
- Git worktrees no longer silently borrow another tree's index; running CodeGraph from a worktree nested inside the main checkout used to return the wrong branch's code with no warning, and now both the status command and every read tool call out the conflict and point you to
codegraph init -iin the worktree (#155). - The file watcher no longer exhausts the OS file-watch budget on large repos: it now excludes the same directories the indexer ignores (defaults plus your
.gitignore) before registering watches, so CodeGraph can run alongside your editor or dev server without hitting the per-user watch ceiling (#276). - The index now stays in sync after
git pull, branch switches, and edits made outside your editor; change detection is filesystem-based instead of relying ongit status, so pulled or checked-out code is picked up without a full re-index. - The MCP server now catches up on connect, reconciling anything that changed while it wasn't running so your first query reflects the current code instead of a stale snapshot.
- Dependency, build, and cache directories like
node_modules,vendor,dist,build,target,.venv,__pycache__,Pods, and.nextare now excluded by default, so context and search reflect your code instead of third-party noise even in a project with no.gitignore; add a.gitignorenegation to index one anyway (#407).
0.9.4 - 2026-05-24
- Request-to-handler flows now trace end-to-end across many web stacks, with new or improved route resolution for Express, Rails, Spring (Java and Kotlin), Django/DRF, Laravel, Flask, FastAPI, Gin, chi, ASP.NET, Drupal, Axum, actix, Vapor, Play, Vue/Nuxt, Svelte/SvelteKit, and React Router.
codegraph_trace,codegraph_callees, andcodegraph_explorenow follow flows that have no static call edge — callback and observer registration, EventEmitter, React re-renders and JSX children, FluttersetStatetobuild, C++ virtual overrides, and Java/Kotlin interface-to-implementation dispatch (like Spring's@Autowiredservice calls) — and each bridged hop is labeled inline in trace with where it was wired up.codegraph_tracenow returns a self-contained flow dossier: every hop shows its full body inline plus the destination's own outgoing calls, so a single trace usually answers a "how does X reach Y" question without a follow-up explore, node, or Read.codegraph_explorenow leads with the execution flow when your query names the symbols of a flow, finding the call path among those symbols (including across dynamic-dispatch hops) so you get a trace-quality answer without switching tools.codegraph_nodeandcodegraph_tracenow emit line-numbered source (matchingcodegraph_exploreand Read), so you can cite or edit exact lines without re-reading the file just to recover line numbers.- New
CODEGRAPH_MCP_TOOLSenvironment variable lets you expose only a chosen subset of codegraph tools over MCP (e.g.trace,search,node,context) without editing your client's MCP config; unset exposes all of them. - Release archives now ship with a
SHA256SUMSfile, and the npm launcher verifies the bundle it downloads against it, aborting on a mismatch (releases published before this change skip verification rather than failing).
- Several static-extraction and resolution correctness fixes underpin the routing work above: C++ inheritance edges that were previously missing, Dart methods that were extracted signature-only, Python handlers named
index/get/updatethat were being silently dropped, and an explore output-budget issue that under-returned source on repos with very large files. codegraph serve --mcpno longer keeps running after its parent agent is force-killed (OOM,kill -9, or container teardown) on Linux, where it used to hold inotify watches, file descriptors, and the SQLite WAL indefinitely; the server now shuts down as soon as its parent process changes, tunable viaCODEGRAPH_PPID_POLL_MS(#277).- Installing
@colbymchenry/codegraphthrough a registry mirror that hadn't yet mirrored the matching per-platform package no longer fails withno prebuilt bundle for <platform>; the launcher now downloads the bundle from GitHub Releases and caches it, withCODEGRAPH_NO_DOWNLOAD=1to disable the fallback andCODEGRAPH_DOWNLOAD_BASEto point it at your own mirror (#303). install.shno longer fails with403/ "could not resolve latest version" on shared or cloud hosts that exhaust GitHub's unauthenticated API rate limit; it now resolves the version through the unthrottled releases redirect, andCODEGRAPH_VERSIONaccepts a bare version like0.9.4as well asv0.9.4(#325).
0.9.3 - 2026-05-22
- New
codegraph uninstallcommand cleanly removes CodeGraph from every agent it's configured on — Claude Code, Cursor, Codex CLI, opencode, and Hermes Agent — in one step, asking whether to clean up your global or this project's local config and reporting exactly which agents it touched; it accepts--location,--target, and--yesfor scripted or non-interactive use, removes only whatcodegraph installwrote, and leaves your.codegraph/index alone (#313).
- Indexing a large multi-language project no longer aborts partway through with a
Fatal process out of memory: Zonecrash on Node.js 22 and 24, even with plenty of RAM free — CodeGraph now launches with a V8 flag that keeps grammar compilation off the optimizing tier, and any launch path that doesn't get the flag directly re-execs once with it automatically (#298, #293). Node 25 stays blocked for now, since its variant of this bug isn't fixed by the same flag. - Uninstalling from Cursor now deletes the leftover
.cursor/rules/codegraph.mdcfile outright instead of leaving an orphaned, empty rule behind, while keeping any content you added outside CodeGraph's markers.
0.9.2 - 2026-05-21
- CodeGraph no longer has a config file:
.codegraph/config.jsonand the entire config surface are gone, and the library API for it (the config type, theconfigoption oninit(), and the get/update config exports) has been removed — existing config files are now ignored, and.gitignoreis the single source of truth for what gets indexed. The.codegraphignoremarker is also no longer supported; use.gitignoreinstead.
codegraph installnow supports Hermes Agent (Nous Research), wiring up the CodeGraph MCP server so Hermes can drive the knowledge graph like the other agents.- Drupal projects (8/9/10/11) are now detected and indexed with framework smarts: routes from
*.routing.ymllink to their controller, form, or entity-handler, and hook implementations across modules are connected to their canonical hook name, so asking for callers of a hook returns every implementation (#268). - Indexing is now zero-config and honors your
.gitignoreeverywhere — in git repos via git, and in non-git projects by reading.gitignorefiles directly — so to keep something out of the graph you just add it to.gitignore. Behavior change: committed files that aren't gitignored are now indexed even undervendor/,Pods/, or a committeddist/; add a.gitignorenegation to exclude them (#283).
- Windows: installing globally and then running any
codegraphcommand no longer fails — the launcher now invokes the bundled runtime directly instead of a.cmdfile that modern Node refuses to spawn, socodegraphworks regardless of your Node version (#289).
- The temp-dir marker written on each
codegraph_contextcall is now opened safely so it can't follow a symlink, closing a hole where another local user on a shared machine could redirect that write onto a file you can write (#280).
0.9.1 - 2026-05-21
- The standalone installers (
curl … | shandirm … | iex) no longer fail to launch on a machine that has no Node installed. - Installing with
npm i -gon Linux x64 now finds its bundle, after the 0.9.0 release silently shipped without the linux-x64 package; the release pipeline now verifies every package reached the npm registry so a release can't pass green-but-broken again.
0.9.0 - 2026-05-21
CodeGraph now ships its own self-contained runtime, so it installs on any Node version — or none at all — with no native build step, and the old intermittent "database is locked" errors are gone for good.
- One-line standalone installers that need no Node.js:
install.shon macOS and Linux, andinstall.ps1on Windows fetch the self-contained bundle and putcodegraphon your PATH (you can still usenpm/npxon any Node version too). - CodeGraph now uses real SQLite with full WAL and FTS5 built into its bundled runtime, which fixes the concurrent-read "database is locked" errors at the root, removes the native build step entirely, and runs faster for anyone who had been stuck on the old WASM fallback (#238).
- Lua: CodeGraph now indexes
.luaprojects (Neovim plugins, Kong, OpenResty, game code), surfacing functions, table methods, local variables,require(...)imports, and the call edges between them. - Luau: CodeGraph now indexes
.luau, Roblox's typed superset of Lua, adding type andexport typealiases, typed function signatures, generics, and Roblox instance-path requires on top of everything Lua extracts (#232). codegraph statusnow reports the effective journal mode, so a "database is locked" report is easy to triage at a glance.
- Re-running
codegraph installnow strips the broken auto-sync hooks that pre-0.8 versions wrote into Claude Code's settings, which had been causing a "Stop hook error: unknown command 'sync-if-dirty'" on every turn. The cleanup is surgical and leaves unrelated hooks untouched. Re-runcodegraph installonce on an affected machine to clear the error.
0.8.0 - 2026-05-20
- The minimum supported Node.js version is now 20 (Node 18 is end-of-life); Node 22 LTS and Node 24 get the fast native backend out of the box, other Node versions still run via the slower WASM fallback, and Node 25+ remains blocked (#81). If you're on an older Node, upgrade to 20 or newer.
- NestJS: CodeGraph now recognizes NestJS projects and surfaces the route that binds each handler across HTTP controllers, GraphQL resolvers, microservice handlers, and WebSocket gateways, detected automatically from any
@nestjs/*dependency (#220). codegraph_exploresource now includes line numbers, so an agent can citefile:linestraight from the result instead of reopening the file to find a line number; setCODEGRAPH_EXPLORE_LINENUMS=0to disable.- On WSL2
/mnt/*drives, where the live file watcher is too slow and could break MCP startup, CodeGraph now skips the watcher and offers to keep the index fresh with git hooks instead; newCODEGRAPH_NO_WATCH=1(orserve --mcp --no-watch) forces the watcher off anywhere, andCODEGRAPH_FORCE_WATCH=1overrides the WSL auto-detect when your setup is actually fast. - CodeGraph now guides agents to answer "how does X work" and architecture questions directly with a couple of codegraph calls instead of delegating to a file-reading sub-agent or a grep-and-read loop, which gives faster, cheaper,
file:line-cited answers on medium and large repos. codegraph_nodewith code on a class, interface, struct, or enum now returns a compact member outline (fields plus method signatures with line numbers) instead of the entire class body; functions and methods still return their full source.codegraph_exploreoutput now scales with project size, so small projects get tighter responses than your native grep-and-read flow would produce while large codebases keep their fuller budget, and a per-file cap stops a single dense file from collapsing into a whole-file dump (#185). Thanks @essopsp.- Search ranking now correctly de-prioritizes CamelCase test files (
FooTest.kt,BarTests.swift,BazSpec.scala,QuxTestCase.cs) and test source-set directories in Kotlin, Swift, Scala, and C#, so real implementations no longer get outranked by tests.
codegraph_exploreoutput is now hard-capped to its size budget, so an oversized response no longer overruns the cap and sits in the agent's context to be re-read every turn.- Newly created untracked files are no longer reported as pending forever and re-indexed from scratch on every
codegraph sync; CodeGraph now hash-compares them against the index the same way it does tracked files (#206). Thanks @15290391025. codegraph init -inow finds source inside nested, independent git repositories that aren't submodules (common in CMake super-repo layouts), instead of reporting "No files found to index" (#193). Thanks @timxx.- On Node 24, indexing no longer silently drops to the slower fallback backend with a warning that couldn't be cleared; a fresh install on Node 22 or 24 now gets the fast native backend with no compiler, and
codegraph statusshould report it (#203). Thanks @Finndersen. - MCP tools no longer fail with "CodeGraph not initialized" when the index actually exists; when the client doesn't report a workspace root, the server now asks for it via the standard MCP
roots/listrequest before falling back, and the error message is actionable when a project still can't be resolved (#196). Thanks @zhangyu1197. - The MCP server no longer hangs on startup under WSL2 when the project lives on an NTFS
/mnt/*mount, so the codegraph tools actually appear; CodeGraph auto-skips the watcher there with manual and git-hook sync fallbacks (#199). Thanks @mengfanbo123. - Claude Code project-local installs now write the MCP server to
.mcp.json(the file Claude Code actually reads for project-scoped servers) instead of a file it ignores, and re-runningcodegraph installmigrates an affected project automatically (#207). Thanks @Jhsmit. - Source-omission markers in
codegraph_exploreandcodegraph_contextoutput are now language-neutral instead of C-style comments, so they no longer look wrong inside Python, Ruby, and other non-C source blocks.
0.7.10 - 2026-05-19
- CodeGraph tools now reliably appear in your client on slow filesystems (Docker Desktop VirtioFS on macOS, WSL2), where the startup handshake could previously time out and leave the process running with no tools visible (#172). Thanks @sashanclrp and @sgrimm.
- On Windows PowerShell and cmd.exe, terminal output during
codegraph indexandcodegraph syncno longer turns into garbled characters; CodeGraph now uses plain ASCII glyphs by default on Windows, withCODEGRAPH_UNICODE=1to opt back into the Unicode glyphs orCODEGRAPH_ASCII=1to force ASCII on any platform (#168). Thanks @starkleek and @Bortlesboat. - Module-qualified symbol lookups now resolve in the codegraph tools, so you can pass names like
module::symbol(Rust, C++, Ruby),Module.symbol(TypeScript, JavaScript, Python), ormodule/symbol, including multi-level paths and Rust prefixes likecrate,super, andself(#173). Thanks @joselhurtado.
0.7.9 - 2026-05-17
- opencode: the installer now writes an
AGENTS.mdfile with CodeGraph usage guidance, so opencode reaches for thecodegraph_*tools instead of falling back to its native search. - opencode: your comments and formatting in
opencode.jsoncnow survive install, re-install, and uninstall, because the installer makes surgical edits instead of rewriting the whole file.
- opencode:
codegraph installnow wires up the MCP server in the file opencode actually reads — previously it wrote to a config file opencode ignores by default, so the CodeGraph entry never appeared in any opencode session; re-runcodegraph install --target=opencodeafter upgrading so the entry lands in the right place.
0.7.7 - 2026-05-17
codegraph installnow sets up Claude Code, Cursor, Codex CLI, and opencode from one multi-select prompt, with any agents it detects pre-checked, so a single install wires up every editor you use (#137).- You can install non-interactively for scripting and CI with flags like
--target,--location,--yes,--no-permissions, and--print-config. codegraph initnow auto-wires project-local agent config for any agent you installed globally, so one globalcodegraph installworks in every project you open without re-installing per project.- Agent instructions are now agent-agnostic and tell each agent to trust codegraph results instead of re-verifying with grep, fixing the case where Cursor and Codex fell back to native search even with codegraph available.
- The install prompts are clearer: the agent picker comes first, and the separate "install the CLI on your PATH" and "apply to all projects or just this one" questions no longer both read as "Global".
- Cursor: a globally-installed codegraph no longer reports "not initialized" in every workspace; the installer now passes the correct project path into Cursor's MCP config to work around Cursor launching MCP servers with the wrong working directory.
Thanks @andreinknv for the substantive draft this release was based on.
0.7.6 - 2026-05-13
- Fixed the
codegraphcommand failing withpermission deniedright after a fresh global install — the 0.7.5 package shipped the CLI without its executable bit, so your shell refused to run it. New installs work out of the box. If you're stuck on 0.7.5, upgrade to 0.7.6 or unblock yourself in place by making the installed binary executable withchmod +x.