give grep, tree-sitter, and cat a shared brain.
tilth reads code the way an agent needs it. small files come back whole, large files as a structural outline, and every search leads to where a symbol is defined. it also answers what text search can’t, such as who calls a function. structural awareness in one call.
cargo install tilth · npx tilth · Rust, zero runtime deps · MIT
an agent makes six calls to find one function.
glob → read → “too big” → grep → read again → read another file. six round-trips to answer a question the file’s own structure already knew.
built-in tools answer in fragments
grep finds where a string appears. it cannot say where a symbol is defined. cat returns a whole file when you needed eight lines, or overflows the context window, so the agent greps and reads again. structure is rediscovered on every call.
structure, resolved in one call
the outline says what is in the file. search says where things are defined, with each hit shown in its surrounding structure. --section returns exactly the lines you asked for. one call, already structured.
questions grep can’t answer.
grep finds where text appears. to learn who calls a function, an agent then has to read files and work it out, and that answer can be wrong without anyone noticing. tilth parses the code and computes the answer. everything below is real output from the FastAPI and Gin repositories, with ... where lines are cut.
where is it defined?
Search uses the syntax tree to tell a definition from a mention, and lists definitions first. Each match sits among the symbols around it, so you know where you are without opening the file.
what does it call?
An expanded definition ends with a -- calls -- footer. It lists the functions the definition calls, and the ones those call, each with file, line range and signature. An agent can follow the chain without searching again.
what depends on this file?
--deps shows what a file uses and what uses it, down to the function and the symbol. Read it before you rename or remove an export.
what changed?
The diff is reported per function. It says what was added, what was removed, and whether a signature or only a body changed, so a review starts from the symbols that moved.
tilth parses syntax and does not resolve types. Callers and dependencies are matched by name, so two functions with the same name in different modules look alike, and dynamic dispatch is out of reach.
it shows you the shape first.
tree-sitter parses the file into an abstract syntax tree, so tilth knows the difference between a definition and a mention. what it returns is decided by token count. a 1-line minified bundle gets outlined, and a 120-line focused module prints whole.
Read a file. Under ~6k tokens it comes back whole with line numbers; over, you get a structural outline with line ranges for every symbol.
--section 44-89 returns exactly those lines. --section "## Install" returns exactly that markdown heading. No re-reading the whole file.
Definitions first, then usages, matched on the syntax tree. Each hit is shown inside its surrounding file structure, so you know what you found.
An expanded definition carries a -- calls -- footer of resolved callees, with file and line. Follow the call chain without a fresh search for each one.
it decides what to show
| input | behaviour |
|---|---|
| empty / binary | [empty] / [skipped] with mime |
| generated (lockfile, .min.js) | [generated] |
| < ~6k tokens | full content, line-numbered |
| > ~6k tokens | structural outline with ranges |
it remembers what the agent saw
Definitions already expanded once come back as [shown earlier] on later searches, so the agent does not receive the same body twice. expand defaults to 2, so there is no flag to remember.
Install with --edit and tilth adds hash-anchored writing: each line carries a hash, and an edit is rejected if the file changed since you read it.
read, search, and navigate by structure.
The same engine behind the CLI is exposed as MCP tools, so an agent reaches for the right one without a wall of upfront instructions.
Definition-first search. Several symbols fit in one call, such as "ServeHTTP, Next", and each gets its own block. --expand inlines source for the top matches.
Every call site of a symbol, matched on the syntax tree, so comments and strings that mention the name are left out.
What a file uses and what depends on it, with the symbols each dependent uses. Read it before you rename an export.
Everything about one symbol in a single call: signature, doc, callers, callees, siblings, tests. The whole neighbourhood at once.
A function-level diff that shows which symbols were added, changed, or had their signature altered. It can stand in for git diff when an agent reviews a change.
Content and glob search on ripgrep’s own engine. When results are cut, the header says how many matches there are in total.
fast enough to sit in the loop.
tilth is one binary with nothing to install behind it. Definitions and usages are searched in parallel, reads are memory-mapped, and the codebase walk pre-filters files with SIMD so most are skipped quickly.
AST-aware, via tree-sitter
Definitions, callees, callers and outlines, all from the syntax tree, across:
milliseconds per call
| operation | gin | fastapi |
|---|---|---|
| file read | 3ms | 3ms |
| callers | 13ms | 64ms |
| symbol search | 20ms | 77ms |
| codebase map | 52ms | 184ms |
Gin has 130 files and FastAPI has 2,700. Median of 15 runs on an Apple M5 Pro, process startup included. Search walks the whole tree, so time grows with the repository. MCP mode pays startup once.
ripgrep’s engine, tree-sitter’s parser
Content search runs on ripgrep’s own grep-regex and grep-searcher. The ignore crate walks directories, memmap2 reads files, and DashMap holds the outline cache, which is invalidated by mtime.
it installs where your agent already lives.
One command writes tilth into a host’s MCP config. Pick your host below to see it.
Smaller models sometimes prefer their built-in tools. Run with --disallowedTools "Bash,Grep,Glob" to make tilth the only way through. You can also call the CLI straight from bash, and the agent prompt lives in AGENTS.md.
is tilth for you?
tilth earns its place when something reads a lot of code and needs to get the structure right. That is most agents, and plenty of humans.
reach for tilth when · a fit
- an AI agent navigates your code, and you want its answers computed from the syntax tree
- the repo is large, unfamiliar, or spans several languages
- you need definitions and call chains, and grep only gives you string matches
- your agent’s built-in search is weak or missing
less to gain when · maybe not
- it’s one small script you already hold in your head
- only you read the code, and only occasionally
- your language isn’t among the 17 tree-sitter grammars
- you need type-aware answers, since tilth matches callers by name and does not resolve types
install it, point an agent at it.
install
cargo install tilth
also: npx tilth · prebuilt binaries on the releases page
read, search, navigate
where tilth is
tilth is the state of soil that’s ready for planting. Your codebase is the soil; tilth gives it structure, so you can find where to dig. Follow along on GitHub →