agentgrep grep¶
The agentgrep grep command searches normalized prompt and history
records with the flag grammar and output behavior of ripgrep and
the_silver_searcher. If you already reach for rg -i or ag -F
without thinking, the same flags work here against your AI history.
Defaults follow rg: smart-case (case-insensitive unless the pattern
contains uppercase), regex pattern interpretation, color on TTY,
and line-aware output. Each matching record emits one row per
matching line. By default each row is just path:text (rg’s
default pipe shape); pass -n / --line-number to add line
numbers, --column to add column numbers (implies -n), and
--vimgrep for the path:line:col:text shape with one row per
match span. On TTY a per-record heading line opens with
agent · timestamp · path. The one deliberate divergence is session
deduplication — see Session deduplication below.
Examples¶
A literal single-pattern search across every agent:
$ agentgrep grep bliss
Force case-insensitive matching:
$ agentgrep grep -i 'serene bliss'
Treat the pattern as a literal substring (not a regex):
$ agentgrep grep -F --type history 'v1.2.3'
Stream an rg-style event stream as JSON:
$ agentgrep grep --json design
Drop session dedup for the raw rg-faithful view:
$ agentgrep grep --no-dedupe foo
Open the Textual explorer pre-filled with the grep query:
$ agentgrep grep -i foo --ui
Silence the stderr spinner:
$ agentgrep grep --no-progress bliss
Output format¶
By default grep emits one stdout line per matching line within a
record, with the matched substring highlighted. The shape mirrors
rg:
On TTY (heading mode, default): a per-record heading line carries
agent · timestamp · path, then each matching line follows astext(orline:textwith-n, orline:col:textwith--column). Records are separated by a blank line. Toggle off with--no-heading.On pipe (flat mode, default when stdout isn’t a TTY): every match emits as
path:text(rg’s default), soagentgrep grep foo | jqor... | awksee one line per match.-nadds:line:after the path;--columnadds:col:(implies-n). Toggle the heading on with--heading.
The --vimgrep flag forces flat mode and emits path:line:col:text
with one row per match span (rather than one per match line), so a
line with two hits produces two rows — useful for vim :cfile
and other editors that consume the
file:line:col:message format.
--only-matching / -o collapses output to just the matched
substrings, one per line — the per-record heading separator is
suppressed under -o, so the stream is exactly bare matches
back-to-back (rg -o parity). -l / --files-with-matches emits
only the deduplicated paths. -c emits path:N per matching
record with the count of matching lines (or just N when exactly
one record matched), matching rg -c.
Live streaming¶
grep consumes the Event-stream engine directly — text and
NDJSON output emit each match as the engine finds it, then flush so
your terminal sees rows live. On a slow store the first matches
appear within milliseconds, not after the whole scan finishes.
The eager output modes (--json, -c, -l, -L, -v) buffer
because their output shape needs the final tally or cross-record
deduplication.
Progress¶
The stderr progress spinner (when stderr is a TTY) lets you know a
search is still running on slow stores. Silence it with
--no-progress or the equivalent --progress=never:
$ agentgrep grep --no-progress bliss
Progress always writes to stderr, so it never collides with stdout
output — agentgrep grep foo | less won’t see the spinner in the
piped buffer.
Command¶
Usage¶
usage: agentgrep grep [-h] [--agent {codex,claude,cursor,gemini,all}] [-F | -E | -w] [-i | -s | -S] [-c] [-l] [-L] [-o] [-v] [--no-dedupe] [-n | -N] [--heading | --no-heading] [-m N] [--vimgrep] [--column] [--type {prompts,history,all}] [--progress {auto,always,never}] [--no-progress] [--style {default,pretty}] [--json | --ndjson | --ui] PATTERN [PATTERN ...]
Positional Arguments¶
- patterns PATTERN¶
One or more patterns (regex by default; combined as AND)
Options¶
- --agent¶
Limit results to a specific agent; repeatable
- -c, --count¶
Print only the number of matches per (agent, store)
- -l, --files-with-matches¶
List source paths with at least one match
- -L, --files-without-match¶
List source paths with no matches
- -o, --only-matching¶
Print only the matched portion of each record
- -v, --invert-match¶
Print records that do NOT match
- --no-dedupe¶
Disable per-session dedup (raw rg-style view; default dedupes)
- -m, --max-count N¶
Stop after N matches
- --vimgrep¶
Emit one match per line as path:line:col:text
- --column¶
Show column numbers in output (implies -n)
- --type¶
Record type to search (default: prompts)
- --progress¶
Show search progress on stderr
- --no-progress¶
Silence the stderr progress spinner (alias for --progress=never)
- --style¶
Output style: default (rg-faithful) or pretty (snippet-first, amber highlights)
- -F, --fixed-strings¶
Treat patterns as literal strings, not regex
- -E, --extended-regexp¶
Treat patterns as regex (default)
- -w, --word-regexp¶
Match the pattern only as a whole word
- -i, --ignore-case¶
Force case-insensitive matching
- -s, --case-sensitive¶
Force case-sensitive matching
- -S, --smart-case¶
Smart-case (default): case-sensitive when pattern has uppercase
- -n, --line-number¶
Force line numbers in output
- -N, --no-line-number¶
Suppress line numbers
- --heading¶
Force file-grouped headings (default on TTY)
- --no-heading¶
Suppress file-grouped headings (default on pipe)
- --json¶
Emit one JSON document
- --ndjson¶
Emit one JSON object per line
- --ui¶
Launch a read-only UI
Exit codes¶
agentgrep grep follows grep’s conventions:
0— at least one matching record was found1— no matches2— error during search (invalid regex, unreadable store, …)
Use these in shell scripts the same way you’d use rg’s exit codes.
Error handling¶
Invalid regex patterns are caught at the argparse layer and surfaced with the standard argparse error shape, then exit 2:
$ agentgrep grep '['
usage: agentgrep grep [...]
agentgrep grep: error: invalid regex '[': unterminated character set at position 0
The check runs before the engine starts so a malformed pattern never
emits partial output and never escapes as a Python traceback. -F
(fixed-strings) skips the check — its patterns are literal substrings,
not regex.
Empty patterns are also rejected at parse time (git-grep parity):
$ agentgrep grep ''
usage: agentgrep grep [...]
agentgrep grep: error: pattern cannot be empty
The check applies to every term — a valid pattern followed by an
empty one (agentgrep grep foo '') still fails.
-v / --invert-match for plain text output is not yet
implemented and is refused at parse time:
$ agentgrep grep -v bliss
usage: agentgrep grep [...]
agentgrep grep: error: --invert-match for text output is not yet
implemented (see https://github.com/tony/agentgrep/issues/8); use
-c or -L
The flag is still honored under -c (returns 0 if any record
matched, 1 if none) and -L (lists sources with no matches),
since both reduce to a “did anything match?” question that the
engine’s current output supports. Tracking issue:
tony/agentgrep#8.
Files without matches¶
-L / --files-without-match lists every planned source whose
records produced no matches — the rg-style “what did I miss?”
view:
$ agentgrep grep -L bliss
~/.codex/sessions/2026/05/b.jsonl
Exit code follows rg: 0 when at least one path is printed
(the listed paths are themselves the “match” for -L), 1 when
every planned source contains a match.
Session deduplication¶
By default grep deduplicates matches by session so a single
conversation that repeats near-identical text doesn’t drown the
output. This is the one place where agentgrep grep deliberately
diverges from rg’s raw behavior — AI history stores often replay
the same message text many times across one session, which makes the
raw rg view noisier than a filesystem grep.
Pass --no-dedupe to disable the per-session dedup and get every
matching record back, exactly matching rg’s “every line is its own
match” convention:
$ agentgrep grep --no-dedupe foo
JSON output¶
Pass --json to emit an rg-shaped per-line event stream:
$ agentgrep grep --json deploy
The output is a JSON document whose events array carries one
begin event opening each matching record, one match event per
matching line within that record, an end event closing the
record, and a final summary event with the total match count.
Each match event mirrors rg’s per-line shape:
{"type":"match","data":{
"path":{"text":"~/.codex/.../sample.jsonl"},
"line_number":1,
"lines":{"text":"The bliss primitive ships with serene defaults"},
"submatches":[{"match":{"text":"bliss"},"start":4,"end":9}]}}
submatches carries byte offsets within the line so consumers can
slice the matched substring directly. Tools written against rg’s
JSON contract can consume agentgrep’s stream with the same parser.
NDJSON output¶
Pass --ndjson for one event per line:
$ agentgrep grep --ndjson foo | jq 'select(.type == "match") | .data.lines.text'
This mode is the right pick when piping into another CLI, into jq,
or into a non-MCP agent that consumes results incrementally.
Interactive UI¶
Pass --ui to open the Textual explorer pre-filled
with the grep query.
Query language¶
grep accepts the same Lucene-style field syntax search does —
mix field predicates with text patterns inline:
$ agentgrep grep agent:codex bliss
$ agentgrep grep '(agent:codex OR agent:cursor) AND deploy'
The text portion (bliss, deploy) feeds grep’s existing line-
aware matching; the field predicates (agent:, path:,
timestamp:) prune sources and filter records around it. A query
with only field predicates and no text errors out — grep needs
text to match lines against, so steer to agentgrep find for
source-level enumeration. See Query language for
the full grammar.