ken
Búsqueda híbrida rápida de código para agentes: es Go puro, binario estático único, 5 incrustaciones semánticas léxicas + Model2Vec + fusión RRF + un reranker consciente del código, con el algoritmo de recuperación portado textualmente de semble
Documentación
ken
Búsqueda híbrida rápida de código para agentes. Go puro, binario estático único, compatible con MCP como reemplazo directo de MinishLab/semble — mismos esquemas de herramientas, mismo formato de salida, pasos de instalación cambiados a un binario Go.
ken es un port a Go de semble: BM25 léxico + embeddings semánticos Model2Vec + fusión RRF + un reranker consciente del código, con el algoritmo de recuperación portado verbatim desde search.py + ranking/*.py de semble.
Por qué ken
- ~97% recall@10 en el modo (híbrido) predeterminado — 0.967 NL / 0.995 símbolo en el benchmark de 1,251 consultas de semble, vs ~99.9% de grep — mientras le cuesta a un agente ~46× menos tokens que
grep + Read(4,120 vs 189,773 tokens medianos en consultas NL — medido en el mismo modo híbrido predeterminado). Para "encuentra el fragmento que responde esto", eso es una ganancia de tokens de 1–2 órdenes de magnitud con recall casi a la par. (Reproducir:docs/BENCH.md.) - Binario estático único. Go puro, sin cgo, sin intérprete de Python en arranque en frío, sin GIL en indexación. Compila cruzado a Linux / macOS / Windows (amd64/arm64) gratis.
- Reemplazo directo para semble. Mismos esquemas de herramientas MCP
search/find_relatedy mismo formato de cadena markdown — cambia la rutacommand:y los agentes existentes funcionan sin cambios. - Local, solo CPU. Inferencia de embeddings, BM25 y fusión se ejecutan en la CPU. Sin claves de API, sin GPU, sin base de datos vectorial, compatible con entornos aislados.
Una perilla controla el recall. La cifra 82–91% en las tablas de presupuesto de tokens es el respaldo solo-BM25 que ken ejecuta cuando no hay un modelo de embeddings instalado. ken-mcp descarga el modelo automáticamente en la primera ejecución (~60 MB, Go puro, sin Python — sirve bm25 hasta que llega, luego mejora a la ruta híbrida ~97%;
KEN_MCP_AUTO_FETCH=0para deshabilitar). Para la CLI, ejecutaken download-modeluna vez. La enumeración exhaustiva (refactorizaciones, auditorías previas a renombrados) sigue perteneciendo a grep; ken es para "encuentra el fragmento que responde esto."
Dónde empezar
- ARCHITECTURE.md — mapa del estado actual: diseño de módulos, modelo de runtime/concurrencia, flujo de datos, invariantes. Empieza aquí para el código.
- docs/USERS.md — usuarios agentes. Instala ken-mcp, apunta tu agente a él, usa las nueve herramientas. On-ramp de 5 minutos.
- docs/DEVELOPERS.md — autores de SDK y ajustadores. La biblioteca de corpus embebido
mcp.Run, índices preconstruidos, indexaciónfs.FS, chunkers personalizados, ajuste de rerank, expectativas de rendimiento. - docs/DESIGN.md + docs/internal/DECISIONS.md — especificación del algoritmo + cada decisión arquitectónica (ADRs).
- docs/BENCH.md — reproducción de benchmarks (NDCG, recall de presupuesto de tokens, la descomposición híbrido-vs-BM25).
Inicio rápido
Instala mediante un gestor de paquetes:
# 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
O con Go:
# 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
O salta el modelo y usa el modo solo-léxico (solo-BM25 cuesta ~14 pp recall@10 vs el híbrido predeterminado — ver docs/BENCH.md):
ken search /path/to/myrepo "validateToken" --mode bm25
¿No estás seguro de que tu configuración sea correcta? ken doctor verifica disponibilidad del modelo, calidez de caché de rerank, enriquecimiento, seguimiento de ahorro de tokens y configuración de ken-mcp, e imprime recomendaciones priorizadas (ej. "sin modelo — ejecuta ken download-model").
Binarios precompilados para macOS, Linux y Windows (amd64/arm64) están adjuntos a cada release — .tar.gz para macOS/Linux, .zip para Windows.
A partir de v0.3, ken index <path> por defecto usa modo watch — permanece activo y re-indexa al detectar cambios (debounce de 2 s); --no-watch restaura compilar-una-vez-y-salir. ken-mcp siempre observa, así un agente que edita el repositorio a mitad de sesión ve sus propios cambios sin reiniciar. ken también respeta archivos .gitignore anidados (por directorio, coincidiendo con git).
Instalar como servidor MCP
ken-mcp habla JSON-RPC sobre stdio y sirve las mismas dos herramientas principales (search, find_related) que semble, con las mismas formas de argumentos y salida markdown.
# 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"] } } }
Transporte remoto (Streamable HTTP)
El predeterminado anterior ejecuta ken-mcp como subproceso local — la opción correcta para la mayoría de configuraciones (el límite usuario-OS es el límite de autenticación; nada está expuesto a la red). Para un servidor de desarrollo centralizado, servidor de staging o instancia compartida por equipo — un ken-mcp alimentando muchos agentes, o un IDE remoto no co-residente con el código — ken-mcp también habla MCP sobre Streamable HTTP (KEN_MCP_TRANSPORT=http, ADR-041). Mismas herramientas, mismo formato de cable; agentes ya entrenados en el servidor stdio funcionan sin cambios.
Esto expone ken-mcp a la red, por lo que la autenticación es obligatoria y varios guardas fallan ruidosamente al arrancar:
# 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
Apunta un agente a él con un token bearer (se muestra Claude Code; cualquier cliente MCP Streamable-HTTP funciona):
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>" } } } }
Guardas: el modo HTTP se niega a arrancar sin token (sin predeterminado inseguro, sin excepción de localhost); KEN_DB_SAMPLE_ROWS>0 es rechazado duramente en modo HTTP (valores de BD muestreados serían buscables en la red); las solicitudes tienen límite de tasa por IP de cliente. TLS está fuera de alcance por diseño — termínalo en un proxy inverso frente a ken-mcp. stdio sigue siendo el predeterminado y no se ve afectado en absoluto.
Variables de entorno principales
| Variable | Predeterminado | Propósito |
|---|---|---|
KEN_MCP_DEFAULT_REPO | (sin establecer) | Fuente preindexada; permite que las herramientas omitan el argumento repo. |
KEN_MCP_MODE | hybrid | bm25 / semantic / hybrid. Sirve bm25 mientras el modelo falta — se obtiene en la primera ejecución por defecto (ver KEN_MCP_AUTO_FETCH). |
KEN_MCP_MODEL_DIR | ~/.ken/model | Ruta a una instantánea de Model2Vec que contiene model.safetensors. Recurre a ~/.ken/model (donde ken download-model escribe) cuando no está establecido. |
KEN_MCP_AUTO_FETCH | 1 | En la primera ejecución con un modo que requiere modelo y sin modelo presente, obtiene potion-code-16M (~60 MB) en segundo plano, sirviendo bm25 hasta que llegue y luego actualizando a híbrido. 0 lo desactiva (sirve bm25, advierte). |
KEN_MCP_CHUNKER | regex | regex / treesitter / line / markdown. Ver Elegir un chunker. |
KEN_MCP_CACHE_SIZE | 16 | Límite LRU en la caché repo→Index. |
KEN_MCP_LOG_LEVEL | warn | debug / info / warn / error. Todos los registros van a stderr; stdout es el canal JSON-RPC (detalles). |
KEN_MCP_TRANSPORT | stdio | stdio (subproceso local, predeterminado) o http (Streamable HTTP de red — ver Transporte remoto). |
KEN_MCP_ADDR | :8080 | Dirección de enlace HTTP (solo modo http). Sin TLS en proceso — coloque un proxy inverso al frente. |
KEN_MCP_AUTH_TOKEN / …_TOKEN_FILE | (sin establecer) | Token Bearer para modo http (_FILE preferido). Requerido — el modo http no se iniciará sin él. |
KEN_MCP_RATE_LIMIT | 100 | Solicitudes/min por IP de cliente (modo http); 0 lo desactiva. KEN_DB_SAMPLE_ROWS>0 se rechaza en modo http. |
KEN_MEMLIMIT | (sin establecer) | Límite de memoria suave para el servidor de larga duración (1GiB, 512MiB o un recuento de bytes), aplicado mediante debug.SetMemoryLimit. Anula GOMEMLIMIT cuando ambos están establecidos. ken-mcp también establece GOGC=50 por defecto (RSS de estado estable más bajo) a menos que establezca GOGC usted mismo. |
KEN_MCP_SHUTDOWN_GRACE | 5s | Después de un SIGINT/SIGTERM, cuánto tiempo permitir que las llamadas de herramientas en vuelo se drenen antes de forzar la salida (cualquier duración Go). Un drenaje limpio sale con 0; una salida forzada es estado 1, y una segunda señal fuerza la salida inmediata con 128+señal (130 / 143). |
KEN_MCP_SNAPSHOT | 1 | Persistir el índice construido en <repo>/.ken/ y, al reiniciar, cargarlo + escaneo de deriva (mtime+tamaño) en lugar de reconstruir cuando el repositorio no ha cambiado — la ruta rápida de frío cotidiano. .ken/ es una caché (seguro de eliminar; agréguelo a .gitignore). Solo repositorios de ruta local. 0 desactiva lectura+escritura. |
KEN_MCP_LAZY_ENRICH | 0 | Diferir el enriquecimiento estructural fuera de la ruta de construcción en frío: servir un índice crudo para una primera consulta rápida en una construcción verdaderamente fría (~2–3× más rápido de servir por primera vez en PHP), luego enriquecer + republicar en segundo plano. Los resultados están bien formados antes del enriquecimiento, solo con menor clasificación hasta que la pasada en segundo plano llegue. Solo afecta una construcción desde cero; una carga de instantánea ya está enriquecida. Opt-in mientras la calibración por defecto está pendiente. |
KEN_MCP_EMBED_CACHE | 0 | Caché persistente de sha256(chunk)→vector en <repo>/.ken/embed.db, de modo que una reconstrucción completa re-embeba solo texto de fragmento nunca visto (semántico/híbrido, repositorios locales). Segunda línea de defensa detrás de la instantánea — ayuda a reconstrucciones recurrentes (deriva pesada, cambio de modo). Con ámbito de modelo (un cambio de modelo lo limpia). Opt-in; la primera construcción lo calienta (aproximadamente a la par con sin caché). KEN_MCP_EMBED_CACHE_MAX limita entradas (predeterminado 1,000,000). |
KEN_MCP_STAGED | 0 | Preparación escalonada: en una construcción híbrida en frío, sirva BM25 (solo léxico) instantáneamente (~4× más rápido de primera consulta en PHP), luego enriquezca + embeba en segundo plano y actualice a híbrido. Las respuestas de herramientas llevan "semantic":"warming" hasta que la actualización llegue. Tiene precedencia sobre KEN_MCP_LAZY_ENRICH. Opt-in; solo afecta una construcción desde cero (una carga de instantánea ya está completa). |
KEN_MAX_FILE_BYTES | 2MiB | Omitir archivos más grandes que esto de la indexación (512KiB / recuento de bytes). Se aplica a ken index y ken-mcp. Redúzcalo en repositorios con muchos artefactos para reducir el índice + memoria. |
KEN_MAX_AVG_LINE_BYTES | 1000 | Omitir archivos minificados cuyo encabezado muestreado promedie más de este número de bytes por línea (paquetes JS/CSS construidos, JSON de una sola línea). 0 desactiva la heurística. |
KEN_SKIP_GENERATED | 0 | Desactivado por defecto: establezca 1 para también omitir código fuente generado cuyo encabezado lleve una etiqueta @generated o un banner Code generated … DO NOT EDIT (stubs de protobuf, listadores client-go, stringer/mockgen). Captura archivos generados que la heurística de minificación no detecta. Opt-in porque algunos corpus quieren su superficie generada buscable. Se aplica a ken index y ken-mcp. |
KEN_MAX_FILES | 1000000 | Límite de admisión en el recuento de archivos indexables — un repositorio por encima se rechaza con un error en lugar de arriesgar OOM. Generoso por defecto (el kernel de Linux es ~80k archivos); redúzcalo para endurecer un servidor contra repositorios hostiles, 0 = ilimitado. |
KEN_ENRICH_FILE_BUDGET_MS | 500 (ken-mcp); 2000 (ken index/search/bench/perf); 0 (ken build-index, biblioteca) | Límite de reloj de pared por archivo en el enriquecimiento Arm B / análisis estructural de tree-sitter. Un archivo cuyo análisis lo excede se omite (indexado sin su etiqueta estructural — los resultados no se ven afectados, solo sin enriquecer), se registra y se cuenta. Protege contra archivos individualmente patológicos similares a plantillas que el límite de tamaño no detecta (ejemplo real: grandes matrices de inicializadores designados en C estilo controlador, gotreesitter#1100). 0 lo desactiva. Desactivado por defecto solo para ken build-index y llamadores directos de biblioteca (BuildAndSerializeIndex), para mantener esa construcción específica byte-determinista. |
KEN_ALLOW_PRIVATE_CLONE_TARGETS | 0 | Desactivado por defecto: para URLs de http(s) repo, ken rechaza direcciones loopback / link-local / RFC1918 (guardia SSRF). Establezca 1 para permitir hosts git internos. |
KEN_MCP_ALLOWED_REPO_ROOTS | (sin establecer) | Confinar argumentos de repo de ruta local proporcionados por el agente a estas raíces (separados por lista de rutas del sistema operativo, como PATH). Sin establecer = sin confinamiento (cualquier ruta local) — y ken-mcp registra una advertencia de seguridad de inicio fuerte en ese caso, ya que un servidor de larga duración cuyo agente también maneja contenido no confiable podría ser dirigido a leer archivos arbitrarios. El análogo de ruta local de la guardia SSRF de clonación: establecerlo evita que el agente apunte ken a /etc, ~/.ssh, etc. (y silencia la advertencia). KEN_MCP_DEFAULT_REPO está exento (el operador lo avaló). Los enlaces simbólicos se resuelven antes de la verificación. |
La referencia completa de variables de entorno — incluidas las variables de base de datos KEN_DB_* — está en docs/USERS.md y docs/db-indexing.md. Para agentes que deberían enrutar entre ken y grep deliberadamente (en lugar de la instrucción predeterminada de ken "preferir ken"), vea el fragmento de enrutamiento en docs/USERS.md.
Herramientas
Ambas herramientas principales devuelven una cadena de markdown formateada idéntica a la salida de _format_results de semble. (ken-mcp también expone siete herramientas estructurales — definition, references, callers, outline, symbols, recently_changed, status — además de reindex_db cuando una base de datos está configurada; ver docs/USERS.md.)
search
| Argumento | Tipo | Requerido | Predeterminado | Descripción |
|---|---|---|---|---|
query | string | ✓* | — | Consulta en lenguaje natural o código. *Proporcione query o queries. |
queries | string[] | — | Lote de consultas en una sola llamada (ahorra viajes de ida y vuelta); resultados agrupados por consulta. El mismo modo/top_k/filtros se aplican a cada una. Limitado a 20. | |
repo | string | — | URL de https:// / http:// o directorio local. Requerido si no hay KEN_MCP_DEFAULT_REPO. | |
mode | hybrid|semantic|bm25 | hybrid | Modo de búsqueda. | |
top_k | int | 5 | Número de resultados (limita el recuento). | |
max_tokens | int | — | Presupuesto opcional de tamaño de respuesta. top_k limita el recuento, pero un fragmento puede ser pequeño o enorme; con max_tokens establecido, ken llena la lista clasificada de arriba hacia abajo y descarta la cola una vez que el costo estimado de tokens lo excedería (el resultado superior siempre se mantiene). Aproximado — ken no incluye un tokenizador BPE, por lo que es una heurística, no un recuento exacto. | |
explain | bool | false | Anotar cada resultado con por qué coincidió: qué términos de consulta aparecen en el fragmento (kind=lexical) o que surgió por similitud semántica sin superposición exacta de términos (kind=semantic). Una explicación de superposición léxica para depurar "¿por qué está esto aquí?", no un desglose completo de clasificación. |
find_related
| Argumento | Tipo | Requerido | Predeterminado | Descripción |
|---|---|---|---|---|
file_path | string | ✓ | — | Ruta tal como aparece en un resultado de search. |
line | int (1-indexado) | ✓ | — | Una línea dentro del fragmento para sembrar la búsqueda de similitud. |
repo | string | — | Igual que para search. | |
top_k | int | 5 | Número de fragmentos similares. | |
max_tokens | int | — | Presupuesto opcional de tamaño de respuesta; misma semántica que search. |
Lo que ken indexa
La recuperación híbrida de ken está calibrada para código fuente (Python / Go / TypeScript / Java / Rust tienen fragmentación consciente del lenguaje; otros recurren al fragmentador de líneas) y documentación (markdown fragmentado en límites de encabezado, bloques de código/tablas mantenidos atómicos, frontmatter manejado). Los corpus mixtos de código y documentación se enrutan por archivo según la extensión.
También indexa esquemas de bases de datos junto con código — archivos estáticos de .sql (con plegado de historial de migraciones) e introspección en vivo de Postgres / SQLite / MySQL / MariaDB — de modo que un agente que responda "cómo se autentican los usuarios" obtenga la función Go, el SQL que ejecuta, la definición de tabla users y las relaciones de clave foránea en una sola lista clasificada. Referencia completa (Tier-1/Tier-2, muestreo de filas, LISTEN/NOTIFY, la herramienta reindex_db, postura de PII, todas las variables KEN_DB_*): docs/db-indexing.md.
Para prosa simple sin código o documentos estructurados, el modo BM25 (--mode=bm25) lleva la carga; el modelo semántico está entrenado en código y no validado en texto literario.
Excluyendo archivos: .kenignore
ken respeta sus archivos .gitignore (anidados, por directorio). Pero muchos repositorios confirman archivos que no desea buscar — migraciones generadas, paquetes JS/CSS construidos, código vendido, fixtures. Coloque un .kenignore en la raíz del repositorio (o en cualquier subdirectorio) para excluirlos de la indexación. Usa la misma sintaxis que .gitignore, se aplica en el momento de la indexación y es honrado tanto por ken index como por la vigilancia en vivo de ken-mcp:
# .kenignore — keep built + generated files out of the search index
web/assets/ # compiled front-end bundles
vendor/ # Composer / third-party PHP
runtime/ # Yii runtime cache + logs
**/migrations/*.php # generated DB migrations
*.min.js
*.min.css
Semántica: unión con .gitignore (una ruta se excluye si cualquiera la ignora), evaluada independientemente de modo que un !negation en un archivo no pueda re-incluir lo que el otro excluyó. .kenignore está activado por defecto — un repositorio sin uno se comporta exactamente como antes. Para una migración directa desde semble, ken también honra .sembleignore como respaldo cuando no hay .kenignore presente (.kenignore gana si ambos existen). En monorepositorios grandes con artefactos confirmados, este es el mayor factor de influencia en el tamaño del índice, el tiempo de inicio en frío y la memoria. Ver ADR-038.
Incluso sin un .kenignore, ken omite automáticamente archivos de más de KEN_MAX_FILE_BYTES (2 MiB) y archivos minificados (longitud promedio de línea muy larga — bundles compilados, JSON de una sola línea) mediante KEN_MAX_AVG_LINE_BYTES. .kenignore es para las rutas específicas del repositorio que esas heurísticas no detectan.
Omisión de código generado (opt-in). Establece KEN_SKIP_GENERATED=1 para omitir también archivos cuyo encabezado lleva un marcador de generación automática — @generated, o un banner de Code generated … DO NOT EDIT (stubs de protobuf, listadores de client-go, salida de stringer/mockgen). Esto detecta código fuente generado que parece normal para la heurística de minificación. Desactivado por defecto, porque algunos corpus legítimamente quieren que su superficie generada sea buscable (un agente que pregunta "dónde está el cliente tipado para X" quiere ese archivo generado). Se respeta tanto en el índice inicial como en la vigilancia en vivo.
Cómo funciona
gitignore + .kenignore respecting walk
→ regex chunker (Python / Go / TS / Java / Rust) with line-chunker fallback
→ BM25 (Lucene variant, k1=1.5, b=0.75) + Model2Vec semantic (cosine over a dense matrix)
→ α-weighted RRF fusion (α auto-detected: 0.3 for symbol queries, 0.5 for NL)
→ file-coherence boost + query-type boosts (definition / embedded-symbol / stem-match)
→ path penalties (test files, compat / legacy, `.d.ts`) + file-saturation decay
→ top-k
El algoritmo de recuperación es un port verbatim de search.py + ranking/*.py de semble; consulta docs/DESIGN.md §7 para cada constante y sutileza del orden del pipeline, y §4 para el contrato de inferencia de Model2Vec (safetensors de tres tensores, la indirección de mapping[], la precisión float64 que es crítica para la paridad de coseno).
Comparación con semble
| Propiedad | semble | ken |
|---|---|---|
| Lenguaje / distribución | Python · uvx / pip | Go · binario estático único |
| Arranque en frío | ~500 ms (intérprete + numpy + modelo) | ~10–20 ms ken search sobre un índice pequeño |
| Algoritmo de recuperación | implementación de referencia | port verbatim (constantes + orden del pipeline de search.py + ranking/*.py) |
| NDCG@10 en el benchmark de semble | 0.854 | 0.842 híbrido (brecha 0.012, 63 repos × 1,251 consultas completas) |
| Recall@10 en consultas de agentes | (no medido) | ~0.97 híbrido (0.967 NL / 0.995 símbolo); respaldo solo-BM25 ~0.84 |
| Tokens para recall@10 | (no medido) | ~46× menos que grep+Read en consultas NL (4,120 vs 189,773 mediana, híbrido) |
| Servidor MCP | sí | sí — drop-in (mismos esquemas + formato de cable) |
| Tamaño del binario | n/a | release (slim) ken ~22 MB · ken-mcp ~38 MB |
Requiere huggingface-cli | sí | no — ken download-model obtiene directamente de HF |
La metodología completa, el desglose por ablación (semántico-crudo coincide con semble dentro de 0.003, validando el port de embedding + tokenizer + ANN), el ancla externa CoIR-CSN-Python, y cada nota al pie están en docs/BENCH.md.
Comparado con otras herramientas de búsqueda de código para agentes
La parte concurrida de esta categoría se divide en un eje: qué tienes que ejecutar. La apuesta de ken es que el modelo de embedding pertenece dentro del binario — inferencia Model2Vec pura en Go, sin cgo — así que no hay nada más que levantar: sin daemon de embeddings, sin base de datos vectorial, sin clave API, aislado de la red. Los dos puntos de comparación más cercanos:
- grepai — el análogo arquitectónico más cercano: un binario Go único con un vigilador de archivos y un servidor MCP, 100% local. Descarga los embeddings a un servidor Ollama separado (instalas + ejecutas Ollama y descargas un modelo).
- claude-context (Zilliz) — el más visible: búsqueda híbrida BM25 + densa, pero respaldada por una base de datos vectorial (Milvus autoalojado vía Docker, o Zilliz Cloud gestionado) y un proveedor de embeddings (API de OpenAI / VoyageAI / Gemini, o Ollama local).
| ken | grepai | claude-context | |
|---|---|---|---|
| Runtime | binario Go estático único (sin cgo) | binario Go único | Node/TS (npm) |
| Embeddings | en proceso, Go puro (Model2Vec) | daemon Ollama externo | proveedor externo (OpenAI / Voyage / Gemini, o Ollama) |
| Servicios externos necesarios | ninguno — obtiene automáticamente un modelo de ~60 MB, luego funciona sin conexión | Ollama (daemon + modelo) | base de datos vectorial (Milvus/Docker o Zilliz Cloud) + una API/daemon de embeddings |
| Recuperación | BM25 + denso + RRF + rerank consciente de código | denso + grafos de llamadas | híbrido (BM25 + denso) |
| Recall / NDCG | 0.967 recall@10 · 0.842 NDCG@10, con un harness de reproducción | no publicado | no publicado |
| Ahorro de tokens | ~46× vs grep+Read, medido + reproducible | no publicado | −39% reclamado por el proveedor vs una línea base |
| Velocidad | índice ~1.6 s / 13 k chunks; búsqueda híbrida p50 ~1.5 ms (medido) | proveedor: "10 k archivos en segundos, consultas en ms" | depende de la base de datos vectorial + red |
| Idiomas (estructural) | 13 (tree-sitter) | 10 | a nivel de chunk, agnóstico al idioma |
| Licencia | MIT | MIT | MIT |
Dos advertencias honestas. Primero, los números de ken incluyen comandos de reproducción (docs/BENCH.md); las celdas marcadas como "no publicado" significan que no encontramos una cifra de benchmark estándar para citar y no hemos evaluado de forma independiente la velocidad de los otros — arquitectura, dependencias y licencia son los ejes verificables (a junio de 2026). Segundo, las herramientas optimizan para cosas diferentes — grepai añade rastreo de grafos de llamadas; claude-context se apoya en una base de datos vectorial gestionada para escalar. La afirmación específica de ken es recall cercano a grep con ~1–2 órdenes de magnitud menos tokens, desde un solo binario sin servicios externos, cada número reproducible.
Elegir un chunker
El chunker regex por defecto maneja bien la mayoría de los casos. El chunker treesitter opt-in (--chunker=treesitter / KEN_MCP_CHUNKER=treesitter, gotreesitter puro en Go) gana de forma medible para Kotlin, Zig, TypeScript, Java, PHP y pierde en Python, C, Rust, Lua, Scala — Δ neto −0.004 NDCG en general (dentro del ruido), así que permanece opt-in. La tabla completa de recomendaciones por idioma está en docs/BENCH.md; la justificación de que el regex siga siendo el predeterminado es ADR-011.
Para autores de SDK: distribuye documentación como un solo binario
La biblioteca mcp.Run te permite hornear un corpus //go:embed + el modelo Model2Vec en un binario de servidor MCP estático — sin backend, sin base de datos vectorial, sin salida de red por consulta, con versión fijada por el artefacto de compilación. ~20 líneas de main.go, go build, publica en un release de GitHub; los usuarios brew install y añaden una línea a su configuración de agente. El walker y el indexador aceptan cualquier fs.FS (embed.FS, fstest.MapFS, respaldado por tarball), lo que también proporciona sandboxing del agente por construcción.
La guía completa — el patrón canónico, índices precompilados para arranque en frío rápido, el contrato de tamaño del binario, y el paquete mcp/db opt-in — está en docs/DEVELOPERS.md.
Demostraciones en vivo (binarios mcp.Run descargables sobre codebases reales, con transcripciones de auditoría): release demos/v0.1.0 — Kubernetes v1.31.0 (59,795 chunks) y PostgreSQL 17.0 (64,506 chunks). Escrito: Envié dos binarios descargables de búsqueda de código. La auditoría detectó dos errores..
Hoja de ruta
El registro de riesgos con disparadores explícitos está en docs/DESIGN.md §10; el tracker vivo de preparación para 1.0 es docs/internal/road-to-1.0.md. La recuperación se trata como cerrada para 1.0 (la curva de relevancia es plana); el trabajo restante es pulido + incorporación (llevar instalaciones nuevas al camino híbrido) + distribución.
Cómo se construyó esto
ken es un port. El algoritmo de recuperación es verbatim de MinishLab/semble (Python); la implementación en Go fue escrita por Claude bajo restricciones fijas: Go puro / sin cgo, constantes del algoritmo portadas verbatim y nunca ajustadas, la fuente original gana siempre que la reconstrucción de Claude diverja del código vivo de semble. Esa última regla detectó cinco errores materiales durante el port del pipeline de rerank — cada uno una alucinación de sonido confiado que era incorrecta al verificarse contra la fuente de Python. La disciplina de verificar siempre, la regla del port verbatim, y el harness de paridad del tokenizer de 11k entradas (que sacó a la luz tres errores que una verificación puntual de 18 casos pasó por alto) son aportados por humanos. Cada decisión arquitectónica está registrada en docs/internal/DECISIONS.md.
Agradecimientos
ken se apoya en los hombros de MinishLab — el algoritmo de recuperación, el modelo, todo el enfoque de tabla de embeddings son suyos.
- semble — la implementación original en Python. © Thomas van Dongen, MIT.
- model2vec — la biblioteca de embeddings estáticos cuyo formato de tres tensores ken implementa. © Thomas van Dongen, MIT.
- potion-code-16M — pesos del modelo, destilados de
nomic-ai/CodeRankEmbed(MIT), a su vez deSnowflake/snowflake-arctic-embed-m-long(Apache-2.0). © Minish Lab. Redistribuido segúnNOTICE.
Licencia
ken tiene licencia MIT. Incluye atribución para los pesos del modelo redistribuidos en NOTICE y una lista generada de licencias de dependencias en THIRD_PARTY_LICENSES.md; cada enlace en la cadena de procedencia es permisivo (MIT, Apache-2.0, MPL-2.0). Consulta docs/DESIGN.md §6.
Para contribuyentes: CLAUDE.md tiene las convenciones de compilación/pruebas/formato y los invariantes del proyecto (contrato de precisión, contrato de stdout/stderr).