| Name | Modified | Size | Downloads / Week |
|---|---|---|---|
| Parent folder | |||
| codegraph-win32-x64.zip | 2026-05-26 | 42.6 MB | |
| SHA256SUMS | 2026-05-26 | 560 Bytes | |
| codegraph-darwin-arm64.tar.gz | 2026-05-26 | 46.8 MB | |
| codegraph-darwin-x64.tar.gz | 2026-05-26 | 48.0 MB | |
| codegraph-linux-arm64.tar.gz | 2026-05-26 | 51.7 MB | |
| codegraph-linux-x64.tar.gz | 2026-05-26 | 52.0 MB | |
| codegraph-win32-arm64.zip | 2026-05-26 | 38.8 MB | |
| README.md | 2026-05-26 | 13.2 kB | |
| v0.9.5 source code.tar.gz | 2026-05-26 | 1.4 MB | |
| v0.9.5 source code.zip | 2026-05-26 | 1.6 MB | |
| Totals: 10 Items | 282.9 MB | 0 | |
[0.9.5] - 2026-05-25
Added
- Shared MCP daemon — running multiple AI agents in the same project no longer multiplies the file-watch, SQLite, and indexing cost. Point more than one
codegraph serve --mcpat a project (two Claude Code windows, an agent in a git worktree,/loopalongside an interactive session, parallel sub-agents) and they now share one background daemon per project: a single file watcher (one inotify set on Linux), one SQLite connection, and one tree-sitter warm-up — instead of N independent copies. Measured on Linux: three agents register ~3× fewer inotify watches sharing one watcher versus three standalone servers. Resolves issue [#411]. (Composable with the per-watcher pruning in [#276]/#346 — that shrinks each watch set; this shares one across agents.) - The daemon runs as a detached background process that outlives any single session, so closing one editor or terminal never severs the others. Each
serve --mcpyour agent host launches is a thin stdio↔socket proxy to it (a Unix-domain socket, or a named pipe on Windows). When the last client disconnects the daemon lingers forCODEGRAPH_DAEMON_IDLE_TIMEOUT_MS(default300000) so back-to-back sessions skip the startup cost, then exits and removes its lockfile — an OOM-killed or force-quit host can't leak it. -
CODEGRAPH_NO_DAEMON=1opts out, restoring one independent server per client (handy for debugging or sandboxes that disallow local IPC sockets). The daemon is also version-pinned: after you upgrade codegraph, sessions already attached to the old daemon keep using it while new sessions run standalone until it idles out — they never mix versions over the socket. -
Per-file staleness banner — codegraph responses now tell the agent which files are pending re-index (#403). When the file watcher has seen edits since the last successful sync, MCP tool responses (
codegraph_search,context,callers,callees,impact,trace,explore,node,files) prepend a⚠️banner naming the stale files referenced in that response, with their edit age and indexing state; pending files elsewhere in the project appear as a small footer. The agent is told which specific files to Read directly; the rest of the response is fresh and codegraph stays authoritative for it. No artificial wait, no static "wait ~500ms" guess — the cost is zero when nothing's pending.codegraph_statusalso surfaces a### Pending sync:section so an agent can ask "is the index caught up?" in one call. -
CODEGRAPH_WATCH_DEBOUNCE_MSenv var lets you tune the file-watcher quiet window (#403). Default stays at 2000ms; workspaces with bursty writes (formatter-on-save chains, multi-file refactors, large generated outputs) can raise it (e.g.5000or10000) without touching their agent's command line. Clamped to[100ms, 60s]; out-of-range or non-numeric values fall back to the default and the active value is logged to stderr on watcher startup so it's discoverable. Pairs with the staleness banner above: the banner stays accurate at any debounce value because it's per-file, not a static "wait N ms" instruction. -
Objective-C indexing —
.m,.mm, and content-sniffed.hfiles now parse with full structural extraction (#165). Adds a tree-sitter-objc extractor that producesclassnodes for@interface/@implementation(deduplicated into one),protocolnodes for@protocol, methods with full multi-part selectors (setObject:forKey:,tableView:didSelectRowAtIndexPath:— not just the first keyword, which would collide distinct methods),+/-static distinction,@propertydeclarations,#importfor both<system>and"local"forms, andextends/implementsedges for superclasses and<Protocol>conformance lists. Call edges come from both C-stylecall_expressionand ObjCmessage_expression(withself/superskipped on qualified callee names). Header files default to C unless content-sniffing finds@interface/@implementation/@protocol/@synthesize, so iOS headers classify correctly without breaking pure-C projects. Validated on AFNetworking (84 files, 100% file coverage, 93 multi-keyword selectors), RestKit (282 files, 99.6%), and Texture (926 files, 100% — including heavy.mmObjC++ content).
Disclosed limitations: categories produce one extra class node per category file (e.g. ASDisplayNode+Yoga.m creates a second ASDisplayNode node attributed to the category file); chained/nested message sends record only the innermost method; [Class alloc] patterns don't yet emit instantiates edges; @protocol Foo <Bar> refinement lists aren't wired to implements; heavy C++ in .mm files may parse incompletely under the ObjC grammar. Mixed Swift/Objective-C cross-language resolution (@objc-exposed Swift methods, bridging headers, React Native's native bridge) is not in scope for this entry — that's a separate effort tracked under the dynamic-dispatch coverage playbook.
-
Mixed iOS, React Native, and Expo cross-language bridging. Real iOS and React Native codebases live across multiple languages — a Swift caller invokes an Objective-C selector that's been auto-bridged, JS calls into a native module via the React Native bridge, JSX delegates to a native view manager. Static tree-sitter extraction stops at each boundary. CodeGraph now bridges them so
trace/callers/callees/impactconnect end-to-end across the gap. Closes the iOS/RN parts of the request thread for [#401]. Bridges added: -
Swift ↔ Objective-C. Swift
@objcauto-bridging rules (func play(song:)↔ ObjC-playWithSong:,init(name:, age:)↔-initWithName:age:,var x: T↔-x/-setX:,@objc(custom:)overrides) plus the Cocoa preposition-prefix forms that reverse-import natively (objectForKey:,stringWithFormat:, etc.). Validated on Charts (28 / 1 bridge edges objc→swift / swift→objc), realm-swift (36 / 1185), wikipedia-ios (52 / 983). The high-confidence direction is ObjC→Swift, since Swift callsites carry the bare method name only and many overlap with Cocoa built-ins. -
React Native legacy bridge + TurboModules. Parses
RCT_EXPORT_MODULE/RCT_EXPORT_METHOD/RCT_REMAP_METHOD(ObjC & ObjC++) and@ReactMethod(Java/Kotlin) declarations; treatsNative<X>.tsTurboModule spec files as ground truth. A JS callsite ofNativeModules.X.fn(...)orimport X from './NativeX'; X.fn(...)resolves to the matching native method. Validated on AsyncStorage (8/8 precise), react-native-svg (9 TurboModule bridges to Java), react-native-firebase (18 precise afterRCTEventEmitterbuilt-in blocklist). -
Native → JS event channel. Synthesizes cross-language edges keyed by literal event name: ObjC
sendEventWithName:@"X"/ SwiftsendEvent(withName: "X", ...)/ Java/Kotlin.emit("X", ...)→ JSnew NativeEventEmitter(...).addListener("X", handler). Falls back to attributing the JS endpoint to an enclosingconstant/variablefor the very commonconst Foo = { watchX(listener) { ... addListener('X', listener) } }wrapper-API pattern. Validated on RNFirebase (3 push-notification flow edges) and RNGeolocation (2 location-event edges). -
Expo Modules. Parses Swift/Kotlin Expo DSL —
Module { Name("X"); Function("y") { ... }; AsyncFunction("z") { ... }; Property("w") { ... } }— and synthesizesmethodnodes named after each declaration. JS callsites ofrequireNativeModule('X').y(...)then resolve via existing name-match. Validated on expo-haptics (6 method nodes across Swift + Kotlin), expo-camera (41 covering the full SDK surface), and a 7-package Expo sweep (134 method nodes). -
Fabric / Codegen + legacy Paper view components. Parses TS
codegenNativeComponent<NativeProps>('Name', ...)Codegen specs AND legacyRCT_EXPORT_VIEW_PROPERTY/@ReactPropview-manager macros. Emits acomponentnode per declaration and apropertynode per declared prop, then a synthesizer links the component to its native impl class by convention-based name+suffix (View/ComponentView/Manager/ViewManager). The existing JSX synthesizer then connects consumer JSX<MyView/>→ component → native class. Validated on react-native-segmented-control (legacy Paper — 1 component, 11 props, 4 bridges), react-native-screens (Codegen Fabric — 27 components, 272 props, 68 bridges), and react-native-skia (hybrid, monorepo — 5 components, 14 props, 15 bridges across Codegen TS specs + Android Java ViewManagers + iOS ObjC).
Each bridge emits provenance:'heuristic' edges with a stable metadata.synthesizedBy: channel name (swift-objc-bridge, react-native-bridge, rn-event-channel, fabric-native-impl, expo-modules) so an agent can tell at a glance how a cross-language hop got into the graph. Per-bridge precision blocklists prevent noisy over-linking on generic Cocoa names (init, description, count, …) and RN event-emitter built-ins (addListener, remove, …) that every NSObject / RCTEventEmitter subclass exposes.
Architectural fix surfaced during validation: the resolver's initialize() runs at CodeGraph construction (before any files are indexed), so framework resolvers whose detect() consults the indexed file list silently dropped themselves. indexAll() now re-initializes the resolver after extraction so all frameworks see the populated index — a pre-existing latent bug that also affected the UIKit and SwiftUI resolvers.
Out of scope for this round: bare JSI (non-TurboModule), dynamic bridge keys (NativeModules[someVar]), Android-Java extraction improvements beyond name-match (we use whatever the existing Java extractor produces). Anti-goals documented in docs/design/mixed-ios-and-react-native-bridging.md.
Fixed
- Git worktrees no longer silently borrow another tree's index (#155). When a worktree is nested inside the main checkout — exactly what agent tools that place worktrees under gitignored paths like
.claude/worktrees/<name>/do — running CodeGraph from that worktree used to walk up to the main checkout's.codegraph/and silently return that tree's code (usually a different branch). Symbols changed only in the worktree were invisible and nothing told you. Nowcodegraph status(CLI + MCP) calls out the conflict explicitly, and every MCP read tool (codegraph_search/context/trace/callers/callees/impact/explore/node/files) prefixes a one-line notice naming the borrowed index and the fix (codegraph init -iin the worktree). Detection is best-effort (no git / not a repo / monorepo subdir → no warning) and runs once per session per start path, so it never costs more than a single pair ofgit rev-parseinvocations. - The file watcher no longer exhausts the OS file-watch budget on large repos (#276). It used to register a recursive watch over the entire project —
node_modules/, build output, caches and all — and filter only after the fact. On Linux that meant hundreds of thousands of inotify watches per project; enough that a second project, or codegraph alongside your editor /next dev, could hit the per-user ceiling and fail with "OS file watch limit reached." The watcher now excludes the same directories the indexer ignores (the built-in default-ignore set plus your.gitignore) before registering a watch — so on a repo with a 900-directorynode_modulesthe watch count drops from ~1,200 to ~14, even when the project has no.gitignore. (Stacks with the shared daemon from [#411]: one watcher across agents, and now that watcher is small.) - The index now stays in sync after
git pull, branch switches, and edits made outside your editor. Incremental sync detected changes viagit status, which only sees uncommitted edits — so code pulled or checked out (which leaves a clean working tree) was silently missed until a fullcodegraph index -f. Change detection is now filesystem-based and git-independent: a(size, mtime)stat pre-filter skips unchanged files, then a content hash confirms the rest. It reconciles committed changes frompull/checkout/merge/rebase, plain edits in non-git projects, and deletions alike. - The MCP server catches up on connect. When your editor connects, codegraph reconciles anything that changed while it wasn't running (e.g. a
git pullfrom the terminal), so the first query reflects the current code instead of a stale snapshot — rather than waiting for the next live edit. - Dependency, build, and cache directories are now excluded by default —
node_modules,vendor,dist,build,target,.venv,__pycache__,Pods,.next, and the like across every supported language/framework — socontextandsearchreflect your code instead of third-party noise, even in a project with no.gitignore(#407). The defaults apply uniformly, including to committed files (vendoring a dependency into the repo doesn't make it project code). To index one anyway, add a.gitignorenegation (e.g.!vendor/). First-party-prone names likepackages/,lib/,app/, andsrc/are never on the default list.