[1.1.2] - 2026-06-28
New Features
- You can now exclude committed directories from the index with an
excludelist incodegraph.json— even when they're git-tracked..gitignorecan't drop a directory git already tracks, so a vendored theme or SDK that's checked into your repo (a committed Metronic theme understatic/, a bundled vendor library) had no supported way to be kept out — it just bloated the graph and slowed indexing. Add a rootcodegraph.jsonwith, e.g.,{ "exclude": ["static/", "**/vendor/**"] }and those paths are skipped on indexing, sync, and file-watching, on both git and non-git projects. Patterns are gitignore-style and matched against repo-root-relative paths. This complements the existingincludeIgnored(its opposite — opt in to gitignored embedded repos). (#999) - CodeGraph now follows C/C++ commands that are dispatched through macro-built function-pointer tables, so the handler functions they reach are no longer dead-ends in the graph. Many C projects register a handler into a struct's function-pointer field through a macro and a generated table — redis is the classic case: every command (
getCommand,decrbyCommand, …) is wired into the command struct'sprocfield by aMAKE_CMD(…)table that lives in a generated,#include-d file, then invoked asc->cmd->proc(c). CodeGraph now reads those macro-built tables — including ones whose struct type is itself a macro alias, whose table sits in an#include-d file that is never indexed on its own, or that are wrapped in conditional compilation (#ifdef) and defined inline with the struct. It recognizes function-pointer fields declared through a function typedef, and follows the receiver — a chained access (c->cmd->proc) or an array subscript through a file-scope table ((cmdnames[i].cmd_func)(…)) — across field types. It also follows dispatch through a bare array of function pointers with no struct wrapper at all — the opcode/handler-table pattern common in interpreters and emulators, where a table likeopcodes[op](…)invokes one of many registered handler functions by index — linking the dispatcher to every handler in the array. The upshot: asking for the callers or blast radius of a command handler now finds the dispatcher that reaches it. For redis,callshows up as a caller of every command; for SQLite, the builtin SQL functions registered throughFUNCTION(...)link to where they're invoked; for Vim, every:exand normal-mode command links from the dispatcher. (#991, extending #932) - CodeGraph no longer times out when many agents query it at once. The shared background server that serves all your editor and agent sessions used to run every query on a single thread, so a burst of concurrent requests — for example a swarm of subagents exploring a large monorepo together — queued up behind one another and, while the heavy ones ran, froze the connection so finished answers couldn't even be sent back until the whole batch drained. Past a handful of simultaneous callers that routinely surfaced as MCP request timeouts. The shared server now answers queries across a pool of worker threads, so concurrent requests run in parallel and the connection stays responsive the whole time; when it's genuinely saturated a call returns a brief "busy, retry shortly" note (not an error) instead of hanging past your client's timeout. The pool sizes itself to your machine — roughly one worker per core, leaving one for coordination — and a single editor session is unaffected (no pool, no overhead). Set
CODEGRAPH_QUERY_POOL_SIZEto choose a specific number of workers, or0to revert to single-threaded in-process queries. - Indexing now parses files across multiple CPU cores instead of one, so building a project's graph —
codegraph index, the first index of a project, and the background re-index after changes — is faster on multi-core machines, most noticeably on large or parse-heavy codebases. The graph it produces is identical to before and re-indexing stays deterministic: parsing runs in parallel, but results are still committed in a fixed order, so the same project always yields the same graph. CodeGraph sizes the pool to your machine automatically (leaving a core free for everything else); setCODEGRAPH_PARSE_WORKERSto choose a specific number of parse workers, orCODEGRAPH_PARSE_WORKERS=1to restore the previous single-core behavior. Peak memory is unchanged — workers reclaim parser memory independently, so it doesn't grow with the number of cores. (#1015, #320) - When CodeGraph's MCP server runs with no default project of its own — started outside any repository (for example behind an MCP gateway), or at a monorepo root whose indexes live in sub-projects — it now marks
projectPathas a required argument on every tool call. Before,projectPathwas always optional, so an agent talking to such a server would often omit it, get back guidance to pass it, and not reliably retry — you had to nudge it by hand every time. Now the requirement is part of the tool definition the agent sees, so it supplies the path to the project it's working on the first time. When the server does have a default project — the normal case, launched inside your repo —projectPathstays optional and a call without it falls back to that project exactly as before. Thanks @wauxhall for the report. (#993) - CodeGraph's MCP tools now work in Cursor's Ask mode (and any other client that only permits read-only tools). Every CodeGraph tool just reads your indexed code — it never changes your workspace — but it didn't advertise that, so Cursor's Ask mode blocked every call with "you are in ask mode and cannot run non read-only tools," and you had to switch to Agent mode to use CodeGraph at all. CodeGraph now declares all its tools read-only using the standard MCP tool annotations, so Cursor (and similar clients) allow them in read-only contexts. Nothing about how the tools behave changes. Thanks @CDsouza315 for the report. (#1018)
Fixes
- A
codegraph indexorcodegraph initthat gets orphaned or wedged now stops itself instead of pinning a CPU core forever. If you killed the command (or the terminal/agent that launched it), the underlying indexer process used to keep running in the background — the parent couldn't pass the signal along — and a genuinely stuck index had nothing watching it either, since the self-recovery watchdogs were wired only into the background MCP server. Both gaps are closed: indexing now self-terminates when its parent goes away, and a main thread that stops making progress is killed so it can't hang indefinitely. Opt out withCODEGRAPH_NO_WATCHDOG=1(liveness) orCODEGRAPH_PPID_POLL_MS=0(orphan detection), matching the server. (#999) - Indexing no longer hangs at "Resolving refs" on a repo that commits a large JavaScript/TypeScript theme or SDK. A vendored admin theme (Metronic is the classic case — ~1,300 committed
.jsfiles) re-declares the same method names (init,update,render,destroy, …) on hundreds of widgets, and resolution used to score every same-named definition against every call — work that grows with the square of how many times a name repeats. On such a repo it pinned a CPU core for 15–30 minutes and effectively never finished. Resolution now declines to guess when a name is defined more times than any real codebase ever repeats one (the cutoff is generous — normal projects top out far below it and are completely unaffected), since no proximity heuristic can pick the one true target among thousands anyway. Indexing that previously wedged now completes in seconds, and precise resolution (imports, qualified names, class-name matches) is unchanged. This is the same class of slowdown as the 1.1.0 import-name fix, now closed for repeated method/symbol names. Tune the cutoff withCODEGRAPH_AMBIGUOUS_NAME_CEILINGif you ever need to. Thanks @DANOX2 for the detailed report and repro. (#999) - Claude Code's front-load prompt hook now fires for non-English prompts. The optional hook that injects CodeGraph context for structural questions only recognized English keywords, so a structural question written in Chinese — or any non-Latin-script language — silently injected nothing: the hook looked like it wasn't wired up despite a correct setup, with no error to explain why. The gate is now language-aware. It recognizes Chinese structural keywords (如何/流程/调用/依赖/实现/架构…), and — in any language — a prompt that names a real code symbol from your project, such as
getUserId,article_publish,user.login, orparseToken()(the name is checked against the index, so an ordinary word that merely looks like code doesn't trigger it). Non-structural prompts ("fix this typo", in any language) stay a no-op as before, so nothing fires where there's no structural answer to give. Thanks @whinc for the detailed report and repro. (#994) - The background auto-sync server now starts for projects kept on an ExFAT or FAT external drive (and some network mounts). Those filesystems don't support the operations the server relies on to coordinate and to listen locally, so it failed immediately and re-logged the same error on every retry — background indexing was broken, so you had to run
codegraph syncby hand after changes. (The MCP tools, the prompt hook, and manualcodegraph index/syncwere unaffected, since none of them need the server.) The server now works around those limitations automatically — falling back to a different coordination method and relocating its local socket to your system temp directory — so background indexing works there exactly like anywhere else, with no configuration needed. Verified end-to-end on real removable-drive filesystems on macOS, Linux, and Windows. Thanks @zengwenliang416 for the detailed report. (#997) - If you use CodeGraph as a library, the
QueryBuilder.deleteResolvedReferences()helper no longer throws "too many SQL variables" when handed a very large list of ids — it issued one unbounded query, so a list longer than SQLite's parameter limit aborted the call. It now splits the work into batches like every other bulk query in the API. CodeGraph's own indexing and reference resolution never called this method (they use a different, already-batched path), so the CLI and MCP server were unaffected. Thanks @inth3shadows for the static analysis. (#1001) - Swift computed properties are now indexed, so you can search for them. A computed property — a
var isCloudProxy: Bool { … }read all over a codebase, a SwiftUI view'svar body: some View { … }, a protocol'svar title: String { get }requirement — produced no symbol at all, socodegraph queryandcodegraph_exploreanswered "No results found" for it, and an agent that trusts an empty result would wrongly conclude the property doesn't exist. Computed properties (and protocol property requirements) are now graph symbols you can find and explore like anything else. A computed property's getter is also read as its body, so a SwiftUI view'sbodylinks to the subviews and helpers it builds — making a view's render flow traceable through the property. Stored properties were already indexed; this closes the computed-property gap. Thanks @monochrome3694 for the precise report and repro. (#1020)