Trail-Code README

The project's README from github.com/trailhq/Trail-Code. As one markdown file: README.md.

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.

trailhq/Graft | Trendshift

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)

This works beyond code too.
A living skill file that learns from every task and gets sharper the more your team works.

Try Trail Brain

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


Contents


Quick start

npm install -g @nanonets/graft   # install the CLI, once
graft init                       # build the graph + wire it into Claude Code

That is the whole setup. graft init asks which of your coding agents to wire up, builds graft/ from your code, and drops a statusline and hooks into .claude/, so from the next session on Graft rides along in Claude Code: it pulls the matching nodes into each prompt and rebuilds the graph in the background after every turn. No daemon, no re-indexing to remember, nothing to run or maintain by default — the graph is just files.

Nothing is written until you pick. Run graft init --dry-run to see every file it would touch first, or graft init --agents claude to skip the prompt and wire Claude Code alone.

graft build adds graft/ to your .gitignore automatically — the graph is a local, regenerable cache (like node_modules), not something you commit. What you share is the wiring init dropped into .claude/; each teammate runs graft build to generate their own graph:

git add .claude && git commit -m "wire in graft"

Prefer not to install globally? npx @nanonets/graft init works the same way.

Two commands — npm install and graft init — then Graft rides along in a Claude Code session, statusline synced


The problem

Every task, your coding agent starts blind. Before it changes anything, it re-explores the repo: grep a term, open a file, follow an import, back out, try again. It is rebuilding a picture of a codebase it mapped an hour ago and threw away. That rediscovery burns most of a run's tool calls, tokens, and latency, and it is pure overhead:

Humans onboard to a codebase once. Agents onboard every single time.

A no-map agent's exploration trail wandering file to file before it finds what it needs


What Graft does

Graft builds that understanding once and writes it into your repo as a folder of linked markdown files, one node per system, API, or concept.

The same task, 'fix the auth bug', run two ways. A cold Claude Code session re-reads the repo and wanders file to file; Claude Code + graft loads its map once and rides the hooks to one clean pass. With Graft: 46% fewer tool calls, 42% fewer tokens, 60% less time, +22% more SWE-bench instances resolved.


Benchmark

An agent that reads the graph should be cheaper and faster without getting more answers wrong. That's the whole claim, so we measured it instead of asserting it.

The harness ran three variants of the same Claude Sonnet 5 agent with the same file tools: cold (explores from zero), Graft (a graft ask --source bundle pushed up front), and pull (graft_find_code/graft_file_api tools, nothing injected — context paid for only when asked). An Opus 4.8 judge scored correctness with a required-keyword floor, so a fast-but-wrong answer couldn't win by being fast. Cost is cache-aware: reads ≈0.1×, writes 1.25×, the billing model agents actually run under.

162 runs, two repos (graft itself and a real Node/Express auth service), 3 trials each, tasks split between single-file and multi-file questions.

Metric (mean/task) Cold Claude Code Claude Code with graft
Cost savings ($) 0.0429 0.0292 (+32%)
Token savings 8,070 4,650 (+42%)
Tool-call savings 4.2 2.3 (+46%)
Latency savings (s) 39.8 15.8 (+60%)
Correctness 93% 93% (equal)

Graft never answered worse than cold, on any corpus. The pull variant gave up most of that speed for something bigger: correctness jumped to 98%, +5 points over cold, the strongest single result in the sweep. Push when speed is what you need; pull when being right matters more.


SWE-bench Verified

The sweep above is our harness measuring our mechanism. So we ran the industry-standard one too — SWE-bench Verified, real GitHub issues from real repos, graded by the official swebench harness. No judge model, no similarity score: your patch is applied, the maintainers' own tests are run, and you either flip the failing test without breaking the passing ones or you don't.

50 instances, same model on both arms — Claude Sonnet 5 — same Docker images, same turn limits. The only difference is whether graft is wired in.

Correctness & efficiency Cold Claude Code Claude Code with graft Improvement
Correctness 27 / 50 (54%) 33 / 50 (66%) +12 pts
Token savings 142.0M 109.4M +23%
Cost savings $52.34 $42.43 +19%
Tool-call savings 1,370 1,031 +25%
API-request savings 2,455 1,875 +24%
Wall-clock savings 13,094s 8,922s +32%

graft resolved 33 of 50 instances against Cold Claude Code's 27 — and got there with 25% fewer tool calls, 23% fewer tokens, and 32% less wall-clock time. Every correctness win has the same shape: the baseline patches one file and misses its siblings. On django-11532 it patched 1 of the 5 files the fix requires and broke 18 previously-passing tests, twice over. On django-16263 it patched 1 of 4 and scored 102 / 103. graft found the rest — and on django-16263 did it in half the tokens and half the time.

Two harnesses, two claims: the controlled sweep says graft is cheaper and faster, SWE-bench says it's also more correct.

Correctness over all instances; tokens, cost and calls over the instances both arms resolved, for a like-for-like comparison. Official SWE-bench Verified images and official swebench 4.1.0 grader, native x86_64.


How the graph gets built

Graft builds the graph in two passes, both powered by a language model:

  1. Read each file. Every source file is summarized once into a short description of what it does.
  2. Group into nodes. Those summaries are grouped into a curated set of nodes (subsystems, key files, and concepts) with typed links between them. Graft chooses the right level of detail for you instead of making one node per file, so a big repo becomes a few dozen readable nodes.
flowchart LR
    S[Source files] --> T["Tier 1 — tree-sitter<br/>no model, no key"]
    S --> P1["Pass 1 — LLM summarizes<br/>each file (--deep)"]
    T --> W["graft/.graph/wiring.json<br/>per-symbol code graph"]
    P1 --> P2["Pass 2 — group into nodes<br/>+ typed links"]
    P2 --> N["graft/*.md<br/>markdown node graph"]

Every pass is cached by content hash — the LLM ones and the tree-sitter parse alike. Re-running only touches the files that changed, so the second build is fast and cheap (on this repo, 124 files: 0.74s cold, 0.18s after one edited file, 0.18s with nothing changed). graft build --no-reuse forces a cold re-parse.

That cheapness is what lets every query refresh the graph before it answers. A retrieval call stats the tree against the last build's fingerprint (~3ms), and rebuilds only if something moved — so ask/grep/callers/skeleton/map describe the code as it is right now, including edits that are unsaved to git: uncommitted, unstaged, or staged all look the same to graft. Git determines the visible file set; freshness compares the working-tree bytes rather than commit or index state. The refresh is structural and $0; it never calls the LLM. Turn it off per-command with --no-refresh, or everywhere with GRAFT_NO_REFRESH=1.

Alongside the markdown graph, graft build builds graft/.graph/wiring.json — a per-symbol code graph — plus a per-file wiring card mirroring your source tree. Tier 1 is pure tree-sitter (every function, class, and call edge; deterministic, no model, no network), which is why plain graft build needs no key. The --deep pass adds a one-line summary and a crux excerpt per symbol, cached by body hash.


Supported languages

Graft parses with tree-sitter at two levels of fidelity, plus an optional compiler-grade layer — all $0 and deterministic (no model, no key):

Twenty-three languages in total. A file whose language isn't listed is skipped, not indexed. Adding a broad-tier language is a small contribution — see CREDITS.md for the folks who added the current set.


What's in a node

A node is a single markdown file. Most code maps stop at an address: this thing lives in that file, on that line. That tells an agent where to look, not what it will find, so it still has to open the source and read. A Graft node holds the meaning inline, so the agent learns what it needs up front and opens the file only when it wants more.

Each node holds:

Part What it holds
Summary A plain-English explanation of what the code does, written by the model and cached. It is there whether or not the code was ever documented, and it is regenerated when the source changes.
Crux The handful of lines that actually carry the logic: the guard, the skip condition, the state change. Lifted straight from the source and stored inline, so the agent sees how it works, not just what.
Sources The exact files the node is built from, each tracked by a content hash, so Graft can tell precisely when a node has gone stale.
Links Typed connections to other nodes (depends_on, part_of, uses, implements, produces), written as [[wikilinks]] your agent can follow.
Notes Anything you write below the generated block. It is preserved across regenerations, so your own context is never overwritten.

That is three depths in one file: the summary says what the code does, the crux shows how, and the sources point to the rest if the agent needs it. A plain index makes it read a whole file to learn one thing. A Graft node hands it the answer inline, and the follow-up read often never happens.

The crux is stored as the code itself, not as a line range, on purpose. Line numbers drift whenever unrelated code above them shifts, but the lines that matter do not. Keeping the text, not the numbers, means the crux stays correct even as the file around it moves.

Summary, sources, links, and notes ship today in markdown nodes. The crux ships per-symbol in the code graph (graft build --deep); inlining it into markdown nodes is next.


What runs where

See .env.example for the full list of settings (model, base URL, graph directory).


Agent integration

One command wires Graft into the coding agents you use:

npx @nanonets/graft init
# detects your agents and writes each one's native instruction file;
# Claude Code additionally gets the live statusline + hooks below

On a terminal, init shows you every agent it knows about — flagging the ones it detected (via their config directories) and listing the exact files each would write — and wires only the ones you select. Claude Code is pre-selected; nothing else is. Selected agents get a marker-fenced Graft section in their shared instruction file — AGENTS.md (Codex, OpenCode and other CLIs that read it), GEMINI.md, .github/copilot-instructions.md — or a wholly-owned rule/skill file for the agents that use one: `.claud

Trail-Code (trailhq/Trail-Code)

Searching Database…

这是做什么的?Graft 会把你的代码库整理成一组互相链接的 markdown 文件——每个系统、API 或概念对应一个节点——并把相关节点喂给 Claude Code、Cursor、Codex、Gemini 这类编程代理,让它们不用每次任务都重新摸索整个仓库,跑得更快、更省钱、也更准确。
Graft 是云服务吗,还是所有东西都存在我的仓库里?它是一个 CLI 加一个 MCP 服务器,图本身就只是你仓库里的一个 markdown 文件夹(graft/)——一个像 node_modules 那样的本地可重建缓存。没有守护进程,没有数据库,默认也不需要运行或维护任何东西。
我要怎么做才能让我的编程代理用上它?运行 'graft init' —— 它会询问要接入哪些代理,生成 graft/ 目录,并在 .claude/ 里配置好状态栏和钩子,这样从你下一个会话开始图就会自动生效。不需要全局安装('npx @nanonets/graft init'),而且 'graft init --dry-run' 会先预览它要改动的每一个文件。
我需要自己准备 API 密钥吗?你需要 Node 20+。结构图(graft build)完全基于 tree-sitter,从不调用模型,所以不需要密钥;只有那些通俗的英文摘要会用到 LLM,用你自己选择的任意服务商——OpenAI、Anthropic、OpenRouter、Fireworks、Groq、LiteLLM 代理或本地模型——配你自己的密钥。
它能解析哪些编程语言?支持 23 种语言。完整精度(作用域感知、跨文件调用和导入解析)覆盖 TypeScript/JavaScript(含 JSX/TSX)、Python、Go、Java、Kotlin、PHP、Swift 和 R;Rust、C、C++、C#、Ruby、Scala 等语言则提供符号和调用关系。可选开启 LSP 处理(rust-analyzer、clangd、gopls、pyright、tsserver)以获得更精确的关联关系。
如果我们团队共用一个仓库,是不是每个人都要自己生成一份图?是的——graft/ 是每个开发者各自的本地缓存,会自动加入 gitignore。你只需提交 init 写入的少量配置文件(.claude/、AGENTS.md、MCP 配置);每位队友各自运行一次 graft build 来生成自己的图。
我在改代码的时候,图会变旧吗?不会——每次查询都会先根据你的工作区刷新图,这一步只做结构分析,完全免费(没有改动时约 3 毫秒),而且未提交、未暂存和已暂存的修改它都能看到。构建结果按内容哈希缓存,所以重跑时只会处理有变化的文件;graft check 是一个本地的时效性检查信号。
每个图节点里面到底装了什么?就是一个 markdown 文件:一段由模型撰写的通俗摘要,说明这段代码做什么;承载核心逻辑的关键代码行('crux');按内容哈希追踪的确切源文件;以及指向其他节点的带类型的 [[wikilinks]](depends-on、part-of、uses)。你在生成内容块之下写的任何东西,在重新生成时都会保留。
它到底能让代理快多少、省多少?在该项目 162 次运行的基准测试中:token 减少 42%,工具调用减少 46%,在同等正确率下延迟降低 60%。在 SWE-bench Verified 上(50 个实例,同样使用 Claude Sonnet 5),它解决了 33 个,而冷启动的 Claude Code 只解决了 27 个,token 少用 23%,总耗时缩短 32%。
除了接入 Claude Code,我还能用它做什么?它可以作为 MCP 服务器,供任何支持 MCP 的代理使用。CLI 提供 graft ask、grep、callers、skeleton 和 map 用于搜索和熟悉代码,graft viz 可以把图可视化,graft build --deep 则为每个符号生成摘要。推送模式(上下文一次性给足)偏重速度;拉取模式在他们测试的速度指标上稍慢,但换来了 98% 的正确率。
Creator
trailhq
Size
70 MB
Stars
10.4K
Updated
CommitOct 15
Age
3mo
Commits · 90 Days