@reactgraph/cli
v0.1.2
Published
Pre-computed React project graph for AI-assisted development
Maintainers
Readme
ReactGraph
Pre-computed React project graph for AI-assisted development. Stop Claude Code from searching — start it navigating.
The Problem
When Claude Code works on a React project, more than half its time and tokens go to file discovery — grep/cat cycles burning 30,000–60,000 tokens per task just to understand the codebase.
The Solution
ReactGraph parses your React project with tree-sitter, builds a graph of components, hooks, state stores, context providers, routes, and API calls, then exposes it via an MCP server or a flat file. Claude reads one compact project map and starts coding immediately.
Before ReactGraph: 40+ tool calls to understand the codebase → 60K tokens wasted After ReactGraph: 1 MCP call → ~2–4K token project map → start coding immediately
Quick Start
# Install
bun install -g reactgraph
# In your React project
cd my-react-app
reactgraph init # detects framework, creates .reactgraph/
reactgraph index # builds the graph (~2-5 seconds)After indexing, .reactgraph/ai-context.md is generated automatically — a flat file Claude can read with zero setup.
Connect to Claude Code
Option 1: MCP Server (recommended)
claude mcp add reactgraph -- reactgraph serveOr add to .mcp.json:
{
"mcpServers": {
"reactgraph": {
"command": "reactgraph",
"args": ["serve"]
}
}
}Use --watch to automatically update the graph when files change:
{
"mcpServers": {
"reactgraph": {
"command": "reactgraph",
"args": ["serve", "--watch"]
}
}
}Option 2: Flat File (zero setup)
Add to your CLAUDE.md:
Read .reactgraph/ai-context.md at session start instead of exploring files.CLAUDE.md Integration
Add these navigation rules to your project's CLAUDE.md:
## Navigation Rules (ReactGraph)
- ALWAYS call reactgraph.get_map() at session start instead of exploring files
- Use reactgraph.get_subgraph(name) before modifying any component or hook
- Use reactgraph.get_file_context(path) for detailed file info before editing
- Use reactgraph.find_nodes({ query: "name" }) to find a node and its connections
- Use reactgraph.impact(target) before refactoring to know what breaks
- Do NOT use grep/find/glob to discover project structure — the graph has it
- If ReactGraph MCP is not available, read .reactgraph/ai-context.md insteadMCP Tools
get_map()
Returns a compact overview of the entire project — routes, components sorted by connectivity, hooks, state stores, context providers, and shared modules.
# REACTGRAPH MAP | 127 components, 43 hooks, 8 stores, 12 routes
# Indexed: 2026-03-22T14:30:00Z | 342 files
## ROUTES
/ → DashboardPage [src/app/page.tsx]
/settings → SettingsPage [src/app/settings/page.tsx]
POST /api/auth [src/app/api/auth/route.ts]
## COMPONENTS (top 30 by connectivity)
Dashboard [src/components/Dashboard.tsx:5]
renders: MetricsCard, FilterBar
hooks: useAuth, useDashboardData
context: ThemeCtx(read)
state: dashboardStore(read)
props: none (page component)
## HOOKS
useAuth [src/hooks/useAuth.ts:3]
returns: { user, login, logout, isLoading }
state: authStore(read/write)
fetches: GET /api/auth/me
used-by: Dashboard, Sidebar, Header (23 total)
## STATE STORES
authStore [zustand] [src/stores/auth.ts]
shape: { user, token, isAuthenticated }
writers: useAuth
readers: Dashboard, Sidebar, Header
## CONTEXT PROVIDERS
ThemeCtx [src/contexts/Theme.tsx] provided-at: App
consumers: Dashboard, Sidebar, Header (12 total)get_subgraph(target, depth?)
Zoom into a specific component, hook, or store. Shows all connections up to the given depth.
> get_subgraph("useAuth", depth=2)
useAuth [src/hooks/useAuth.ts:12]
├─ reads_store → authStore [src/stores/auth.ts]
│ └─ reads_store → Dashboard, Sidebar, Header
├─ fetches → GET /api/auth/me
├─ uses_hook → useState, useEffect
used-by (23):
│ ← uses_hook ← Dashboard [src/pages/Dashboard.tsx]
│ ← uses_hook ← Sidebar [src/components/Sidebar.tsx]
│ ← uses_hook ← Header [src/components/Header.tsx]get_file_context(path)
Everything about a specific file — exports, imports, components, hooks, stores, effects, and all relationships.
> get_file_context("src/components/Dashboard.tsx")
FILE: src/components/Dashboard.tsx
EXPORTS: Dashboard (default)
IMPORTS:
useAuth ← src/hooks/useAuth.ts
MetricsCard ← src/components/MetricsCard.tsx
COMPONENT: Dashboard (line 5)
RENDERS: MetricsCard
HOOKS: useAuth → { user, isLoading }
STATE: authStore(read)
CONTEXT: ThemeCtx(read)
RENDERED BY: Apptrace_flow(from, to)
Trace the data flow path between two nodes. Shows how data gets from A to B.
> trace_flow("LoginForm", "/api/auth/login")
LoginForm → POST /api/auth/login
LoginForm [src/components/LoginForm.tsx]
└─ uses_hook → useAuth [src/hooks/useAuth.ts]
└─ fetches → endpoint:POST:/api/auth/loginimpact(target)
Analyze what would break if a component, hook, or store is changed.
> impact("useAuth")
IMPACT ANALYSIS: useAuth [src/hooks/useAuth.ts]
DIRECT (23 dependents):
uses_hook ← Dashboard [src/pages/Dashboard.tsx]
uses_hook ← Sidebar [src/components/Sidebar.tsx]
uses_hook ← Header [src/components/Header.tsx]
INDIRECT (via components using useAuth):
App [src/App.tsx]
SAFE TO CHANGE:
Internal implementation (same return type + same store writes = no breakage)
RISKY:
Return type shape — 23 consumers destructure { user, login, logout, isLoading }find_nodes(filters)
Query the graph. Use query to find a node and see all its connections. Use other filters for bulk searches.
> find_nodes({ query: "useUIStore" })
useUIStore [Store] [src/lib/ui-store.ts:69]
reads_store ← Sidebar [src/components/Sidebar.tsx], Header [src/components/Header.tsx]
writes_store ← useUIActions [src/hooks/useUIActions.ts]
> find_nodes({ kind: "Hook", fetches: true })
Found 4 nodes:
useAuth [Hook] [src/hooks/useAuth.ts:3]
useDashboardData [Hook] [src/hooks/useDashboardData.ts:5]
> find_nodes({ kind: "Component", orphan: true })
Found 2 nodes:
DeprecatedBanner [Component] [src/components/DeprecatedBanner.tsx:1]
OldUserCard [Component] [src/components/OldUserCard.tsx:1]Available filters: query, name, kind, using_hook, using_store, fetches, orphan
CLI Commands
| Command | Description |
|---------|-------------|
| reactgraph init | Detect framework, create .reactgraph/ config |
| reactgraph index | Build the project graph with progress display |
| reactgraph serve | Start the MCP server (stdio transport) |
| reactgraph serve --watch | Start MCP server + auto-update on file changes |
| reactgraph unused | Find orphan components, unused hooks, dead exports |
How It Works
- Walk — finds all
.ts,.tsx,.js,.jsxfiles, respecting.gitignore - Parse — tree-sitter builds ASTs (fast, handles broken code)
- Extract — nine extractors run per file in order:
- imports — import/export graph, path resolution
- components — function, arrow, memo-wrapped, class components
- hooks — custom hook definitions + all hook call sites
- jsx-tree — which components render which, prop passing
- context — createContext, Provider, useContext tracking
- state — Zustand, Redux Toolkit, Jotai, Recoil store detection
- api-calls — fetch, axios, API wrapper call extraction
- routes — React Router, Next.js App/Pages Router
- effects — useEffect dependency arrays, cleanup detection
- Resolve — two-pass indexing ensures cross-file references (stores, contexts, components) are fully linked regardless of file processing order
- Persist — graph saved to
.reactgraph/graph.jsonwith SHA256 file hashes for incremental re-indexing - Format — token-optimized structured text output for AI consumption
What It Detects
| Category | What's Tracked |
|----------|---------------|
| Components | Function, arrow, class, memo/forwardRef wrapped |
| Hooks | Custom definitions, all call sites, destructured returns |
| Render tree | Which components render which, prop passing |
| Context | createContext, Provider wrapping, useContext consumers |
| State | Zustand create(), Redux createSlice(), Jotai atom(), Recoil atom() |
| Store usage | Readers (useStore, useSelector, useAtomValue) and writers (setState, dispatch, useSetAtom) |
| API calls | fetch(), axios.*(), custom API wrappers |
| Routes | React Router <Route>, Next.js file-based routing (App + Pages) |
| Effects | useEffect/useLayoutEffect deps, cleanup, triggers |
| Imports | Full import/export graph with path resolution |
Graph Schema
Node kinds: Component, Hook, BuiltinHook, Context, Route, Module, Store, ApiEndpoint, Type, Util, Constant
Edge kinds: imports, renders, passes_prop, uses_hook, provides, consumes, calls, fetches, reads_store, writes_store, routes_to, type_of
Configuration
After reactgraph init, settings are stored in .reactgraph/config.json:
{
"srcDirs": ["src"],
"framework": "next",
"exclude": ["**/*.test.*", "**/*.spec.*", "**/*.stories.*"]
}.reactgraph/ is automatically added to .gitignore — it's a local cache, not a shared artifact.
Tech Stack
| Layer | Choice | |-------|--------| | Parser | tree-sitter (TS/TSX/JS/JSX) | | Graph | Custom in-memory with secondary indexes | | CLI | Commander + Ink | | MCP | @modelcontextprotocol/sdk (stdio) | | File watching | chokidar (incremental re-parse) | | Persistence | JSON with file hash caching |
Five runtime dependencies. No databases, no API keys, no Docker.
Development
bun install
bun test # run tests (37 tests)
bun run build # compile TypeScript
bun run dev # run CLI directlyLicense
MIT
