karst
A 4-step walkthrough

How karst works

Your AI tools read your repo blind and bill you for it. karst gives them a map first — so they load only what matters, and you see the cost before every call.

The problem

AI dev tools read your code blind.

Ask Cursor or a custom agent “how does checkout work?” and it dumps tens of thousands of tokens of vaguely-related files into the model — every single time. You can’t see what it loaded, you can’t scope it, and the bill arrives at the end of the month.

  • Bill shock. A single question can burn 30k+ input tokens. Usage-based pricing turns that into real money, fast.
  • Black-box context. When the answer is wrong you can’t tell if it was the model or the context it never saw.
  • No blast radius. Nothing tells you what else breaks when you change a function.
agent · “how does checkout work?” context window
42,000 tokens loaded · mostly irrelevant $0.13 / question
The fix, in four moves

Give the model a map before it reads

Click a step — or just watch. This is exactly what the engine does to your repo today.

byfoods / src / orders / orders.ts — karst
▾ src
▾ auth
users.ts
login.ts
▾ billing
stripe.ts
▾ orders
orders.ts
cart.ts
// imports
import { getUser } from '../auth/users';
import { charge } from '../billing/stripe';

chunk · checkout()export async function checkout(cartId: string) {
  const cart = await loadCart(cartId);
  const user = await getUser(cart.userId);
  const total = cart.items.reduce((s, i) => s + i.price, 0);
  return charge(user, total);
}

chunk · loadCart()async function loadCart(id: string) {
  return db.carts.findById(id);
}
checkout() getUser() charge() loadCart()
Files that change & call together → one named pack
ordersorders.ts · cart.ts · ~2 chunks
authusers.ts · login.ts
billingstripe.ts
› how does checkout work? — packs: orders
checkout() loads the cart, fetches the buyer via getUser() [orders/orders.ts:5], sums item prices, then calls charge() [billing/stripe.ts].
~3,800 tok · $0.019 vs $0.13 unscoped — shown before the call
01 · INDEX
Parse into chunks
Tree-sitter splits every function, class and method into a real chunk — never blind line-windows.
02 · GRAPH
Map who calls who
A knowledge graph of calls & imports. Now “what breaks if I change this?” is a graph walk, not a guess.
03 · PACK
Group into named packs
Related files become attachable packs — auth, billing, orders. The atomic unit of context.
04 · ASK
Load only what matters
A question loads only its pack. 60% fewer tokens, every answer cited, the cost shown before you spend it.
What actually changes

Same question. One-seventh the cost.

WITHOUT karst
$0.13
  • • 42,000 tokens dumped per question
  • • You can’t see what was loaded
  • • No citations — trust it or don’t
  • • No idea what a change will break
WITH karst
$0.019
  • • ~3,800 tokens — only the relevant pack
  • • You see (and pin) exactly what loads
  • • Every claim cited to file:line
  • karst impact lists the blast radius

Measured on Byfoods — a real 246-file NestJS + Next.js repo: 906 chunks, re-index 343s → 2.3s.

Straight about what’s built

Does it solve your problem? Here’s the honest map.

LIVE TODAY
  • ✓ MCP server — plug into Cursor & Claude Desktop
  • ✓ AST chunking across 6 languages
  • ✓ Call/import graph + impact analysis
  • ✓ Pack-scoped retrieval & cost meter
  • ✓ Incremental indexing + embedding cache
  • ✓ Diff code review with citations
COMING NEXT
  • ◷ Hosted indexing (no local daemon)
  • ◷ Team-shared pack library
  • ◷ GitHub PR review bot
  • ◷ Published to PyPI & the MCP registry

The engine and the MCP server that exposes it to Cursor & Claude Desktop are both real and tested — every number on this page is measured, not promised. What’s left is distribution: a one-line install once it’s on PyPI. We’d rather tell you exactly where the line is than pretend.

Want it pointed at your repo?

Get an early-access invite when the MCP server lands, or try the CLI today.

Try the CLI Get early access