Semantic Search
Search your codebase in natural language with grepai search, filter by path, and get JSON or TOON output for AI agents.
grepai search finds code by meaning instead of exact text. You describe what the code does, and grepai returns the chunks whose embeddings are closest to your query.
Quick Start
You need an index first. Build it with grepai watch (keeps it up to date) or grepai index (one-shot), then search:
# Build or update the index once
grepai index
# Search in natural language
grepai search "user authentication flow"
# Return 5 results instead of the default 10
grepai search "error handling" --limit 5
# Only search under a directory (relative to the project root)
grepai search "input validation" --path src/middleware/
# Structured output for scripts and AI agents
grepai search "database queries" --json --compact
Features
- Natural language queries: describe what the code does.
- Path filter: restrict results to a directory with
--path. - Ranking controls: structural boost, optional hybrid keyword matching, and one result per file.
- Structured output: JSON or TOON, with a
--compactmode that drops code content. - Workspaces: search several projects at once with
--workspace.
Flags
| Flag | Short | Default | Description |
|---|---|---|---|
--limit | -n | 10 | Maximum number of results |
--path | Only return files whose path starts with this prefix | ||
--json | -j | false | Output JSON |
--toon | -t | false | Output TOON (cannot be combined with --json) |
--compact | -c | false | Omit the content field (requires --json or --toon) |
--workspace | Search a workspace instead of the current project | ||
--project | Limit a workspace search to one or more projects (repeatable, requires --workspace) |
See the grepai search reference for the generated flag list.
Filtering by Path
--path keeps only results whose file path starts with the given prefix:
- A relative prefix is matched against paths relative to the project root, not your current directory.
--path src/api/matchessrc/api/handler.go. - An absolute path is converted to a project-relative prefix. It must be inside the project.
- Matching is a plain prefix test, so
--path src/apialso matchessrc/api_old/. Add a trailing/to match a directory only.
In workspace mode, an absolute path also selects the matching project.
How It Works
- Query embedding: grepai converts your query to a vector with the embedder configured in
.grepai/config.yaml. - Similarity search: the store returns the closest chunks. It fetches more candidates than
--limit(2x, or 4x whensearch.dedupis enabled) so the next steps have room to reorder. - Hybrid fusion (optional): if
search.hybrid.enabledis true, vector results are merged with keyword matches. See Hybrid Search. - Boost: scores are multiplied by path-based factors (tests and docs down, some source directories up). See Search Boost.
- Deduplication: if
search.dedup.enabledis true, only the best chunk per file is kept. - Limit: the top
--limitresults are returned.
Writing Effective Queries
| Good Query | Bad Query | Why |
|---|---|---|
| ”user login validation" | "login” | More context improves matches |
| ”how errors are handled in API" | "error” | Describes intent, not keyword |
| ”where users are saved to database" | "save user” | Natural language works best |
| ”JWT token authentication" | "token” | Specific terminology |
Query Tips
- Use English: most embedding models work best with English queries.
- Describe intent: “handles user login” rather than “func Login”.
- Be specific: “JWT token validation” is better than “token”.
- Looking for an exact identifier? Enable hybrid search or use a text search tool such as
grep.
Understanding Results
The default output looks like this:
Found 2 results for: "user authentication flow"
─── Result 1 (score: 0.8125) ───
File: middleware/auth.go:15-45
15 │ func AuthMiddleware() gin.HandlerFunc {
16 │ return func(c *gin.Context) {
17 │ token := c.GetHeader("Authorization")
...
│ ... (16 more lines)
─── Result 2 (score: 0.7500) ───
File: handlers/login.go:10-32
...
- score: higher is better. Without hybrid search it is the vector similarity multiplied by the boost factors, so a boosted result can exceed 1.0. With hybrid search it is an RRF score (small values, around 0.03 at most before boosting).
- File: path relative to the project root, with the chunk’s start and end lines.
- Content: up to 15 lines of the chunk, then a count of the remaining lines.
- If RPG is enabled,
Feature:andSymbol:lines may appear underFile:.
If nothing matches, grepai prints No results found.
Structured Output
For AI agents and scripts, use --json or --toon. Add --compact to drop the content field and return locations only.
grepai search "authentication" --json # JSON with content
grepai search "authentication" --json --compact # JSON without content
grepai search "authentication" --toon # TOON with content
grepai search "authentication" --toon --compact # TOON without content
JSON Format
--json prints an indented array:
[
{
"file_path": "middleware/auth.go",
"start_line": 15,
"end_line": 45,
"score": 0.8125,
"content": "File: middleware/auth.go\n\nfunc AuthMiddleware() gin.HandlerFunc {\n..."
}
]
contentis the indexed chunk text, which starts with aFile: <path>header.--compactremovescontent.feature_pathandsymbol_nameare added when RPG provides them.- On error, the output is
{"error": "..."}instead of an array.
TOON Format
TOON (Token-Oriented Object Notation) is a tabular format that repeats field names once per array instead of once per result, which makes it shorter than JSON. Example with --toon --compact:
[2]{end_line,file_path,score,start_line}:
70,recovery.go,0.63798773,1
78,recovery_test.go,0.29077357,1
The header lists the fields in alphabetical order, with the same names as the JSON output. feature_path and symbol_name appear only when RPG provides them, as in JSON.
When to use TOON:
- AI agents with tight token budgets
- High-volume automated searches
When to use JSON:
- Integration with existing JSON tooling (for example
jq) - Debugging and inspection
Search Enhancements
Three settings under search: in .grepai/config.yaml change ranking. A new grepai init writes them with these defaults:
search:
boost:
enabled: true # path-based score multipliers
hybrid:
enabled: false # vector + keyword fusion
k: 60
dedup:
enabled: true # keep only the best chunk per file
Note: these values come from the config file. If a key is missing (for example in a config created by an older version), the feature is off. Add the key to turn it on.
Structural Boosting (enabled by default)
Multiplies scores by factors based on the file path:
- Penalized: tests, mocks, fixtures, generated files, Markdown and docs
- Boosted: paths containing
/src/,/lib/or/app/
See Search Boost for the rules and how they match.
Hybrid Search (disabled by default)
Merges vector results with keyword matches using Reciprocal Rank Fusion (RRF). Useful when queries contain exact identifiers.
See Hybrid Search for configuration.
Deduplication (enabled by default)
With search.dedup.enabled: true, each file appears at most once in the results (its highest-scoring chunk). Set it to false to see several chunks from the same file.
Workspace searches
grepai search --workspace does not read the project’s search: settings. It always uses the default boost rules, with hybrid search and deduplication off.
Troubleshooting
| Problem | Solution |
|---|---|
no grepai project found | Run grepai init in the project first |
| No results | Build the index with grepai index or grepai watch, then check it with grepai status |
No results with --path | The prefix is relative to the project root, not your current directory |
| Poor relevance | Use a more descriptive query, or check the embedder model |
| Missing files | Check ignore in .grepai/config.yaml, .gitignore and .grepaiignore |
| Slow search on a large index | The GOB backend scans every vector in memory. Consider PostgreSQL or Qdrant |
--compact flag requires --json or --toon flag | Add --json or --toon |
Use Cases
Finding Implementation
# Where is authentication handled?
grepai search "user authentication logic"
# How are errors processed?
grepai search "error handling middleware"
Understanding Codebase
# Find database interactions
grepai search "database connection and queries"
# Locate API endpoints, only under internal/
grepai search "REST API route handlers" --path internal/
AI Agent Integration
Give an agent file locations, then let it read the files it needs:
grepai search "payment processing" --json --compact --limit 5
grepai search "payment processing" --toon --compact --limit 5
Commands Reference
grepai search: full CLI referencegrepai index: build or update the index oncegrepai watch: keep the index up to date