DEV Community

Cover image for Stop letting your AI agent read whole files: a code map for Claude Code, Cursor and MCP
Makra Gergő
Makra Gergő

Posted on Edited on Originally published at callgraph.eu

Stop letting your AI agent read whole files: a code map for Claude Code, Cursor and MCP

When an AI coding agent needs to change one method, it usually reads the whole file first. Then the next file. Then it greps, and reads a few more.
Most of those tokens are spent on finding the way, not on the task.

I built callgraph to give the agent a map instead: the structure of a file, every call labelled by kind, who calls a method across the project, and only then the one method body it actually needs.

What the agent sees

Take a 400-line Laravel service. Instead of reading all of it, the agent asks for the outline:

$ callgraph.sh app/Services/OrderService.php
class OrderService  L30-412
  constants (1):
    MAX_ITEMS = 100
  properties (7):
    OrderRepository $orders [readonly]
    PaymentService $payments [readonly]
    …
  updateOrders()  L44-109
    framework_use     Illuminate\Support\Facades\DB::transaction
    internal_helper   updateOrder
    model_use         App\Models\Order::query
    static_call       App\Values\OrderUpdateResult::make
    💬 A single-order update keeps the old values of empty optional fields.
  …
Enter fullscreen mode Exit fullscreen mode

Every method with its line range, and every call grouped by what it is: ORM / model use, framework facade, internal helper, static call. The comments that explain intent stay. If the agent needs the code of one method, it asks for exactly that: callgraph.sh app/Services/OrderService.php::updateOrders --body.

"Who calls this?"

Before changing updateOrders, the agent wants to know what depends on it:

$ callgraph.sh app --grep '(^|::|\.|->)updateOrders$'
app/Http/Controllers/OrderController.php
  class OrderController  L18-80
    update()  L45-66
      L52 │ $result = $this->orderService->updateOrders($request->orders, $request->toDto());
Enter fullscreen mode Exit fullscreen mode

The caller, its line, and the call itself — no file read needed. --depth 2 follows the chain one level further (impact analysis), and calls through interfaces, traits and parent classes are found too.

"Where do I start?"

For a task description, locate takes the names and words from it and ranks the few files worth opening first, each with the reason:

$ callgraph.sh locate CheckoutController applyCoupon coupon
1. app/Http/Controllers/CheckoutController.php  ★★★
   class CheckoutController  L16-74  ← "CheckoutController" (exact class)
   apply()  L38  calls CouponService::applyCoupon  ← "applyCoupon" (call)
2. resources/js/types.d.ts  ★
   interface Coupon  L120-131  ← "coupon" (exact interface)
…
Enter fullscreen mode Exit fullscreen mode

And for an unfamiliar project, callgraph.sh profile describes the architecture in about 15 lines: which folder holds which layer (controllers, services, models, Vue components, stores…), the patterns in use, and the direction the layers call each other.

How it works

  • AST analysis, not regex: PHP (Laravel, Yii), JavaScript / TypeScript, Vue, Rust and Swift, plus CSS / SCSS, JSON and Markdown outlines.
  • A project map in .callgraph/, updated file by file, so "who calls this?" across a large project is answered from one read.
  • Local and read-only. Your code never leaves your machine. No PHP, Node or Rust toolchain needed: it is one static binary for macOS, Linux and Windows.
  • Three ways to use it: a Claude Code skill, plain CLI from any terminal, or an MCP server for Cursor, VS Code, Claude Desktop and any MCP client.
  • Honest about gaps: a file with a syntax error is still outlined up to the broken part, and the output says so instead of silently returning nothing.

Try it

# download the package for your OS from https://callgraph.eu/ , unzip, then:
bash callgraph/install.sh
bash ~/.claude/skills/callgraph/callgraph.sh --version
Enter fullscreen mode Exit fullscreen mode

The installer can also register the MCP server for Claude Code. Setup recipes for Cursor, VS Code and Claude Desktop are on callgraph.eu/mcp.

Free and open source (MIT): github.com/GeRiY/callgraph


How does your agent find its way around a large codebase today? I'd love to hear what works for you — and which languages or frameworks you'd want next.

Top comments (2)

Collapse
 
itsvicmoreno profile image
Vic Moreno •

Agreed on where the tokens go: 412 lines read versus a 12-line outline is the right trade. The catch I'd watch is staleness, since once the agent edits OrderService mid-session the line ranges in the map drift. Does callgraph re-index on file change, or on each query?

Collapse
 
makra_gerg_8b963cb7a1cfd profile image
Makra Gergő •

Good catch — staleness is the first thing that bites with any code map. Both, actually:

  • Every query checks the files it touches (mtime + size) against the project map in .callgraph/ and re-analyses only what changed before answering. So if the agent edits OrderService and asks again, the next outline already has the new line ranges — no manual step.
  • The MCP server also watches the project and refreshes a changed file a moment after it's saved, so queries stay fast during a long session.
  • In Claude Code there's an optional hook that refreshes a file in the background right after the agent writes it, and callgraph.sh refresh does the whole project after a git pull.

A file with a syntax error mid-edit is still outlined up to the broken part, and the output says so ("⚠ syntax error at L…") instead of silently returning stale or empty results.