ken

by townsendmerino

Not rated
GitHub

About

Fast hybrid code search for agents - it's pure Go, single static binary, 5 lexical + Model2Vec semantic embeddings + RRF fusion + a code-aware reranker, with the retrieval algorithm ported verbatim from semble

Details

Author
townsendmerino
Categories
Developer Tools, Search, Knowledge Base

Setup

Install ken in your MCP client (Claude Desktop, Cursor, Windsurf, and others).

Repository: https://github.com/townsendmerino/ken

Follow the installation instructions in the repository README, then restart your MCP client.

Fast hybrid code search for agents.Pure Go, single static binary, drop-in MCP-compatible withMinishLab/semble— same tool schemas, same output format, install steps swapped to a Go binary.

ken is a Go port ofsemble: BM25 lexical + Model2Vec semantic embeddings + RRF fusion + a code-aware reranker, with the retrieval algorithm portedverbatimfrom semble'ssearch.py+ranking/.py.

- ~97% recall@10 in the default (hybrid) mode0.967 NL / 0.995 symbolon semble's 1,251-query benchmark, vs grep's ~99.9% — while costing an agent~46× fewer tokensthangrep + Read(4,120 vs 189,773 median tokens on NL queries — measured in the same default hybrid mode). For "find the chunk that answers this," that's a 1–2 order-of-magnitude token win at near-parity recall. (Reproduce:docs/BENCH.md.)
- Single static binary.Pure Go, no cgo, no Python interpreter on cold start, no GIL on indexing. Cross-compiles to Linux / macOS / Windows (amd64/arm64) for free.
- Drop-in for semble.Samesearch/find_relatedMCP tool schemas and the same markdown-string wire format — swap thecommand:path and existing agents work unchanged.
- Local, CPU-only.Embedding inference, BM25, and fusion all run on the CPU. No API keys, no GPU, no vector DB, air-gapped friendly.

One knob controls recall.The82–91%figure in the token-budget tables is theBM25-only fallbackken runs in when no embedding model is installed.ken-mcp fetches the model automatically on first run(~60 MB, pure-Go, no Python — serves bm25 until it lands, then upgrades to the~97%hybrid path;KEN_MCP_AUTO_FETCH=0to disable). For the CLI, runken download-modelonce. Exhaustive enumeration (refactors, pre-rename audits) still belongs to grep; ken is for "find the chunk that answers this."

- ARCHITECTURE.md— current-state map: module layout, runtime/concurrency model, data flow, invariants. Start here for the code.
-
docs/USERS.md— agent users. Install ken-mcp, point your agent at it, use the nine tools. 5-minute on-ramp.
-
docs/DEVELOPERS.md— SDK authors and tuners. Themcp.Runembedded-corpus library, prebuilt indices,fs.FSindexing, custom chunkers, tuning rerank, performance expectations.
-
docs/DESIGN.md+docs/internal/DECISIONS.md— algorithm spec + every architectural decision (ADRs).
-
docs/BENCH.md— benchmark reproduction (NDCG, token-budget recall, the hybrid-vs-BM25 decomposition).

# macOS / Linux (Homebrew) — installs both ken and ken-mcp: brew install --cask townsendmerino/tap/ken
# Windows (Scoop): scoop bucket add townsendmerino https://github.com/townsendmerino/scoop-bucket scoop install ken
# Install both binaries (Go 1.26+). go install github.com/townsendmerino/ken/cmd/ken@latest go install github.com/townsendmerino/ken/cmd/ken-mcp@latest # Download the default Model2Vec model (~60 MB, one-time). Pure Go, no Python. # (ken-mcp auto-fetches this on first run; the CLI needs it explicitly.) # This is the single biggest retrieval-quality lever — it puts you on the ~97% path. ken download-model # Search any local repo from the CLI. ken search /path/to/myrepo "save model to disk" --model ~/.ken/model

Or skip the model and use lexical-only mode (BM25-only costs ~14 pp recall@10 vs the hybrid default — seedocs/BENCH.md):

ken search /path/to/myrepo "validateToken" --mode bm25

Not sure your setup is right?ken doctorchecks model availability, rerank-cache warmth, enrichment, token-savings tracking, and ken-mcp config, and prints prioritized recommendations (e.g. "no model — runken download-model").

Pre-built binaries formacOS, Linux, and Windows(amd64/arm64) are attached to eachrelease—.tar.gzfor macOS/Linux,.zipfor Windows.

As of v0.3,ken index <path>defaults towatch mode— it stays alive and re-indexes on change (2 s debounce);--no-watchrestores build-once-and-exit.ken-mcpalways watches, so an agent editing the repo mid-session sees its own changes without a restart. ken also respectsnested.gitignorefiles (per-directory, matching git).

ken-mcpspeaks JSON-RPC over stdio and serves the same two core tools (search,find_related) semble does, with the same arg shapes and markdown output.

# Claude Code claude mcp add ken -s user -- /absolute/path/to/ken-mcp
// ~/.cursor/mcp.json (or .cursor/mcp.json) — also .vscode/mcp.json with "servers" { "mcpServers": { "ken": { "command": "/absolute/path/to/ken-mcp" } } }
# ~/.codex/config.toml [mcp_servers.ken] command = "/absolute/path/to/ken-mcp"
// ~/.opencode/config.json { "mcp": { "ken": { "type": "local", "command": ["/absolute/path/to/ken-mcp"] } } }

The default above runs ken-mcp as alocal subprocess— the right choice for most setups (the OS-user boundary is the auth boundary; nothing is network-exposed). For acentralized dev box, staging server, or team-shared instance— one ken-mcp feeding many agents, or a remote IDE not co-resident with the code — ken-mcp also speaks MCP overStreamable HTTP(KEN_MCP_TRANSPORT=http, ADR-041). Same tools, same wire format; agents already trained on the stdio server work unchanged.

This exposes ken-mcp to the network, so auth is mandatory and several guards fail loud at startup:

# On the server (front with a TLS-terminating reverse proxy — ken-mcp does NOT do TLS): export KEN_MCP_TRANSPORT=http export KEN_MCP_ADDR=:8080 # default export KEN_MCP_AUTH_TOKEN_FILE=/etc/ken/token # preferred (keeps the secret out of the environment) export KEN_MCP_DEFAULT_REPO=/srv/code export KEN_MCP_RATE_LIMIT=100 # req/min per client IP (0 disables); default 100 ken-mcp # exits non-zero if no token is set

Point an agent at it with a bearer token (Claude Code shown; any Streamable-HTTP MCP client works):

claude mcp add --transport http ken https://ken.example.com \ --header "Authorization: Bearer $TOKEN"
// Cursor / VS Code mcp.json — remote form (check your editor's remote-MCP docs) { "mcpServers": { "ken": { "url": "https://ken.example.com", "headers": { "Authorization": "Bearer <token>" } } } }

Guards: HTTP moderefuses to start without a token(no insecure default, no localhost exception);KEN_DB_SAMPLE_ROWS>0ishard-rejectedin HTTP mode (sampled DB values would be network-searchable); requests are rate-limited per client IP. TLS is out of scope by design — terminate it at a reverse proxy in front of ken-mcp. stdio stays the default and is completely unaffected.

The full env reference — including theKEN_DB_database variables — is indocs/USERS.mdanddocs/db-indexing.md. For agents that should route between ken and grep deliberately (rather than ken's default "prefer ken" instruction), see the routing snippet in[docs/USERS.md.

No reviews yet — be the first

Sign in to leave a review

Use Google, GitHub, or an email account so ratings stay tied to real people.

Email sign in

No reviews posted yet.