assistgraph
v0.4.1
Published
Fast local dependency and symbol graph CLI for JS/TS/Python codebases, with agent skills and an optional MCP adapter.
Maintainers
Readme
assistgraph
A fast, local dependency index for JavaScript, TypeScript, and Python codebases. Its compact CLI helps agents answer structural questions without repeatedly grepping the repository.
The problem
Large codebases are expensive to reason about. Developers spend hours tracing imports before a migration, agents burn tokens grepping through dozens of files to answer "who uses this?", and shared components get refactored without understanding their blast radius.
assistgraph build scans the source tree, resolves imports, indexes top-level declarations, and writes a reusable graph. Agents query that index through a compact CLI; humans can explore the generated Obsidian vault; integrations can use the JSON or optional local MCP adapter.
What this unlocks
For migrations and refactors
Instead of guessing which files belong to a feature, query the graph for the exact dependency tree. Planning to migrate pipelines? The graph tells you it's 10 components, 5 hooks, 1 store, and 3 type files — plus exactly which shared files they depend on and what depends on them.
- Precise scope —
assistgraph depsreturns every file a feature touches, no manual tracing - Impact analysis —
assistgraph dependentsshows what breaks before you move anything. A file likeapi-client.tswith 42 dependents needs careful handling; a leaf component with 1 dependent can move freely - Dead code exclusion — orphan detection separates genuinely unused files from legitimate entrypoints (
index.ts,main.py, etc.), so you skip or delete dead code rather than migrate it - Cycle detection — tangled features need decoupling before they can move independently. The graph finds these upfront
For AI agents (Claude Code, Codex, Cursor)
The CLI exposes focused, bounded queries that turn expensive exploration into cheap lookups. A bundled skill teaches Claude Code and Codex when to use them.
Without the graph, an agent answering "what does the auth feature depend on?" has to recursively open files, parse imports, search for usages, and iteratively discover the file set. With the graph, it is one assistgraph deps query returning compact JSON.
The same applies to questions such as "what imports this hook?", "where is this class declared?", "are there cycles in this module?", and "what is the shortest path between these files?" The source is still read for behavior and semantics, but not rediscovered for every structural question.
For codebase health
assistgraph audit gives you a snapshot of structural health:
- Hub files — the most-imported files in your codebase, ranked by dependents. These are your highest-risk shared dependencies
- Bloat candidates — files with the most outgoing imports (god files that know too much)
- Cross-folder coupling — exactly how many edges cross between
ui/andapi/, quantifying how tangled your architecture really is - Orphans — files with zero incoming edges, separated from entrypoints so you can confidently clean up dead code
For visual exploration
Open the generated Obsidian vault and see your entire dependency graph with colour-coded communities, wiki-linked imports, and pre-configured graph settings. Each file note includes exports, imports, reverse imports, and metrics — all cross-linked.
Quick start
npm install -g assistgraph
assistgraph install-skills
cd your-project
assistgraph buildThe build creates or updates the scan root's .gitignore, adding .assist/graph/ as the final entry when needed.
That's it. You now have:
.assist/graph/graph.json— the machine-readable dependency graph.assist/graph/vault/— an Obsidian-compatible knowledge vault with wiki links and colour groups- An optional local MCP adapter (via
assistgraph mcp) — the same focused queries over stdio
# Check whether the graph still matches the source tree
assistgraph status
# Return compact dependency data for an agent
assistgraph deps src/features/auth/Login.tsx --depth 2
assistgraph dependents src/features/auth/Login.tsx
# Locate top-level declarations without searching every source file
assistgraph symbols Login --limit 20
# Full audit: cycles, orphans, hubs, coupling (writes .assist/graph/audit.md)
assistgraph auditThen point Obsidian at ./.assist/graph/vault/ to see the graph visually.
Install
The fastest way is npx — no install needed. Or install a persistent global binary:
# Node / npm
npm install -g assistgraph
# Bun
bun install -g assistgraphoxc-parser ships platform-specific native bindings that npm picks automatically on install. Once installed globally, drop the npx -y prefix from every command.
Features
- Languages: TypeScript, TSX, JavaScript, JSX, MJS, CJS, MTS, CTS, Svelte and Vue component scripts, Python, and Python stubs
- Strict
.gitignoreenforcement: anything in.gitignoreis invisible to assistgraph - CWD is the scan root: run it anywhere — at the repo root for the full picture, or in a subfolder for a focused graph
- Framework-neutral JS/TS resolution: discovers
tsconfig*.jsonandjsconfig*.json, followsextends, resolves declarative aliases, packageimports, workspace packages, and CommonJSrequire() - Path alias resolution:
@/*,~/*,$lib/*, and custom project mappings resolve without an Angular, Electron, React, Svelte, or Vite-specific mode - Python project resolution: detects repository and nested
pyproject.tomlroots plus conventionalsrc/layouts used by uv, Conda, FastAPI, Poetry, setuptools, and related tooling - Folder-based communities: folders become feature communities automatically, mirroring your codebase structure
- Cycle detection: iterative Tarjan SCC — handles deep dependency chains without blowing the stack
- Import evidence: exact source spans, raw specifiers, and imported/local aliases for each import
- Top-level symbol index: functions, classes, interfaces, types, enums, constants, and variables with declaration locations and signatures
- Freshness without guesswork: distinguishes content-only edits from structural changes, added files, and removed files
- Compact bounded queries: pagination and traversal limits keep agent context predictable
- Hub/bloat metrics: top imported files, top bloat candidates, cross-folder coupling
- Orphan detection with entrypoint heuristics: dead code is separated from legitimate entrypoints (
index.ts,main.py,manage.py, etc.) - Content and structure hashing: detect exact changes without rebuilding for every function-body edit
- Obsidian colour groups: each top-level folder gets its own colour automatically
All parsing is deterministic and offline. Zero LLM calls, zero databases, zero Python runtime required.
Requirements
- Node 18+ or Bun 1.0+
- No Python runtime required even for Python projects — parsing is pure JavaScript
Claude Code / Codex integration
Recommended: CLI + skill
npm install -g assistgraph
assistgraph install-skillsThe package contains one shared skills/assist-graph/SKILL.md with portable Claude and Codex metadata. The command installs that same canonical skill to:
~/.claude/skills/assist-graph/SKILL.md~/.codex/skills/assist-graph/SKILL.md
The skill teaches agents to use compact CLI queries for structural questions, check graph freshness, and fall back to source inspection only when semantics or unindexed references are needed. It does not install or configure MCP.
To update the skills after upgrading assistgraph, re-run with --force:
assistgraph install-skills --forceWithout --force, existing skill files are skipped. You can also install selectively with --claude-only or --codex-only.
Optional: local MCP adapter
MCP does not need to be hosted. assistgraph uses the local stdio form of MCP: Claude or Codex launches assistgraph mcp as a child process when it needs the connection, communicates over standard input/output, and stops it with the session. There is no daemon, listening port, account, or remote server.
Register the globally installed command with both supported harnesses:
assistgraph install-mcpOr register selectively:
assistgraph install-mcp --claude-only
assistgraph install-mcp --codex-onlyThe installer invokes the harnesses' own configuration commands and skips a harness that is not installed. It is deliberately separate from npm install and install-skills; package installation never edits Claude or Codex configuration automatically.
Equivalent manual registration commands are:
claude mcp add --scope user assistgraph -- assistgraph mcp
codex mcp add assistgraph -- assistgraph mcpThe process inherits the harness workspace as its working directory and reads ./.assist/graph/graph.json. It holds the graph in memory for fast repeated calls, so call reload_graph after a rebuild. If no graph exists, the server still starts and explains how to create one.
MCP tools
| Tool | What it answers |
| --- | --- |
| graph_stats | How big is this codebase? How many files, edges, cycles? |
| graph_status | Is the graph exact, structurally fresh, or stale? |
| list_files | What files exist? (paginated, filterable by language) |
| get_file | Full metadata for one file — imports, exports, dependents, community |
| search_symbols | Where is a top-level function, class, type, or constant declared? |
| get_dependencies | What does this file (or feature) depend on? (transitive, depth-limited) |
| get_dependents | What breaks if I change this file? (transitive, depth-limited) |
| find_path | How are these two files connected? (shortest dependency path) |
| search_files | Find a file by name (fuzzy substring match) |
| list_communities | What are the feature boundaries in this codebase? |
| get_community | What files belong to this feature/folder? |
| find_cycles | Where are the circular dependencies? |
| find_orphans | What files are unused? (with entrypoint detection) |
| reload_graph | Pick up a rebuild without restarting the server |
Obsidian integration
Point Obsidian at ./.assist/graph/vault/ and open the graph view. Colour groups are pre-configured so each top-level folder gets its own colour, with language colours as a fallback.
To customise colours manually: Graph view → Settings (gear) → Groups. Your changes are preserved on subsequent assistgraph build runs — the default config is only written when no custom colour groups exist.
Each file note contains:
- YAML frontmatter (path, language, community, loc, exports, tags)
## Exports— named + default exports## Symbols— indexed top-level declarations with signatures and source lines## Imports— wiki-linked to sibling files + external stubs## Imported By— reverse index## Metrics— LOC, size, import/dependent counts, content hash
CLI reference
assistgraph build [--root <dir>] [--no-vault] Scan CWD -> graph.json + vault/
assistgraph status Compare graph hashes with the source tree (compact JSON)
assistgraph files [query] [--language <lang>] [--limit <n>] [--offset <n>]
assistgraph file <path> [--limit <n>] File metadata, symbols, imports, direct dependents
assistgraph deps <path> [--depth <n>] [--limit <n>]
assistgraph dependents <path> [--depth <n>] [--limit <n>]
assistgraph path <from> <to> [--limit <n>] Shortest dependency path
assistgraph symbols [query] [--path <text>] [--kind <kind>] [--exported] [--limit <n>]
assistgraph communities [id] [--limit <n>] List communities or get one
assistgraph cycles [--limit <n>] Dependency cycles (compact JSON)
assistgraph orphans [--include-entrypoints] [--limit <n>]
Files with no incoming edges
assistgraph query <path> Deps + dependents for a file
assistgraph stats Graph stats
assistgraph audit [--out <path>] Cycles, orphans, hubs, coupling (+ audit.md)
assistgraph install-skills [--force] [--claude-only] [--codex-only]
Install the shared Claude + Codex skill
assistgraph install-mcp [--claude-only] [--codex-only]
Register the optional local MCP adapter
assistgraph mcp Start the MCP stdio process
assistgraph init Create assistgraph.config.jsonOutput layout
<cwd>/
├── assistgraph.config.json <- optional, check into git
└── .assist/
└── graph/ <- generated and automatically ignored
├── graph.json <- canonical graph
├── audit.md <- generated by `assistgraph audit`
└── vault/ <- Obsidian-compatible vault
├── .obsidian/graph.json <- pre-configured colour groups
├── README.md <- entry MOC
├── _communities/ <- one MOC per folder community
├── _externals/ <- one stub per external package
└── <mirror of your source tree>/*.mdConfiguration
Optional assistgraph.config.json at the scan root:
{
"include": ["**/*"],
"exclude": [
".assist/graph/**",
"node_modules/**",
"dist/**",
"build/**",
"__pycache__/**",
".venv/**"
],
"resolver": {
"tsconfig": null,
"aliases": {
"@/*": ["src/renderer/*"],
"$lib/*": ["src/lib/*"]
},
"pythonRoots": [".", "src"]
},
"output": {
"dir": ".assist/graph"
}
}Everything has sensible defaults. Aliases already declared in a tsconfig*.json or jsconfig*.json are discovered automatically. Use resolver.aliases when a bundler-only alias is declared in executable Vite, Electron Vite, Webpack, or framework configuration; mappings are relative to the scan root and do not change application behavior.
Running in a subfolder
cd src/features/auth
npx -y assistgraph buildThe scan root becomes the current folder. Imports that leave the scan root become external leaf nodes (with their absolute path preserved). This is useful for:
- Focused feature analysis — build a graph of just
src/features/pipelines/to see its internal structure without noise from the rest of the codebase - Shared component mapping — build from
src/shared/components/to see how shared components relate to each other - Pre-migration scoping — graph a feature folder to understand its internal dependencies before extracting it into a package
When scanning a subfolder, assistgraph still walks up to find parent tsconfig.json and jsconfig.json files, stopping at a parent package.json boundary. Named project configs inside the scan root are also discovered.
Graph schema
interface Graph {
version: '1.1';
generatedAt: string;
scanRoot: string;
stats: { nodes; edges; symbols; orphans; cycles; languages };
nodes: Record<string, GraphNode>;
edges: GraphEdge[];
communities: Record<string, GraphCommunity>;
cycles: GraphCycle[];
}
interface GraphNode {
id: string; // scan-root-relative path
name: string; // basename
path: string;
absolutePath: string;
language: 'ts' | 'tsx' | 'js' | 'jsx' | 'mjs' | 'cjs' | 'py' | 'external';
isExternal: boolean;
loc: number;
sizeBytes: number;
exports: string[];
symbols: SymbolDeclaration[];
imports: ImportRef[];
community: string;
contentHash: string;
structureHash: string;
}
interface ImportRef {
target: string;
resolved: boolean;
symbols: string[];
type: 'import' | 'dynamicImport' | 'typeImport' | 'reExport' | 'require' | 'py-import' | 'py-from';
rawSpecifier: string;
bindings: Array<{ imported: string; local: string; isType: boolean }>;
location: SourceSpan;
}
interface SymbolDeclaration {
id: string; // e.g. "src/auth.ts#authenticate"
name: string;
kind: 'function' | 'class' | 'interface' | 'type' | 'enum' | 'constant' | 'variable';
exported: boolean;
defaultExport: boolean;
async: boolean;
signature: string; // bounded declaration header, not the body
location: SourceSpan;
}
interface GraphEdge {
from: string;
to: string;
type: ImportRef['type'];
symbols: string[];
rawSpecifier: string;
bindings: ImportRef['bindings'];
location: SourceSpan;
}
interface SourceSpan {
start: { offset: number; line: number; column: number };
end: { offset: number; line: number; column: number };
}
interface GraphCommunity {
id: string;
name: string;
path: string;
parent?: string;
nodes: string[];
nodeCount: number;
}
interface GraphCycle {
id: string;
nodes: string[];
size: number;
}What assistgraph does NOT do
- Symbol reference resolution — declarations are indexed, but usages are not linked to them
- Runtime analysis — static AST parsing only
- Type inference beyond what's declared in imports
- HTML/template registration, framework-generated routes, and Astro component parsing
- Runtime-only wiring such as Electron
BrowserWindowpreload paths or plugin registration that has no static module import - Call graph construction
- LLM-based enrichment (roadmap)
FAQ
Why are all the files the same colour in Obsidian's graph view?
Obsidian starts every vault with no colour groups. assistgraph build writes .obsidian/graph.json with sensible defaults (one colour per top-level folder). If you already had the vault open, quit Obsidian fully (Cmd+Q), re-run assistgraph build, then reopen — Obsidian caches the settings in memory and overwrites the file on close.
Why aren't my ui/ and app/ folders visually split?
Obsidian uses a force-directed layout; folder structure isn't an input. If ui/ and app/ are intermingled, they're geometrically intertwined because of edges between them. Run assistgraph audit and check the "Cross-folder Coupling" section to see exactly how many edges cross the boundary.
Does this work in a monorepo?
Yes. Run assistgraph build at the repo root for a unified view, or in a specific package for a focused view. The resolver discovers named TypeScript/JavaScript project configs, follows extends chains, resolves workspace package source entrypoints, and detects nested Python project and src/ roots.
Does this support Angular, Electron, React, Svelte, Vite, Node, Bun, uv, Conda, and FastAPI? Yes at the static module-graph layer. Those tools share a smaller set of resolution conventions: JS/TS project paths, aliases, package imports/workspaces, relative imports, CommonJS, Python packages, and Python source roots. Assistgraph resolves those conventions rather than maintaining brittle framework modes. Runtime-only framework registration remains outside a static import graph and is reported as a limitation rather than inferred.
How do I update the agent skills after upgrading assistgraph?
Run assistgraph install-skills --force. Without --force, existing skill files are preserved and the install is skipped.
Does the MCP need to be hosted or kept running? No. It is a local stdio child process launched and stopped by Claude or Codex after registration. The CLI and skill work without MCP.
Should I commit .assist/graph/ to git?
No. The build automatically adds .assist/graph/ to the scan root's .gitignore, creating the file when needed. The graph is generated output — anyone can rebuild it with assistgraph build. The optional assistgraph.config.json at the project root should be committed if you customise it.
Does this replace dependency-cruiser / madge?
No — those are richer JS-only tools. assistgraph trades depth for breadth: one local CLI across JS/TS + Python, an Obsidian vault for humans, agent skills, and an optional MCP adapter.
License
MIT.
