Fast Context is a lightweight codebase context locator designed for coding agents (such as Codex, Claude, and similar LLM agents).
It provides a standalone Python CLI that integrates local Semble chunk prefetching with remote Windsurf (SWE-grep) symbol reasoning. This hybrid pipeline enables agents to rapidly pinpoint relevant files and line numbers in large repositories without drowning in context.
- Fast Local Prefetch: Retrieves cached code chunks in milliseconds using Semble.
- Remote Symbol Expansion: Injects local lexical anchors and query-relevant subtrees into Windsurf to verify and expand call chains.
- Graceful Fallback: Automatically degrades to local Semble chunks if remote requests hit rate limits, timeouts, or missing credentials.
- Token-Efficient Repo Maps: Ranks directories with BM25F and applies adaptive Top-K to build a focused Hotspot Repo Map, keeping payloads small while preserving exact file recall.
- Zero-Setup Credentials: Automatically extracts credentials from local Windsurf / Devin databases.
In large codebases, naive regex searches (like rg) miss high-level architectural semantics, while feeding full directory trees to remote models wastes context budgets and easily triggers rate limits. Fast Context bridges both worlds with a two-stage hybrid retrieval loop:
- Local Semantic Prefetch: Query Semble for warm, cached code chunk candidates.
- Lexical Anchoring: Extract exact candidate filenames, path tokens, and literal terms from the local repo.
- Hotspot Repo Mapping: Score directories with BM25F to construct an adaptive subtree map.
- Remote Verification: Pass local chunks, anchors, and the hotspot map to Windsurf for agentic verification (
rg,readfile,tree,ls,glob) and call-chain expansion. - Fallback on Failure: If the remote service is throttled or unavailable, return the local Semble chunks so the agent never stalls.
- Focused Handoff: Deliver 3-10 high-confidence candidate files with exact line ranges and suggested follow-up grep terms.
User Query
│
├── 1. Local Semble Prefetch ───> Cached Code Chunks
│
├── 2. Local Lexical Analysis ──> Extract Anchors & Hotspot Repo Map
│
└── 3. Remote Verification ─────> Windsurf Validates & Expands Call Chains
│
├─ (Success) ──> Return "Start Here" Files & Line Ranges
└─ (Failure) ──> Fall Back to Local Semble Chunks
Feeding a full, deep tree into an LLM context is expensive and noisy. Fast Context dynamically generates a query-shaped map:
- Repository Map: A compact top-level outline preserving global structural orientation.
- Relevant File Paths: Exact file paths surfaced by local lexical probes, prioritized when prompt budgets shrink.
- Hotspot Subtrees: Directories ranked by BM25F heat and expanded with adaptive
topK, providing granular visibility into likely feature areas.
In an A/B benchmark across 16 queries on a large private repository, hotspot maps delivered significantly higher exact-file visibility compared to traditional compact trees:
| Variant | File Recall | Deep Directory Coverage | File MRR | p50 Build Latency | Avg Map Size |
|---|---|---|---|---|---|
classic |
0.0000 | 1.0000 | 0.0000 | 10 ms | 2.4 KB |
hotspot |
0.4792 | 1.0000 | 0.0184 | 120 ms | 11.9 KB |
Note: The hotspot map trades roughly ~100 ms of local preprocessing and a slightly larger prompt payload for direct candidate-file visibility before remote verification begins.
fast-context/
├── benchmarks/
│ ├── data.py # Semble benchmark subset loader and pinned repo checks
│ ├── metrics.py # File-level retrieval metrics and bootstrap CIs
│ └── run_retrieval_benchmark.py # Paced local/remote/hybrid benchmark runner
├── assets/
│ └── images/
│ └── retrieval_benchmark_speed_vs_quality.svg
├── src/
│ ├── core.py # Protocol, search loop, repo map, local lexical anchors
│ ├── decision_layer.py # Lexical caller and guard expansion
│ ├── extract_key.py # Windsurf credential extraction from state.vscdb
│ ├── local_rank.py # Local noise demotion and sibling-app ranking
│ ├── local_repo_map.py # BM25F directory heat, adaptive topK, path spines
│ ├── local_semble.py # Local Semble adapter
│ └── fast_context_cli.py # CLI entrypoint for the skill
├── SKILL.md # Skill instructions
├── pyproject.toml
└── uv.lock
- Python
>=3.10 uv- A Windsurf login on the same machine, or
WINDSURF_API_KEY - Semble for local chunk search.
uv syncinstalls it as a normal runtime dependency. rgis optional but recommended. Python fallback search is built in.
Install dependencies into the project environment:
uv syncRun the CLI through uv:
uv run fast-context --helpRefresh the lockfile after dependency or Python-version changes:
uv lock --default-index https://pypi.org/simpleUse this when your coding agent needs fast repo orientation before editing, review, or debugging:
Use the installed `fast-context` skill for intent-based or open-ended codebase search when the exact path or symbol is not known yet.
Run:
python "$HOME/.agents/skills/fast-context/src/fast_context_cli.py" search \
--query "<natural language query>" \
--project "<repo-root>"
Notes:
- Prefer `fast-context` before `rg` for vague questions: debugging explorations, "where is X?", flow tracing, or feature-oriented repo navigation.
- If the exact filename, path, or symbol is already known, use `rg` or open the file directly instead of starting with `fast-context`.
- Prefer hybrid `search` when accuracy matters. Use `local-search` when a fast local candidate list is enough and you will verify the hits. Hybrid time is dominated by the remote Windsurf call, so a warm Semble cache does not make hybrid fast.
- Treat `fast-context` as a candidate-file generator, not a proof source. After it returns results, read the relevant files and use exact search only to confirm names, events, tests, or call sites.
- For "what decides whether X applies", read the `Callers / guard sites (low confidence, lexical):` section or run `find-related`, then open the guard definition.
- Pass an explicit path to `rg` (`rg -n pattern <repo-root>`). With no path, a non-interactive shell makes `rg` read stdin and wait.
- Split unrelated questions into separate `fast-context` queries. Long natural-language queries are fine when they describe one workflow, but multi-topic queries can drop weaker subtopics.
- Do not treat "results found" as evidence that a feature exists. For negative or fictional queries, `fast-context` may still return approximate matches; verify existence from the code before concluding.
- Prefer queries that describe behavior and data flow, not just nouns: include user action, runtime boundary, expected effect, and any known payload fields.
- If remote Windsurf search fails, use the returned local Semble results to keep moving.
uv run fast-context search \
--query "where is the desktop browser login handoff state validated" \
--project .Useful options:
--backend hybrid|remote|local(hybridis default)--tree-depth <1-6>--max-turns <1-5>--max-results <1-30>--timeout-ms <ms>--verbose(includes a[timing]breakdown)--no-decision-layeronsearchandlocal-search(alsoFAST_CONTEXT_DECISION_LAYER=0)--exclude <path-or-glob>repeatable--content code|docs|config|allfor Semble prefetch and local-only search
Example output:
Start here:
1. /repo/apps/desktop/src/auth/session.ts
- L18-102: applyExternalSession() - matches: handoff, state
2. /repo/apps/desktop/src/auth/handoff.ts
- L5-88: createAuthHandoff() - matches: handoff, desktop-launch
3. /repo/apps/desktop/test/ipc-auth-boundary.integration.test.ts
- L40-141: rejects external-session callbacks without state - matches: state
Follow-up search terms:
applyExternalSession, createAuthHandoff, handoff.*state
Callers / guard sites (low confidence, lexical):
- /repo/apps/desktop/src/auth/ipc.ts:40 calls applyExternalSession; guard requireTrustedHandoff defined at /repo/apps/desktop/src/auth/policy.ts:12
--backend hybrid runs Semble first, injects the top local chunks into the Windsurf search prompt, then asks Windsurf to verify and expand with restricted repo tools. If the remote path fails, including auth errors, timeouts, and upstream resource_exhausted, the CLI still returns the local Semble chunks so the agent can keep moving. Hybrid search is the accuracy path. Most of its time is the remote Windsurf call, so a warm Semble cache does not make hybrid fast. local-search is the fast Semble path when a local candidate list is enough.
search and local-search append Callers / guard sites (low confidence, lexical): for the top result files. It lists caller file:line and, when resolved, the guard definition file:line (at most about six entries). Guard names are also appended to the follow-up search terms. For "what decides whether X applies", read that section or run find-related, then open the guard definition. --no-decision-layer and FAST_CONTEXT_DECISION_LAYER=0 skip it.
Code queries demote (keep, with a lower score) *.sql, paths under deploy/ or migrations/, .env*, *.example, lockfiles, *.min.js, generated/, dist/, build/, and *.snap. A query that names sql, migration, env, deploy, or lock keeps those scores. Sibling roots under apps/<name>/, packages/<name>/, or services/<name>/ prefer the app named by the query or by the majority of the top hits (or hybrid anchors). The same basename stays higher in that preferred app. Local search fetches about twice --max-results before this rerank.
Run cached local chunk retrieval directly:
uv run fast-context local-search \
--query "how semantic and lexical scores are fused" \
--project .Search documentation or config:
uv run fast-context local-search \
--query "deployment guide" \
--project . \
--content docsFind chunks related to a prior result:
uv run fast-context find-related \
--file src/search.py \
--line 77 \
--project .Clear the cache for one project:
uv run fast-context cache-clear --project .Garbage-collect stale Semble cache entries whose indexed root_path no longer exists:
uv run fast-context cache-gcPreview without deleting:
uv run fast-context cache-gc --dry-runLocal install:
uv run fast-context extract-keyCopied database or Devin CLI credentials file:
uv run fast-context extract-key --db-path /tmp/state.vscdb
uv run fast-context extract-key --db-path ~/.local/share/devin/credentials.tomlAuto-discovery checks Devin CLI credentials on Linux/WSL first, then local app databases under Deviv, Devin, and Windsurf app data paths, probing both the canonical and lowercase directory spelling because installers disagree on casing (a Windows Devin install writes devin). Current installs may store either classic API keys or session-style credentials such as devin-session-token$.... This repo accepts either form as long as Windsurf/Devin accepts it.
Inside WSL the Linux Devin CLI credentials (~/.local/share/devin/credentials.toml) are what gets read; a key extracted on the Windows side can return 403 from WSL, in which case run devin login inside WSL and retry.
When no source is usable the error lists the paths that were searched. Credentials copied from another host can either be placed at one of those local paths so auto-discovery picks them up, or read directly by pointing WINDSURF_CREDENTIALS_DB at the copy.
WINDSURF_API_KEY: explicit credential overrideWINDSURF_CREDENTIALS_DB: explicit credentials file (state.vscdborcredentials.toml). When set, only that file is read and the local app-data paths are not probedWS_MODEL: optional model override. Default isswe-1-7; useswe-1-7-lightningto opt into LightningWS_FALLBACK_MODELS: optional comma-separated fallback chain. Default isMODEL_SWE_1_6_FAST,MODEL_SWE_1_5WS_REMOTE_LOCK_PATH: optional cross-process Windsurf lock file. Defaults to a per-user path under the system temp directoryWS_REMOTE_LOCK_TIMEOUT_MS: maximum wait for the shared remote slot. Default is120000WS_REMOTE_LOCK_POLL_MS: lock retry interval. Default is100WS_APP_VERWS_LS_VERFAST_CONTEXT_DECISION_LAYER: set to0(alsofalse,no, oroff) to skip lexical caller/guard expansionFAST_CONTEXT_JWT_CACHE: set to0to skip the on-disk user JWT cache. Otherwise the file is$XDG_CACHE_HOME/fast-context/jwt-<sha256(api_key)[:16]>.json, or~/.cache/fast-context/...whenXDG_CACHE_HOMEis unset. It is created mode0600and stores the token plusexp. The payloadexpis read without signature verification. A token with noexpis stored as fetched-at plus 10 minutes. It is reused only whileexp - 60sis still in the future. HTTP 401, HTTP 403, orunauthenticateddrops the file and refetches once. The token is never logged.- A successful
CheckUserMessageRateLimitpre-check is reused for about 30 seconds, in memory and inrate-ok-<hash>.jsonunder the same cache directory. A 429 is not cached.
Remote Windsurf sessions are serialized per local user with an OS-level file lock. Local repo-map construction and Semble prefetch still run concurrently; only JWT acquisition, rate-limit checks, model retries, fallback, and the remote semantic loop share the slot. The OS releases the lock if a process exits unexpectedly. If lock waiting times out, hybrid degrades to its local Semble results instead of adding another remote request.
Live validation on 2026-08-09 established these practical defaults:
- Current models use string
model_uidvalues. The default isswe-1-7; guessed numeric enum names such asMODEL_SWE_1_7_FASTare not used. swe-1-7andswe-1-7-lightningeach completed 3/3 candidate-only remote probes with fallback disabled and returned results. The client cannot observe the server-side model identity (_meta.modelonly echoes the requested uid), so these probes establish that the uid is accepted, not which backend model served the request.swe-1-7-lightningis an explicit opt-in throughWS_MODEL. Its tiny-fixture p50 was effectively tied with base SWE-1.7, so Lightning is not the default.- The default fallback order is
MODEL_SWE_1_6_FASTthenMODEL_SWE_1_5. SetWS_FALLBACK_MODELSto override it or to an empty string to disable fallback.
These results are empirical rather than guaranteed. Upstream capacity variance can affect both latency and success rate.
The original 12-query smoke test is replaced by a full 40-query run over the two Semble benchmark repos already synced locally on this machine:
fastapiatc3c9dd6b1a08(benchmark_root=fastapi)axiosatc7a76ddbf277(benchmark_root=lib)- 40 labeled queries total: 12
architecture, 17semantic, 11symbol
The benchmark runner is benchmarks/run_retrieval_benchmark.py. By default it mirrors Semble's protocol where that still fits this repo:
- reuse Semble annotation JSON as ground truth
- enforce pinned repo revisions before the run starts
- score all backends against the same file-level relevance targets
- file-level scoring is deliberate:
remotereturns file/range hits, whilelocalreturns chunks
- file-level scoring is deliberate:
- warm the local Semble cache once per repo, then measure query latency
- run
remoteandhybridsequentially with a completion-based cooldown- current fair defaults are
remote_cooldown_ms=10000,remote_jitter_ms=2000,retry_base_ms=15000,retry_max_ms=60000,max_retries=4 - cooldown is measured after each remote attempt completes, not just between request start times
- current fair defaults are
- alternate
remote/hybridorder per query to reduce order bias - compute 95% bootstrap confidence intervals from per-query metrics
Reproduce the run and regenerate the chart:
uv run python -m benchmarks.run_retrieval_benchmark \
--clear-local-cache \
--remote-cooldown-ms 10000 \
--remote-jitter-ms 2000 \
--retry-base-ms 15000 \
--retry-max-ms 60000 \
--max-retries 4 \
--output benchmarks/results/retrieval-fastapi-axios-2026-06-01.json \
--plot assets/images/retrieval_benchmark_speed_vs_quality.svgThe benchmark script looks for a sibling ../semble/benchmarks checkout by default. Override with SEMBLE_BENCHMARK_ROOT=/path/to/semble/benchmarks when needed.
Artifacts from the run:
- JSON summary and per-query traces:
benchmarks/results/retrieval-fastapi-axios-2026-06-01.json - Speed-vs-quality chart:
assets/images/retrieval_benchmark_speed_vs_quality.svg
Use benchmarks/run_repo_map_ab.py when tuning repo-map behavior. It compares the classic compact tree against the hotspot map without making remote Windsurf calls, so it is deterministic and safe to run on private repos.
Prepare a task JSON outside the repo when labels or paths are sensitive:
[
{
"category": "desktop-feature",
"query": "where is feature setup validated and persisted",
"relevant_paths": [
"apps/desktop/src/lib/feature-store.ts",
"apps/desktop/electron/ipc/feature.ts"
]
}
]Run it with a redacted repo label:
uv run python -m benchmarks.run_repo_map_ab \
--repo /path/to/repo \
--tasks /path/to/repo-map-tasks.json \
--repo-label private-large-repo \
--output /tmp/repo-map-ab.jsonThe main metrics are:
file_recall: exact labeled files visible in the map.deep_cover_recall: labeled files covered by a directory at depth two or deeper.file_mrr/deep_cover_mrr: how early the first exact file or covering directory appears.avg_size_bytesandp50_latency_ms: prompt and local preprocessing cost.
The 2026-06-01 baseline numbers below were recorded using an earlier test harness that paced requests solely by start-time intervals. Because each remote interaction took ~5 seconds, back-to-back runs quickly saturated upstream Windsurf rate limits. Consequently, older remote and hybrid results reflect heavy upstream throttling rather than pure model capability.
The current runner enforces completion-based cooldowns and bounded exponential backoff retries. Future benchmark refreshes will be published under these fairer pacing constraints.
| Backend | NDCG@10 | 95% CI | Recall@10 | 95% CI | Top-1 | MRR |
|---|---|---|---|---|---|---|
local (Semble only) |
0.854 | 0.774-0.926 | 0.946 | 0.875-1.000 | 0.775 | 0.850 |
remote (Windsurf only) |
0.453 | 0.309-0.604 | 0.467 | 0.312-0.617 | 0.450 | 0.475 |
hybrid (Two-stage) |
0.890 | 0.835-0.939 | 0.979 | 0.946-1.000 | 0.825 | 0.896 |
| Backend | Batch p50 Latency | Batch p90 Latency | Valid Output Rate | Remote Success | resource_exhausted / Fallbacks |
Total Retries |
|---|---|---|---|---|---|---|
local |
30 ms | 39 ms | 100% | N/A | 0 | 0 |
remote |
24.4 s | 37.5 s | 50% | 52.5% | 19 | 43 |
hybrid |
28.3 s | 40.0 s | 100% | 50.0% | 20 degraded | 44 |
Local warm-cache index build time (measured prior to query evaluation):
fastapi: 422 msaxios: 65 ms
| Query Category | local |
remote |
hybrid |
|---|---|---|---|
architecture |
0.718 | 0.506 | 0.819 |
semantic |
0.855 | 0.473 | 0.869 |
symbol |
1.000 | 0.364 | 1.000 |
localis a reliable, high-throughput baseline: With a warm p50 of30 msand strong retrieval metrics (0.854NDCG@10 /0.946Recall@10 with zero failures), it is ideal for CI, bulk evals, and latency-critical offline pipelines.hybridis the recommended interactive default: Combining Semble prefetch hints with Windsurf verification achieves top retrieval quality (0.890NDCG@10 /0.979Recall@10) while ensuring the agent never stalls due to remote limits. On a large private monorepo the hybrid median was about 7.8s, and a warm Semble cache did not shorten it, because the remote Windsurf call dominates.remoteserves as an ablation baseline: Useful for isolating raw Windsurf reasoning performance without prior local chunk hints.
Fast Context works best when configured as an agent skill via SKILL.md, but the CLI is equally suited for direct interactive exploration:
- Prefer hybrid
searchwhen accuracy matters: Submit natural-language queries with the default--backend hybrid. Most of that time is the remote Windsurf call, so a warm Semble cache does not make hybrid fast. - Use
local-searchfor a fast candidate list:--backend localreturns Semble chunks with no remote account. Read the hits before you treat them as the answer. - Trace one layer up for "what decides whether X applies": Read
Callers / guard sites (low confidence, lexical):, or runfind-relatedand then open the guard definition. - Confirm with exact search: Use
rgorast-grepon the candidate files. Pass an explicit path torg. With no path, a non-interactive shell makesrgread stdin and wait.
- Zero Middleware & No Telemetry: Fast Context runs completely locally. It does not host any proxy servers or intermediate backends, and collects no telemetry, tracking, or logs. The code is fully open source.
- Direct Official Communication: In hybrid or remote modes (
--backend hybrid/remote), all requests communicate directly from your machine to official Windsurf / Devin API endpoints using your local credentials. Any data processed or retained by those models is governed strictly by your agreement with Windsurf / Devin, independent of this project. - Fully Offline Local Search (
--backend local):- Indexing and search execute entirely on your machine using Semble with zero external network requests. All chunks and caches remain on local disk. Ideal for air-gapped environments or strict corporate compliance.
- Local Protection Safeguards:
- Path Sanitization: Real local absolute paths (e.g.
/Users/.../project) are masked and remapped to virtual/codebasepaths before leaving your machine, protecting local usernames and directory layouts. - No Repository Dumping: The codebase is never bundled or uploaded wholesale. Payloads are limited to queries, masked tree outlines (Repo Map), lexical anchors, and bounded code snippets read on-demand by model-instructed
rg/readfilecommands. - Local Sandboxing: Read-only tools invoked by the remote model run with strict root-directory boundaries, preventing access outside the project.
- Path Sanitization: Real local absolute paths (e.g.
- Lexical Anchors: Heuristically extracts exact filenames, path segments, and verbatim literals from the user query.
- Decision layer: After
searchandlocal-search, a bounded lexical pass looks for callers of symbols defined in the top files and for conditional guards around those calls. Failures are skipped.--verboseincludes this step in[timing]. - Local ranking: Code queries demote non-source noise and sibling-app duplicates after fetching extra candidates, then truncate to
--max-results. - Dynamic Tree Pruning: Repo maps prioritize top-level trees and exact lexical hits. When token budgets shrink, hotspot subtrees compress dynamically before falling back to classic compact trees.
- Cache Invalidation: Leverages Semble's native cache tracking, invalidating indexes incrementally only when files change.
- Verification Rule: Search results are candidate pointers rather than definitive proofs; agents should inspect targeted source files before committing edits.
MIT
On a private TypeScript monorepo (about 4.4k files, 5 known-answer questions), this release kept hybrid accuracy at 5/5 top3, cut median hybrid latency from 7.3 s to 6.7 s, raised local-search top3 from 4/5 to 5/5, and surfaced the cross-module guard for the "what decides whether it applies" question in 2/2 runs (was 0/2). Details: benchmarks/results/private-monorepo-ab-2026-10-12.md.