Releases: colbymchenry/codegraph
Releases · colbymchenry/codegraph
Release list
v1.5.0
[1.5.0] - 2026-07-21
⚡ The Rust engine release — with near-instant sync
This release rebuilds CodeGraph's parsing engine as a native Rust kernel, overhauls the resolution pipeline around it, and makes the live graph effectively instant: a save now reaches the graph in well under a second, even on a 27,000-file repository. It is the largest performance upgrade in the project's history — and every graph is verified byte-for-byte identical to the previous engine.
- Native Rust parsing for 20 languages — TypeScript, JavaScript (+TSX/JSX), Java, Python, Go, C, C++, Rust, C#, Ruby, PHP, Swift, Kotlin, Scala, Dart, R, Lua, and Luau now parse in a compiled Rust kernel (Metal and CUDA ride the C++ path). Platforms without a prebuilt binary, and individual files with syntax errors, fall back to the previous engine automatically — same graph either way, proven on repositories from small libraries to the Linux kernel.
- Adaptive to your machine — CodeGraph sizes its parse workers, resolver pool, and caches from what the system actually has: real core counts (container/cgroup-aware, not the host's), honest available memory on macOS and Linux, and measured per-project resolution cost. A big workstation gets the full parallel pipeline; a 2-core VPS gets a pipeline tuned to finish reliably instead of running out of memory — the Linux kernel (70k files) indexes to completion on a 2-core, 6GB machine in under 12 minutes — down from 26 at the start of this cycle.
- Resolution is dramatically faster across the board — adaptive parallel resolution, smarter method-candidate lookup, and memoized supertype/conformance walking. The Swift compiler repository (27k files, Swift + C++) went from over 3 minutes to about 100 seconds within this release cycle; Rust, Lua, and Java-family projects all see double-digit improvements.
- Sync is now near-instant — a save reaches the graph in well under a second, even at compiler scale. The always-on watcher fires after a 300ms quiet window for lone saves (bursts of edits still coalesce), and hands the exact changed paths to sync instead of re-scanning the whole tree — measured save-to-fresh-graph work of ~0.3s on a 4,400-file Java project and ~0.4s on the 27,000-file Swift compiler repository, byte-identical to a full reconciliation.
Full details in the entries below.
New Features
- Indexing TypeScript, TSX, JavaScript, JSX, Java, Python, Go, C, C++, Rust, C#, Ruby, PHP, Swift, Kotlin, Scala, Dart, R, Lua, and Luau projects is faster: parsing and symbol extraction now run in a native engine when a prebuilt binary is available for your platform (release bundles include one), producing exactly the same graph — verified byte-for-byte against the previous engine on real repositories, from small libraries up to vscode-, dubbo-, django-, git-, protobuf-, tokio-, rust-analyzer-, jellyfin-, rails-, symfony-, swift-nio-, kotlinx.coroutines-, ggplot2-, Kong-, Scala-3-compiler-, and Flutter-scale codebases (Lombok-generated members, C function-pointer tables, and Unreal-Engine-style macro-heavy headers included; CUDA and Metal sources ride the C++ path). The speedup is largest on resource-constrained machines like CI runners. No setup needed: platforms without the native binary, and individual files with syntax errors, automatically use the previous engine, and
CODEGRAPH_KERNEL=0turns the native path off entirely. - Reference resolution now runs in parallel on large projects. When a project has enough pending references to make it worthwhile (roughly 150k+, typical for big Java/Kotlin/Spring codebases), resolution fans out across worker threads while results are applied in the exact order the single-threaded path would have used — the graph comes out byte-for-byte identical, about twice as fast end-to-end on a 4,000-file Java project in our testing. Small projects keep the single-threaded path automatically (the fan-out costs more than it saves there). Set
CODEGRAPH_NO_PARALLEL_RESOLVE=1to disable, orCODEGRAPH_PARALLEL_RESOLVE_MIN=<count>to tune when it engages. - Indexing large projects got another sizeable speedup — about a quarter less wall-clock on the same 4,000-file Java project, with the graph still byte-for-byte identical. Two changes: the database no longer interleaves expensive checkpoint housekeeping into the middle of resolution on a fresh index (it's folded once at the end instead), and while one batch's results are being written out, the worker threads are already resolving the next batch instead of sitting idle.
- The dynamic-dispatch analysis that runs at the end of indexing (callback, event, and framework wiring) now runs its passes in parallel on large projects, cutting that stage roughly in half there — and a pass that crashes now retries safely instead of failing the whole index, which also makes very large codebases that previously died in this stage more likely to index to completion. Graphs remain byte-for-byte identical.
- On large projects, indexing writes its relationship data noticeably faster: secondary database indexes are set aside during the bulk of reference resolution and rebuilt once at the end, instead of being maintained row by row. Graphs remain byte-for-byte identical, and small projects are unaffected.
- Very-large-codebase reliability: on multi-million-symbol projects, an analysis pass that fails on a worker thread is now skipped with a clear message instead of being retried in a way that could take down the whole index, and the end-of-indexing index rebuild no longer risks tripping the liveness watchdog on huge graphs. Validated end-to-end on the Linux kernel (70k files, 2M symbols, 6.4M relationships) — it now indexes to completion even on a 2-core machine.
- Indexing is significantly faster — a fresh
codegraph initon a medium TypeScript project takes about a third less wall-clock time, with the same graph produced byte-for-byte. The gains come from batching database writes, storing files on a dedicated writer thread, memoizing repeated import-resolution lookups, skipping per-row search-index maintenance during the bulk build (rebuilt once at the end), and — on completely fresh databases only — deferring disk durability until the index completes, since an interrupted first index is simply re-run. SetCODEGRAPH_NO_FAST_INIT=1to keep full crash-durability during the initial build, orCODEGRAPH_NO_STORE_WORKER=1to store on the main thread. codegraph installandcodegraph upgradenow offer CodeGraph Pro beta access after finishing — answer yes, type your email, and you join the same waitlist as the getcodegraph.com homepage form. Strictly opt-in and asked at most once per machine total: nothing is sent unless you say yes and enter an email, either answer is remembered so no later install or upgrade ever re-asks, and non-interactive runs (--yes, scripts, CI) never see the question.- Every release is now cryptographically verifiable: npm packages publish with npm provenance (the "Provenance" badge on npmjs.com, proving each version was built by this repository's release workflow from a specific commit), and the GitHub Release bundles carry signed build attestations you can check with
gh attestation verify <file> -R colbymchenry/codegraph. - Indexing inside CPU- or memory-limited containers (Docker, CI runners) now sizes its worker pools from the container's actual allowance instead of the host machine's, and giant codebases no longer balloon temporary database files during indexing (previously tens of GB of transient disk on Linux-kernel-scale projects). Together these prevent out-of-memory and out-of-disk failures on constrained machines; set
CODEGRAPH_RESOLVE_WORKERSto override the resolution worker count explicitly. - Indexing very large projects on multi-core machines got faster again: the parallel-resolution workers now periodically refresh their read-only database connections, which lets database housekeeping advance instead of silently building up a backlog behind long-lived readers — a backlog that was taxing the indexer's own writes. Graphs remain byte-for-byte identical; the win is largest at Linux-kernel scale on many-core machines.
- Indexing on macOS now uses the machine's real memory headroom when sizing its parallel-resolution workers. macOS deliberately keeps RAM filled with reclaimable cache, so the previous free-memory reading came back tiny (~1GB on an otherwise idle machine) and silently halved the worker pool — a medium Java project's fresh index ran about 15–20% slower than the hardware allowed. Graphs remain byte-for-byte identical; the same fix also lets a memory-driven analysis cache engage fully on macOS for large C codebases.
- Fresh indexing got a sizeable across-the-board speedup: during the initial build, the database's secondary lookup indexes are set aside and rebuilt once after parsing instead of being maintained row by row — the same proven trick the later linking phase already used, now applied to the whole parse lane — and the reference-resolution loop likewise stops maintaining lookup indexes it never reads, rebuilding them at the end when almost nothing is left in the table. A medium Java project's parse phase runs about 58% faster and its full fresh index about 19% faster end-to-end; a Linux-kernel-scale index that took ~15 minutes on an 8-core machine now completes in about 11, with the resolution phase alone dropping by a third. Graphs remain byte-for-byte identical, and incremental syncs are unaffected.
- Saving a file now updates the graph almost immediately: the file watcher fires after a 300ms quiet window for one or two changed files (bursts still coalesce under the full debounce, and
CODEGRAPH_WATCH_DEBOUNCE_MSremains the upper bound), and watcher-triggered syncs reconcile exactly the changed paths instead of stat-walking the entire repository. Directory deletions and event storms still run the full scan-diff, so nothing the events can't describe is eve...
v1.4.1
[1.4.1] - 2026-07-10
New Features
- The MCP server now notices when a newer CodeGraph release exists and tells you — a long-running server used to drift behind releases silently until something broke. On startup it checks the latest release in the background (never blocking, at most once a day, cached across all servers on the machine) and surfaces a one-line "update available — run
codegraph upgrade" notice in the server log, in the instructions your agent sees on connect, and incodegraph_status. Nothing updates by itself, and being offline just means no notice. Opt out withCODEGRAPH_NO_UPDATE_CHECK=1;DO_NOT_TRACK=1disables it too. (#1243)
Fixes
codegraph upgradeon a Windows npm install actually runs npm again — modern Node refuses to launchnpm.cmddirectly, so the upgrade failed with a spawn error before doing anything. npm is now invoked the way a terminal would run it. (#1238)codegraph uninstallnow actually uninstalls CodeGraph. It used to remove only the agent configurations and leave every installed binary behind, socodegraphstill ran afterward — especially confusing when both an npm global install and a standalone install were present and removing one still left the other answering on PATH. Uninstall now finds every install on the machine (the standalone bundle, the npm global package, the launcher link) and removes them all, after showing you exactly what it found and asking first (--yesskips the prompt). Machine-level settings like your telemetry choice are preserved, a source checkout is never touched, and the new--keep-cliflag restores the old configs-only behavior. (#1071)codegraph_exploreno longer lets ordinary English words in a natural-language question hijack the ranking when they happen to match a code symbol's name. A question like "how does the upgrade flow check the latest version" used to treat "check" as a symbol the agent asked for by name, rank that unrelated definition's file first, and crowd the files the question is actually about out of the answer entirely. Precisely written symbol names (camelCase, PascalCase, snake_case, qualified names) still get top billing exactly as before, as do plain-word symbol bags whose words belong together in the same file.- PHP method calls made through a class property —
$this->dep->method(), the dominant call shape in constructor-injection codebases (Symfony, Laravel) — now resolve to the method on the property's declared type, so callers and impact analysis see production call sites instead of reporting a DI-heavy method as uncalled or test-only. Promoted constructor parameters, typed properties, classic constructor assignment (including multi-line signatures), and typed setter injection all count; interface-typed properties resolve to the interface method, and inherited methods resolve through the type hierarchy. Only property-shaped declarations are consulted — a same-named local variable or parameter elsewhere can never mistype the property — and a property whose type can't be recovered statically stays unlinked rather than guessed. Thanks @w0lan. (#1220) codegraph upgradenow also refreshes what previous versions installed into your agents — the CodeGraph section in CLAUDE.md / AGENTS.md / GEMINI.md and the MCP entry — so upgrading no longer leaves agents following instructions written for tools that have since been renamed or removed. Refresh-only: agents you never configured are not touched, and your permission and hook choices are preserved. Also available manually ascodegraph install --refresh, and skippable withCODEGRAPH_NO_INSTALL_REFRESH=1. (#1238)codegraph upgradeon an npm install now upgrades through npm again instead of quietly creating a second copy that never wins the PATH race — previouslycodegraph --versionkept reporting the old version forever, no matter how many times you upgraded. (#1238)- After every upgrade, CodeGraph now checks that the
codegraphcommand your terminal resolves actually serves the freshly installed version — confirming you don't need a new terminal, or telling you exactly which stale install is shadowing the new one. (#1071) - The safety watchdog no longer kills a healthy index on severely degraded storage. It used to judge liveness purely by the event loop, so one long database write on a struggling disk looked identical to a hung process and could get a valid, in-progress index terminated. During
codegraph index/codegraph initthe watchdog now also checks whether the index files on disk are advancing before it acts: slow-but-progressing work is left alone (bounded by a hard cap), while a genuinely hung process is still killed exactly as fast as before. (#1231) - Incremental sync now picks up cross-file relationships that only become resolvable after an edit — for example, when a file gains an export that another, unchanged file was already importing or calling. Previously the reference in the unchanged file was never revisited, so callers, impact, and flow results silently omitted the new edge (while status reported a clean index) until a full re-index. References that can't be resolved yet are now remembered and automatically retried whenever a change introduces a symbol that could satisfy them — this also covers a class gaining a new method that other files already call. Thanks @loadcosmos for the report with a minimal reproduction. (#1240)
- The reverse case is fixed too: when an edit removes or moves a symbol (or deletes its file), callers in unchanged files now re-resolve during the same sync — rebinding to the symbol's new home when it moved, or waiting to reconnect automatically when it comes back — instead of silently losing their relationship until a full re-index. (#1240)
v1.4.0
[1.4.0] - 2026-07-10
New Features
- Indexing is dramatically faster on slow storage — mechanical HDDs, network folders, and virtualized disks. The database no longer folds its write journal back into the main file thousands of times during a bulk index (that folding was ~95% of all disk activity); it now streams writes sequentially and folds them back in a few large, coalesced passes that run off the main thread. In a disk-throttled benchmark matching the reported hardware, a mid-size Java project went from over 25 minutes to under a minute, and there is no change on fast disks. Opt out with
CODEGRAPH_NO_WAL_DEFER=1; tune the fold-back threshold withCODEGRAPH_WAL_VALVE_MB. (#1231) - New
CODEGRAPH_PARSE_TIMEOUT_MSenvironment variable to raise the per-file parse budget on unusually slow storage, the same wayCODEGRAPH_PARSE_WORKERSalready tunes the worker count. (#1231)
Fixes
- Indexing on slow storage (mechanical HDDs, network folders) no longer collapses into false "parse timeout" failures. When disk writes stalled the coordinating thread, parses that had already finished — including empty files — were being misjudged as hung, their workers killed, and the files silently dropped from the index. A parse result is now judged by the worker's own clock, so a stalled coordinator accepts the finished result instead of killing the worker; only a genuinely hung parse is terminated (after a wider grace window). Files that do hit the timeout are retried at the end of indexing instead of being silently lost. Thanks @KnifeOfLife for the exceptional report. (#1231)
- Parse workers now receive their grammar files from memory instead of each re-reading them from disk on spawn, eliminating a feedback loop on slow disks where every worker restart added more disk contention — and making worker restarts cheaper everywhere. (#1231)
v1.3.1
[1.3.1] - 2026-07-09
Fixes
- Indexing very large codebases no longer dies at the end of the "Resolving refs" step. Two failure modes are fixed: on multi-million-symbol projects (e.g. the Linux kernel, ~95,000 files) the final analysis phase ran out of memory and crashed the process outright, and on large projects on slower machines (reported on a 24,000-file Java project on Windows) the same phase could stall long enough that the safety watchdog killed a healthy, still-progressing index at ~98% (#1212). The whole phase now streams its work instead of holding whole-graph snapshots in memory, keeps the process responsive throughout, and skips analysis passes for languages a project doesn't contain — which also makes the tail of indexing noticeably faster on single-language repos. The resulting graph is identical, and a genuinely wedged process is still detected and killed.
- Indexing and
codegraph syncstay responsive through their heaviest internal steps on huge projects: the post-index database maintenance (which on a multi-gigabyte index could stall the process for minutes and get a fully successful index killed by the safety watchdog at the finish line) now runs on a background thread, storing a giant generated file no longer freezes the process mid-extraction, and the reference-resolution bookkeeping between progress updates is broken into small responsive steps. The resulting graph is byte-for-byte identical. - Fixed a race that could leave a freshly-attached MCP session permanently silent: when a client's first messages arrived glued together during the daemon's connection handshake (roughly one attach in five on a busy machine), the daemon could drop them and stop reading that connection entirely — every tool call from that session then hung with no reply. The handshake now hands the connection over losslessly, and the fix is validated by hammering the previously-flaky attach test 25× under load.
- The first tool call after the shared daemon starts no longer waits behind the query workers' cold start (which can take many seconds on a busy machine) — it's served directly until the first worker is warm, so a fresh session answers immediately.
v1.3.0
[1.3.0] - 2026-07-07
New Features
- CodeGraph now indexes Nix (
.nix) — flakes, NixOS and home-manager modules, overlays, and package sets join the graph:letand attrset bindings, functions (simple, destructured{ pkgs, ... }, and curried), andinheritbindings all become searchable symbols, with call edges between bindings. File-level wiring follows the ways Nix actually connects files:import ./relative/path.nix(withimport ./dirreaching the directory'sdefault.nix), NixOS moduleimports = [ ./hardware.nix ../common ]lists, flake-stylemodules = [ ./configuration.nix ]lists, and the nixpkgscallPackage ./pkgs/foo { }idiom — so "what does this configuration actually pull in" and "what uses this module" are answerable on real setups. Dynamic references (import <nixpkgs>, variable paths, flake-input module references) are deliberately left unlinked rather than guessed. Thanks @TyceHerrman. (#324, #332, #648) - The NixOS module system's option wiring is bridged, so flow questions cross the module boundary instead of going dark at it: a config write like
launchd.user.agents.myapp = { ... }orhome.file.".gitconfig" = { ... }links to the module that declares that option (options.launchd.user.agents = mkOption { ... }— flat and nested declaration spellings both count, quoted keys likesystem.defaults.NSGlobalDomain."com.apple.dock"match their exact declaration), which makes "how does enabling this service produce the launchd daemon / generated config file" traceable end-to-end and "what sets this option" answerable across modules, tests included. Precision is deliberately conservative: interpolated${...}paths, options declared in more than one module, and submodule-internal option namespaces stay unlinked rather than guessed, and every bridged hop is labeled as heuristic module-system wiring rather than shown as a plain reference. - CodeGraph now indexes ArkTS (
.ets) — the language of HarmonyOS / OpenHarmony apps. Everything TypeScript gets extracted (classes, interfaces, enums, type aliases, imports/exports, call edges), plus ArkTS's own constructs:@Component/@ComponentV2structs with their decorators (@Entry,@State,@Prop,@Link,@Local,@Param, …) captured and searchable,build()view trees linked parent→child so "which pages render this component" is answerable, chained attributes connected to the@Extend/@Stylesfunctions they invoke,@Buildermethods and functions wired into the call graph, and.onClick(this.handler)-style event bindings linked to their handler methods. Modular HarmonyOS projects resolve across module boundaries too: a bareimport { CartRepository } from "data"follows theoh-package.json5file:dependency to the right module — honoring each module's declaredmainentry, from.etsand.tsconsumers alike — while ambiguous names in multi-app monorepos deliberately stay unlinked rather than guessed, and mixed.ets/.tscodebases cross-link freely. Validated on real HarmonyOS apps including the official OpenHarmony samples monorepo. (#396, #512, #648, #890) - ArkUI's dynamic hops are bridged so flow questions cross them instead of going dark, each labeled as dynamic dispatch rather than shown as a plain call: methods that assign a reactive property (
@State,@Local, …) link to the component'sbuild()(the re-render hop — assignment-gated, so a method that merely reads state gets no edge);emitter.emit(eventId)links to the matchingemitter.on/oncesubscriber when both sides share a statically-recoverable event key (numeric ids pair within one file only, named constants within one module, so unrelated samples in a monorepo never cross-link); androuter.pushUrl({ url: 'pages/Detail' })links to the target page's@Entrystruct, with ambiguous urls left unlinked rather than guessed. - Interrupted or incomplete indexing is now visible instead of silent: a run killed mid-index (crash, out-of-memory, watchdog) leaves a marker that
codegraph statusreports as a truncated index, a completed run that dropped files reports itself as partial — both in the human output and instatus --json— andcodegraph indexprints a warning with the exact counts when its result doesn't add up to what the scan discovered. - CodeGraph now indexes Terraform and OpenTofu (
.tf,.tfvars,.tofu) — resources, data sources, modules, variables, outputs, providers, and everylocalsattribute become symbols (e.g.aws_s3_bucket.my_bucket,var.region,module.vpc,local.prefix), and uses likevar.region,module.vpc.id,data.aws_caller_identity.current, oraws_s3_bucket.my.arnare wired up cross-file, so search, callers, and impact queries return real results on infrastructure repos instead of nothing. Module calls are bridged across the module boundary: amoduleblock's inputs link to the child module's variables,module.vpc.vpc_idreaches the child'soutput "vpc_id"definition, and the block's localsourcepath links to the module's files — so "what breaks if I change this module's variable" reaches every caller instead of dead-ending at the declaration (registry and git sources are deliberately left as visible boundaries rather than guessed). Cross-component wiring through the cloudposse/atmosremote-statemodule connects too:module.vpc.outputs.vpc_cidrin one component reaches thevpccomponent's own output when the component name is statically declared (a literal, or a variable with a literal default) and exactly one directory matches — anything dynamic or ambiguous stays unlinked. Aliased providers are first-class:provider "aws" { alias = "east" }gets its own symbol, andprovider = aws.easton a resource (or a module'sprovidersmap) links to that configuration, found up the module tree the way Terraform actually inherits it.moved/import/removedstate-migration blocks andcheckassertions reference the resources they name, so a refactor's paper trail is part of the graph..tfvarsassignments link to the variables they set, including var-files kept in a subdirectory. Resolution follows Terraform's real per-directory scoping, so same-named variables across modules never cross-link and "what depends onvar.project_id" in a multi-module repo never mixes in unrelated modules. Thanks @Javviviii2. (#83, #310, #648) - CodeGraph now indexes CUDA (
.cu,.cuh) — kernels, device/host functions, structs, and classes become symbols, and the host→kernel call edge survives the<<<grid, block>>>launch syntax, so questions like "how does this call reach the GPU kernel?" trace across the CPU/GPU boundary instead of going dark at the launch site. Real-world launch styles all connect: templated launches (my_kernel<Traits, 256><<<grid, block>>>(args)), launches through a local function pointer (auto kernel = &my_kernel<...>; ... kernel<<<grid, block>>>(args)— each branch-assigned target linked), brace-initialized launch configs (<<<dim3{1,1,1}, dim3{256,1,1}>>>), and kernels defined through a name-in-first-argument macro (flash-attention'sDEFINE_FLASH_FORWARD_KERNEL(kernel_name, ...) { ... }style), which now index under their real kernel names. CUDA that lives in plain.h/.hppheaders — where much real-world device code sits, launch-template headers included — is recognized by content and indexed the same way. Validated on llm.c, flash-attention, and NVIDIA CUTLASS. (#387, #648) - C++ symbols defined inside
namespaceblocks now carry the namespace in their qualified name (flash::compute_attn, C++17namespace a::b {included), and namespace-qualified calls (ns::fn(...)) resolve to their definitions — previously such calls never linked at all, which hid much of the call graph in namespace-heavy C++ codebases from callers and impact analysis. - C++ calls that spell out template arguments (
fn<T, 256>(args)) now link to the function they instantiate, the same normalization templated base classes already had. - CodeGraph now indexes Solidity (
.sol) — contracts, libraries, interfaces, structs, enums, modifiers, events, errors, and state variables become first-class symbols, with call edges that followemit,revert, modifier guards (onlyOwner-style, including base-constructor chains likeconstructor() ERC20(...)), and library/method calls (includingusingdirectives).importdirectives resolve to the imported file, so cross-contract questions like "tracetransferFromthrough allowance and balance updates" or "how doesonlyRolereach the role storage?" work out of the box on real Solidity codebases (validated on solmate, solady, and OpenZeppelin Contracts). Thanks @naiba. (#374, #648) - Erlang behaviour dispatch is now followed through the graph: a framework call through a variable module — cowboy's
Handler:init/Middleware:executefolds, a plugin manager'sMod:callback(...)— links to the repo's implementations of the behaviour that declares that callback, so flow traces and impact cross the OTP callback boundary instead of stopping at it. The links are precision-gated: the callback arity must match, exactly one behaviour may own that callback shape (a collision stays unlinked rather than guessed), the implementer must actually export the callback, and the fan-out is bounded — a behaviour with hundreds of implementers stays a visibly dynamic boundary. Every bridged hop is labeled as dynamic dispatch with its wiring site, never shown as a plain static call. - CodeGraph now indexes Erlang (
.erl,.hrl) — functions, with clauses and arities of the same name grouped as one symbol spanning all of them, plus records with their fields,-type/-opaquealiases,-definemacros, and-specsignatures attached to every function. Cross-modulemod:fn(...)calls resolve to the target module's function,fun name/arityvalues are captured as references (so callback registrations like `lists:foreach(fun submit/...
v1.2.0
[1.2.0] - 2026-07-02
New Features
- Method calls made through a local variable now resolve to the method in many more languages. When code does
const logger = new Logger(); logger.log();(or the equivalent), CodeGraph infers the local variable's type from its declaration or initializer and links the call to the right method — so these calls now show up in callers, impact/blast-radius, andcodegraph_exploreflow traces instead of being dropped. Previously only C++ handled this; it now also covers TypeScript, JavaScript, Python, Java, C#, Kotlin, Swift, Go, Rust, Dart, Scala, and PHP. (#1108) - Ruby method calls made on a receiver (
logger.log) now record an edge to the method. Previously the Ruby indexer kept only the receiver and discarded the method name, so a method called through a variable or object had no recorded callers and was missing from impact/blast-radius and flow traces; combined with the local-variable type inference above,logger = Logger.new; logger.lognow links toLogger#log. Calls to a class method (Foo.bar) and object construction (Foo.new) are still recorded too. (#1110) - The same local-variable method-call resolution now extends to Lua, Luau, R, and Pascal/Delphi. A method invoked through a local — Lua/Luau
local lg = Logger.new(); lg:log(), Rlg <- Logger$new(); lg$log(), or Pascalvar lg: TLogger; ... lg.Log— now links to the right method instead of being dropped. (#1112)
Fixes
- Indexing a large project no longer gets killed partway through with a "Main thread unresponsive — killing the wedged process" message. The safety watchdog that stops a genuinely stuck index was mistaking slow-but-normal work for a hang: on a big repo, linking up references and cross-file relationships can legitimately run for a while, and that work now regularly yields so the watchdog can tell real progress from a true stall. Projects that previously failed to finish
codegraph init/codegraph index(and had to fall back toCODEGRAPH_NO_WATCHDOG=1) now complete normally, while a genuinely hung process is still caught. Thanks @zmcrazy, @YoungLiao, and @GeeLab-Mob for the reports. (#1091) - On Windows, a console window no longer briefly flashes when CodeGraph runs as a background MCP server. When the npm launcher started the bundled runtime — which happens every time an editor starts the server or reconnects after the daemon idles out — and during its self-heal step that extracts a missing platform bundle, Windows would pop up a black console (conhost) window for a moment. Both now launch hidden, matching how the daemon already behaved; the browser-open step of
codegraph loginwas hardened the same way. Thanks @luoyerr for the report and root-cause analysis. (#1092) - C++ forward declarations no longer crowd out the real class definition. A
class Foo;forward declaration — common in large C++ and Unreal Engine codebases, where a heavily used class is forward-declared across dozens of headers — was indexed as its own class node every time it appeared. So exploring that class returned mostly forward-declaration sites, and could even pick one of them as the representative for blast-radius, burying the actual definition and its members and callers. Bodiless forward declarations are now skipped for C and C++, exactly as forward-declared structs and enums already were, so only the real definition is indexed. Languages where a class with no body is a complete definition — such as Kotlin'sclass Emptyand Scala — are unaffected. Thanks @luoyxy for the report and root-cause analysis. (#1093) - C++ methods that return a reference, and user-defined conversion operators, are now indexed under their correct names. An inline getter like
const FGameplayTagContainer& GetActiveTags() const— everywhere in Unreal Engine headers — was indexed as& GetActiveTags() constinstead ofGetActiveTags, and a conversion operator likeoperator EALSMovementState() constkept its trailing() constinstead of readingoperator EALSMovementState. In both cases the garbled name meant you couldn't find the symbol by name and its callers weren't linked. Both now read cleanly, matching how pointer-returning and value-returning methods already worked. (#1096) - C++ functions written with an inline-specifier macro before the return type are now indexed correctly. In Unreal Engine, inline helpers are commonly written
FORCEINLINE FString GetEnumerationToString(...); theFORCEINLINEmacro made the parser read the return type as part of the function's name (FString GetEnumerationToStringinstead ofGetEnumerationToString) and lose the real return type, so the function couldn't be found by name and its callers weren't linked. CodeGraph now recognizes the standard Unreal inline macros (FORCEINLINE,FORCENOINLINE,FORCEINLINE_DEBUGGABLE), so both the name and the return type are captured. (#1100) - The same function-name recovery now covers inline macros from common third-party C++ libraries, not just Unreal Engine — including pugixml (
PUGI__FN,PUGIXML_FUNCTION), Godot (_FORCE_INLINE_), Boost (BOOST_FORCEINLINE), and genericALWAYS_INLINE/FORCE_INLINE. Functions decorated with these are now indexed under their real names. On a large Unreal project vendoring these libraries this cleaned up the large majority of remaining function-name garbling. (#1101) - C++ function names are now recovered even when decorated with a macro CodeGraph doesn't specifically know about. A function written
SOME_LIBRARY_MACRO ReturnType doWork(...)previously had the macro or return type absorbed into its name whenever the macro wasn't one CodeGraph recognized; now the real name (doWork) is recovered regardless of the macro, so it's findable and its callers link — no per-library configuration needed. The recognized-macro list was also broadened (Qt, Folly, Abseil, LLVM, V8, Eigen, rapidjson) so those additionally capture the return type. This only ever cleans up an already-garbled name and is limited to C and C++, so ordinary names — and languages like Kotlin and Scala where identifiers can legitimately contain spaces — are unaffected. (#1102) - The set of C++ libraries whose macros are recognized for full return-type recovery was expanded well beyond Unreal Engine — now spanning Mozilla, Protobuf, {fmt}, nlohmann/json, GLM, Bullet, Skia, OpenCV, EASTL, Cocos2d-x, GLib, SQLite, and the common Windows calling conventions (so
HRESULT WINAPI CreateThing(...)indexes asCreateThingreturningHRESULT). Functions from libraries not on the list still get their name recovered automatically; being listed additionally recovers the return type. (#1103) - Graph traversal and blast-radius results no longer drop or miscount relationships in a handful of edge cases. When a symbol could be reached by more than one path, an impact/blast-radius query could leave out a direct dependency between two symbols that were already linked another way; separately, the lower-level graph traversal used by the library API could keep only one of several relationships between the same pair of symbols (for example a symbol that both calls and references another), count a caller reached through two different call sites twice, or return slightly more results than the requested size limit on a very highly-connected symbol. These were long-standing and mostly masked by later de-duplication, so day-to-day query results were largely unaffected, but the traversal now returns the complete, correctly-bounded set. Thanks @inth3shadows for the precise, individually-traced reports. (#1086, #1087, #1088, #1089, #1090)
- Method calls to same-named classes in different files now resolve to the right definition. If two files each declared, say, a
Loggerclass with its ownlog()method, a call could be linked to whichever definition happened to be indexed first — so a call in one file wrongly pointed at the class in another, mixing up that method's callers and blast radius. This affected calls written asobj.log(),Logger.log(), andLogger::log()across many languages, including C++, Python, TypeScript, Java, C#, and Rust. When a method name is ambiguous, CodeGraph now prefers the definition in the calling file itself — the correct target in the common case — while Java/Kotlin calls that animportalready pins to another file are unaffected. Thanks @inth3shadows for the minimal repro and root-cause analysis. (#1079)
v1.1.6
[1.1.6] - 2026-06-30
Fixes
- The standalone installer (
install.sh) no longer leaves old versions piling up on disk. Each upgrade installed the new release into its own directory and re-pointed the launcher at it, but never removed the previous ones — so on macOS and Linux a full vendored Node runtime (tens of MB per version) accumulated with every update. The installer now keeps only the version it just installed and removes the older ones automatically (the npm installer's download-fallback cache prunes the same way). Windows installs already replaced a single directory in place, so they were never affected. Anything still left behind under~/.codegraph/versionsfrom earlier upgrades is safe to delete. Thanks @lalanbv for the report. (#1074) codegraph indexcan now rebuild an existing oversized index from an older version, instead of hanging until the watchdog kills it. The previous fix (#1065) stopped new indexes from sweeping in a gitignored corpus of nested repos, but a project that had already built the multi-gigabyte graph before upgrading couldn't recover:codegraph indexis meant to rebuild from scratch, yet it cleared the old graph by deleting every row one at a time, and on a graph of well over a million symbols that took longer than the 60-second responsiveness watchdog allows — so the command was killed before indexing even started, leaving the bad index in place. A full re-index now discards the old database outright and starts fresh, which is near-instant regardless of the old size and also frees the disk the bloated database was holding. Thanks @AriaShishegaran for the detailed follow-up report. (#1067)
v1.1.5
[1.1.5] - 2026-06-30
Fixes
- C++ classes annotated with an export or visibility macro are now indexed as real classes. This is the
class MYMODULE_API UMyComponent : public UActorComponentstyle used throughout Unreal Engine — where anXXX_APImacro sits betweenclass/structand the type name — as well as the equivalent*_EXPORT/*_ABImacros common in Qt, Boost, LLVM, and many other libraries. Previously that macro made the parser misread the whole declaration as a function, so the class was dropped entirely: it never appeared in the graph and its base class went unrecorded, which made "find subclasses", type-hierarchy, and impact-through-inheritance queries come back empty for effectively every gameplay class in an Unreal Engine project. The class, its members, and its inheritance link are now all captured. Thanks @luoyxy for the detailed report and proposed fix. (#1061) codegraph_explorenow surfaces the options/config type behind a function when you ask, in plain language, what to change to add a parameter to it. A question like "what do I need to change to add a new parameter to X" shares no words with the file that actually defines X's options — for example a functional-options struct and itsWith…builders living in a separateoptions.go, reachable only through X's signature — so that file scored near-zero on every text and connectivity signal and got dropped: explore returned X itself but not the file you'd edit, and the agent fell back to grep. Explore now follows a named function's parameter and return types and pulls in the file that defines them when ranking would otherwise bury it, so the options/config file shows up with its fields. Well-connected types that already rank are left untouched, so ordinary "how does X work" flow questions are unchanged. (The separate toolscodegraph_search/codegraph_impact/codegraph_noderemain available viaCODEGRAPH_MCP_TOOLSfor anyone who prefers driving each step explicitly.) Thanks @wauxhall for the detailed investigation. (#1064)
v1.1.4
[1.1.4] - 2026-06-29
Fixes
- CodeGraph again respects
.gitignorefor nested repositories that git tracks as gitlinks. The recent change that taught CodeGraph to descend into nested repos recorded as160000"commit" pointers (#1031, #1033) did so even when your.gitignoreexcludes the directory those repos live in — so a gitignored reference or benchmark corpus full of cloned repositories got pulled into the index anyway. One project with a gitignoredbenchmark/repos/of 19 cloned repos saw over 138,000 files swept in and a 4.8 GiB graph, and a full index then stalled in the "Resolving refs" phase until the watchdog killed it. CodeGraph now treats a gitignored gitlink the same as any other gitignored embedded repo: excluded by default, and re-included only when you opt the directory in withcodegraph.jsonincludeIgnored. Nested repos in non-ignored locations — the case #1031/#1033 fixed — are unchanged. Thanks @AriaShishegaran for the detailed report. (#1065)
v1.1.3
[1.1.3] - 2026-06-29
Fixes
- CodeGraph now indexes nested repositories that git records as gitlinks, so a workspace built by stacking several repos inside one another indexes completely from a single
codegraph initat the top. When a repo contains another git repo that wasgit added into it — so git tracks it as a160000"commit" pointer rather than a folder of files — or a submodule that isn't an active, initialized submodule in your checkout, that nested repo's source used to be skipped entirely: indexing the top level stopped at the nested repo's boundary and pulled in only the outer repo's own files, so a stacked-repo project came up nearly empty (one report saw ~10 files indexed at the root). CodeGraph now descends into each such nested repo that has a real working tree on disk and indexes it as its own embedded repository, recursively, so every layer of a stacked workspace is covered. Active submodules (already handled) and plain untracked nested clones are unchanged; a nested repo under a dependency directory such asvendor/ornode_modules/stays excluded; and a submodule with nothing checked out on disk is correctly left alone rather than reported as empty. Thanks @ofergr and @kun-yx for the reports. (#1031, #1033) - CodeGraph no longer shows a misleading "different git working tree" warning when you work inside a submodule (or other nested repo) of a workspace you indexed at its root. Because indexing a workspace now pulls in its submodules and embedded clones, a query run from inside one correctly resolves up to the workspace's single index — but it was still warning that the results came from "a different working tree" and suggesting you run
codegraph init -i, which would have split the submodule back out into its own separate index and undone the unified view. CodeGraph now recognizes that the nested repo's code is already part of the workspace index and stays quiet. The warning still appears for a genuine git worktree — a second checkout of the same repository on another branch, which really does have its own uncommitted symbols — since that's the case it exists for. (#1031, #1033) - On Windows, CodeGraph's background server now shuts down cleanly instead of occasionally aborting with a crash error. When the indexed project contained a nested repository (a submodule or embedded clone), stopping the server could race the file watcher's teardown and exit with a Windows crash code rather than a clean exit. Shutdown now lets that teardown finish first, so the server stops cleanly and promptly. (Windows only; other platforms were unaffected.) (#1033)
- C++ classes that inherit from a templated base —
class Widget : public Base<int>, a CRTP base likeclass App : public CRTPBase<App>, or a struct inheriting a template — are now linked to that base class in the graph. Previously the template arguments (<int>) made the inheritance go unrecognized, so these classes looked like they inherited from nothing and impact/callers analysis stopped at the boundary; the connection is now followed like any other base class. Thanks @ryancu7 for the report. (#1043) - C++ objects constructed on the stack —
Calculator calc(0)orWidget w{1, 2}— now record that the enclosing function instantiates that class, the same as heap construction (new Calculator(0)) already did. Previously only thenewform was tracked, so a function that built objects with the ordinary stack syntax looked like it didn't construct them and the dependency was missing from impact/callers. Thanks @Dshuishui for the report. (#1035) - The graph no longer stores duplicate copies of the same relationship. The same dependency between the same two symbols at the same spot could be recorded more than once, which inflated edge counts and let callers/impact results list a relationship twice. Each relationship is now stored exactly once, and existing projects are de-duplicated automatically the next time CodeGraph opens them. Thanks @inth3shadows for the detailed report. (#1034)
codegraph nodecan now read a file from the command line. File-read mode — pass-f/--fileto get a file's source with line numbers plus the files that depend on it, the same output as thecodegraph_nodeMCP tool — was rejected with "missing required argument 'name'", because the command always demanded a symbol name even though file mode has none, leaving the feature unreachable from the CLI. The symbol name is now optional:codegraph node -f src/auth.ts(orcodegraph node src/auth.ts) reads the file,codegraph node parseTokenlooks up a symbol, and running it with neither prints a short usage hint instead of a cryptic error. Thanks @jcrabapple for the report. (#1044)codegraph queryno longer prints meaningless relevance percentages like "12042%" next to each result. The number was a raw full-text search score — useful only for ordering the results, not as a real 0–100% figure — so multiplying it by 100 produced wild values that made the output look broken. Results are already listed best-match first, so the CLI now just shows them in that order with no score, matching what the search tool reports to AI agents. If you script againstcodegraph query --json, the rawscoreis still included for sorting or thresholding. Thanks @jcrabapple for the report. (#1045)codegraph exploreno longer reports an alarming, inflated result count on broad natural-language queries. The "Found N symbols across M files" summary used to count every symbol the search swept in while ranking, so a broad query (for example "publish status to the API") on a large project could announce hundreds of symbols across a big fraction of the codebase — reading as if you had to wade through all of them — even though only the most relevant handful are actually shown with their source. The summary now counts just the files explore returns source for, so the number matches what you see. Ranking and results are unchanged: the right symbols still come first, and any further relevant files are still listed by name under "Not shown above" so nothing is hidden. Thanks @jcrabapple for the report. (#1046)- Android resource files no longer bloat the index. A
res/tree — layouts, drawables, value bags (strings, colors, styles), menus, navigation graphs — contains no code symbols, but on an Android app it can be the overwhelming majority of files (one project: 26,000+ XML files, ~97% of everything, contributing zero symbols), which inflated the database, slowed indexing, and padded file counts andcodegraph explore/search results with entries that have nothing to find. CodeGraph now skips Android resource directories by default —res/layout/,res/values/,res/drawable/,res/menu/, and the rest, including their locale/density/version variants likeres/values-es/orres/drawable-hdpi/. Your actual code is untouched, and so is the one kind of XML that does carry symbols — MyBatis mapper files, which live undersrc/main/resources/, notres/.res/raw/is deliberately kept (it can hold real assets), and you can re-include any excluded directory with a.gitignorenegation such as!res/values/. Thanks @jcrabapple for the report. (#1047)