
Turn Claude Code into Cursor.
Semantic code search that understands your codebase — find code by meaning, not just string matching.
Quick Start · Usage · Models · Commands · Config · Examples
98.3% accuracy · 5x faster than grep
Author's 20-query benchmark on one codebase. Numbers depend heavily on corpus and query style —
measure on your own repo before relying on them. See Retrieval quality.
Quick Start
1. Install Ollama (local embeddings, free)
brew install ollama
ollama serve &
ollama pull qwen3-embedding:0.6b
2. Install the Beacon plugin
claude plugin marketplace add sagarmk/beacon-plugin
claude plugin install beacon@beacon-plugin
3. Start Claude Code
claude
That's it. On first session start, Beacon will:
- Install npm dependencies automatically (native modules like
better-sqlite3 — takes a few seconds)
- Index your codebase in the background
No npm install, no manual setup. Just install and go.
Usage
After installing, Beacon indexes automatically on session start. Here's the essentials:
Force a full re-index
> /reindex
Deletes existing embeddings and rebuilds from scratch — useful after switching models or if the index gets stale.
Check index health
> /index
Beacon Index
● ● ● ● ● qwen3-embedding:0.6b · Ollama (local)
● ● ● ● ● 1024 dims · 3.8 MB
● ● ● ● ●
● ● ● ● ● Coverage: 100% (38/38 files)
Indexed by extension
● .js 25 files
● .md 13 files
Statistics
Indexed files 38
Total chunks 109
Avg chunks/file 2.9
Last sync 2 minutes ago
For a quick numeric summary:
> /index-status
{
"files_indexed": 38,
"total_chunks": 114,
"last_sync": "2026-03-01T04:30:21.453Z",
"embedding_model": "qwen3-embedding:0.6b",
"embedding_endpoint": "http://localhost:11434/v1"
}
Search your codebase
> /search-code "authentication flow"
[
{
"file": "src/middleware/auth.ts",
"lines": "12-45",
"similarity": "0.82",
"score": "0.74",
"preview": "export async function verifyAuth(req, res, next) {\n const token = req.headers.authorization?.split(' ')[1];\n ..."
},
{
"file": "src/routes/login.ts",
"lines": "8-32",
"similarity": "0.78",
"score": "0.65",
"preview": "router.post('/login', async (req, res) => {\n const { email, password } = req.body;\n ..."
}
]
Hybrid search combines semantic similarity (understands meaning), BM25 keyword matching, identifier boosting, and a symbol reference graph — so searching "auth flow" finds code about authentication even if it never uses the word "auth".
Options: --top-k N (results count), --threshold F (min score), --path <dir> (scope to directory), --no-hybrid (pure vector search).
Tools Claude uses
Beacon ships an MCP server, so Claude picks the right tool for the question
instead of grepping and hoping. Three of these never run the embedding model at
all — they are indexed lookups over the symbol tables.
| Tool | For | Cost |
|---|
find_symbol(name) | Where a symbol is defined | ~0.01 ms, exact |
find_references(name) | Every call site — exhaustive, not a ranked sample | ~0.01 ms |
outline(file) | A file's symbols with line numbers | ~0.01 ms |
search_code(query) | Code matching a description you can't name | ~200 ms, ranked |
index_status() | Index health, when results look stale | ~0.01 ms |
find_references is the one worth knowing about: it is exhaustive over indexed
files, so it is the only correct tool for "what breaks if I change this".
Ranked search returns a sample and will quietly miss call sites.
search_code also takes mode: "lexical" (keyword only, skips the embedding
model entirely) and mode: "semantic" (embeddings only).
Grep is still the right tool for literal text, regex, case-sensitive
matches, and anything outside the index — node_modules, dist, lockfiles,
.env. Beacon leaves those alone.
Retrieval quality
The symbol graph exists because embeddings are blind to structure. A function
with no doc comment has almost no natural-language surface, so no phrasing
reaches it — but whatever calls it usually is retrievable, one reference edge
away. Personalized PageRank seeded on the current best matches walks that edge.
Measured on this repo, 12 natural-language queries with no lexical overlap with
their targets:
| top-1 | MRR |
|---|
| Vector only | 5/12 | 0.552 |
| Hybrid, no graph | 7/12 | 0.722 |
| Hybrid + symbol graph | 9/12 | 0.813 |
Two caveats worth stating plainly:
- Twelve queries on one repo is a small sample. Treat the direction as
meaningful and the exact numbers as noisy.
- Hybrid weights are a deliberate compromise. Dropping BM25 scores better on
prose queries (0.813) and much worse on exact-identifier lookup (0.563 vs
0.988 on a 40-query benchmark). The shipped
.4 / .3 / .3 split is the only
configuration that holds up on both.
Run search.js with search.hybrid.debug: true in .claude/beacon.json to see
every scoring component per result.
Embedding Models
Beacon runs on open-source models by default — no API keys, no cloud costs, fully local via Ollama.
| Model | Dims | Speed (M2, measured) | Best for |
|---|
| qwen3-embedding:0.6b (default) | 1024 | 24 chunks/s | Strong code retrieval, instruction-aware queries |
| nomic-embed-text | 768 | 43 chunks/s | Fastest indexing; set dimensions: 768 |
| qwen3-embedding:4b | 1024 | 4 chunks/s | Highest quality, ~10x slower to index |
| all-minilm | 384 | very fast | Lightweight, low resource usage |
Throughput measured warm on an M2/16GB — a cold model load makes the first run
look far slower than steady state.
Changing model or dimensions invalidates the index. Beacon detects the
mismatch, refuses to search rather than returning nonsense, and tells you to run
/reindex.
To switch models, pull with Ollama and update your config:
ollama pull mxbai-embed-large
// .claude/beacon.json
{
"embedding": {
"model": "mxbai-embed-large",
"dimensions": 1024,
"query_prefix": ""
}
}
Then run /reindex to rebuild with the new model.
Cloud Providers
For cloud-hosted embeddings, create .claude/beacon.json in your repo:
OpenAI
export OPENAI_API_KEY="sk-..."
{
"embedding": {
"api_base": "https://api.openai.com/v1",
"model": "text-embedding-3-small",
"api_key_env": "OPENAI_API_KEY",
"dimensions": 1536,
"batch_size": 100,
"query_prefix": ""
}
}
Voyage AI
export VOYAGE_API_KEY="pa-..."
{
"embedding": {
"api_base": "https://api.voyageai.com/v1",
"model": "voyage-code-3",
"api_key_env": "VOYAGE_API_KEY",
"dimensions": 1024,
"batch_size": 50,
"query_prefix": ""
}
}
LiteLLM proxy (Vertex AI, Bedrock, Azure, etc.)
pip install litellm
litellm --model vertex_ai/text-embedding-004 --port 4000
{
"embedding": {
"api_base": "http://localhost:4000/v1",
"model": "vertex_ai/text-embedding-004",
"api_key_env": "LITELLM_API_KEY",
"dimensions": 1024,
"batch_size": 50,
"query_prefix": ""
}
}
Custom endpoint
Any server implementing the OpenAI /v1/embeddings API will work. Set api_base, model, dimensions, and optionally api_key_env in .claude/beacon.json.
Commands
Beacon indexes your codebase automatically on session start and re-embeds files as you edit — no manual steps needed.
Search
| Command | Description |
|---|
/search-code | Hybrid code search — semantic + keyword + BM25 matching. Supports --path <dir> to scope results |
Index
| Command | Description |
|---|
/index | Visual overview — files, chunks, coverage, provider |
/index-status | Quick health check — file count, chunk count, last sync |
/reindex | Force full re-index from scratch |
/run-indexer | Manually trigger indexing |
/terminate-indexer | Kill a running sync process |
Config
| Command | Description |
|---|
/config | View and modify Beacon configuration |
/blacklist | Prevent indexing of specific directories |
/whitelist | Allow indexing in otherwise-blacklisted directories |
Beacon also provides a code-explorer agent and a semantic-search skill that Claude can invoke automatically.
Why Beacon?
- Understands your questions — ask "where is the auth flow?" and get
lib/auth.ts, not every file containing "auth"
- Query expansion — searches for "auth" automatically find code mentioning "authentication", "authorize", and "login"
- Stays in sync automatically — hooks handle full index, incremental re-embedding on edits, and garbage collection
- Resilient — retries with backoff on transient failures, auto-recovers from DB corruption, debounces GC
- Works with any embedding provider — Ollama (local/free), OpenAI, Voyage AI, LiteLLM, or any OpenAI-compatible API
- Gives Claude better context — MCP tools it selects itself, slash commands, a code-explorer agent, and a search-redirect hook
How It Works
Beacon uses Claude Code hooks to stay in sync with your codebase:
| Hook | Trigger | What it does |
|---|
| SessionStart | Every session | Ensures npm deps are installed (first run only), then full index or diff-based catch-up |
| PostToolUse | Write, Edit, MultiEdit | Re-embeds the changed file |
| PostToolUse | Bash | Garbage collects embeddings for deleted files |
| PreCompact | Before context compaction | Injects index status so search capability survives compaction |
| PreToolUse | Grep, Bash | Redirects a codebase search to the matching Beacon tool. Covers shell grep/rg too, since that is what agents actually run. Skips regex, literals, and anything outside the index. |
Configuration
Default configuration (config/beacon.default.json):