Offline Semantic Code Search for Local Repositories
Aperture is a local-first code search engine for developers who need to search private source code by exact text and by intent. It combines repository walking, ignore rules, AST-aware chunks, BM25 lexical search, deterministic embedding plumbing, HNSW vector search, hybrid rank fusion, and CLI/TUI output.
No source code needs to leave your machine during indexing or search.
Index once (offline): walk the repo, chunk source, build a BM25 lexical index, embeddings → HNSW vector index, and a chunk manifest — all under .aperture/.
Search (each query): the CLI or TUI runs a query against both indexes, fuses lexical + semantic hits with RRF, hydrates path/symbol/preview from the manifest, and shows ranked results. Nothing leaves your machine.
flowchart TB
subgraph index["① Index — offline"]
direction LR
repo["Source repository"] --> walk["Walk + ignore rules"]
walk --> chunk["AST / plaintext chunks"]
chunk --> lex["BM25 lexical index"]
chunk --> embed["Embedding provider"]
embed --> vec["HNSW vector index"]
chunk --> meta["Chunk manifest"]
lex --> store[(".aperture/")]
vec --> store
meta --> store
end
subgraph search["② Search — each query"]
direction LR
dev["Developer"] --> cli["CLI / TUI"]
cli --> q["Query engine"]
q --> bm25["BM25 candidates"]
q --> hnsw["HNSW candidates"]
bm25 --> rrf["RRF fusion"]
hnsw --> rrf
rrf --> hyd["Hydrate results (manifest + preview)"]
hyd --> cli
end
store --> q
Step list (same pipeline)
Index: repository -> walk + ignore -> AST/plaintext chunks
-> BM25 lexical index
-> embedding provider -> HNSW vector index
-> chunk manifest
(persisted under .aperture/)
Search: CLI/TUI -> query engine -> BM25 + HNSW retrieval
-> reciprocal rank fusion (RRF)
-> hydrate (manifest + previews) -> results
- README (this file)
- Architecture · See it in use · Install · Quickstart
- Getting started · FAQ · Documentation index
- Current limitations · Roadmap · CHANGELOG
- Commands · Contributing · License
Aperture indexes a repository into searchable code chunks and returns ranked results with useful metadata:
- Walk the repository while respecting
.gitignore,.ignore,.apertureignore, size limits, and configured globs. - Parse supported languages with tree-sitter and extract meaningful chunks such as functions, methods, classes, structs, and interfaces.
- Fall back to text chunks when language parsing is unavailable or unnecessary.
- Build a BM25-style lexical index for exact terms, identifiers, paths, and strings.
- Build a semantic vector index through the
EmbeddingProviderabstraction. - Fuse lexical and semantic candidates with Reciprocal Rank Fusion (RRF).
- Hydrate results with path, symbol, language, line range, match type, and preview.
The default embedding provider is deterministic mock embeddings (pipeline-complete, not ML-quality semantic search). Real local GGUF support is planned — see docs/embeddings.md and docs/roadmap.md.
Offline search on mini-redis (Tokio’s tutorial Redis clone): initialize a local index, search by intent or exact symbol, and browse results in the TUI. Nothing leaves your machine.
git clone --depth 1 https://github.com/tokio-rs/mini-redis.git /tmp/mini-redis-demo
aperture init /tmp/mini-redis-demo
aperture doctor /tmp/mini-redis-demo --offline-check
aperture index /tmp/mini-redis-demo
aperture status /tmp/mini-redis-demoNatural-language query; top hits land in shutdown and server code even when the query does not match symbol names. Results print as an aligned table (#, score, match type, location) — not tab-separated columns.
aperture search "graceful shutdown signal handling" --repo /tmp/mini-redis-demo
# Compact table only (good for screenshots / narrow terminals):
aperture search "graceful shutdown signal handling" --repo /tmp/mini-redis-demo --no-preview --limit 10aperture search Shutdown --repo /tmp/mini-redis-demo --lexicalHuman-readable CLI output uses tables (above). Use --json for scripts, agents, and CI — complete document, not head on partial JSON.
aperture search "connection semaphore limit" --repo /tmp/mini-redis-demo --json --limit 2aperture tui --repo /tmp/mini-redis-demov0.1.0: mock embedder for hybrid/semantic ranks; lexical search is solid.
| Area | Status |
|---|---|
| Semantic quality | Mock embedder by default — use lexical/hybrid knowing the vector leg is not “real AI” yet |
| Languages | AST chunking for Rust, TS/TSX, Python, Go, Java; others use plaintext chunks |
| Scope | Single-repo index; CLI + TUI (no web UI) |
| Eval gate | No labeled Hit@k/MRR regression in CI yet |
Details: docs/how-aperture-works.md · docs/gaps-and-contributions.md.
Install once; use aperture from any directory against any local repository.
Recommended: download a prebuilt archive from GitHub Releases, verify SHA256SUMS, and put aperture on your PATH. No Rust toolchain required.
# Example (Linux x86_64) — adjust VERSION and PLATFORM; see docs/installation.md
VERSION=0.1.0
PLATFORM=linux-amd64
curl -LO "https://github.com/onahFran6/aperture/releases/download/v${VERSION}/aperture-${VERSION}-${PLATFORM}.tar.gz"
curl -LO "https://github.com/onahFran6/aperture/releases/download/v${VERSION}/SHA256SUMS"
sha256sum -c SHA256SUMS
tar -xzf "aperture-${VERSION}-${PLATFORM}.tar.gz"
install -m 755 "aperture-${VERSION}-${PLATFORM}/aperture" ~/.local/bin/aperture
aperture --helpAlternative (Rust 1.74+ installed):
cargo install --locked --git https://github.com/onahFran6/aperture apertureFull instructions (all platforms, PATH, upgrade, uninstall, offline guarantee): docs/installation.md.
Point Aperture at a repository (your project, not necessarily this repo):
export REPO=~/code/my-project
aperture init "$REPO"
aperture doctor "$REPO" --offline-check
aperture index "$REPO"
aperture search "where search results are fused" --repo "$REPO"Lexical-only or JSON output:
aperture search "RRF" --repo "$REPO" --lexical
aperture search "where search results are fused" --repo "$REPO" --jsonInteractive UI:
aperture tui --repo "$REPO"Contributors work inside a clone with cargo run --:
cargo build
cargo test --workspace
cargo run -- init .
cargo run -- index .
cargo run -- search "where search results are fused" --repo .See CONTRIBUTING.md and docs/getting-started.md.
aperture init [path]
aperture index [path]
aperture search "<query>" --repo <dir> [--lexical | --semantic | --hybrid] [--json] [--no-preview] [--limit N]
aperture status [path]
aperture doctor [path] [--offline-check]
aperture clean [path] [--all]
aperture tui --repo <dir>
aperture bench --repo <dir> [--json] [--output metrics.json]Index artifacts live under:
.aperture/
config.toml
models/
index/
active/
staging/
previous/
Aperture/
├─ src/
│ ├─ main.rs # CLI entrypoint and command dispatch
│ ├─ lib.rs # Index/search orchestration
│ ├─ walk.rs # Repository walk, ignore rules, chunk dispatch
│ ├─ ast/ # Tree-sitter parsing and AST chunk extraction
│ ├─ bm25.rs # Lexical index and ranking
│ ├─ embed/ # EmbeddingProvider trait, mock provider, cache keys
│ ├─ semantic.rs # Semantic manifest, vectors, HNSW search
│ ├─ vector/ # Vector index implementations
│ ├─ fusion.rs # Reciprocal Rank Fusion
│ ├─ hybrid.rs # Hybrid search and result hydration
│ ├─ ops/ # init, status, doctor, clean, bench
│ ├─ output/ # JSON, terminal tables (comfy-table), highlighted previews
│ └─ tui/ # Ratatui/crossterm interactive UI
├─ docs/ # Public beginner docs, architecture, research, and contribution map
├─ tests/ # Integration tests and fixtures
├─ Cargo.toml
├─ CONTRIBUTING.md
├─ LICENSE
└─ README.md
Full index: docs/README.md
| Doc | Purpose |
|---|---|
| installation.md | Install, PATH, upgrade, troubleshooting |
| getting-started.md | First index and search |
| configuration.md | config.toml reference |
| supported-languages.md | AST languages and extensions |
| embeddings.md | Mock vs future local models |
| faq.md | Common questions |
| how-aperture-works.md | Architecture and modules |
| roadmap.md | Planned work |
| gaps-and-contributions.md | Contributor backlog |
| CONTRIBUTING.md | PR workflow, MSRV, CoC |
cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspaceContributions are welcome. Read CONTRIBUTING.md, docs/build-slices.md, and docs/gaps-and-contributions.md before opening a PR.
Keep PRs focused, test behavior changes, and preserve Aperture's offline runtime guarantee.
Licensed under the MIT License. See NOTICE for third-party components.






