Documentation

greppy

greppy is a tool for navigating and changing code, built for coding agents. It also accepts ordinary grep invocations: they run through the real system grep and forward stdout, stderr and the exit code byte for byte. Everything else is a structured command over a precomputed symbol graph and a semantic index that runs on your machine.

The commands answer the questions an agent otherwise spends several rounds of searching and reading on: Who calls this function? What breaks if I change it? Where is the code that does X? Deterministic evidence from source and graph is the authority. The locally generated summaries sit next to the exact signature as navigation hints; you decide on the returned code.

In this demo, the same coding agent (MiniMax-M3, driven by Pi) answers a who-calls question on a real repository: on the left with grep, on the right with greppy.

Split screen: the same coding agent answers a who-calls question, left with grep, right with greppy.

The questions greppy answers

All examples in these docs run against serde version 1.0.229.

You want to know Command
Who calls this function? greppy who-calls visit_content_map
What breaks if I change this? greppy impact get_renames
Where is the code that does X? greppy search "check whether a field should be skipped when serializing"
What does this function do? greppy brief visit_content_map
How do I change exactly this code? greppy read visit_content_map --handle, then an edit command
Did the build pass, and if not, why? greppy bash-smart -- cargo test

Every answer is a compact list: the location as file:line, the resolved name and, after an em dash, a generated hint. who-calls gives the line of the call.

$ greppy who-calls visit_content_map
serde/src/private/de.rs:1152  ContentDeserializer::deserialize_any
serde/src/private/de.rs:1399  ContentDeserializer::deserialize_map
serde/src/private/de.rs:1415  ContentDeserializer::deserialize_struct

impact returns the whole tree of transitive callers in one call. An indented line calls the line above it, and (above) points to an entry that is already in the tree. Here the path leads from a helper function up to the entry points of #[derive(Serialize)] and #[derive(Deserialize)].

$ greppy impact get_renames
serde_derive/src/internals/attr.rs:237  Container::from_ast — builds rename rules from a DeriveInput's attributes
  serde_derive/src/internals/ast.rs:62  Container::from_ast — converts a syn::DeriveInput into a Container, handling enums and structs
    serde_derive/src/de.rs:25  expand_derive_deserialize — expands a syn::DeriveInput into a TokenStream
      serde_derive/src/lib.rs:122  derive_deserialize — derives deserialize code from a TokenStream
    serde_derive/src/ser.rs:13  expand_derive_serialize — expands a syn::DeriveInput into a TokenStream of serialize methods
      serde_derive/src/lib.rs:114  derive_serialize — derives serialization from a TokenStream
serde_derive/src/internals/attr.rs:748  Variant::from_ast — parses rename and alias attributes from a syn::Variant
  serde_derive/src/internals/ast.rs:133  enum_from_ast — converts a list of syn::Variant entries into a flat list
    serde_derive/src/internals/ast.rs:62  Container::from_ast  (above)

search finds code by its meaning, even when you don't know its name.

$ greppy search "check whether a field should be skipped when serializing"
serde_derive/src/internals/attr.rs:1286  skip_serializing — returns the skip_serializing field value as a boolean
serde_derive/src/ser.rs:160  needs_serialize_bound — decides whether a field should be serialized
serde_derive/src/internals/check.rs:455  allow_transparent — decides whether a field is allowed to be transparent
serde_core/src/ser/mod.rs:1923  SerializeStruct::skip_field — acts as a no-op skip that returns Ok without doing anything
serde_derive/src/internals/check.rs:226  check_variant_skip_attrs — reports errors when variants lack required serialization attributes
serde_derive/src/internals/attr.rs:1290  skip_deserializing — returns the skip_deserializing flag
serde_core/src/ser/mod.rs:1993  SerializeStructVariant::skip_field — acts as a no-op skip that returns Ok without doing anything
serde_derive/src/internals/attr.rs:956  Variant::skip_serializing — returns the skip_serializing field value as a boolean

Ordinary grep keeps running through the same binary, with grep output and grep exit codes.

$ greppy -c deny_unknown_fields serde_derive/src/internals/attr.rs
7
$ cmp <(greppy -rn deny_unknown_fields serde_derive/src) <(grep -rn deny_unknown_fields serde_derive/src) && echo identical
identical
$ greppy -rn TODO serde/src; echo "exit $?"
exit 1

Get started

New to greppy? The Quickstart walks you through installation, the first query and connecting your agent.

  • How greppy works: the graph, the embedded models, the index lifecycle and the freshness check.
  • Agent setup: one prompt file, no MCP server.

Use greppy

Reference