DEV Community

Cover image for Graft: Persistent Code Context That Can Survive AI Session Compaction
Smyekh David-West
Smyekh David-West

Posted on

Graft: Persistent Code Context That Can Survive AI Session Compaction

The tool that helps solve context loss in long AI-assisted development sessions

TL;DR: Give Your AI Agent Persistent Code Context

  1. npm install -g @nanonets/graft - install the CLI once.
  2. Run graft init --agents claude in each repo - integrate Graft into Claude Code and build the initial graph.
  3. Write a lightweight CLAUDE.md per repo - keep only rules and context the codebase can't explain itself.
  4. Commit the agent configuration and CLAUDE.md - keep Graft's local graph out of Git.
  5. Start a new session and let Graft help the agent rediscover the codebase context.

Long sessions stay oriented through compaction, and new sessions can quickly rediscover the context they need.

The Real Problem: AI Forgets What You Taught It

Long Claude Code sessions eventually get compacted. Sometimes, depending on the kind of day you're having as a developer, it's very easy to hit those "session limits".

And when that happens, some of the context you've built during the session can disappear.

This is especially noticeable when you're working on production software and you've spent a long session explaining architecture, dependencies, business rules, or why something was implemented a particular way.

Start a new session and much of that understanding has to be rebuilt.

You can point Claude at the code again, but the problem isn't that the code disappeared. The problem is that the understanding you built around the code isn't necessarily available anymore.

That's the problem I wanted to solve.

Why This Matters: Use Case Over Hype

In my previous article on building production software with AI, I emphasised that what differentiates expertise in AI-assisted development today is understanding which tools solve which problems.

It's not about using the most sophisticated model. It's about matching tools to use cases.

Graft is a good example.

Most of the conversation around AI development focuses on token savings, context windows, and model efficiency. Those things matter. Graft can reduce the amount of code Claude needs to consume by querying a structured representation of the codebase instead of repeatedly reading everything.

But that's not the most interesting part to me.

The bigger problem is knowledge transfer.

When I work on a codebase for long enough, I accumulate context that isn't necessarily written down anywhere: why a service exists, which parts of the system depend on it, what will break if I change something, and which seemingly unused pieces of code should be left alone.

Normally, I'm the knowledge layer.

Graft gives the codebase a way to carry some of that knowledge with it.

Graft lets your codebase teach Claude (and new developers) without you having to repeat yourself.

That's not just a token optimisation problem solved.

That's a knowledge transfer problem solved.

What is Graft? (And Why It Helps Solve Compaction)

Graft builds a persistent, queryable graph of your codebase. It maps the structure of your code — functions, classes, files, imports, calls, and relationships between them — into a form that can be queried by your AI coding agent.

The important part isn't simply that Graft indexes your code.

It's that the index exists outside the AI's current conversation.

That means when a session ends or gets compacted, the codebase's structural knowledge doesn't disappear with the conversation.

GitHub logo trailhq / Graft

Turbocharge Claude Code, Cursor, Codex, Gemini & every coding agent: faster, cheaper, with contextual understanding specific to your codebase.

Graft — open-source context layer for large codebases

Turbocharge Claude Code, Cursor, Codex, Gemini & every coding agent: faster, cheaper, with contextual understanding specific to your codebase.

Up to 4× cheaper and 3× faster, with better or no loss of correctness.































Metric Cold Claude Code Claude Code with graft
Tool-call reduction Baseline +46%
Token savings Baseline +42%
Time savings Baseline +60%
Correctness 54% 66% (+12 pts)

Efficiency is a 162-run controlled benchmark (same agent, same file tools, only the context differs). Correctness is SWE-bench Verified, graded by the official harness — graft resolved 66% of instances tested against Cold Claude Code's 54%. Efficiency method ↓ · SWE-bench ↓ · Per-repo numbers ↓

Side-by-side comparison of a coding agent working with and without graft


Contents

Here's what makes it different: the codebase's knowledge doesn't have to live inside the current AI conversation.

When Claude compacts a long session, some of the architectural understanding you've built together may no longer be available in the same detail. Graft gives Claude another way to rediscover that information. Instead of having to hunt for forgotten context, Claude can query the graph you've built and retrieve the relevant information when it needs it. It's like handing Claude a Google Map of your codebase: even after a session ends, it has another way to navigate the system.

But Graft is useful for more than recovering context after compaction. New developers can also ask questions they'd normally ask the people who wrote the code. Questions like:

  • "How does auth flow through the system?"
  • "What breaks if I change this function?"
  • "Which services depend on this API?"

And they can get meaningful answers by querying the codebase without having to ask you first.

That also means a new session can start with more confidence. Instead of spending the first part of the session reconstructing how the system works, you can get to planning and building sooner.

Graft Doesn't Replace Your Instructions

There's an important distinction here.

Graft can discover things from the codebase. It can map relationships, trace calls, identify dependencies, and retrieve relevant code.

But there are things your code cannot tell an agent:

  • Why was this approach chosen?

  • Is this apparently unused module intentionally retained?

  • Which business rule must never be changed?

  • Why does this database constraint exist?

That's where CLAUDE.md comes in.

Graft handles discoverable knowledge. Your agent instructions handle non-discoverable knowledge.

Together, they give the agent a much more complete picture of the system.

How It Works

  • Free structural layer: functions, classes, call edges, and imports via tree-sitter (no LLM, no API key). This alone is powerful.

  • Optional LLM layer: graft build --deep adds LLM-generated summaries, concept nodes, typed relationships, and per-symbol summaries/cruxes. This is where some of the magic happens. This adds plain English descriptions that help Claude understand not just where things are, but also what the code appears to do and how the pieces fit together.

  • MCP server: Claude Code can query the graph actively during conversations via graft_find_code, graft_trace_calls, etc. It's not passive context; it's active knowledge retrieval.

  • Auto-sync: Graft checks the working tree before queries and structurally refreshes the graph when files have changed. The refresh is deterministic and does not call the LLM.

  • Language support: 23 languages, including TypeScript/JavaScript, Python, Go, Java, Kotlin, PHP, Swift, Rust, C++, C#, Ruby, Scala, Elixir, Solidity, OCaml, Zig, Dart, Clojure, Nix, and Lua.

A Quick Note on MCP

MCP (Model Context Protocol) is what allows Claude Code to communicate with external tools.

In Graft's case, the MCP server exposes the code graph to Claude.

When Claude needs to understand how part of the system connects to another, it can query Graft instead of blindly reading large numbers of files.

For example, it can ask Graft questions such as:

  • Which functions call this function?
  • Where is this API used?
  • What depends on this service?
  • Where does this data flow next?

The important distinction is that Graft isn't simply dumping the entire codebase into Claude's context.

Claude queries the persistent graph when it needs the information.

Seeing Graft Work in Real Time

When Graft is active in a Claude Code session, you get a small status line showing what's happening with the graph and context:

Here's what each part means:

Graph Metrics & Savings:

  • graft: Indicates that Graft is active in the current session.

  • 3960 nodes / 7858 edges: The size of Graft's code graph. Nodes represent code entities, while edges represent relationships between them such as imports, calls, and inheritance.

  • ✓ synced: Confirms Graft's background graph index is up to date with your local files.

  • ~775,596 tok saved: Estimated total API tokens saved by serving precise code context via graph traversal instead of dumping whole files into Claude's context window.

Context Window State:

  • ctx 30%: The current fill level of Claude Code’s active context window (30% consumed).

  • last: app.js: The last file or context node referenced or modified by the agent.

This statusline updates in real-time as you work, giving you instant feedback that Graft is synced and active.

Agent Mode:

  • ⏸ manual mode on: Automatic graph traversal/injection is paused. Graft will not automatically pull graph dependencies into the prompt unless instructed.

  • • ← for agents: Key command guidance. Pressing the Left Arrow key (←) toggles between manual mode and automatic/agentic mode, giving you manual control over when Graft feeds context to the agent versus letting Graft auto-retrieve code relations.

Setup: Start With the Free Structural Graph

You don't need an API key to get started.

The structural graph is generated locally from your codebase, so you can install Graft, build the graph, and start querying your code without paying for an LLM.

Here's the setup I use.

Step 1 - Install Graft

First, install Graft globally:

npm install -g @nanonets/graft
graft version   # confirm it installed
Enter fullscreen mode Exit fullscreen mode

Step 2 - Setup Your Repo

For each repository, run these commands in order. Here's what each one does:

graft init --agents claude --dry-run

This previews what Graft will touch without actually writing anything. Use this first to be safe.

What it does:

  • Scans your repo structure
  • Detects your programming languages
  • Lists every file Graft would create: .claude/settings.json, .mcp.json, hooks, skill files
  • Exits without writing anything

Example output:

would write — this repo:
  .claude/settings.json                 graft statusline + hook blocks
  .claude/helpers/graft-statusline.cjs  statusline shim
  .claude/helpers/graft-hooks.cjs       hooks shim
  .claude/skills/graft/SKILL.md         graft skill
  .mcp.json                             mcpServers.graft
Enter fullscreen mode Exit fullscreen mode
cd ~/repos/core-api  # navigate into your directory
graft init --agents claude --dry-run   # see what it would touch
Enter fullscreen mode Exit fullscreen mode

graft init --agents claude

This integrates Graft with Claude Code for this repo.

What it does:

  • Creates .claude/settings.json with the statusline and hooks configuration
  • Creates hook shims (helpers) that Claude Code runs at specific moments (session start, after edits, before tool use)
  • Creates .claude/skills/graft/SKILL.md which tells Claude Code how to use Graft
  • Creates .mcp.json, it registers the Graft MCP server so Claude Code can call Graft tools natively
  • Auto-adds graft/ to .gitignore (the graph is a local cache, not committed)
  • Builds the initial graph unless --no-build is specified

What "agents" means: By default, graft init detects which coding agents you have (Claude Code, Cursor, Copilot, etc.) and prompts you to pick which ones to integrate. The --agents claude flag skips that prompt and integrates Claude Code only.

If you add another agent later (say Cursor), just run:

graft init --agents claude cursor
Enter fullscreen mode Exit fullscreen mode

Graft merges the new agent wiring with your current Claude Code wiring, rather than overwriting it.

Why Multiple Agents?

You might use Claude Code for general development and another coding agent for specific tasks.

All of them can use Graft's codebase context, while each repository maintains its own local, regenerable graph.

cd ~/repos/core-api
graft init --agents claude        # run it after the dry-run
Enter fullscreen mode Exit fullscreen mode

graft build

This builds or refreshes Graft's local code graph.

What it does:

  • Reads the source files in your repo
  • Uses tree-sitter to build the deterministic structural graph: functions, classes, methods, types, imports, and call relationships
  • Creates graft/, including .graph/wiring.json and per-file wiring cards
  • Caches work by content hash, so unchanged files are reused
  • Automatically adds graft/ to .gitignore because the graph is a local, regenerable cache

Cost: Free. No API key needed.

Speed:

  • First run: 30 seconds to 2 minutes (depends on repo size)
  • Subsequent runs: ~0.2 seconds if nothing changed and updates only modified files if there was a change or an update.

graft map

This prints a human-readable summary of what Graft found — no output file, just terminal output.

What it shows:

  • Directory clusters with file/symbol counts
  • Hubs in each directory (most-called functions/classes)
  • Global hotspots (most-coupled symbols across the entire repo)
  • Token savings (how many tokens Graft saved you vs reading all files).

Use this to verify Graft found everything important in your repo.

Example:

repo map — 314 files · 3809 symbols · 7552 edges · javascript, python, tsx, typescript

src/                142 files · 1823 symbols   hubs: AuthService (auth.ts, 21←), validateToken (middleware.ts, 14←)
backend/             89 files · 934 symbols    hubs: UserSerializer (serializers.py, 8←), create_record (views.py, 7←)

hotspots: AuthService · class · src/auth/auth.ts:L12-L89 · 21←
Enter fullscreen mode Exit fullscreen mode

The 21← means "21 things depend on this" — you know immediately which parts of your code are most critical.

cd ~/repos/core-api
graft map
Enter fullscreen mode Exit fullscreen mode

Full Setup Workflow for One Repo

cd ~/repos/core-api
graft init --agents claude --dry-run   # preview
graft init --agents claude             # write the files
graft build                            # explicitly rebuild/refresh the graph when needed
graft map                              # verify it found everything
Enter fullscreen mode Exit fullscreen mode

Technically, graft build is not required immediately after init because init already builds unless you use --no-build. build is the command for explicitly rebuilding/refreshing the graph.

This creates:

  • .claude/settings.json — Claude Code configuration
  • .claude/helpers/ — statusline and hooks scripts
  • .claude/skills/graft/SKILL.md — Graft instruction file
  • .mcp.json — MCP server registration
  • graft/ — the actual graph (gitignored, local only)

Repeat for each repo in your codebase.

Graft + CLAUDE.md: Two Different Kinds of Context

Graft handles code discovery. But agents still need to know about things the code itself cannot reliably explain: dead code, business decisions, architectural constraints, operational rules, and decisions that aren't obvious from implementation.

Personally, I use CLAUDE.md as a helper and keep it very light. Mine sits just below 100 lines and focuses on business decisions or code choices the agent repeatedly gets wrong.

I don't want CLAUDE.md to become a second copy of the codebase. I want it to contain the things the codebase can't tell the agent by itself.

That's the distinction:

Graft tells the agent what exists and how it connects.

CLAUDE.md tells the agent what it needs to know that isn't obvious from the code.

This file should focus on non-discoverable information: dead code warnings, database constraints, policy decisions, and performance hotspots. Here's an example from my production codebase:

# Agent & Contributor Guidelines

This document serves as an operational guide for AI agents and human developers working on this codebase.

## Engineering Practices

Our core engineering principles prioritize long-term maintainability over quick hacks:

1. **Keep It Simple (KISS):** Avoid over-engineering. Write straightforward, readable code over clever optimizations.
2. **Modularity & Separation of Concerns:** Keep components, modules, and services loosely coupled with single, well-defined responsibilities.
3. **Root-Cause Fixes over Patches:** Do not apply temporary workarounds or band-aids. Address underlying architectural root causes before committing changes.

## Codebase Architecture & Dead Code Warnings

### 1. Ingestion Module (Deprecated)

* **Path:** `backend/app/ingestion/`
* **Status:** **DEAD CODE.**
* **Instruction:** Do not use, modify, reference, or refactor any code inside `backend/app/ingestion/` or its related files. It is strictly unused and should not be treated as legacy code.
Enter fullscreen mode Exit fullscreen mode

Working with Graft in a Team

Commit the wiring that graft init adds to the repository. The graft/ graph itself is a local, regenerable cache and is kept out of Git.

Each teammate can run:

git clone <repo>
npm install -g @nanonets/graft
graft build   # free, local, no key needed
Enter fullscreen mode Exit fullscreen mode

They get their own local graph from the same codebase. The CLAUDE.md you maintain provides the shared context that isn't discoverable from the code itself.

The graph is cached by content hash, so rebuilding the same unchanged content doesn't require generating the summaries again.

You're no longer the only place that onboarding knowledge lives.

Advanced: Adding LLM Summaries (--deep) Later

The free build gives you Graft's deterministic structural graph. --deep adds the LLM-generated understanding layer.

The Two Tiers Explained

Free Tier (graft build):

  • What you get: per-symbol code graph, file wiring cards, functions, classes, call edges, imports, and other structural relationships
  • Cost: Free
  • API key needed: No
  • LLM used: No

Deep Tier (graft build --deep):

  • What you get: LLM-generated file summaries, concept nodes, typed relationships, plus per-symbol summaries and crux excerpts
  • API key needed: Yes
  • LLM calls: Yes
  • Cached by content/body hash
graft init --agents claude
        │
        ├── integrates Claude Code
        ├── installs hooks/statusline/MCP configuration
        └── builds initial graph
                    │
                    ▼
               graft build
                    │
                    └── rebuild/refresh graph when needed

graft build --deep
        │
        └── adds LLM-generated understanding
Enter fullscreen mode Exit fullscreen mode

Your Codebase Should Explain Itself

Graft isn't the solution to every problem.

But it solves a specific problem I've run into repeatedly while building production software with AI: the codebase shouldn't lose its ability to explain itself just because an AI session ended.

When a long session gets compacted, the conversation may lose context.

When a developer leaves, their personal knowledge leaves with them.

When a new developer joins, someone has to explain the architecture again.

The code hasn't changed. What's missing is the context around it, and that's where Graft becomes useful.

It gives your AI coding agent a persistent way to rediscover how the codebase is structured, how things connect, and where to look next.

And when you combine that with a lightweight CLAUDE.md containing the things the code itself can't explain, you stop relying on one person to be the permanent knowledge layer for the system.

You don't have to be the person who explains the codebase every time someone needs to understand it.

Your codebase should be able to explain itself.

That's worth more to me than the token savings.


Cover Photo by Alina Grubnyak on Unsplash

Top comments (0)