Code Intelligence
REAP ships a code index. Nothing to install, nothing to start, no background process. A Tree-sitter parser walks every tracked file, records the symbols it defines and the calls and imports between them, and stores the result in .reap/.index/ as gzipped JSON. Fifteen languages ship with it, and there is no native build — the grammars are WebAssembly.
Commands
Every subcommand emits JSON on stdout like the rest of REAP, so an agent can parse it and a human can read the message field.
reap index # update — the default
reap index update [--full] # bring the index level with HEAD
reap index status # counts, import resolution rate, indexed commit
reap index impact <file>... # what breaks if you change this file
reap index search <query> # find a definition, with file:line
reap index callers <symbolId> # who calls this
reap index callees <symbolId> # what this callsA symbolId is <file>::<name> — for example src/core/lifecycle.ts::nextStage. reap index search prints them.
The unit of change is a commit
The index records the SHA it describes. Deciding what to re-parse is one git diff, and deciding whether to bother is one string comparison. Queries refresh the index themselves when HEAD has moved — after a commit, a branch switch, a rebase or a pull — so REAP refreshes eagerly only where it has just committed: at the end of completion, and in early-close.
reap index update # Indexed 412 file(s) — full, 1530 symbols at 1a2b3c4 (612ms)
reap index update # Index is current at 1a2b3c4 (1530 symbols, 3688 edges)The trade-off: uncommitted work is not in the index. A symbol you wrote a minute ago and have not committed will not be found by search, and a new file will not appear in impact — use Grep for those. A git repository is required, since without one there is no commit to key the index to.
Read status before trusting impact
Everything impact knows comes from resolved import edges. A low imports rate means the graph is incomplete, and an empty blast radius then means unknown rather than none. status also warns when a grammar fails to load, which is the other way a language goes silently unindexed.
files: 412
symbols: 1530 (function 902, method 341, class 187, type 100)
edges: 3688 (CALLS 3145, IMPORTS 543)
imports: 543/543 resolved (100%)
commit: 1a2b3c4(Illustrative figures.) The line that matters is imports. Everything impact knows comes from resolved import edges, so a low rate means the graph is incomplete — and an empty blast radius then means unknown rather than none. A resolver that cannot map a ./x.js specifier to the x.ts producing it reports zero here, which is why the rate is on screen rather than inferred from whether indexing ran.
Where the index lives
In .reap/.index/ — a manifest.json plus one gzipped graph — and both reap init and reap update add it to .gitignore. Deleting the project deletes the index with it; nothing accumulates in your home directory. The ignore is not about size: committing the index would mean the commit containing it has to be indexed, which does not terminate. Deleting .reap/.index/ is always safe, since the next command rebuilds it.
When to use it
The two are complementary — the index answers with file:line, which you then read.
| Reach for | When the question is |
|---|---|
| reap index | Where is this defined, who calls it, what depends on this file, what is the blast radius of this change |
| Grep / Glob | Literal strings, comments, config files, languages with no grammar, and anything not committed yet |
