simgrep is a command-line tool for semantic search in local files. It finds text snippets based on meaning, not just keywords — useful when you know what you're looking for but not the exact words used.
Unlike grep or ripgrep, simgrep embeds your query and your files into a shared vector space and retrieves the most semantically similar chunks. A search for "database connection errors" will surface code that says pool exhausted or timeout connecting to postgres — things a regex would miss.
Requirements: Python 3.12+
# recommended: use uv to create a virtual environment
uv venv
source .venv/bin/activate
# Install the package
uv pip install .
For development (editable install + dev dependencies):
make install
If you run simgrep from source without installing, you can invoke it from any directory via:
uv run --project /path/to/simgrep python -m simgrep.main --help
simgrep has two modes:
Retrieval is dense-only: sentence-transformer embeddings, USearch vectors, DuckDB metadata, and lexical term tables for hybrid ranking.
Initialize from repository root (creates .simgrep/project.toml):
simgrep init
No setup needed. simgrep builds a temporary in-memory index on the fly, searches it, and discards it.
Default interactive behavior:
lexical_top=50, lexical_weight=0.25).--why flag (hidden by default).--diversity window (use none|file|package).Search a directory:
simgrep search "database connection errors" ./src
Filter by file type:
simgrep search "async function examples" ./my_project --pattern "*.py"
# Multiple patterns
simgrep search "api documentation" ./docs --pattern "*.md" --pattern "*.rst"
Change output format — list only file paths instead of showing matching text:
simgrep search "user authentication flow" ./docs --format paths
Limit results — top 3 most relevant:
simgrep search "database connection pool" ./configs --top 3
Force pure semantic ranking (disable hybrid defaults):
simgrep search "database connection pool" ./configs --no-hybrid
Force one-off ephemeral mode even if an indexed project exists for the path:
simgrep search "database connection pool" ./configs --ephemeral
Use persistent projects when you search the same directory repeatedly — a codebase, a notes folder, etc.
1. Initialize a project from the directory you want to search:
cd /path/to/my-codebase
simgrep init
This creates .simgrep/project.toml and marks the current directory as an indexed path.
2. Add more paths (optional):
simgrep project add-path ./backend
simgrep project add-path ./docs
3. Build the index:
simgrep index
The first run downloads the embedding model and indexes all files — this takes a moment. Subsequent runs are incremental.
4. Search:
simgrep search "user session management"
simgrep detects the active project from your current directory.
When a search path is provided, simgrep prefers persistent search if that path is covered by the active indexed project. Use --ephemeral to force one-off mode or --persistent to fail fast when no persistent index is usable.
5. Update after file changes:
simgrep index
Only new and modified files are processed.
Speed up indexing with concurrent file processing:
simgrep index --workers 4
Default worker count is conservative; increase it for large repositories.
simgrep status
Run a persistent interactive session that reuses loaded model/index:
simgrep repl
simgrep reads plain-text formats directly: .txt, .md, .rst, .py, .js, .ts, .tsx, .jsx, .java, .go, .rs, .c, .cpp, .h, .cs, .rb, .php, .swift, .kt, .scala, .sh, .bash, .zsh, .toml, .yaml, .yml, .json, .xml, .html, .css, .sql, Dockerfile.
Other text-like formats (e.g. .org, .tex) are attempted via the unstructured fallback. Binary formats (.pdf, .zip, images, databases) are skipped.
Default model: ibm-granite/granite-embedding-30m-english.
Pre-download models before going offline:
make download-models
"Persistent index not found" — run simgrep index from within the project directory before searching.
Slow first run — the embedding model is downloaded from Hugging Face Hub on first use (~hundreds of MB). Use make download-models to pre-cache it.
No results returned — your --pattern may not match any files. Try simgrep search "..." ./path --pattern "*.py" with an explicit pattern, or omit --pattern to search all files.
139 commits
Python
98.7%
Makefile
1.3%
simgrep is a command-line tool for semantic search in local files. It finds text snippets based on meaning, not just keywords — useful when you know what you're looking for but not the exact words used.
Unlike grep or ripgrep, simgrep embeds your query and your files into a shared vector space and retrieves the most semantically similar chunks. A search for "database connection errors" will surface code that says pool exhausted or timeout connecting to postgres — things a regex would miss.
Requirements: Python 3.12+
# recommended: use uv to create a virtual environment
uv venv
source .venv/bin/activate
# Install the package
uv pip install .
For development (editable install + dev dependencies):
make install
If you run simgrep from source without installing, you can invoke it from any directory via:
uv run --project /path/to/simgrep python -m simgrep.main --help
simgrep has two modes:
Retrieval is dense-only: sentence-transformer embeddings, USearch vectors, DuckDB metadata, and lexical term tables for hybrid ranking.
Initialize from repository root (creates .simgrep/project.toml):
simgrep init
No setup needed. simgrep builds a temporary in-memory index on the fly, searches it, and discards it.
Default interactive behavior:
lexical_top=50, lexical_weight=0.25).--why flag (hidden by default).--diversity window (use none|file|package).Search a directory:
simgrep search "database connection errors" ./src
Filter by file type:
simgrep search "async function examples" ./my_project --pattern "*.py"
# Multiple patterns
simgrep search "api documentation" ./docs --pattern "*.md" --pattern "*.rst"
Change output format — list only file paths instead of showing matching text:
simgrep search "user authentication flow" ./docs --format paths
Limit results — top 3 most relevant:
simgrep search "database connection pool" ./configs --top 3
Force pure semantic ranking (disable hybrid defaults):
simgrep search "database connection pool" ./configs --no-hybrid
Force one-off ephemeral mode even if an indexed project exists for the path:
simgrep search "database connection pool" ./configs --ephemeral
Use persistent projects when you search the same directory repeatedly — a codebase, a notes folder, etc.
1. Initialize a project from the directory you want to search:
cd /path/to/my-codebase
simgrep init
This creates .simgrep/project.toml and marks the current directory as an indexed path.
2. Add more paths (optional):
simgrep project add-path ./backend
simgrep project add-path ./docs
3. Build the index:
simgrep index
The first run downloads the embedding model and indexes all files — this takes a moment. Subsequent runs are incremental.
4. Search:
simgrep search "user session management"
simgrep detects the active project from your current directory.
When a search path is provided, simgrep prefers persistent search if that path is covered by the active indexed project. Use --ephemeral to force one-off mode or --persistent to fail fast when no persistent index is usable.
5. Update after file changes:
simgrep index
Only new and modified files are processed.
Speed up indexing with concurrent file processing:
simgrep index --workers 4
Default worker count is conservative; increase it for large repositories.
simgrep status
Run a persistent interactive session that reuses loaded model/index:
simgrep repl
simgrep reads plain-text formats directly: .txt, .md, .rst, .py, .js, .ts, .tsx, .jsx, .java, .go, .rs, .c, .cpp, .h, .cs, .rb, .php, .swift, .kt, .scala, .sh, .bash, .zsh, .toml, .yaml, .yml, .json, .xml, .html, .css, .sql, Dockerfile.
Other text-like formats (e.g. .org, .tex) are attempted via the unstructured fallback. Binary formats (.pdf, .zip, images, databases) are skipped.
Default model: ibm-granite/granite-embedding-30m-english.
Pre-download models before going offline:
make download-models
"Persistent index not found" — run simgrep index from within the project directory before searching.
Slow first run — the embedding model is downloaded from Hugging Face Hub on first use (~hundreds of MB). Use make download-models to pre-cache it.
No results returned — your --pattern may not match any files. Try simgrep search "..." ./path --pattern "*.py" with an explicit pattern, or omit --pattern to search all files.
139 commits
Python
98.7%
Makefile
1.3%