loupe is a developer productivity tool: a source-code search engine that software engineers run
locally (via the CLI, an editor extension, or an AI coding agent) to find code across their own
repositories. Plain recursive grep re-scans the whole tree on every query, editor search crawls on
big projects, and most code-search tools assume everything is UTF-8. loupe trades a one-time index
build for near-instant searches afterward, and decodes each folder by its own encoding so legacy
non-UTF-8 sources are searchable too — Docker-free, no runtime deps.
It works on any project, and it shines where search usually hurts: large or multi-encoding
codebases — for example a monorepo holding many repositories, or a tree mixing modern UTF-8 code with
legacy Shift_JIS assets.
- ⚡ Compact n-gram index — a small fraction of your code size, not a copy of it.
- 🈶 Per-folder encoding — each folder is decoded (UTF-8 / Shift_JIS / EUC-JP …) at index time, so a
single index serves mixed-encoding trees and non-UTF-8 text is searchable without mojibake.
- 🔁 Incremental — search auto-syncs changed files first; the daemon/extension also watch the tree and
reindex only what changed, so the index stays fresh without re-scanning everything.
- 🔎 Substring and regex — n-gram candidates → exact verify (Zoekt/codesearch style); 2-char queries work (incl. 2-char CJK words).
- 🔡 Case-sensitive or case-insensitive — your choice per query.
- 🧩 One index, three front-ends — the CLI, an MCP server (for AI agents), and the VS Code
extension all read the same index and the same
settings.json, so they can never disagree about what's
indexed.
- 🪶 Self-contained native binary — one
loupe executable per platform, no Docker, no runtime deps.
🧠 Model
Three steps, separated on purpose:
init — choose which folders to index and each folder's encoding. Writes
<index-dir>/settings.json — the single source of truth shared by all front-ends.
build — create the index from settings.json.
search — the everyday operation; it auto-syncs changed files first.
The index lives in <workspace>/.loupe/ by default (override with --index-dir or
LOUPE_INDEX_DIR). settings.json is safe to commit; the index body (tantivy/, meta.json) is
git-ignored automatically.
📦 Install
Prebuilt binaries for Linux, macOS, and Windows are published to GitHub Releases (built by
cargo-dist). One-line installers:
# Linux / macOS
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/ukitomato/loupe/releases/latest/download/loupe-installer.sh | sh
# Windows (PowerShell)
powershell -ExecutionPolicy Bypass -c "irm https://github.com/ukitomato/loupe/releases/latest/download/loupe-installer.ps1 | iex"
Or grab a tarball from the Releases page, or build
from source: cargo install --git https://github.com/ukitomato/loupe loupe.
Windows binaries are intended to be signed for free by the SignPath Foundation
(application pending — see Code Signing Policy).
🚀 CLI
# 1. configure roots (interactive in a terminal, or via flags); add @enc for non-UTF-8 folders
loupe init --root src --root lib
loupe init --root src --root legacy@shift_jis # mixed encodings in one index
# 2. build the index from settings.json
loupe build
# 3. search (auto-syncs first)
loupe search "calcTotal"
loupe search "calcTotal" --case-sensitive # exact case
loupe search "parse[A-Za-z]+Request" --regex
loupe search "parseRequest" --regex --case-sensitive
loupe search "calcTotal" --max 50 --json # JSON array of { file, line, text }
loupe status # built? file count, roots, last build/sync
| Command |
Purpose |
init [--root PATH[@ENC]]… [--force] |
Configure roots/encodings → settings.json |
build [--force] |
(Re)build the index from settings.json |
sync |
Incremental catch-up (search does this automatically) |
search <q> [--regex] [--case-sensitive] [--max N] [--json] [--no-sync] |
Search the index |
status [--json] |
Index statistics |
serve |
NDJSON daemon used by the VS Code extension |
mcp |
MCP (Model Context Protocol) stdio server |
🤖 MCP server (AI agents)
loupe mcp speaks the Model Context Protocol over stdio. Register it with your MCP client:
{
"mcpServers": {
"loupe": {
"command": "/path/to/loupe",
"args": ["mcp", "--index-dir", "/path/to/workspace/.loupe"]
}
}
}
Tools exposed: search_code, search_regex, build_index, sync_index, index_status. The server
opens the shared index and keeps it fresh via a file watcher for the lifetime of the session.
🧩 VS Code extension
Two search UIs share the same index and update it automatically in the background.
Click the loupe icon in the Activity Bar, or press Ctrl+Alt+Shift+F to focus it.
- Streaming results grouped by file. Each file header shows the filename prominently on its own
line with the directory path below. Hover the header to see the full path as a tooltip.
- Match highlighting in every result row. Click a row to open the file at that line.
Aa — case-sensitive toggle (default: case-insensitive).
.* — regular expression toggle (needs a ≥3-character literal run in the pattern).
- Max results dropdown — 50 / 100 / 300 / 1000 / ∞. Changes take effect on the next search.
··· — reveals two path-filter fields:
- Files to include — only show results from matching paths (e.g.
src/, *.java, delivery/**/*.java).
- Files to exclude — hide results from matching paths (e.g.
*.min.js, test/).
- Both accept glob patterns (
* = within a segment, ** = across segments, ? = single char);
plain text without wildcards is treated as a substring of the path.
- Filters are applied client-side: no re-search is triggered when you change them.
QuickPick
Press Ctrl+Alt+F for a lightweight one-shot search. Results stream into a filterable dropdown;
press Enter to open the selected file.
| Command |
Keybinding |
Description |
| loupe: Search (substring) |
Ctrl+Alt+F |
QuickPick — substring search |
| loupe: Search (regex) |
— |
QuickPick — regex search |
| loupe: Focus Search View |
Ctrl+Alt+Shift+F |
Focus the sidebar search panel |
| loupe: Build / rebuild index |
— |
Full (re)build |
VS Code settings cover only the editor side — loupe.indexDir, loupe.binaryPath,
loupe.maxResults. Roots and encodings are not VS Code settings; they live in
settings.json so the CLI, MCP server, and extension stay in agreement.
⚙️ Configuration — settings.json
<index-dir>/settings.json is the one place that defines what gets indexed:
{
"roots": [
{ "path": "src", "encoding": "utf-8" },
{ "path": "assets", "encoding": "shift_jis" }
]
}
Write it with loupe init, or edit it by hand. Relative paths resolve against the workspace root
(the parent of the index dir).
🔧 How it works
CLI / MCP server / VS Code extension
│ (all read settings.json + the same index)
▼
loupe (Rust / Tantivy)
├─ build: parallel walk → per-file decode (UTF-8/Shift_JIS/EUC-JP) → DISTINCT bigrams+trigrams → index
├─ sync: compare mtimes → reindex only changed files, drop deleted ones
├─ watch: notify FS events → incremental update (delete+add, debounced)
└─ search: n-gram-AND candidates → parallel verify (substring/regex, case-sensitive option)
📊 Measured (≈290k files: ~260k UTF-8 + ~29k Shift_JIS)
|
|
| Index size |
≈237 MB |
| First build (cold, one-time) |
~28 min · then incremental is instant |
| Search — specific identifier |
~180 ms |
| Search — Japanese in Shift_JIS |
~156 ms |
| Search — very common term |
<1 s |
📋 Notes
- Binaries are distributed via GitHub Releases (built by cargo-dist), not committed to the repo.
The VS Code extension's CI downloads the matching one and bundles it under
bin/<os>-<arch>/ at
package time; for local development, cargo build and point loupe.binaryPath (or $PATH) at it.
- regex uses the index only when the pattern contains a literal run of ≥2 characters, ASCII or CJK (e.g.
func\s+\w+, 契約.*情報).
- Case-sensitive mode: the n-gram phase always over-approximates with lowercase n-grams, then the
verify step re-checks original bytes for exact case — so case-sensitive searches are safe but slightly
slower on large candidate sets.
- If antivirus scans the index directory, builds can occasionally hit a transient I/O error; loupe
retries automatically. Excluding the index folder from AV avoids it entirely.
🔏 Code Signing Policy
We are applying to the SignPath Foundation program for free Windows code
signing. Status: pending approval. Once approved, the statement required by the program will be:
"Free code signing provided by SignPath.io, certificate by SignPath Foundation".
What will be signed: Windows binaries (loupe.exe), built from this public repository by GitHub
Actions (cargo-dist, see .github/workflows/release.yml) and
distributed in two forms — the standalone CLI archive/installer on
GitHub Releases, and the copy bundled into the
win32-x64 VS Code extension .vsix (see .github/workflows/vscode.yml).
The .vsix reuses the exact same released binary; there is no separate build path, so only one
signed artifact needs to be produced per release.
- Authors (commit access): ukitomato (sole maintainer).
- Reviewers (review required for non-committer changes): ukitomato —
all external pull requests are reviewed by the maintainer before merge.
- Approvers (approve each signing request): ukitomato — each
signing request requires explicit approval by the maintainer.
- Privacy: This program will not transfer any information to other networked systems unless
specifically requested by the user.
loupe builds and searches its index entirely on your local
filesystem and makes no network calls.
📄 License
MIT — see the LICENSE file. Built on Tantivy (MIT).