Guide

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.

bash
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 calls

A 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.

bash
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.

text
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 forWhen the question is
reap indexWhere is this defined, who calls it, what depends on this file, what is the blast radius of this change
Grep / GlobLiteral strings, comments, config files, languages with no grammar, and anything not committed yet