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

mincut-context

v1.7.0

Published

Token-minimal context selection for AI coding agents. Builds a symbol graph of your repo and uses personalized PageRank + budget-constrained min-cut to pick the smallest provably-relevant context for any task.

Readme

mincut-context

Token-minimal context selection for AI coding agents.

A symbol graph of your repo + personalized PageRank + budget-constrained min-cut — picks the smallest provably-relevant context for any task.

npm version downloads bundle size types node ci tests coverage license

npm install -g mincut-context     #   global CLI: mcx
npx mincut-context pack "fix the login validation bug" --budget 4000

One sentence: an agent that opens mincut-context first gets the minimum cohesive region of code its task depends on — not a grep hit, not a whole file, not the whole repo.

What's new in v1.7 — proven on 3 real codebases. 28 labeled tasks, full report at eval/CROSS-REPO-RESULTS.md. Aggregate: mincut catches 83% of correct files vs grep's 42%. Plus 88.6% test coverage with CI gate. See CHANGELOG.md.



Why

AI coding agents waste your context window. Two failure modes:

| | What it does | Cost | |---|---|---| | Over-stuff | Dumps whole files / all of src/ | Burns tokens, drowns the model, hurts answer quality | | Under-stuff | Grep a string, return 3 lines | Misses callers, dependents, tests — model hallucinates |

Neither uses what the code actually is: a graph.

The idea

Treat context selection as a graph problem.

Given a symbol graph G = (V, E, w) where V are code units (functions, classes), E are dependency edges (imports, calls, references), w(v) is the token cost of v, a token budget B, and seeds S ⊆ V derived from the task:

Find T ⊇ S with Σ tokens(T) ≤ B minimizing the boundary cut cost cut(T, V\T) = Σ w(e) for edges crossing the boundary.

In plain English: pick a connected, low-token region that has few "loose ends" pointing outside it. The inside of the cut is what the agent needs to see; the outside is safely ignorable.

The objective is submodular, so a greedy algorithm gives a (1 - 1/e) ≈ 0.63 approximation guarantee. Full math in SPEC.md.


Install

# global CLI (recommended)
npm install -g mincut-context

# or per-project
npm install --save-dev mincut-context

# or one-shot, no install
npx mincut-context pack "your task" --budget 4000

Requires Node ≥ 18.17. TypeScript types ship with the package.

Optional peer dependencies:

| When you want | Install | |---|---| | --lsp type-aware call resolution | npm i -g typescript-language-server | | --embed semantic seeding | (auto — @xenova/transformers ships in the package) |

Quick start

# 0. (One-time) sanity check the environment
mcx doctor

# 1. Index any repo once (warms the gzipped cache)
mcx index . --cache

# 2. Ask for context for a task
mcx pack "fix the login validation bug" --budget 4000 --cache

# 3. Pipe straight into your agent
mcx pack "..." --format markdown > context.md
mcx pack "..." --format json | jq '.files[].path'

# 4. Stay-running mode during dev
mcx watch "fix the login bug" --budget 4000 --cache

Use it three ways

1. As an MCP server — recommended for agents

Drop into Claude Code, Codex, Cursor, or any MCP-aware client:

{
  "mcpServers": {
    "mincut-context": {
      "command": "npx",
      "args": ["-y", "mincut-context", "mcp"]
    }
  }
}

Your agent now has three tools:

| Tool | Description | |---|---| | pack_context(task, repo, budget?, cache?, cacheDir?, communityBoost?) | Get a token-minimal, structurally-relevant context window | | expand_node(node, depth?) | Pull more around a specific symbol | | explain_selection() | The rationale for the last selection | | find_callers(node) | Symbols that call this one (incoming edges) | | find_callees(node) | Symbols this one calls (outgoing edges) | | search_symbols(query, limit?) | Substring search across the cached graph |

2. As a CLI

mcx pack "your task description" --budget 4000             # plain output
mcx pack "..." --format tree                               # directory-grouped tree
mcx pack "..." --format json | jq                          # pipe-friendly
mcx pack "..." --format markdown > context.md              # ready-to-paste
mcx pack "..." --interactive                               # Ink TUI (vim keys + preview)
mcx pack "..." --embed                                     # semantic seeding
mcx pack "..." --cache                                     # persistent parse cache (5× speedup)
mcx pack "..." --parallel 4                                # worker-thread parser pool
mcx pack "..." --chunk                                     # split huge functions into sub-symbols
mcx pack "..." --lsp                                       # type-aware call resolution (TS)
mcx pack "..." --verbose                                   # algorithm trace
mcx watch "..." --debounce 300                             # re-pack on file change
mcx index . --cache                                        # warm the parse cache
mcx doctor                                                 # environment self-check
mcx mcp                                                    # run as MCP server

3. As a library

import { pack } from 'mincut-context';

const result = await pack({
  task: 'fix the login validation bug',
  repo: process.cwd(),
  budget: 4000,
  cache: true,            // persistent gzipped parse cache
  communityBoost: 0.5,    // Louvain intra-cluster bias
  parallel: 4,            // worker-thread parsing
  chunk: { enabled: true, maxTokens: 400 },  // sub-symbol chunking
  trimScoreRatio: 0.02,   // drop tail files below 2% of top score
});

for (const f of result.files) {
  console.log(f.path, f.score.toFixed(3), f.tokens, '·', f.reasons[0]);
}
// → src/auth/login.ts        0.541  612 · seed — matched directly by task
// → src/auth/session.ts      0.408  483 · attached (60%)

Full TypeScript types — pack, indexRepo, indexRepoAsync, SymbolGraph, personalizedPageRank, greedySelect, detectCommunities are all exported.


How it works

flowchart LR
    A[Repo files] -->|tree-sitter| B[Symbol graph<br/>V: functions/classes/chunks<br/>E: imports/calls]
    T[Task string] -->|keyword IDF| S[Seeds S ⊆ V]
    T -->|optional: --embed| S
    B --> R[Personalized<br/>PageRank<br/>α=0.85]
    S --> R
    B --> L[Louvain<br/>communities]
    R --> C[Greedy<br/>budget min-cut<br/>1−1/e bound]
    L --> C
    B --> C
    C --> P[Packed context<br/>files + ranges<br/>+ per-node reason]

The five steps in pseudocode:

pack(task, repo, budget):
  1. graph  = index(repo)                       # tree-sitter → symbol+edge graph
                                                # optionally chunked into sub-symbols
                                                # optionally refined by LSP
  2. seeds  = scoreSeeds(task, graph)           # keyword IDF (+ embeddings if --embed)
  3. ranks  = personalizedPageRank(graph, seeds, α=0.85)
  4. comm   = louvainCommunities(graph)         # for intra-cluster boost
  5. T      = greedyMinCut(graph, ranks, seeds, budget, comm):
       T ← seeds
       while Σ tokens(T) < B:
         v* ← argmax_{v ∉ T, attach(v,T) > 0}
                 rank(v) · attach(v,T) · communityBonus(v) / tokens(v)
         T ← T ∪ {v*}
  6. ranges = collapseToFileRanges(T)
  7. return { files: ranges, tokens, graph: {...}, explain, trace? }

The "no isolated nodes" rule (attach(v, T) > 0) is what gives you the cohesion guarantee — adding a fully-detached node would strictly increase the cut without benefit, so the greedy refuses. That's why an "auth" task never drags in unrelated UI files even when budget permits.

Semantic embeddings (optional)

Pure keyword matching misses semantic neighbors:

$ mcx pack "ranking and centrality algorithm" --repo .
no context selected — no symbols matched

$ mcx pack "ranking and centrality algorithm" --repo . --embed --embed-weight 0.8
→ src/core/graph.ts         0.638  205 tok
→ src/core/pagerank.ts      0.282  725 tok   ← the actual algorithm!
→ src/seeds/keyword.ts      0.080   18 tok

"Centrality" never appears in any symbol name — only embeddings could find this. Uses @xenova/transformers (Transformers.js + ONNX). Fully local, ~22 MB model download on first use.

LSP-backed call resolution (optional)

Syntactic name matching can be ambiguous when two files export functions with the same name. --lsp asks typescript-language-server for the authoritative answer and adds higher-weight edges where it disagrees:

npm i -g typescript-language-server     # one-time
mcx pack "your task" --repo . --lsp

If the LSP fails or the binary is missing, mincut falls back silently to syntactic edges.


Real-world examples

On the Fluent Player free repo (225 files, 845 symbols, 2,726 edges):

$ mcx pack "analytics visit tracking" --budget 3000 --exclude tests/**
→ resources/js/utils/googleAnalytics.js   0.553   556 tok   ← seed
→ resources/js/utils/ajax.js              0.174   254 tok
→ resources/js/AnalyticsTracker.js        0.162  1477 tok
→ resources/admin/utils/Notify.js         0.077   104 tok
→ [5 tail files pulled in by graph attachment]
selected 20 / 845 symbols (2.4% of codebase)

On the Fluent Forms plugin (809 files of mixed PHP + Vue + JS, 4,333 symbols, 3,776 edges):

$ mcx pack "payment stripe processor" --budget 3000 --cache --community-boost 0.8
→ app/Modules/Payments/PaymentMethods/Stripe/StripeProcessor.php       1955 tok  ← seed
→ app/Modules/Payments/PaymentMethods/Stripe/StripeHandler.php         246 tok
→ app/Modules/Payments/AjaxEndpoints.php                               152 tok
→ app/Modules/Payments/PaymentMethods/Stripe/API/RequestProcessor.php  159 tok
→ app/Modules/Payments/PaymentMethods/Stripe/API/Plan.php              331 tok
→ app/Modules/Payments/PaymentMethods/Stripe/API/ApiRequest.php         26 tok

That's exactly the Stripe cluster — no UI noise, no test fixtures, no unrelated modules.


Languages

| Language | Status | Notes | |---|---|---| | TypeScript / JavaScript | ✅ v1.0 | .ts .tsx .js .jsx .mjs .cjs | | Python | ✅ v1.0 | .py .pyi, relative imports, decorators, methods | | PHP | ✅ v1.2 | .php, namespaces, traits, use (incl. grouped + aliased), $this->, Foo::bar() | | Vue SFC | ✅ v1.2 | .vue, <script> Options API + <script setup> Composition API, lang="ts" honored | | Rust, Go, Svelte, … | community welcome | tree-sitter grammar + symbol queries |

Sub-symbol chunking is supported on all 4 languages above as of v1.4 (TS/JS/Vue + Python + PHP).

LSP-backed call resolution currently covers TypeScript / JavaScript / Vue via typescript-language-server. Adding Python (pyright) or PHP (intelephense) is a small adapter.

Adding a language is one parser file implementing LanguageParser + one line in parseForExt. See src/parsers/py.ts as a template.


Usage: mcx pack [options] <task...>

Pack a token-minimal context window for the given task.

Options:
  -r, --repo <path>               Repository root (default: cwd)
  -b, --budget <tokens>           Token budget (default: 4000)
  -k, --seeds <count>             Top-k seeds (default: 8)
      --alpha <number>            PageRank damping (default: 0.85)
      --include <pattern...>      Restrict to glob patterns (e.g. src/auth/**)
      --exclude <pattern...>      Extra ignore patterns appended to .gitignore
  -f, --format <fmt>              plain | tree | json | markdown
      --no-color                  Disable colored output
      --embed                     Use semantic embeddings (~22 MB model first run)
      --embed-weight <number>     Blend 0..1 (0=keyword, 1=embedding only)
      --embed-model <id>          HF model id (default Xenova/all-MiniLM-L6-v2)
  -i, --interactive               Ink TUI for pin/exclude with preview pane + vim keys
      --cache                     Use persistent parse cache (.mincut-cache/) — fast repeat runs
      --cache-dir <path>          Override cache directory (absolute path)
      --community-boost <number>  Louvain same-community boost (default 0.5, 0 = disabled)
  -v, --verbose                   Print algorithm trace (seeds, ranks, selection, timings)
  -j, --parallel <n>              Use n worker threads to parse in parallel (default 0)
      --chunk                     Split large functions into sub-symbol chunks (TS/JS/Vue/Py/PHP)
      --chunk-tokens <n>          Token threshold for chunking (default 400)
      --lsp                       Refine call edges via typescript-language-server
      --trim-ratio <r>            Drop tail files scoring < r × top file (default 0.02, 0 disables)

Other commands:

mcx watch '<task>' --repo . --budget 4000 [--debounce 300] [--cache] [--parallel n]
mcx index [path] [--cache] [--include glob]
mcx mcp                                                # run as MCP server over stdio
mcx doctor                                             # environment self-check

How it compares

| Approach | Token-aware | Structural | Semantic | Type-aware | Explainable | |---|---|---|---|---|---| | Whole file dump (cat, Read) | ❌ | ❌ | ❌ | ❌ | trivially | | Grep / ripgrep | ❌ | ❌ | ❌ | ❌ | yes | | Cursor/Continue RAG | partial | ❌ | ✅ | ❌ | hard | | AST/symbol graph alone | ❌ | ✅ | ❌ | ❌ | yes | | mincut-context | ✅ (budget) | ✅ (graph) | ✅ (--embed) | ✅ (--lsp) | per-node reason |

Measured

28 hand-labeled tasks across 3 real codebases at a 4000-token budget — full report in eval/CROSS-REPO-RESULTS.md:

| strategy | precision | recall | F1 | token-efficiency | |---|---:|---:|---:|---:| | mincut | 0.27 | 0.83 | 0.39 | 0.270 | | mincut + --embed | 0.27 | 0.83 | 0.39 | 0.270 | | grep keyword baseline | 0.11 | 0.42 | 0.16 | 0.105 | | random selection (control) | 0.01 | 0.04 | 0.01 | 0.009 |

Per-repo breakdown:

| repo | tasks | mincut R | grep R | mincut F1 | grep F1 | |---|---:|---:|---:|---:|---:| | mincut-context (self) | 12 | 0.97 | 0.56 | 0.44 | 0.30 | | FluentForm | 8 | 0.88 | 0.13 | 0.43 | 0.04 | | Fluent Player | 8 | 0.63 | 0.56 | 0.31 | 0.13 |

Reproduce locally:

npm run eval                                                       # self-repo
npx tsx eval/runner.ts --fixtures eval/fixtures/fluentform-tasks.json
npx tsx eval/runner.ts --fixtures eval/fixtures/fluentplayer-tasks.json

Add your own labeled tasks under eval/fixtures/ to score against your codebase.


Roadmap

  • [x] Core: graph + personalized PageRank + greedy min-cut (v1.0)
  • [x] TS/JS parser (v1.0)
  • [x] Python parser (v1.0)
  • [x] CLI (plain / JSON / markdown) (v1.0)
  • [x] MCP server (v1.0)
  • [x] Local embeddings (@xenova/transformers) (v1.0)
  • [x] Ink TUI (v1.0)
  • [x] Persistent on-disk parse cache (v1.1) — 5.2× warm-run speedup
  • [x] Louvain community boost (v1.1)
  • [x] PHP parser (v1.2)
  • [x] Vue SFC parser (v1.2)
  • [x] Parallel parsing (worker pool) (v1.3) — 2.7× cold-index speedup
  • [x] Sub-symbol AST-block chunking (TS/JS/Vue) (v1.3)
  • [x] mcx watch long-running mode (v1.3)
  • [x] TUI v2: preview pane + vim keys + fuzzy filter (v1.3)
  • [x] --verbose algorithm trace (v1.3)
  • [x] --format tree directory-grouped output (v1.3)
  • [x] Sub-symbol chunking for Python + PHP (v1.4)
  • [x] LSP-backed type-aware call resolution (v1.4) — typescript-language-server
  • [x] Path-aware + kind-aware seed scoring + test-dir penalty (v1.5)
  • [x] gzip-compressed parse cache (v1.5) — ~3.5× smaller on disk
  • [x] Tail-file trimming (v1.5) — drops weak attachment-only files
  • [x] mcx doctor environment self-check (v1.5)
  • [x] MCP graph-navigation tools: find_callers, find_callees, search_symbols (v1.5)
  • [x] Evaluation suite — labeled tasks + baselines + precision/recall/F1/tok-eff (v1.6)
  • [x] Examples directory — Claude Code, Codex, Cursor, GitHub Actions, library, shell (v1.6)
  • [x] Cross-repo eval — FluentForm + Fluent Player (28 tasks total, 3 codebases) (v1.7)
  • [x] CI coverage gate (>=85%) (v1.7)
  • [x] CELF lazy-greedy algorithm research (greedy stays — CELF diverges on our objective) (v1.7)
  • [ ] Pyright / Intelephense LSP adapters
  • [ ] Svelte / Rust / Go parsers

| What's not optimal | What we do | |---|---| | True optimal min-cut is NP-hard | Greedy submodular — (1−1/e) bound | | Tree-sitter symbols are syntactic, not type-aware | --lsp refines TS/JS via typescript-language-server | | Embedding model adds ~22 MB on first run | Opt-in behind --embed flag | | LSP startup is slow (~1-5s) | Opt-in behind --lsp flag; cached after init | | Cold start parses whole repo | --cache (5× speedup) + --parallel n (2.7× speedup) | | Cross-file call resolution is heuristic | LSP-refined where the binary is available |


Contributing

git clone https://github.com/dhrupo/mincut-context.git
cd mincut-context
npm install --legacy-peer-deps
npm test           # 217 tests across unit + integration + MCP + CLI + TUI + LSP
npm run build
node dist/adapters/cli/bin.js pack "..." --repo /path/to/some-repo

PRs especially welcome for:

  • New language parsers — tree-sitter grammar + symbol queries
  • New LSP adapters — pyright (Python), intelephense (PHP), gopls (Go), rust-analyzer (Rust)
  • Sub-symbol chunking for new languages — straightforward extension since the helper is language-agnostic

Each PR must keep the test suite green (npm test). New behavior requires tests first (TDD).

Built with

License

MIT © Dhrupo Nil