GitHub

Grep

Grep is exact, line-oriented matching over your working tree, delegated to ripgrep. It is always live: it reads files from disk at call time, so it needs no index and can never be stale. By default it is aligned to the same corpus RCE Code indexes — the same ignore rules apply — so its hits correspond to the files your other searches see.

Reach for grep when you know the literal text or a regular expression you are looking for. Unlike lexical or semantic search, it returns precise line and column positions rather than ranked chunks.

How it works

engine.grep(...) shells out to the rg binary with --json and parses the structured output into GrepHit objects. By default it runs as a fixed-string search (literal text), switches on smart-case matching, and applies RCE Code's built-in ignore globs so generated, vendored, and binary paths are skipped — this is what “corpus-aligned” means. Pass raw=True to bypass those ignore globs and search everything ripgrep would otherwise see.

ripgrep must be installed

Grep requires the rg binary on your PATH. If it is missing, engine.grep(...) raises RipgrepNotFound. ripgrep exit codes are handled for you: “no matches” returns an empty list, while a genuine ripgrep error raises RipgrepError.

Python API

signature
engine.grep(
pattern: str,
*,
glob: str | None = None, # restrict to paths matching this glob
regex: bool = False, # treat pattern as a regex (default: fixed string)
case_sensitive: bool = False, # default is smart-case
max_count: int | None = None, # cap matches per file
raw: bool = False, # bypass the corpus ignore set
) -> list[GrepHit]

Every GrepHit is a frozen record with these fields:

FieldTypeMeaning
file_pathstrRepo-relative path of the matching file
lineint1-indexed line number of the match
columnint1-indexed column of the first submatch on that line
line_textstrThe full matching line, trailing newline stripped
context_beforelist[str]Lines of preceding context (empty by default)
context_afterlist[str]Lines of following context (empty by default)

Literal search

literal.py
from rce.code import CodeEngine
engine = CodeEngine.open_or_create("/path/to/repo")
# fixed-string search (the default): the pattern is matched verbatim
for hit in engine.grep("TODO(auth)"):
print(f"{hit.file_path}:{hit.line}:{hit.column} {hit.line_text}")
engine.close()

Regex search

regex.py
# pass regex=True to interpret the pattern as a regular expression
hits = engine.grep(r"def\s+test_\w+", regex=True, case_sensitive=True)
for hit in hits:
print(hit.file_path, hit.line, hit.line_text)

Restricting by glob

glob.py
# only search Python files, and stop after the first hit per file
hits = engine.grep("import requests", glob="*.py", max_count=1)
# bypass the corpus ignore set to search everything, including ignored paths
all_hits = engine.grep("API_KEY", raw=True)

CLI

The grep subcommand exposes the literal/regex toggle and prints one line per hit as file:line:column text.

terminal
# literal search (default)
rce-code grep "TODO(auth)"
# regex search
rce-code grep --regex "def\s+test_\w+"
# search a different repo
rce-code grep "import requests" --repo /path/to/repo

CLI vs. Python surface

The rce-code grep command currently exposes only --regex/--literal (and --repo). The richer options — glob, case_sensitive, max_count, and raw — are available through the Python engine.grep(...) call.

No index, no staleness

Because grep reads the working tree directly, it does not depend on having run index() and never reports a Freshness — what it returns is exactly what is on disk right now. That makes it the right tool the moment after an edit, before re-indexing.