[1.1.0] - 2026-06-23
New Features
-
Claude Code: an optional front-load hook makes your agent reach for CodeGraph automatically. When you ask a structural question — "how does X work", "what calls Y", "trace the flow from A to B" — CodeGraph injects the relevant source and call paths into the prompt up front, so the agent answers from the graph instead of grepping around to rebuild it. You're asked during
codegraph install(default yes; Claude Code only, since it's the agent with prompt hooks), it's removed bycodegraph uninstall, andcodegraph upgradeturns it on for existing Claude setups. It's strictly additive and degradable — non-structural prompts and un-indexed projects are left alone — and you can switch it off any time without uninstalling by settingCODEGRAPH_NO_PROMPT_HOOK=1. -
Vue store actions, mutations, and getters are now indexed as symbols you can find and read. Whether your store is Vuex (
mutations/actionsobjects in a module) or Pinia — both the options form (defineStore({ actions: { … } })) and the setup form (defineStore('id', () => { … }), where actions are local functions) — each action, mutation, and getter is now a real node. Socodegraph searchfindsloginorgetSessionList, andcodegraph_explore/codegraph_nodeshow its body and what it calls, instead of "not found" because the function only existed as an object-literal property. -
codegraph_explorenow connects a Vue component to the Pinia store action it calls. When code doesconst store = useUserStore()and thenstore.fetchUser(), that call now links through to thefetchUseraction in the store module — so "what happens when this view loads its data?" traces from the component into the action's body instead of stopping at thestore.fetchUser()line. Works for both Pinia store styles (options and setup), and stays precise (a built-in likestore.$patch()or an unrelated same-named method isn't mislinked). -
codegraph_explorenow follows Vuex string dispatch. Adispatch('user/login')orcommit('SET_TOKEN')call — namespaced'module/action'keys included — now links to the action or mutation it names, resolved to the correct store module even when several modules share an action name (and without being fooled by a same-namedapi/helper). So "what runs when this dispatches?" traces from the call into the store handler and on to the mutations it commits. Vuex's canonicalexport default { namespaced, actions, mutations }module shape is now indexed too, so those handlers are findable symbols. -
codegraph_explorenow connects React data-fetching flows built on RTK Query (Redux Toolkit'screateApi). An endpoint defined insidecreateApi({ endpoints })and theuseGetXQuery/useUpdateYMutationhook it generates were both invisible to analysis — so "what does this component fetch?" or "where doesuseGetThingQueryget its data?" dead-ended, because the hook, the endpoint, and the component had nothing linking them. CodeGraph now indexes each endpoint and each generated hook as real symbols and wires the pathcomponent → useGetXQuery → getX → queryFn, so the flow resolves in one explore call instead of reading the API slice by hand. Both the arrow (endpoints: build => ({ … })) and method (endpoints(builder) { return { … } }) styles are recognized, along with theuseLazyGetXQueryvariant; hand-written hooks of a similar name are left untouched. -
codegraph_explorenow follows Celery task dispatch in Python. Asend_email.delay(...)orsend_email.apply_async(...)call now links to the@shared_task/@app.taskfunction it runs — typically defined in a different module (tasks.py) from where it's triggered (a view or service) — so "what actually happens when this is dispatched?" traces from the call site straight into the task body instead of stopping at the.delay()line. Both decorator dialects are recognized (bare@shared_taskand the arg'd@app.task(bind=True, …)form), including the module-qualifiedtasks.invalidate_cache.apply_async()call style. It stays precise: a.delay()on something that isn't a Celery task is never mislinked, so a project that doesn't use Celery is unaffected. -
codegraph_explorenow follows Spring application events in Java. ApublishEvent(new OrderShippedEvent(...))call now links to every@EventListenerthat handles that event — usually in a different class — so "what reacts when this is published?" traces from the publisher straight into each listener method instead of dead-ending atpublishEvent(...). The link is by event type, and all the common listener styles are recognized: a@EventListenertyped on its parameter, the@EventListener(SomeEvent.class)form,@TransactionalEventListener, and the olderimplements ApplicationListener<SomeEvent>. One event fans out to all its listeners, and a plain Spring app with no event bus is unaffected. -
codegraph_explorenow follows MediatR request and notification dispatch in C#/.NET. A_mediator.Send(command)or_mediator.Publish(notification)call now links to theHandlemethod of the matchingIRequestHandler<>/INotificationHandler<>— usually in a different file in a Clean Architecture layout — so "what handles this command?" traces from the controller straight into the handler instead of stopping at the mediator call. The sent type is recognized whether it's constructed inline (Send(new GetFooQuery())), built into a local first (var cmd = new …; Send(cmd)), or passed in as a parameter, and it's matched by type — so aMessagingCenter.Send(...)or a same-named DTO that isn't a request is never mislinked, and a project without MediatR is unaffected. -
codegraph_explorenow follows Sidekiq background-job dispatch in Ruby. ADestroyUserWorker.perform_async(id)(or.perform_in/.perform_at) call now links to that worker'sperformmethod — usually inapp/workers/away from the controller or model that enqueues it — so "what runs in the background here?" traces from the enqueue straight into the job body. Both the moderninclude Sidekiq::Joband the olderSidekiq::Workerare recognized, namespaced workers resolve to the right class even when several share a name (e.g.Comments::NotifyWorkervsArticles::NotifyWorker), and Rails ActiveJob'sperform_later— a different mechanism — is intentionally left alone. -
codegraph_explorenow follows Laravel events in PHP. Anevent(new OrderShipped($order))call now links to every listener that handles it — each listener'shandle()method, usually a separateapp/Listeners/class — so "what reacts to this event?" traces from the dispatch straight into the listener bodies. Listeners are found both ways Laravel registers them: by a typedhandle(OrderShipped $event)(auto-discovery, including ahandle(A|B $event)union that listens for two events) and by theprotected $listenmap in yourEventServiceProvider(which also catches a listener whosehandle()has no type-hint). One event fans out to all its listeners, and queued jobs — dispatched via::dispatch()rather thanevent()— are correctly left out. -
CodeGraph now understands Lombok-generated methods in Java.
@Getter,@Setter,@Data,@Value, and@Buildergenerate getters, setters,builder(),equals/hashCode/toString, and the@Slf4jlogfield at compile time, so those methods never appear in the source — and auser.getName(),User.builder(), orlog.info(...)call used to resolve to nothing, silently breaking call-chain analysis (the agent would conclude the method didn't exist and reconstruct it by hand). Those members are now indexed from the annotations and fields, so they appear incodegraph searchandcodegraph_explore/codegraph_node, and callers trace through them like any hand-written method. They're marked as Lombok-generated so they read as generated, not hand-written; a method you write yourself is never overridden, static fields get no accessor, and a class without Lombok is unaffected. Thanks @git87663849. (#912) -
codegraph_explorenow follows C and C++ function-pointer dispatch. C does polymorphism with function pointers: a struct carries a function-pointer field, concrete functions are registered into it through a table (static struct cmd commands[] = {{"add", cmd_add}, …}), a designated initializer (.handler = on_open), or an assignment, and the code dispatches indirectly (p->fn(argv)). None of that was visible to analysis — the indirect call resolved to nothing, sogit's command runner looked like it called nothing and a vtable's implementations had no callers. CodeGraph now links the dispatch site to the registered handlers, keyed by the struct field, so "what runs when this dispatches?" traces fromp->fn(...)into every function registered for that field. This covers the command-table idiom (git, redis) and the ops-struct/vtable idiom (curl's content-encoders, protocol handlers), including the case where a generic hook slot is reassigned from a registry (h->func = found->fn). It stays precise — distinct function-pointer fields don't cross-link, a plain data field is never treated as a dispatch, and a project without function-pointer dispatch is unaffected. (#932) -
codegraph_explorenow follows GoFrame route bindings in Go. GoFrame's standard router wires routes reflectively: the path and method live in ag.Metastruct tag on a request type (g.Meta `path:"/user/sign-in" method:"post"`), the controller method that serves it is matched by that request type, and the two are joined at runtime bygroup.Bind(...)— so there was no path string and no edge from a route to its handler, and "where is/user/sign-inhandled?" or "where are the routes bound to controllers?" could only be answered by reading. CodeGraph now indexes eachg.Metaroute as a real route node and links it to the controller method whose signature takes that request type, so a route resolves to its handler structurally in onecodegraph_explorecall. The link is by request type, not method name — so it's correct even when the two differ (aDeptSearchReqserved by aListmethod); it tells apart the many identical request types a large app defines one-per-module (cash.ListReqvsorder.ListReq) by package, including cloned addon modules; and a route whose handler isn't present is left unlinked rather than guessed. (#747) -
The MCP server now works in monorepos and multi-project setups. Before, if you started CodeGraph somewhere with no
.codegraph/of its own — most often a monorepo root where you only indexed individual services — the server exposed no tools at all, so your agent couldn't query CodeGraph even for the sub-projects that were indexed. Now the tools are always available: point a query at any indexed project with theprojectPathargument (its path, or anywhere inside it) and CodeGraph answers from that project's index — for as many projects as you like in one session. It also means a project you index after the server started is picked up without restarting, where before the tools stayed hidden because the server only checked for an index once at launch. A project that genuinely has no index still cleanly tells your agent to use its built-in tools there (and that you can runcodegraph initto enable it), so single-project use is unchanged. Thanks @MaiLunJiye. (#964) -
The Claude front-load hook now finds your indexed sub-projects in a monorepo. The optional
UserPromptSubmithook that injects CodeGraph context for structural questions previously only looked for an index at or above your working directory — so if you opened the monorepo root but indexed individual packages (packages/api,services/auth), it found nothing and stayed silent exactly where it was most useful. It now also looks into sub-projects: a single indexed sub-project gets its context front-loaded automatically, and with several the hook front-loads the one your question names (and lists the rest so the agent can target them byprojectPath). Single-project repos are unaffected, and the scan is bounded and skipped entirely outside a recognizable workspace root. (#964) -
codegraph_explorenow surfaces the right code in large multi-layer projects. When you ask a backend-flow question in a repo that pairs an API server with a big frontend that mirrors the same domain words — say anapp/admin UI sitting over anapi/server — the server-side file that genuinely matches several of your query's terms is no longer pushed out of the results by the larger, more interconnected frontend layer. A file corroborated by two or more distinct query terms is now kept in the answer even when a denser unrelated layer would otherwise crowd it out, so "how does X read items / handle the request" returns the service or handler that does the work instead of a wall of frontend views. Single-layer projects are unaffected; setCODEGRAPH_RANK_NO_MULTITERM=1to revert to the previous ranking. -
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.) -
You can now teach CodeGraph about custom file extensions. Drop a
codegraph.jsonat your repo root with anextensionsmap —{ "extensions": { ".dota_lua": "lua", ".tpl": "php" } }— and files with those extensions get indexed under the language you name, instead of being silently skipped because the extension wasn't one of the built-in defaults. It's opt-in and committed alongside your code so the whole team shares it, your mappings layer on top of the built-ins and win on conflict (you can even re-point a built-in, e.g..h→cpp), and a typo'd language or a malformed config is warned about and skipped rather than breaking indexing. Projects without acodegraph.jsonbehave exactly as before. (#906)
Fixes
codegraph indexandcodegraph initno longer crawl during the "Resolving refs" phase on large projects — most painfully ones that mix a big front-end and back-end, where the phase could stretch to many minutes. A package or module imported across hundreds or thousands of files (react, a shared UI package, Pythonlogging/typing) was being treated as if every one of those import statements might be its definition, so the resolver compared each import against all the others — work that grows with the square of how widely a package is imported, which is why it blew up only on big, import-heavy repos. Imports now resolve straight to the definitions they actually point at, so those redundant comparisons are gone (reference resolution is dramatically faster on large repos), and the graph no longer accumulates the meaningless import-to-import links the old fallback created. (#915)- MCP tool results no longer show up as oversized headings in Markdown-rendering clients (such as the Claude Code VSCode extension). Results used Markdown headings (
##/###) for things like the status summary, each search hit, and every file section in an exploration, so a normal query filled the transcript with large-font lines — worst withcodegraph_searchandcodegraph_explore, where the noise grew with the number of results. Section headers are now bold labels, which render at normal text size while keeping the same structure. Terminal/CLI output is unchanged. (#778) - An MCP server pointed at a very large repository (tens of thousands of files) no longer hangs on the first tool call after a fresh start. On startup CodeGraph reconciles its index against the current files on disk, and on a huge repo that reconcile could run for minutes while blocking the very first request — long enough that the background server was sometimes force-restarted mid-scan, so the first query never came back at all. The reconcile now yields as it runs (keeping the server responsive instead of pinning it), and the first tool call waits only briefly for it before answering and letting the rest finish in the background — so you get a fast first response and the index still catches up. Set
CODEGRAPH_CATCHUP_GATE_TIMEOUT_MSto tune how long that first call waits (default 3000ms), or=0to always wait for the full reconcile. (#905) codegraph installnow wires up your agents and stops there — it no longer indexes the current directory. Building a project's graph is always the explicitcodegraph init(orcodegraph index), so you decide what gets indexed and when, and the steps are the same whether you installed globally or just for one project. This clears up the confusion where a project-local install silently indexed but a global one didn't, and where the docs and the tool disagreed about whether you still had to runinit. (#826)- React components declared with
forwardRef,memo, or styled-components / emotion (const Button = forwardRef(...),const Card = memo(...),const Box = styled.button\…`) are now recognized as components, so finding where they're used works. Before, they were indexed as plain constants, socodegraph callersand impact analysis reported "no callers found" even when the component was rendered across dozens of files — a dangerous false "safe to change" right before refactoring a shared component. Now every` usage links back to the component, so callers and blast radius are complete. This is the standard shadcn/ui declaration style, so for typical React design systems the whole UI layer is no longer invisible to impact analysis. Thanks @Arlandaren for the report and @maxmilian for the root-cause. (#841) - React Router and Next.js routes defined in
.tsx/.jsxfiles are now indexed. Routes written as JSX —<Route path="/users" element={<UsersPage/>}/>,createBrowserRouter([...]), and Next.jsapp//pages/page files — were being skipped entirely (only routes that happened to live in plain.ts/.jswere picked up), so "what renders at this path?" and the route → page-component link were missing for most React apps. Now those routes show up incodegraph search/codegraph_exploreand connect to the component they render, just like the backend route → handler links on other frameworks. codegraph sync(and the file-watcher auto-sync behind always-on / MCP use) no longer drops a function's callers when you edit the file that function lives in. Re-indexing a file after an edit — even a docstring-only change — was severing thecalls/referencesedges coming from other, unchanged files (e.g.from pkg import mod; mod.fn()callers, or any cross-file reference), socodegraph callers/impactwould abruptly report "no callers" for a function that's used throughout the codebase, until the next full re-index. Sync now preserves those incoming cross-file edges across the re-index, re-matching them to the symbol even when the edit shifted its line number. Most visible in large Python package trees, but it applies to every language. Thanks @JosefAschauer. (#899)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) - A long-running MCP server now notices when a git worktree gains its own index. Before, if the server (or shared daemon) first saw a worktree before you ran
codegraph initin it — so the lookup walked up to the main checkout's index — it pinned that decision for its whole life: even after the worktree had its own.codegraph/, every query kept hitting the main checkout's index and every result carried a false "this index belongs to a different git working tree" warning, until you restarted the server. The CLI got it right but the MCP server didn't, and re-indexing didn't help. The server now re-checks which index a path belongs to on each call, so the worktree's own index is picked up — and the stale warning drops — without a restart. (#926) - A long-running MCP server now recovers when your index is deleted and rebuilt at the same path. If
.codegraph/was removed and recreated while the server held it open — most easily by recreating a git worktree at the same path, orrm-ing.codegraph/and runningcodegraph initagain — the server kept reading the old, deleted database file and served a frozen snapshot: renamed or removed symbols still showed as live, new ones were missing, andcodegraph synccouldn't refresh it — only restarting the server fixed it. The server now detects that the database file was swapped out from under it and reopens the live one in place, so results stay correct without a restart. (On Linux and macOS; Windows doesn't allow deleting an open file, so it isn't affected.) (#925) - The MCP server now opens and auto-syncs a project that lives inside a folder an enclosing git repository ignores. Before, if the directory you indexed sat within a larger repo that gitignored it, the shared MCP daemon failed to open the project — its log repeated
Failed to open project … path should be apath.relative()d string, but got "./"— so the file watcher never started and the index silently went stale until you rancodegraph syncby hand (settingCODEGRAPH_NO_DAEMON=1was the only workaround). The daemon now opens the project and starts watching as expected. Most visible with Codex on Windows, but the cause wasn't platform-specific. (#936) - A git worktree of a submodule is no longer indexed as a duplicate copy of that submodule's code. CodeGraph already skips ordinary worktrees (a second working view of a repo it indexes), but a worktree created from a submodule — common in monorepos that check submodules out into worktrees for parallel feature work — was mistaken for a genuine embedded repo and swept in, duplicating every symbol it shared with the real submodule checkout (one report had ~28% of its index as duplicates, inflating both query results and the database). These submodule worktrees are now recognized and skipped, while the submodule's own checkout stays indexed as distinct code. Thanks @charlesxu2026-ship-it. (#945)
- A C++ class or struct annotated with an export/visibility macro —
class MYLIB_EXPORT Foo : public Bar { … }, the common DLL-export / visibility pattern in headers — is no longer mis-indexed as a function spanning the whole class body. Not knowing the macro is a macro, the parser read it as a type and the whole declaration as a function, so the class surfaced as a phantomfunctionthat showed up as a false caller incodegraph callers,codegraph impact, and blast-radius analysis, and skewed symbol counts. CodeGraph now recognizes this misparse and drops the bogus node. Thanks @spwlyzx. (#946) codegraph statusno longer reports phantom pending changes for files CodeGraph deliberately keeps out of the index — a tracked file inside a committed dependency dir (a checked-invendor/ornode_modules/), or a tracked file under a.gitignored directory. A full index correctly excludes these, andcodegraph syncnever indexes them, but the fast change-detector behindcodegraph statusflagged every edit to such a file as "modified" (and a new one as "added") — so the pending-changes count never cleared no matter how many times you synced. Change detection now applies the same ignore rules the full index does, sostatusagrees withsync, and tools built on CodeGraph's change-detection API get the same corrected list. (#766)- Files reached through a symlinked directory that points outside your project now index instead of being silently skipped. When a folder in your repo is a symlink to a location outside the repo root — the standard layout for Dota 2 custom games and similar SDK-linked projects, where
game/andcontent/link into the engine tree — CodeGraph followed the symlink to discover those files but then blocked every one of them while reading, loggingPath traversal blocked in batch readerand indexing nothing under them. The reader now agrees with the directory scan and indexes those files. The guard against../path escapes is unchanged, and the protection that keeps your agent from being served file contents from outside the repo is also unchanged — only the indexer's own read path follows these in-repo symlinks. (#935)