npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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.

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 deps returns every file a feature touches, no manual tracing
  • Impact analysis — assistgraph dependents shows what breaks before you move anything. A file like api-client.ts with 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/ and api/, 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 build

The 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 audit

Then 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 assistgraph

oxc-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 .gitignore enforcement: anything in .gitignore is 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*.json and jsconfig*.json, follows extends, resolves declarative aliases, package imports, workspace packages, and CommonJS require()
  • 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.toml roots plus conventional src/ 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-skills

The 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 --force

Without --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-mcp

Or register selectively:

assistgraph install-mcp --claude-only
assistgraph install-mcp --codex-only

The 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 mcp

The 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.json

Output 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>/*.md

Configuration

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 build

The 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 BrowserWindow preload 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.