Skip to content

Repository files navigation

Aperture

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.

CI Rust 1.74+ Offline runtime CLI and TUI MIT License

Architecture

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
Loading
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

Contents


Project Overview

Aperture indexes a repository into searchable code chunks and returns ranked results with useful metadata:

  1. Walk the repository while respecting .gitignore, .ignore, .apertureignore, size limits, and configured globs.
  2. Parse supported languages with tree-sitter and extract meaningful chunks such as functions, methods, classes, structs, and interfaces.
  3. Fall back to text chunks when language parsing is unavailable or unnecessary.
  4. Build a BM25-style lexical index for exact terms, identifiers, paths, and strings.
  5. Build a semantic vector index through the EmbeddingProvider abstraction.
  6. Fuse lexical and semantic candidates with Reciprocal Rank Fusion (RRF).
  7. 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.


See it in use

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.

Aperture demo: init, index, and search mini-redis offline

Setup and health check

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-demo

aperture doctor offline check

aperture index and status

Search by intent (hybrid)

Natural-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 10

hybrid search by intent — ranked table output

Exact symbol (lexical)

aperture search Shutdown --repo /tmp/mini-redis-demo --lexical

lexical search for Shutdown — BM25 table

JSON output (automation)

Human-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 2

JSON search output — two complete results

Interactive TUI

aperture tui --repo /tmp/mini-redis-demo

Aperture TUI hybrid search

v0.1.0: mock embedder for hybrid/semantic ranks; lexical search is solid.


Current limitations (v0.1.0)

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

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 --help

Alternative (Rust 1.74+ installed):

cargo install --locked --git https://github.com/onahFran6/aperture aperture

Full instructions (all platforms, PATH, upgrade, uninstall, offline guarantee): docs/installation.md.


Quickstart

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" --json

Interactive UI:

aperture tui --repo "$REPO"

Developing from source

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.


Command Reference

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/

Repository Structure

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

Documentation

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

Development Checks

cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace

Contributing

Contributions 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.


License

Licensed under the MIT License. See NOTICE for third-party components.

About

Local-first hybrid code search for private repos: AST chunks, BM25, HNSW vectors, RRF fusion. Rust CLI/TUI — offline by default.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages