Local code search for AI coding agents. Six fast, purpose-built tools that hand Claude Code, Codex & friends ranked answers, not raw grep. Zero API keys, 100% on-device.
Maybe grep isn't all you needโฆ ๐ฌ Every coding agent today reaches for grep + Read by reflex. sweet-search challenges the narrative. ๐
โจ Highlights
- Hybrid retrieval โ one of the six tools uses BM25F lexical + dense semantic + structural graph signals, fused per query and reranked by late-interaction
- Agent-native by design โ token-budgeted output tiers, an optional MCP server (and default zero-overhead CLI), and a GEPA-evolved system prompt โ one
initinstalls it into Claude Code by default (Codex, Gemini CLI, and Cursor via flags) - Indexed grep, ~10ร faster than ripgrep โ a sparse n-gram prefilter skips the files that provably can't match
- ColBERT-style reranking, locally โ per-token MaxSim late interaction on hand-written SIMD kernels
- GPU-accelerated indexing โ Apple Metal, CUDA, CoreML Neural Engine, or plain CPU via ORT; same engine, auto-selected
- Never stale โ incremental indexing keeps the index aligned with your working tree, uncommitted edits included
- No storage hassle โ indexed artifacts maximally optimized without any accuracy tradeoff; up to INT4 quantization
- Local-first โ all models run on-device; nothing is sent anywhere, ever. CPU-inference supported for all models
๐ Table of Contents
GET STARTED
๐ Quickstart three commands to a searchable repo
๐ฅ๏ธ Platform Support macOS ยท Linux ยท WASM fallback
USE IT
๐งฐ The Six Tools search ยท grep ยท find ยท semantic ยท trace ยท read
๐ง The Evolved Agent Prompt GEPA-optimized search discipline
๐ Works With Your Agent MCP ยท Claude Code ยท Codex ยท Gemini ยท Cursor
UNDER THE HOOD
โก GPU-Accelerated Indexing candle ยท fused kernels ยท cAST chunking
๐ An Index That Never Goes Stale reconcile daemon tracks your working tree
๐ฆ The Native Engine Room four Rust crates + INT4 LI compression
THE RECEIPTS
๐ Benchmarks agent cost savings ยท engine speed ยท full-corpus MRR
๐งญ Where sweet-search Fits honest wins & trade-offs vs peers
๐ Prior Art & Acknowledgements the shoulders we stand on
๐ License Apache-2.0
๐ Quickstart
Requirements: Node.js 18+ on macOS (Apple silicon or Intel) or Linux (x64 or ARM64). On Windows, run sweet-search inside WSL2.
npm install -g sweet-search
cd your-repo
sweet-search init # one-time: downloads local models, wires up your agent
sweet-search index # builds the index โ GPU-accelerated where available
sweet-search "where do we validate JWT tokens?"
That's it. init is idempotent and SHA256-verifies every model binary; re-running it is always safe.
From then on, the index stays up to date automatically as you work.
To uninstall ๐ข:
sweet-search uninstall --keep-models # current repo only; keeps shared models and the global CLI
sweet-search uninstall # current repo plus its shared model downloads; keeps the global CLI
npm uninstall -g sweet-search # global CLI only; does not clean initialized repos
Run sweet-search uninstall inside each initialized repo before removing the global CLI.
sweet-search init --wizard # interactive: shows your hardware, recommends a model tier
sweet-search init --profile core # lexical-only, no model downloads (CI-friendly)
sweet-search init --li-model edge # compact late-interaction model for constrained machines
sweet-search uninstall --dry-run # preview cleanup for the current repo
- Footprint: CPU-only hosts download a few hundred MB of INT8 models; GPU hosts add ~1.2 GB of FP32 backbones (skipped automatically where they'd be useless); M3+ Macs can additionally fetch a ~3.2 GB CoreML cascade for Neural Engine acceleration. Everything lands in
~/.cache/sweet-search/models/and is used strictly on-device. - Agent wiring: init injects the tool-routing system prompt into
CLAUDE.md(andAGENTS.md,GEMINI.md, Cursor rules via flags), registers a session-start prewarm hook so your first query hits a warm daemon, and installs a/sweet-indexskill in Claude Code. - What gets indexed: what you'd expect โ
.gitignoreis respected,node_modules/build dirs/minified artifacts are denied, files over 1 MB skipped, with a.sweet-search-ignorefor extra rules.
๐ Benchmarks
We measure sweet-search four ways โ from how much it helps a real agent down to raw engine throughput:
๐ค โ Code-retrieval (agent-in-the-loop) Does it make a real coding agent cheaper and more useful when it searches your repo? Paired against each model's own grep-and-read loop.
๐ง โก Task-completion (coming soon) Does cheaper, denser context compound into a higher resolve-rate on multi-step engineering tasks? Harness in progress.
๐ โข Paper-type IR (academic) The standard NLโcode retrieval suites (GCSN, M2CRB, CoSQAโฆ), full-corpus MRR@10.
โก โฃ Engine speed Raw systems numbers โ grep throughput, query latency, rerank kernels, HNSW.
๐ค 1. Code-retrieval benchmarks โ the agent-in-the-loop test
One variable changes: how the agent searches a real repository.
- ๐ฌ sweet-search: the model gets our GEPA-evolved search discipline and search tools.
- ๐ Native: the same model uses its built-in grep-and-read loop.
Same tasks, same judge, paired probe-for-probe.
sealed vault ยท exact paired results ยท five representative profiles ยท full 11-cell matrix and held-out/OOD replication below
The headline, in four claims:
- ๐ฐ Cheaper where the agent thrashes โ up to โ34% realized cost on Codex; โ18 to โ32% across the GPT-5.5 / opencode / bare-API harnesses.
- ๐ง Fewer round-trips โ up to โ56% tool calls, significant on 9 of 11 cells.
- โจ More useful per response โ +0.18 to +0.31 on a 5-dimension usefulness score, and still denser when length-matched (significant on 8 of 11 cells).
- ๐ฏ Accuracy held โ and lifted on the weak โ a statistical tie on flagship models (saturated at 0.94โ0.99), and +3 pp (up to +8 pp out-of-distribution) on weaker models like GLM-5.1 and DeepSeek.
The win is harness-adaptive: where the native loop is disciplined (Claude Code) it shows up as denser, more useful context per token; where it thrashes (Codex floods 30k+ tokens of its own grep output into context) it shows up as a large cost and tool-call cut. Either way, final-answer accuracy never significantly regresses.
| ๐งฐ Native agent harness | ๐ฐ Realized cost | ๐ง Tool calls | โจ Useful content / response | ๐ฏ Final accuracy |
|---|---|---|---|---|
| ๐ค Codex (GPT-5.5) | โ30 to โ34% | โ44 to โ56% | +0.06 โ +0.17 โ | tie (saturated) |
| ๐ opencode (GPT-5.5 / GLM-5.1) | โ18 to โ22% | โ15 to โ49% | +0.23 to +0.31 โ | tie |
| ๐ bare API (GPT-5.5 / GLM / DeepSeek) | โ15 to โ32% แต | โ15 to โ33% | +0.08 to +0.24 โ | tie ยท +3 pp on weak models |
| ๐ฃ Claude Code (Sonnet / Opus) | โ10% to +14% แต | โ5 to โ33% | +0.18 to +0.29 โ | tie |
โ "Useful content / response" is the per-response delta on a 5-dimension usefulness score (answer-grounding ยท workable-code ยท navigability ยท edit-locality ยท sufficiency), 0โ1 scale. "tie" = final-answer correctness statistically indistinguishable (saturated in the 0.94โ0.99 band on flagships).แต the two cheapest bare models cost fractions of a cent either way (GLM +27% of $0.008; DeepSeek โ15% of $0.004). แต Opus โ5/โ10%; Sonnet +8โ14%, which is โ1ยข on a flat-rate subscription for a richer answer.
Denser, not just longer. The usefulness lift survives length-matching โ comparing sweet-search and native responses of equal token length, sweet-search's content is significantly higher on 8 of 11 cells. The validated single-number usefulness composite (grounding ร content ร density) is significant on all 11 sealed cells.
- What's being compared: the installed
sweet-searchagent prompt + tools vs. the same model using only its built-in file-reading and shell-grep tools. Not a different model โ the same model, with and without sweet-search. - Design: 11 modelรharness cells. Sealed vault (n=60/arm, the pre-registered primary) opened once; plus held-out (n=30) and out-of-distribution (n=40) sets for generalization. Stratified, fixed-seed splits.
- Judging: 3-judge panel (DeepSeek-V4-flash + Gemini-3.1-flash-lite + MiniMax-M2.7), paired by probe, 20k-sample bootstrap CIs, BenjaminiโHochberg FDR multiplicity correction across each metric family. We report family-level survival counts, never a single cherry-picked cell.
- What survives FDR (vault): useful-content 10/11, density-composite 11/11, length-matched content 8/11, fewer-tool-calls 9/11. Generalization (held-out + OOD): content 17โ18/20, fewer calls 14/20.
- The token fact that drives everything: sweet-search's footprint is nearly constant (~1.3kโ3.3k tokens) because the tool responses are capped; native's footprint is whatever the model decides to grep โ up to 37k tokens on Codex. That single fact is what drives the cost and tool-call gaps.
- Honest caveats we keep attached: (1) accuracy ties on flagship models โ it is not an accuracy win there, it's saturated; the accuracy gains are real only on weaker models. (2) The two weakest cells for length-matched density (Codex-low, DeepSeek) are correct-sign but underpowered โ Codex's responses are so token-divergent that too few equal-length pairs exist to reach significance, and DeepSeek is simply under-powered. Those are honest non-victories, not wins.
- Full methodology and per-cell tables:
docs/PHASE7.md.
๐ง 2. Task-completion benchmarks โ coming soon
Retrieval quality is necessary but not sufficient. Cheaper, denser context only matters if it compounds across a real, multi-step engineering task โ finding the code, understanding it, changing it, and not breaking anything. The next suite measures exactly that: resolve-rate on SWE-bench-style multi-file tasks, sweet-search-wired vs. native, on the same paired, multiplicity-controlled bar as above. Harness and pilot are in progress โ numbers land here when they clear that bar, and not before.
๐ 3. Paper-type retrieval benchmarks โ academic NLโcode IR
Every number below is the ss-search pipeline end-to-end โ the same binary you install โ run
against the full benchmark corpus (no 99-distractor shortcuts), zero-shot (we never
fine-tune on these tasks). Where a benchmark's queries are docstrings, we strip the docstring out of the
indexed code so the query can't trivially match itself โ the standard retrieval protocol.
We're SOTA in June 2026 on 3/4 attempted benchmarks at HARDER settings (running on full pool) than most other attempts!
| ๐ Benchmark | ๐ What it tests | # Queries | ๐ Pool | ๐ฏ MRR@10 | ๐ SOTA? |
|---|---|---|---|---|---|
| ๐ GenCodeSearchNet | NLโcode, 6 languages | 6,000 | full 6,000 | 86.6 | YES โ |
| ๐ CoSQA | web queries โ Python | 500 | full 6,267 | 65.5 | โ (zero-shot) |
| ๐บ๏ธ M2CRB | multilingual NLโcode (ES/PT/DE/FR โ Py/Java/JS) | 5,795 | full 5,795 | 54.0 | YES โ |
| ๐ก๏ธ AdvTest | adversarial, identifier-obfuscated Python | 19,210 | full 19,210 | 51.4 | NO โ |
SOTA = best result we can find in the published literature as of June 2026; cross-metric/protocol comparisons are spelled out per benchmark below.
๐ GenCodeSearchNet โ 86.6 ย ยทย ๐ SOTA in June 2026
- The BEST PUBLISHED number we can find, anywhere
- The benchmark's own paper caps at MRR โค 0.42 for fine-tuned baselines (โค 0.10 cross-lingual); even zero-shot OpenAI Ada-2 reaches 0.79โ0.94 โ but all of it against a tiny 99-distractor pool.
- We score 0.866 against the entire 6,000-document corpus โ a strictly harder setting โ and zero-shot. ๐ฅ
๐ CoSQA โ 65.5 ย ยทย ๐ฅ Zero-shot SOTA in June 2026
- Beats EVERY PUBLISHED zero-shot model
- Canonical setup: 500 real web queries โ the fixed 6,267-code database, no fine-tuning.
- Clears the strongest zero-shot results out there โ CodeSage-Large
47.5ยท OpenAI text-embedding-3-large55.4ยท OASIS55.8โ and goes toe-to-toe with fine-tuned CodeBERT / GraphCodeBERT (64.7 / 67.5). ๐ช - CoSQA has known label noise, so we read the absolute height with a pinch of salt.
๐บ๏ธ M2CRB โ 54.0 ย ยทย ๐ SOTA in June 2026
- the BEST PUBLISHED number we can find, anywhere โ and zero-shot
- ๐ช๐ธ Spanish ยท ๐ต๐น Portuguese ยท ๐ฉ๐ช German ยท ๐ซ๐ท French โ Python / Java / JavaScript.
- The paper's best โ a CodeBERT fine-tuned on the task โ reaches 52.7 auMRRc, a metric that averages over easier, smaller pools (so
auMRRc โฅ full-pool MRRfor any model). Our 54.0 is full-pool MRR@10 over all 5,795 functions in one pool โ a strictly harder measure, cleared with no fine-tuning. ๐ฅ
๐ก๏ธ AdvTest โ 51.4 ย ยทย ๐งช our honest worst case โ and we publish it anyway
- Adversarial obfuscation (
def Func(arg_0):) deletes the lexical + graph signals our hybrid feeds on โ yet we still beat the classic fine-tuned baselines (CodeBERT27ยท GraphCodeBERT35ยท UniXcoder41), and our stack still lifts our own encoder ~3pp even here. - ๐ Full transparency: we could not reproduce the often-cited
59.5for the bare CodeRankEmbed encoder โ the reference FP32 model scores 54.7 on our leak-free corpus, our shipped INT8 build 51.4. The gap is stricter preprocessing + INT8 quantization, not the retrieval pipeline. We report exactly what we measured.
- Reproduction: result artifacts live in
eval/results/; rerun viaeval/run_all.js. The canonical full-pool loaders are ineval/download_data.py. - Full corpus, not distractors. Published baselines for GCSN- and CoSQA-style benchmarks typically rank the gold against 99 sampled distractors; every number here ranks against the benchmark's full corpus (6kโ19k candidates) โ strictly harder.
- Zero-shot + docstring-stripped. We never fine-tune on these tasks. For docstring-derived benchmarks (AdvTest, M2CRB) we strip the docstring from the indexed code โ otherwise the NL query matches itself verbatim (a no-strip AdvTest run scores a meaningless 0.98). This is the standard protocol; it is also why our AdvTest is lower than naรฏve setups that leave the docstring in.
- Dev/held-out split. Our ranking work iterates against a fixed dev split of each benchmark (e.g. GCSN: 600 dev + 400 held-out per language, stratified, seed=42) and treats the remainder as held-out, inspected aggregate-only at milestones. The table figures are full-corpus runs โ they include the dev portion we tuned against; a held-out-only breakdown ships with the next results refresh.
- What we deliberately don't claim yet. CoIR (official metric NDCG@10 over per-subtask corpora up to ~1M docs), CoSQA+ (multi-positive, MAP-primary), and CLARC (per-group pools) use protocols and metrics our single-pool MRR@10 harness doesn't currently match. Rather than publish apples-to-oranges numbers, we omit them; faithful per-subtask CoIR (NDCG@10) runs are queued.
- M2CRB โ the paper's metric is auMRRc (area under the MRR-vs-pool-size curve; best published 52.7, fine-tuned). Because that area averages over easier small pools,
auMRRc โฅ full-pool MRRfor any model โ so our 54.0 full-pool MRR@10 (all 5,795 functions, zero-shot) clears their best on a strictly harder measure. No one publishes a plain full-corpus MRR@10 on M2CRB, so ours is the best available. - AdvTest honesty note. We could not reproduce the commonly-cited 59.5 for the bare CodeRankEmbed encoder on our corpus: the reference FP32 model scores 54.7 on our leak-free, docstring-stripped, full-19,210 setup, and our shipped INT8 build 51.4. We report our measured numbers and the reference check rather than the leaderboard figure.
- Honesty corner: CrossCodeEval โ cross-file completion-context retrieval, a different task than NL search โ sits at 0.12. We don't optimize for it and report it anyway.
โก 4. Engine speed โ systems benchmarks, measured in-repo
10.2ร ripgrep's median grep ย ยทย 2.9 ms warm queries ย ยทย 47ร MaxSim kernels ย ยทย โ33% HNSW search p50
| โ๏ธ What | ๐ Result | ๐ Source |
|---|---|---|
| โก Indexed grep vs ripgrep | 10.2ร faster at the median (8.5โ17.7ร across 5 repos, 353 realistic queries, 1 ms p50 โ identical match counts on every query) | docs/GREP_INDEXING_STRATEGY.md |
| โฑ๏ธ Warm query latency (native CLI) | 2.9 ms warm ยท 108 ms cold | docs/INIT_STRATEGY.md |
| ๐งฎ MaxSim rerank kernels | 1.26 s โ 27 ms for a 231-candidate pass (47ร native Rust; 16ร WASM SIMD) | docs/MAXSIM_OPTIMIZATION.md |
| ๐ง HNSW tuning for code | โ33% search p50, +5.9 pp recall@200 | docs/HNSW_APPROACH.md |
| ๐พ Indexing memory | peak JS heap 785 MB โ 213 MB | docs/DISK_FLUSHING_STRATEGY.md |
| ๐ CoreML cascade (M3 Max) | 18% faster full indexing vs the Metal baseline | docs/INIT_STRATEGY.md |
๐งญ Where sweet-search Fits
Code search is a crowded space. Here's an honest read on where sweet-search wins and where it gives ground, against the trending leaders and our closest local peers.
| Capability | sweet-search | claude-context | Cursor index | codebase-memory | SocratiCode |
|---|---|---|---|---|---|
| 100% local โ code never leaves your machine | โ | โ ยน | โ | โ | โ |
| Works with zero API keys | โ | โ ยน | โ | โ | โ |
| No external service to run (vector DB ยท Ollama ยท Docker) | โ | โ Milvus | โ cloud | โ | โ ๏ธโต |
| ColBERT late-interaction rerank | โ | โ | โ | โ | โ |
| Faster-than-ripgrep exact grep | โ | โ | โ โท | โ | โ |
| Call-graph trace (callers ยท callees ยท impact) | โ | โ | โ | โ | โ |
| Drives any terminal agent (Claude Code ยท Codex ยท Gemini CLI) | โ | โ | โยฒ | โ | โ |
| Published NLโcode retrieval benchmarks | โ | โ ๏ธยณ | โ | โ ๏ธยณ | โ ๏ธยณ |
| โฆand where sweet-search gives ground | |||||
| Native Windows | โโด | โ | โ | โ | โ ๏ธโธ |
| Deep-AST language coverage | โ ๏ธ 14 (+70 via regex) | โ ๏ธ | โ ๏ธ | โ 158 | โ ๏ธ |
| In-editor GUI ยท writes & edits code | โ | โ | โ | โ | โโถ |
| Org-wide, multi-repo scale | โ | โ ๏ธ | โ ๏ธ | โ ๏ธ | โ |
โ yes ยท โ ๏ธ partial / with caveats ยท โ no. Verified June 2026; capabilities drift. ยน claude-context's local path (Milvus Lite + Ollama embeddings) needs no API key, but it defaults to OpenAI/Voyage embeddings + Zilliz Cloud โ and still runs Milvus + Ollama either way. ยฒ Cursor's index is editor-locked โ external terminal agents can't query it. ยณ Reports token-reduction / efficiency, not a public NLโcode retrieval-quality leaderboard. โด Runs on Windows via WSL2. โต SocratiCode manages a bundled Qdrant for you, but uses an auto-detected Ollama for local embeddings. โถ Ships an interactive HTML graph viewer, but doesn't edit code. โท Cursor's local Instant Grep โ a literal + regex index it benchmarks at ripgrep 16.8 s โ 13 ms (the post that inspired our own n-gram prefilter). โธ SocratiCode runs on Windows via Docker only โ no native binary, and no GPU there.
Where we lose, plainly: no native Windows yet, no editor GUI, and we index one repo at a time. If you need org-wide search across many repos and branches, that's where SocratiCode and Sourcegraph are built to win. If you live inside one editor, Cursor's index is already there. sweet-search is for the terminal agent that wants the best local retrieval on the repo in front of it. No one else combines all of it: ColBERT late-interaction reranking and faster-than-grep search, fully on-device, with nothing to sign up for.
Also in the space: Sourcegraph/Cody (org-scale, server-based), Continue.dev (local-default RAG), Serena (LSP symbol search, no embeddings), grepai (local CLI + trace), and cocoindex-code (embedded AST search).
๐งฐ The Six Tools
Six small tools, one shared index. Each returns ranked, deduplicated, token-budgeted output designed to be consumed by an agent โ a useful answer, not a wall of matches to scroll through.
| Tool | What you give it | What you get back |
|---|---|---|
1. ss-search |
a natural-language query | ranked, self-contained code blocks |
2. ss-grep |
an exact regex/literal | every file:line hit, ripgrep-identical |
3. ss-find |
a regex + a query | regex matches, semantically re-ranked, as code blocks |
4. ss-semantic |
a file + a question | just the relevant spans of that file |
5. ss-trace |
a symbol | callers + callees + impact, in one call |
6. ss-read |
a file (ยฑ line range) | exact bytes + symbol metadata |
1. ๐ ss-search โ hybrid search powerhouse
A hybrid search pipeline with late interaction reranking that returns actual code blocks.
Leading published-benchmark results โ strongest we can find on GenCodeSearchNet, and above every published
zero-shot model on CoSQA. See benchmarks.
flowchart TD
Q(["๐ natural-language query"]) --> ROUTE{{"๐งญ WASM CatBoost router ยท lexical / hybrid"}}
ROUTE --> BM["๐ <b>BM25F</b><br/>field-weighted FTS5"]
ROUTE --> ANN
subgraph ANN ["๐งฌ three-stage ANN cascade"]
direction LR
BIN["binary <b>HNSW</b><br/>Hamming ยท ~100ยตs"] --> INT["INT8<br/>rescore"] --> FL["float32<br/>mmap sidecar"]
end
BM --> FUSE
ANN --> FUSE
FUSE["๐ <b>CCFusion</b><br/>convex combo ยท RRF fallback"] --> ROW1
subgraph ROW1 [" "]
direction LR
IAR["โ <b>IAR</b><br/>exact-symbol injection"] --> INTENT["๐ฏ intent rerank<br/>demote docs ยท tests ยท config"]
end
ROW1 --> ROW2
subgraph ROW2 [" "]
direction LR
GRAPH["๐ธ๏ธ graph expansion<br/>typed edges ยท 1โ2 hops ยท <b>PathRAG</b>"] --> MAXSIM["๐งฎ <b>Late-Interaction Rerank</b><br/>โก native Rust MaxSim kernel"] --> OUT(["๐ <b>self-contained code blocks</b><br/>whole functions ยท 3k/8k/12k budget"])
end
classDef io fill:#fde68a,stroke:#f59e0b,color:#000;
classDef out fill:#bbf7d0,stroke:#15803d,color:#000,stroke-width:3px;
classDef route fill:#e0e7ff,stroke:#818cf8,color:#000;
classDef lex fill:#dbeafe,stroke:#60a5fa,color:#000;
classDef fuse fill:#f3e8ff,stroke:#c084fc,color:#000;
classDef rank fill:#ffe4e6,stroke:#fb7185,color:#000;
class Q io;
class OUT out;
class ROUTE route;
class BM,BIN,INT,FL lex;
class FUSE,IAR fuse;
class INTENT,GRAPH,MAXSIM rank;
style ANN fill:#eff6ff,stroke:#93c5fd,color:#000;
style ROW1 fill:none,stroke:none;
style ROW2 fill:none,stroke:none;
โ The diagram traces the hybrid route. A pure-lexical query โ or a literal file path โ short-circuits at the router straight to BM25F, skipping the vector cascade and fusion.
| Stage | What it actually does |
|---|---|
| ๐งญ Route | WASM-exported CatBoost ยท lexical / hybrid ยท ~10 ยตs routing ยท low-confidence โ max-recall hybrid |
| ๐งฌ Retrieve | โข Lexical โ BM25F over field-weighted FTS5 (name 10ร ยท signature 5ร ยท alias 4ร ยท doc 1ร)โข Embed โ query vectorized by the local CodeRankEmbed model (swappable for Voyage / Jina / Codestral)โข Vector cascade โ binary HNSW (Hamming, 64-byte, ~100 ยตs) โ INT8 rescore โ exact float32 from a memory-mapped sidecar |
| ๐ Fuse | โข CCFusion โ convex-combine both rankings ยท per-route weights ยท quantile-normalizedโข MMR (ฮป=0.9) diversity pass over the fused listโข auto RRF (k=60) fallback on degenerate score distributions |
| โ Anchor | โข IAR (Identifier Anchor Retrieval) โ a real symbol in the query fires an exact-name code-graph lookup that injects that entity, even when the encoder ranked it too low |
| ๐ฏ Intent Rerank | โข demote docs / tests / config when you want implementationโข log-scaled call-site boosts surface the most-referenced function |
| ๐ธ๏ธ Graph Expansion | โข typed-edge walks (imports/extends/calls/uses) ยท adaptive 2-hop on the AST graph ยท edges picked by intentโข PathRAG flow pruning + degree normalization โ hubs can't dominate |
| ๐งฎ Late interaction Rerank | โข Query embedded per-token by LateOn-Code (149M; a 17M edge variant auto-selected on low-RAM hosts)โข MaxSim against the pre-indexed quantized token vectorsโข native Rust+Rayon MaxSim kernel โก ยท WASM-SIMD fallback (1.26 s โ 27 ms on a 231-candidate rerank) |
| ๐ฆ Package | โข entity-aware expansion โ whole functions (imports, docstrings, decorators)โข same-file overlap demotion โ diverse, non-overlapping spansโข symbol-family completion (agent mode) โ generated/width families surface as a compact indexed manifest instead of truncating silently, inside the same budgetโข auto-selected 3k / 8k / 12k token budget |
๐ง The HNSW, in full (full writeup). Stage 1 is a from-scratch binary HNSW, and every "advanced" trick ships on by default:
- Heuristic neighbor selection (HNSW Algorithm 4) + M0 = 2M on layer 0 โ a real graph backbone, not naรฏve closest-M
- Shuffled insertion order โ no filesystem-ordering bias baked into the highway structure
- Discovery-rate adaptive early termination + adaptive ef โ easy queries stop early, hard ones keep their budget
- A denser graph than most vendors ship (M=64 ยท efC=800 ยท efS=400) โ which broke an 80.6 % โ 86.5 % recall@200 plateau and cut p50 latency ~33 %
- Zero-GC search: typed-array heaps + generation-stamped visited lists โ no per-query allocation
- 64-byte sign-bit vectors (Hamming) โ INT8 โ exact float32 from a memory-mapped sidecar
โก Why it's quick. A native Rust + Rayon MaxSim kernel (47ร over scalar; 16ร WASM-SIMD fallback) ยท int4-quantized, binary-packed token vectors (plain INT4 is the shipped path โ the full TurboQuant algorithm is researched but deferred; binary packing alone cut the LI index ~3.4ร, 1.34 GiB โ ~396 MiB) ยท a memory-mapped float32 sidecar that skips SQL on the rescore hot path ยท score-spread adaptive pooling (decisive queries shrink the rescore pool, ambiguous ones widen it) ยท and a warm daemon that answers in a single NAPI call โ no process is ever forked.
๐๏ธ Priors & structure.
- Quality priors: every chunk carries a 0โ1 prior from test proximity, git recency, symbol centrality (PageRank), comment density, and complexity โ production code surfaces, stale fixtures sink.
- Community structure: a canonical Leiden pass detects code communities on the entity graph at index time, feeding vocabulary prewarming and structural signals โ it understands your modules, not just your directories.
- Multilingual: 14 languages get full tree-sitter AST treatment; a 39-config registry covers 70+ extensions beyond that. Router features handle camelCase/snake_case, CJK density, and German compounds.
- Format-gated signals: structure-aware boosts and demotions (symbol-exact, path-token, anomalous-chunk, mega-entity) fire only in agent mode โ they help agent-shaped queries and would hurt plain NL, so they stay gated by default.
๐ Rescues & honest trade-offs.
- Long-query rescue: wordy NL queries that FTS5 would tokenize into an unsatisfiable
ANDfall back to multi-query BM25F + RRF โ one query per content keyword, fused. - Near-duplicate dedup: a SimHash + MinHash-LSH pass (Jaccard ฯ=0.9) clusters copy-paste and vendored code at index time; aliases reuse their exemplar's vectors and skip both the bi-encoder and late-interaction encoding.
- A negative result we ship anyway: we built a full cross-encoder rerank cascade behind an adaptive confidence gate, measured it on our eval sets โ and it didn't beat MaxSim at 3ร the latency. So it ships disabled (
SWEET_SEARCH_CASCADE_ENABLED=trueto try it). We'd rather ship the faster path than a fancier diagram. - Budget tiers: the expensive 8k/12k tiers fire on ~1โ5 % of queries โ the default stays cheap. Force one with
--full/--xl, or pick a mode with--mode lexical|semantic|hybrid|pattern.
Also available as sweet-search "<query>" on the CLI and the search MCP tool.
2. โก ss-grep โ grep, minus every wasted millisecond
10.2ร faster than ripgrep end-to-end at the median โ measured across 353 realistic queries on 5 real repos (range 8.5โ17.7ร per repo, 1 ms p50), with identical match counts on every single query. Three things buy that:
- A sparse n-gram index (inspired by Cursor's fast-regex-search and GitHub's Blackbird): instead of a fixed trigram table, gram boundaries adapt to your codebase's character-pair frequencies, so common trigrams get absorbed into longer, more selective grams.
- Regex-AST literal extraction + SIMD intersection: required substrings are pulled from the pattern's syntax tree, posting lists are intersected with NEON/SSE2 block merges (galloping search for skewed sizes), and only the files that can match โ typically 0.1โ5% of the corpus โ see the real regex.
- Fully in-process: verification runs on Rust's regex crate with Rayon across all cores, inside the warm daemon, in a single NAPI call. No child process is ever spawned โ zero fork/exec, zero pipe I/O, zero JSON re-parsing.
Every match comes back in stable file:line order โ ripgrep-identical counts, optional context lines โ with no relevance guessing, no subprocess, in one warm call.
- Full methodology, per-repo table, and the optimization log:
docs/GREP_INDEXING_STRATEGY.md. - Regexes with no extractable literals fall back to native grep over the indexed file set; fixed-string and glob queries use a ripgrep fallback.
- Dialect recovery (agent mode): patterns written in GNU-grep BRE muscle memory (
foo\|bar,\(group\)) are literals in Rust's regex dialect and used to silently match nothing โ a zero-hit exact search now gets one gated auto-retry with the translated pattern instead of a false "no matches".
3. ss-find โ ColGrep, on a faster engine
ss-find "token refresh logic" --regex "refresh.*[Tt]oken"
Inspired by LightOn's ColGrep โ regex precision, semantically ranked โ but rebuilt on our own substrate:
- The regex stage runs on the same indexed sparse-gram engine as
ss-grep(in-process, no subprocess), not a filesystem scan. - The ranking stage scores candidates with per-token MaxSim over pre-indexed late-interaction embeddings โ no model inference over documents at query time โ on our custom kernels: native Rust + Rayon takes a 231-candidate MaxSim pass from 1.26 s down to 27 ms (WASM SIMD fallback at 16ร).
- Regex tokens are merged into the semantic query, so the ranking sees both what you typed and what you matched.
- Like
ss-search, it answers with ranked, self-contained code snippets โ not barefile:lineโ so the find and the read collapse into one tool call. In our 30-question agent-workflow eval that eliminated every follow-up read and cut tokens 25.4% vs a grep + read workflow, at quality parity (gap of 0.01 on a 5-point scale). - On the 60-query pattern benchmark, MaxSim ranking lifts MRR@10 to 0.45 vs 0.11 for raw grep ordering โ 4ร more likely the right hit lands on top.
- Requires the late-interaction index (built by default;
--li-model nonedisables pattern mode). - Also available as
sweet-search --mode patternand via thesearchMCP tool'sregexargument.
4. ss-semantic โ hybrid retrieval, scoped to one file
ss-semantic src/auth/session.ts "where does the cookie get its expiry?"
You know the file; this finds the lines. Every indexed chunk of the file is scored by three independent signals โ BM25-style lexical term match, exact symbol-name match (weighted 1.5ร), and per-token MaxSim late interaction over the LateOn-Code embeddings โ fused with Reciprocal Rank Fusion (k=60), with symbol-less fragment chunks demoted 0.85ร so real definitions win ties. The top spans are then re-read from disk (ยฑ2 context lines, overlapping spans merged), so the answer is filesystem ground truth even mid-edit; if the file is newer than its index entry you get an explicit staleness warning.
The useful answer: just the relevant spans with line numbers โ not the whole file through your context window.
- Unindexed files degrade gracefully to a plain read. Defaults: top 5 spans, relevance threshold 0.4, 8k-char cap.
- Also available as
sweet-search read-semanticand theread-semanticMCP tool.
5. ss-trace โ graph algorithms, not grep guesswork
ss-trace processOrder --in src/orders/service.py
One call returns a symbol's callers, callees, and transitive impact paths from the AST-derived code
graph (entities + typed calls/imports/extends/uses edges, persisted in SQLite at index time).
Ranking fuses three signals:
- Query-time Personalized PageRank via Forward Push โ a local algorithm that spreads mass directionally from your target symbol and touches only the neighborhood it reaches, never the whole graph;
- Index-time edge-weighted global PageRank (damping 0.85), precomputed into a
page_rankcolumn โ a function called from five sites carries five units of mass, and it costs zero at query time; - Structural heuristics โ relationship type, depth, exported-API status, fan-in โ with penalties for test-only and external paths.
Because the graph is prebuilt, the global ranking is precomputed, and the personalized walk is local,
a full three-section trace costs milliseconds. The relation word (callers / callees / impact)
re-weights how the response token budget is split; --in disambiguates duplicate names; --depth
bounds impact traversal (1โ4).
- Honest caveat: call-graph extraction is precise but incomplete on highly dynamic code (bare-name dispatch, metaprogramming) โ traces can be sparse there, and the agent prompt teaches a recovery strategy for exactly that case.
- Also available as
sweet-search traceand thetraceMCP tool.
6. ss-read โ exact bytes, with the index's knowledge attached
ss-read src/db/pool.js 120 180
A read tool that is filesystem-grounded by construction: bytes come straight from disk (never from the index, so never stale), but each indexed file arrives annotated with its cAST chunk metadata โ symbol name, entity type, signature, line span โ joined from the AST chunk index. The agent gets the code and the structural map of what it's looking at in one call: cite, navigate, or trace next without another search.
- The CLI/MCP form scales it up:
sweet-search read <file...>(and thereadMCP tool) batches 1โ20 files in a single call, each with the same symbol metadata โ twenty files for the price of one tool invocation. - Query-aware continuation (agent mode): a range read that stops before EOF names the unread symbols below it โ ranked by relevance to the session's recent queries, not just declaration order โ plus the exact command to continue.
- Shown-span receipts (agent
No comments yet
Be the first to share your take.