Semantic code search for code symbols and docs.
unch indexes functions, methods, types, classes, interfaces, and attached docs with Tree-sitter, then lets you search them from the terminal. It is useful when you know what the code does, but not the symbol name or file path. Local indexing is the default; remote publishing is optional.
- Indexes symbols, not just lines.
unchstores top-level API objects and attached docs forGo,TypeScript,JavaScript, andPython. - Keeps the local workflow simple. Build an index once, search from the CLI, and keep everything on your machine unless you explicitly publish a remote index.
- Still works with CI. If you want a shared index, GitHub Actions publishing is available, but it is not required for the normal local flow.
Homebrew on macOS:
brew install uchebnick/tap/unchRelease installer on macOS and Linux:
curl -fsSL https://raw.githubusercontent.com/uchebnick/unch/main/install.sh | sudo sh -s -- -b /usr/local/binThis installs unch into a system PATH directory so you can run it immediately after the installer finishes.
On Apple Silicon macOS, use /opt/homebrew/bin instead of /usr/local/bin:
curl -fsSL https://raw.githubusercontent.com/uchebnick/unch/main/install.sh | sudo sh -s -- -b /opt/homebrew/binPowerShell installer on Windows:
iwr https://raw.githubusercontent.com/uchebnick/unch/main/install/install.ps1 -useb | iexThis makes unch available immediately in the current PowerShell session.
To keep it available in future PowerShell or terminal sessions, add $HOME\AppData\Local\Programs\unch\bin to your user PATH.
Source install:
go install github.com/uchebnick/unch/cmd/unch@latestThis install path requires a cgo-capable Go toolchain. It is smoke-tested in CI in the official Debian-based Go container image. To pin a specific release, use @<tag>.
If you want to build from the current checkout:
go build -o unch ./cmd/unchPublished release archives:
- macOS:
arm64,x86_64 - Linux:
arm64,x86_64 - Windows:
arm64,x86_64(unch.exe)
On those targets, the installers use published release archives by default, so Go is not required. install.sh and install/install.ps1 only fall back to go install when no matching archive is available. install.sh is smoke-tested in CI on Ubuntu, Debian, Arch, and NixOS-like environments, including the default no--b path selection flow; the PowerShell installer is smoke-tested on Windows arm64 and x86_64.
Verify the installed binary:
unch --version
unch --helpSee Compatibility for the support matrix and upgrade rules, and Benchmarks for the checked-in smoke, ci, and default suites.
Model selection accepts either a known model id or a direct .gguf path:
unch index --model embeddinggemma
unch index --model qwen3
unch search --model qwen3 "create a new router"OpenRouter is also supported as an embedding provider:
unch auth openrouter --token sk-or-...
unch index --provider openrouter --model openai/text-embedding-3-small
unch search --provider openrouter --model openai/text-embedding-3-small "create a new router"By default unch auth openrouter writes ~/.config/unch/tokens.json, so you do not need to keep the token in your shell environment. Use --local if you want to store it in .semsearch/tokens.json for one repository.
cd path/to/repo
unch index --root .
unch search "create a new router"
unch search --details "get path variables from a request"OpenRouter flow:
cd path/to/repo
unch auth openrouter --token sk-or-...
unch index --root . --provider openrouter --model openai/text-embedding-3-small
unch search --provider openrouter --model openai/text-embedding-3-small "create a new router"Real output from indexing gorilla/mux:
$ unch index --root .
Loaded model dim=768
Indexed 278 symbols in 16 files
$ unch search "create a new router"
1. mux.go:32 0.7747
2. mux.go:314 0.8135
$ unch search --details "get path variables from a request"
1. mux.go:466 0.7991
kind: function
name: Vars
signature: func Vars(r *http.Request) map[string]string
docs: Vars returns the route variables for the current request, if any.
The first local llama.cpp run may download the default embedding model, fetch local yzma runtime libraries, and create ./.semsearch/.
Each provider and model pair keeps its own active index snapshot. Rebuilding openrouter/openai/text-embedding-3-small does not replace the active llama.cpp/embeddinggemma snapshot until the new run finishes successfully.
- Tree-sitter indexing for
Go,TypeScript,JavaScript, andPython - Top-level API objects and attached documentation
- Local indexing and search first, optional remote publishing through GitHub Actions
auto,semantic, andlexicalsearch modes- Legacy
--comment-prefixand--context-prefixonly forindexfallback on unsupported files or parser failures
Build or refresh the local index for a repository.
unch index --root .Useful flags:
--excludeto skip generated, vendor, or irrelevant paths--providerto switch between localllama.cppembeddings and remoteopenrouter--modelto useembeddinggemma,qwen3, or a custom.ggufpath--ctx-sizeto override the selected model context size;0uses the model default--libto use an existingyzmaruntime directory--state-dirto keep index state in a custom.semsearchdirectory
Query the current index.
unch search "sqlite schema"
unch search --mode lexical "Run"Useful flags:
--modeforauto,semantic, orlexical--limitto control result count--max-distanceto narrow semantic matches--providerto select the embedding provider that matches the indexed snapshot--modelto search withembeddinggemma,qwen3, or a custom.ggufpath--ctx-sizeto override the selected model context size;0uses the model default--state-dirto search against a custom.semsearchdirectory--detailsto print symbol metadata, signature, docs, and body context for each match
Remote indexing is optional. Use it when you want GitHub Actions to publish an index for a repository. The generated workflow file is .github/workflows/unch-index.yml.
Create the workflow scaffold:
unch create ciBind the local repository state to a GitHub repo or workflow URL:
unch bind ci https://github.com/uchebnick/unchAfter the workflow is committed and runs successfully once, unch search can refresh the published index automatically when a newer remote version exists. Use unch remote sync when you want to force a refresh before searching.
The cross-platform benchmark matrix stays separate from ordinary push CI. It runs on release-tag pushes and manual workflow_dispatch, uses the checked-in ci suite with a lighter 1 cold / 1 warm / 1 search repeat profile, and publishes per-platform summaries for Linux, macOS, and Windows.
- See CONTRIBUTING.md for the local dev loop.
- Open a bug report if search quality or indexing behavior looks wrong.
- Open a feature request if you want new language support, ranking behavior, or workflow features.
