v1.3.0
ken v1.3.0 — cold-start campaign
ken-mcp no longer rebuilds the index from scratch on every launch.
Warm search in ken was always fast (tens of ms). The rough edge was cold
start — every IDE restart re-walked, re-chunked, re-parsed, and re-embedded the
whole repo before serving a single query. This release makes cold start a
one-time cost, not a per-launch tax, and adds opt-in modes that serve a first
query almost immediately on a true-cold index.
Motivated by #61.
The headline (on by default)
Persistent index snapshots + reconcile-on-boot. ken-mcp now persists the
built index to <repo>/.ken/ and, on restart, loads it and drift-scans
(config-key + per-file mtime/size) instead of rebuilding when the repo hasn't
changed. Edit a few files and restart? It reconciles only the changed files
rather than the whole tree.
Time to a servable first query — yii2 PHP corpus (~12k chunks), hybrid, M1 Pro, median of 3:
| scenario | before | after | speedup |
|---|---|---|---|
| restart, repo unchanged | 2.39 s | 573 ms | 4.2× |
| restart after a 1-file edit | 2.39 s | 746 ms | 3.2× |
It's safe by construction: any missing / corrupt / config-mismatched / drifted
snapshot silently falls back to a normal live build, and both on-disk loaders
are fuzzed against hostile input. .ken/ is a plain cache — delete it anytime;
add it to your .gitignore. Turn the whole thing off with KEN_MCP_SNAPSHOT=0.
(This is separate from, and coexists with, the ADR-024 operator prebuilt
.ken/index.bin.)
Serve-before-warm (opt-in)
For the first-ever index of a repo — where there's no snapshot to load yet —
three opt-in knobs move the expensive work off the first query:
| env var | what it does |
|---|---|
KEN_MCP_STAGED=1 |
Serve BM25 lexical results instantly on a cold hybrid build (~4.2× faster first query), then embed to full hybrid in the background. Responses carry "semantic":"warming" until the upgrade lands. |
KEN_MCP_LAZY_ENRICH=1 |
Defer the structural-enrichment tree-sitter parse off the cold path (serve raw, enrich in the background). |
KEN_MCP_EMBED_CACHE=1 |
Persistent sha256(chunk)→vector cache at <repo>/.ken/embed.db, so a full rebuild re-embeds only never-seen text. |
Also new:
ken index --write-snapshot— build once and persist, so a later
ken-mcplaunch on that repo loads instead of rebuilds (CI prewarming).- Lazy structural index —
ken-mcpdefers the symbol index for the
definition/references/callers/outline/symbolstools to first use,
removing a redundant full-corpus parse from every cold start. KEN_ENRICH_FILE_BUDGET_MS— a per-file wall-clock parse budget that
skips (and logs) a pathological template-like file the size cap misses.
Honest notes
- All numbers above are M1 Pro (10-core / 16 GB). The speedups should port,
but absolute times won't hold on a 4-core laptop — so the serve-before-warm
modes ship off by default until we've measured them on that hardware
class. If you run ken on a constrained machine, tryKEN_MCP_STAGED=1and let
us know how it lands. - Why "take the parse off the cold path" rather than "make it faster": the
gotreesitter0.20.5 → 0.47.0bump we shipped in 1.1.1 (a correctness fix)
regressed the PHP tree-sitter parse ~2.7×, and that parse is ~50% of cold
index time. Details + the upstream data point are in the repo docs. - Index throughput and warm-search latency are unchanged — the opt-in modes are
off by default, and the default index path is untouched.
Install / upgrade
brew upgrade ken # Homebrew
scoop update ken # Scoop
go install github.com/townsendmerino/ken/cmd/ken@v1.3.0
go install github.com/townsendmerino/ken/cmd/ken-mcp@v1.3.0No config changes needed — snapshots turn on automatically. Full details in
CHANGELOG.md.