Your code is a database. Why query it with full-text search?
Agents using grep have to regex their way to understanding — pattern-matching raw text, parsing noise, running multiple commands to answer one question. smartgrep parses source files via tree-sitter, extracts symbols into a structured index, and lets agents query the code the same way you'd query a database.
The queries are designed to be readable by humans and generatable by LLMs, unlike grep regexes.
# grep — terse, brittle, requires regex expertise to read
grep -rn "^pub\s\+fn\|pub async fn" src/commands/ | grep -v "//\|mod.rs"
# smartgrep — reads like a sentence
smartgrep query "functions where visibility = public and file contains 'commands/'"When Claude uses smartgrep, you can see exactly what it's looking for at a glance.
macOS, Linux, FreeBSD, Android (Termux):
curl -fsSL https://raw.githubusercontent.com/rohitkg98/smartgrep/main/install.sh | shWindows (PowerShell):
irm https://raw.githubusercontent.com/rohitkg98/smartgrep/main/install.ps1 | iexBoth install a prebuilt binary for your platform from the latest release. No Rust required.
| OS | Architectures | Release asset |
|---|---|---|
| macOS | Apple Silicon (arm64), Intel (x86_64) | smartgrep-{aarch64,x86_64}-apple-darwin.tar.gz |
| Linux | x86_64, arm64, armv7, armv6 (Raspberry Pi Zero/1), i686, riscv64, ppc64le, loongarch64 | smartgrep-<arch>-unknown-linux-musl*.tar.gz (static, any distro) |
| Linux | s390x | smartgrep-s390x-unknown-linux-gnu.tar.gz (glibc 2.17+) |
| Windows | x86_64, arm64 | smartgrep-{x86_64,aarch64}-pc-windows-msvc.zip |
| FreeBSD | x86_64 | smartgrep-x86_64-unknown-freebsd.tar.gz |
| Android (Termux) | arm64, armv7 | uses the static Linux binaries; installs into $PREFIX/bin |
Where it installs: /usr/local/bin if writable, else ~/.local/bin (Termux: $PREFIX/bin; Windows: %LOCALAPPDATA%\Programs\smartgrep, added to your user PATH). Options, as environment variables for either script:
curl -fsSL https://raw.githubusercontent.com/rohitkg98/smartgrep/main/install.sh | SMARTGREP_VERSION=0.4.0 sh # pin a version
curl -fsSL https://raw.githubusercontent.com/rohitkg98/smartgrep/main/install.sh | SMARTGREP_INSTALL_DIR=~/bin sh # install elsewhere$env:SMARTGREP_VERSION = "0.4.0"; irm https://raw.githubusercontent.com/rohitkg98/smartgrep/main/install.ps1 | iexChecksums: every release has a SHA256SUMS file. The install scripts verify the download against it (when sha256sum, shasum, sha256 or openssl is available; always on Windows). To check a manual download: sha256sum -c SHA256SUMS --ignore-missing.
Other platforms: no prebuilt binary? Build from source (Rust 1.70+):
cargo install --git https://github.com/rohitkg98/smartgrepsmartgrep updateFetches and runs the install script to replace the binary in-place.
git clone git@github.com:rohitkg98/smartgrep.git
cd smartgrep
cargo install --path .Requires Rust 1.70+.
curl -fsSL https://raw.githubusercontent.com/rohitkg98/smartgrep/main/install.sh | sh
cd your-project
smartgrep initsmartgrep init makes the project agent-ready in one non-interactive step: it detects languages, builds the index, adds a short smartgrep section (between <!-- smartgrep:start --> / <!-- smartgrep:end --> markers) to CLAUDE.md and/or AGENTS.md with examples that use your project's real symbols, installs the repo-scoped Claude Code skill, and adds .smartgrep/ to .gitignore. Re-running it refreshes the section in place; nothing outside the markers is touched.
smartgrep init --dry-run # show what would change, write nothing
smartgrep init --agents-md # also create/update AGENTS.md
smartgrep init --no-skill # skip .claude/skills/smartgrep/SKILL.mdsmartgrep init (above) covers this for a single repo. To install only the skill:
Install as a Claude Code skill so Claude automatically uses smartgrep for structural questions — no prompting needed:
smartgrep install-skill --global # all projects (~/.claude/skills/)
smartgrep install-skill # this repo only (.claude/skills/)Or add to your project's CLAUDE.md manually:
## Code Navigation
Use `smartgrep` for structural code queries instead of grep/find.
- `smartgrep query "<dsl>"` for composable one-shot structural questions
- `smartgrep context <file>` for a structural overview of a file
- `smartgrep query "symbol <Name> | with deps, refs"` to understand a symbol's role
- Use batch queries (semicolon-separated) to answer multi-part questions in one callEvery smartgrep call is logged. Run this to see Claude's recent queries:
smartgrep logExample output:
ts command args results ms
2026-03-14 10:42:11 query classes where attributes contains '@RestController' 4 12
2026-03-14 10:42:18 query methods where parent = UserController | with signature 7 9
2026-03-14 10:42:31 query symbol OrderService | with deps, refs 1 8
2026-03-14 10:43:02 query functions where file contains 'commands/' | with params 6 11
Each line is one tool call Claude made. Compare these to what you'd have had to decipher with grep:
# What Claude asked for (smartgrep) # What you'd have with grep
classes where attributes contains '@RestController' grep -rn "@RestController" src/ | grep "^class\|^public class"
methods where parent = UserController grep -rn "UserController" src/ | grep "^\s\+public\|void\|String"
symbol OrderService | with deps, refs grep -rn "OrderService" src/ | grep "import\|extends\|new OrderService"The smartgrep query column tells you exactly what Claude was looking for, in plain language.
The query command is the main feature. Queries compose a source, optional filters, and pipeline stages:
source [where conditions] [| stage] [| stage] ...
Side by side with grep, for the same questions:
| What you want to know | grep | smartgrep |
|---|---|---|
| All public functions | grep -rn "^pub fn|pub async fn" src/ |
functions where visibility = public |
| Spring REST controllers | grep -rn "@RestController" src/ | grep "class " |
classes where attributes contains '@RestController' |
| Methods on UserService | grep -rn "UserService" src/ | grep "def |public " |
methods where parent = UserService |
| Structs with 5+ fields | (requires reading each file) | structs | with fields | where field_count > 5 |
| What does Config depend on | grep -rn "Config" src/ | grep "use |import |new " |
symbol Config | with deps |
The grep column requires knowing the language's syntax, writing a correct regex, and filtering noise. The smartgrep column reads like a question.
symbols / structs / classes / interfaces / records / functions / methods
traits / enums / impls / consts / types / modules
symbol <name> -- single symbol lookup
deps [<name>] -- dependencies (all, or for one symbol)
refs [<name>] -- references (all, or to one symbol)
<source> in '<path>' -- restrict to files matching a path substring
where <field> <op> <value> [and|or ...]
| Field | Applies to |
|---|---|
name, file, visibility, kind, parent |
symbols |
attributes |
symbols with annotations/decorators |
field_count, param_count |
after with fields / with params |
from, to, dep_kind |
dependency rows |
| Operator | Meaning |
|---|---|
= / is |
equals (case-insensitive) |
!= |
not equals |
contains |
substring match |
starts_with / ends_with |
prefix / suffix |
not contains / not starts_with / not ends_with |
negated match (true when the field is absent) |
> < >= <= |
numeric comparison |
Stages follow | and apply left to right:
with fields— add struct/class/enum field list and countwith params— add function/method parameter list and countwith deps— add outbound dependencieswith refs— add inbound referenceswith signature— add full type signatureshow col1, col2— select specific output columnswhere field_count > 5— filter after enrichmentsort field asc|desc— sort resultslimit N— cap output
Separate queries with ; to run multiple in one call:
smartgrep query "structs | with fields; enums | with fields"
smartgrep query "classes where file contains 'service/'; methods where parent = UserController"Results print under # Query 1, # Query 2 headers.
Long file paths in text output are automatically shortened. src/main/java/com/example/catalog/controller/ProductController.java becomes [P]controller/ProductController.java, with a [paths] legend at the top. JSON output always keeps full paths.
- Rust — full support via tree-sitter-rust
- Java — full support via tree-sitter-java
- Go — full support via tree-sitter-go
- TypeScript — full support via tree-sitter-typescript (
.ts,.tsx) - Python — full support via tree-sitter-python (
.py,.pyi)
Adding a language means writing one parser and registering it in src/lang.rs. The IR layer and query engine are language-agnostic.
Parser (tree-sitter) --> IR --> Index Builder --> Index --> Commands / Query Engine
- Parser (
src/parser/) — language-specific, produces the IR - IR (
src/ir/types.rs) — language-agnostic symbol and dependency maps - Index (
src/index/types.rs) — queryable, with lookup tables for fast symbol resolution
Auto-indexing: queries trigger indexing implicitly. The index rebuilds when source files change.
See AGENTS_README.md for the agent-targeted reference.
Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in smartgrep by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.