
We watched an agent spend the first half of a bugfix doing the same tour every senior on the team already knows. Grep a name. Open a file. Follow an import. Back out. Try again. Then it patched one file and missed the sibling that had to change with it.
That is not a model problem. It is an onboarding problem. Humans onboard to a codebase once. Agents onboard every session, then throw the map away.
Graft is one attempt to keep that map. We are not selling it. We are stealing the part that matches how we already want client repos to work.
The cost is the second look

Before an agent changes anything, it rebuilds a picture of the system. On a small service that is a few greps. On a client app with modules, shared UI, and a mobile backend, it is most of the tool calls, tokens, and time. The next person on the team pays it again. So does their agent.
Graft’s own writeup of the problem is the useful one: the exploration is repeated, discarded, and unshared. That is the bill we keep paying when the only context in the repo is source code plus a README nobody updates.
Their SWE-bench Verified run (50 instances, same Claude model on both sides) is the number that made us look twice. Cold Claude Code resolved 27 of 50. With Graft wired in, 33 of 50. The failures they call out have the same shape: the baseline patches one file and misses its siblings. We have reviewed that patch. It is locally fine and globally wrong, which is the same drift we wrote about last week.
Take the percentages as theirs, not ours. The shape of the failure is something we see on client work without any benchmark.
A map the agent can grep

Graft does not hide the map inside an embedding index. It writes linked markdown into a graft/ folder. One node per subsystem, API, or concept. Each node says, in plain language, what that part does and how it connects. Typed links (depends_on, part_of, uses) are wikilinks the agent can follow the same way it follows any other file.
The structural graph underneath is tree-sitter. Functions, classes, call edges. No model, no API key, no network. graft build is that pass. graft build --deep is the optional one: a model writes the summaries, under your key, and caches them by content hash so the next build only touches files that changed.
That split matters. The address book (where does this live, who calls it) should be cheap and deterministic. The explanation (what does this mean) can cost a model call, and it should be cached, not rewritten every prompt.
npm install -g @nanonets/graft
graft init
graft init builds the graph and asks which agents to wire. Claude Code gets hooks so later turns pull matching nodes in. The graph itself is gitignored, like node_modules. What you commit is the wiring: AGENTS.md, the Claude hooks, the MCP config. Each teammate runs graft build and gets their own cache.
We like that. A committed graph goes stale the first afternoon someone forgets to regenerate it. A local cache plus a shared instruction file is the same deal as a lockfile: the recipe is shared, the artifact is rebuilt.
Push the map, or let the agent pull it
Their smaller harness compared three ways of using the same agent: cold (explore from zero), Graft pushed up front, and tools the agent can call when it wants (graft_find_code and friends). Push was faster and cheaper. Pull was slower, and more correct in that sweep.
That matches how we already think about context. Dumping the whole map into the first prompt saves a wandering session. It also spends tokens on nodes the task never needed. Letting the agent ask is closer to how a human uses a wiki: open the page when the question is real.
For a one-file bug we would push a small neighborhood. For a cross-module change we would rather the agent pull callers and dependents than read a 40-node essay it will not use. The tool should support both. The default should not be “always inject everything.”
What we would actually put in a client repo
We would not paste Graft’s marketing table into a sprint plan. We would take the shape.
- A short ruleset the agent must read. We already do this. Folder layers, import direction, form and empty-state contracts. Graft does not replace that. It does not know your product rules unless you write them in a node and preserve them under the notes section (Graft keeps notes you add below the generated block).
- A subsystem map in plain files, not only in someone’s head. Even a hand-written
docs/map/of ten markdown pages beats another cold session. Graft is a way to generate and refresh that map. A human can still write the first version.
- Callers before patches. The recurring miss is “changed the function, not the three callers.” A tool that answers “who calls this” from a local graph is worth more than another search prompt. Tree-sitter gets you most of that without a model. Language servers (
graft build --lsp) fill the member calls the static pass cannot type. Use them when they are already on the path. Do not block the map on rust-analyzer being installed.
- Do not commit the cache. Commit the wiring and the rules. Ignore
graft/. Rotate the model summaries when the source hash changes. If a node is wrong, the notes block is where a human correction should live, not a Slack thread.
- Treat the map as a hint, not an authority. Summaries drift. Crux excerpts can miss the guard that matters. The agent still opens the source before it edits. The win is that it opens the right file first.
What we would not do
We would not turn this on for every repository on day one. A tiny service does not need a graph. A generated map of a mess just documents the mess faster. Write the layers first, then generate the map so the nodes have somewhere honest to live.
We would not treat their 4x cheaper line as a forecast for our bill. Different harness, different model, their numbers. Use Graft if the rediscovery tax is visible in your own sessions. Measure tool calls and wrong-file patches on your own tasks. If those do not drop, the graph is decoration.
We would also keep secrets out of the graph. graft build --deep sends file contents to whatever provider you configured. The structural build does not. Default to the cheap pass. Turn on summaries for the modules where a one-line explanation actually saves a read. Do not run the deep pass over credential files, dump folders, or generated vendors.
A map is the other half of a ruleset
Last week we argued for writing the ruleset before the AI writes the frontend. That is policy: how we want new code to look. Graft is geography: where the current system lives, and how the pieces connect.
An agent with rules and no map invents a local solution and misses the sibling files. An agent with a map and no rules follows the existing mess faithfully. You want both. The ruleset in the repo. A graph the next session can open without grepping its way there. And a human still reading the diff, because the map does not review itself.
If you are about to point a coding agent at a client repo that has already been mapped by three people and zero files, start smaller than a new platform. Write ten nodes. Or run graft init on a branch, read the graph, and delete the nodes that lie. The useful artifact is the one the next session actually opens.