Features

Find code you can describe but not name

What you get

Your agent does not need to know a function's name to find it. It describes what the code does, and greppy returns the matching definitions with file and line. Under each hit is a sentence on what it is for, so the agent picks the right one before it reads a line. You can write the description in German even when the code is in English.

Before and after

The question for serde: How does the deserializer know how many elements to expect?

Without greppy

grep needs a word that appears in the code. The agent guesses phrasings from comments and reads on at the most promising spot.

$ grep -rniE 'how many|number of elements' --include='*.rs' .
./serde_core/src/de/mod.rs:238:            /// The `len` argument is the number of elements encountered. The sequence
./serde_core/src/de/mod.rs:1129:    /// knows how many values there are without looking at the serialized data.
./serde_core/src/de/mod.rs:1776:    /// Returns the number of elements remaining in the sequence, if known.
./serde_core/src/de/value.rs:1035:            // First argument is the number of elements in the data, second
…
./serde/src/private/de.rs:2761:                // argument is the number of elements expected by the Deserialize.
$ sed -n 1774,1780p serde_core/src/de/mod.rs
    }

    /// Returns the number of elements remaining in the sequence, if known.
    #[inline]
    fn size_hint(&self) -> Option<usize> {
        None
    }

With greppy

$ greppy search "wie viele Elemente der Deserializer erwarten soll"
serde/src/private/de.rs:1582  SeqDeserializer::size_hint — returns a size hint computed from the iterator bounds
serde/src/private/de.rs:1764  MapDeserializer::size_hint — returns a size hint computed from the iterator bounds
serde/src/private/de.rs:2541  SeqRefDeserializer::size_hint — returns a size hint computed from the iterator bounds
serde/src/private/de.rs:2710  MapRefDeserializer::size_hint — returns a size hint computed from the iterator bounds
serde_core/src/de/value.rs:1434  MapDeserializer::size_hint — returns a size hint computed from the value's iter
serde_core/src/de/value.rs:1103  SeqDeserializer::size_hint — returns a size hint computed from the value's iter
serde_core/src/de/mod.rs:1778  SeqAccess::size_hint — returns None unconditionally
serde_core/src/de/mod.rs:1937  MapAccess::size_hint — returns None unconditionally
without greppy with greppy
Calls 2 1
Output characters 3,535 850
Tokens 791 198

How it works

While indexing, greppy computes an embedding for every definition with Google's EmbeddingGemma. search embeds your description the same way and returns the definitions closest in meaning, eight per query. The sentences after the hits are written from the source by a Qwen3.5-0.8B that we trained by distillation. Both models run locally on your GPU; index and embeddings stay on your machine. For names and text you have search-symbol and search-pattern; plus combines text, name, meaning and graph signals into one ranked list.

The commands

Command what it does
greppy search "…" definitions that do what the description says, each with a sentence on its purpose
greppy search-symbol NAME definitions whose name contains NAME; without a hit, similar names follow
greppy search-pattern REGEX every source line the regular expression matches, with the definition it sits in
greppy plus QUERY one ranked list from text, symbol, meaning and graph signals as grep-style lines

More in the docs