Slimdex
Recuperación de código precisa para agentes de codificación: esquemas, cuerpos de símbolos, gráficos de dependencias y memoria persistente en lugar de lecturas de archivos completos.
Documentación
slimdex-mcp
Tu agente lee un archivo de 900 líneas para cambiar una función — y luego paga por ese archivo de nuevo en cada turno siguiente. Toda la conversación se reenvía cada vez, así que una lectura temprana no es un costo único. Es un alquiler.
Slimdex es un servidor MCP local que les da a los agentes de codificación recuperación estrecha en su lugar: el esquema de un archivo, el cuerpo de un símbolo, quién lo llama, qué se rompe si cambia — y memoria que sobrevive a la sesión, para que el próximo chat comience informado en lugar de re-derivar el repositorio desde cero.
claude mcp add slimdex -- npx -y slimdex-mcp
~50% menos tokens en uso diario — ~55–60% en trabajo pesado de navegación, ~45% en trabajo pesado de salida, y 85–90% en el peor caso para el que fue construido (un archivo de 6,200 líneas, explorado a través de un esqueleto y 12 cuerpos de símbolos en lugar de cuatro lecturas completas).
Estado: 1.1.0, en npm y en el Registro MCP. Esos números son auto-medidos en los repositorios donde se ha ejecutado, sesiones individuales, no validados independientemente — y
statscuenta caracteres, no tokens. Lee Lo que está realmente verificado antes de confiar en ello.
| Herramienta | Qué devuelve |
|---|---|
index_repo | Construye/actualiza un índice persistente de símbolos e importaciones; solo los archivos cambiados se re-analizan |
outline_file | Declaraciones de un archivo con números de línea |
get_file_skeleton | Firmas con cuerpos omitidos, anidamiento preservado |
read_lines | Un rango de líneas |
get_symbol_context | Un cuerpo de función/clase ±2 líneas, limitado por maxLines; names:[...] trae varios cuerpos en una sola llamada |
search_code | path:line:col + la línea correspondiente con resaltado de caret; paginación con limit/offset/cursor |
find_definition | Sitio(s) de definición de un símbolo como path:line:col |
search_symbols | Búsqueda difusa por nombre de símbolo, clasificada exacto→prefijo→subcadena→subsecuencia |
search_intent | Consulta en lenguaje natural clasificada sobre símbolos por BM25 (sin embeddings) — encuentra código por lo que hace |
context_pack | Una llamada: clasifica los símbolos de un tema, muestra cómo se conectan, y agrupa los cuerpos principales bajo un presupuesto — toda la exploración en un solo viaje de ida y vuelta |
find_references | Referencias textuales como path:line:col + función contenedora |
find_tests | De las referencias a un símbolo, cuáles viven en archivos de prueba — o una advertencia de que ninguna lo hace |
replace_symbol | Sobrescribe el cuerpo de un símbolo dirigido por nombre (sin reenviar código antiguo); primero hace instantáneas, re-indexa después |
get_context | Una llamada: definición / firma / llamadores / importaciones / dependientes opt-in, con presupuesto |
repo_map | Conteos de archivos/líneas/símbolos a nivel de directorio; path: profundiza en los archivos más grandes de un directorio |
changed_files | Archivos cambiados + en qué símbolos cae cada hunk |
dep_graph | imports / dependents / un diagrama Mermaid (root+depth BFS) |
stats | Conteos de llamadas por herramienta y tamaños de respuesta, en caracteres, más seguimiento de lectura y disciplina de escritura |
batch | Ejecuta varias llamadas en una sola solicitud |
recap | Actividad de sesiones anteriores, reconstruida automáticamente desde el diario de llamadas de herramientas del servidor — funciona incluso cuando no se guardó nada |
brief | Abridor de sesión de un solo disparo: resumen del repositorio + enfoque derivado del diario + conclusiones guardadas verificadas contra el índice en vivo (✓ vivo / ⚠ posiblemente obsoleto) |
digest_save / digest_get | Guarda una hoja de trucos compacta de arquitectura del repositorio una vez; léela de vuelta con un veredicto de frescura por archivo cubierto, para que la próxima sesión omita re-explorar |
snapshot | Copia archivos no confirmados en .slimdex/snapshots/ (también se ejecuta automáticamente cada hora vía index_repo en un árbol sucio) — seguro contra resets accidentales, no un sustituto para hacer commit |
memory_save/search/list/delete | Notas duraderas en .slimdex/memory.json |
La guía de recuperación a continuación también se incluye en el instructions del servidor, para que los clientes la inyecten automáticamente en el contexto del modelo.
Flujo de agente recomendado
brief primero, al comienzo mismo de una sesión — una llamada que informa qué es el repositorio, dónde estaban cavando las sesiones recientes, y qué conclusiones guardadas aún coinciden con el código (las obsoletas se marcan), para que un chat nuevo comience informado en lugar de en blanco. Luego get_context("Foo") para responder "¿qué es esto, quién lo llama, de qué depende" en una sola respuesta. Para entender un área completa en lugar de un símbolo, context_pack("how does auth work") ejecuta toda la exploración del lado del servidor y devuelve un único paquete acotado — los símbolos relevantes, cómo se conectan, y los cuerpos principales — para que gastes una llamada y una entrada de transcripción en lugar de diez. ¿No sabes el nombre, solo lo que hace? — search_intent("parse the config file") clasifica símbolos por intención con BM25, sin embeddings. Baja a get_symbol_context para un cuerpo (se marca a sí mismo si el archivo se desvió del índice, para que no tengas que releer para verificar), get_file_skeleton para la forma de un archivo, y read_lines cuando necesitas el código fuente exacto. Antes de editar un símbolo, find_tests sobre él para ver qué lo cubre; para reescribir una función completa, replace_symbol (envías solo el nuevo cuerpo — el código antiguo no se reenvía solo para localizar la edición). Usa batch para agrupar varias búsquedas. Cada herramienta de búsqueda acepta limit (por defecto 20) y offset.
Presupuesto de respuesta: las secciones de get_context son opt-in vía include (por defecto: definición, firma, llamadores, importaciones — agrega body o dependents explícitamente), los llamadores están limitados por callerLimit, y la respuesta está acotada por maxChars (por defecto 12,000). Cada límite que se dispara imprime un aviso explícito (showing 3 of 68, truncated at maxChars=...) en lugar de descartar datos silenciosamente. get_symbol_context limita su alcance con maxLines de la misma manera, y memory_list devuelve los 50 hechos más recientes a menos que se indique lo contrario, como vistas previas de ~150 caracteres en lugar de cuerpos completos (memory_get ids:[...] los expande, full:true vuelca todo). En un almacén de 18 hechos, esa es la diferencia entre ~4,100 y ~18,600 caracteres en la llamada con la que cada sesión abre.
Config: <root>/.slimdex.json (opcional)
{
"ignoreDirs": ["fixtures", "backend/src/main/resources/static/assets"],
"extensions": [".astro", ".vue"],
"suffixes": [".stories.mdx"],
"exclude": ["generated/", "legacy/vendor"],
"maxFileBytes": 2000000
}
suffixes coincide con un final de nombre de archivo, para tipos de archivo que una extensión no puede identificar. Los sidecars de metadatos de Salesforce vienen integrados: AccountSvc.cls-meta.xml, panel.js-meta.xml y Account.object-meta.xml se indexan, mientras que pom.xml, web.xml y manifest/package.xml no — agregar .xml a extensions habría arrastrado cada árbol de configuración en el repositorio. Los archivos con coincidencia de sufijo se indexan para búsqueda y alcance de lectura, no para símbolos.
Se fusiona sobre la lista de ignorados integrada (node_modules, dist, .venv, .svelte-kit, Pods, .pytest_cache, …). Una entrada de ignoreDirs es o un nombre simple, que coincide con cualquier directorio así llamado a cualquier profundidad, o una ruta que contiene /, anclada en la raíz del repositorio y respetando los límites de directorio (src/gen no ignorará también src/generated). index_repo hace eco de lo que cargó y advierte sobre claves desconocidas, tipos incorrectos o JSON inválido, para que una configuración con errores tipográficos no sea silenciosamente indistinguible de ninguna.
La salida de compilación generalmente no necesita configuración en absoluto. Más allá de la lista de directorios, cualquier archivo cuyas líneas superen ~5,000 caracteres se trata como salida de compilación minificada y se deja fuera del índice — los bundlers eliminan los saltos de línea, y el código fuente escrito a mano no se ve así. Esto captura lo que una lista de nombres estructuralmente no puede: un bundle con nombre hash (index-B7xK2p9q.js) dentro de un directorio llamado assets. assets, public y static deliberadamente no se ignoran por nombre, porque el código fuente real vive en ellos; index_repo informa el conteo como skipped(minified build output): N.
Cómo funciona el ahorro de tokens
No hay truco de compresión. El ahorro es conductual: estas herramientas permiten que un agente recupere esquemas, rangos y ubicaciones en lugar de archivos completos, y el índice persistente significa que las búsquedas repetidas golpean una consulta en caché en lugar de una relectura.
Dos sesiones posteriores, ejecutadas por diferentes modelos en diferentes formas de repositorio, agregaron números del mundo real al informe original:
Aplicación web de múltiples archivos, sesión de corrección de errores (GPT-5.3-Codex). 19 créditos reportados con slimdex; la estimación del propio modelo para el mismo alcance sin él: 45–70 créditos. Matemáticas: 19/45 → 19/70 ≈ 58–73% más barato. El contrafactual es la estimación del modelo, no un A/B medido — direccional.
Un solo archivo gigante (folio-app: un app.js de 6,200 líneas, 313 KB). Estadísticas propias de Slimdex: ~34,000 caracteres en 8 llamadas ≈ 9–10k tokens — un esqueleto (213 firmas), luego cuerpos de solo ~12 funciones relevantes, 9 de ellas obtenidas en una sola llamada get_symbol_context names:[...]. El camino ingenuo: 313 KB ≈ 78–85k tokens en 3–4 lecturas completas forzadas. Matemáticas: ~10k vs ~80k ≈ ~70k tokens ahorrados, una reducción del 85–90% en exploración. El diagnóstico del error (una ruta de exportación sin ruta de importación coincidente) era visible desde las firmas del esqueleto antes de abrir un solo cuerpo.
Juntos esbozan la ley de escala: el ahorro escala con cuánto código irrelevante arrastraría el camino ingenuo. Un archivo gigante es el mejor caso; un repositorio normal aterriza alrededor de la mitad a dos tercios más barato; un repositorio de archivos diminutos se equilibra. Mismas advertencias permanentes que todo aquí: las estadísticas cuentan caracteres, no tokens (÷3.5–4), y las sesiones individuales son evidencia, no puntos de referencia.
Ambas cifras anteriores miden solo lectura, que es la mitad más barata. La salida cuesta aproximadamente 4–5× la entrada, así que una edición indisciplinada desperdicia más que una lectura indisciplinada: reescribir una función completa a través de una herramienta de edición genérica significa reenviar todo el cuerpo antiguo solo para que la herramienta pueda localizarlo. replace_symbol se dirige por nombre y ese costo desaparece. stats informa esto junto con el seguimiento, porque la fuga es invisible de otro modo — el camino costoso aún produce una edición correcta, así que nada señala que pagaste de más:
write discipline:
replace_symbol: 0 call(s), 0 symbol(s) rewritten by name
changed outside slimdex: 12 file(s)
pre-edit checks (find_tests/dep_graph/get_context/changed_files): 0
Las ediciones externas se infieren de los hashes de contenido que se mueven entre dos ejecuciones de index_repo, así que el número es honesto sobre sus límites: ve que los bytes cambiaron, nunca qué herramienta los cambió, y un humano editando en otra ventana también cuenta.
La banda realista de todo el flujo de trabajo
Las cifras anteriores son números de exploración de un solo escenario — el mejor caso, donde el camino ingenuo habría arrastrado la mayor cantidad de código irrelevante. Promediado a lo largo de un día laboral real completo, no solo la porción de exploración, la banda se asienta más baja:
- ~55–60% en trabajo pesado de navegación — leer y entender un código base, donde la recuperación estrecha reemplaza las lecturas de archivos completos con mayor frecuencia.
- ~45% en trabajo pesado de salida — producir código nuevo, donde más del costo es generación que el servidor no toca (aunque
replace_symbolahora también reduce el lado de escritura). - ~50% promediado sobre el uso regular día a día. El ahorro se compone cuanto más sesiones pasan por él, porque
briefy la memoria significan que cada nuevo chat comienza informado en lugar de re-derivar el repositorio desde cero.
Úsalo regularmente a través de sesiones en tu IDE para obtener lo mejor de esto.
Trata estos como un solo punto de datos, no un punto de referencia. Un solo repositorio, una sola tarea, una ejecución A/B cada uno, auto-medido, sin repeticiones ni varianza. Tu kilometraje depende en gran medida de si tu agente realmente alcanza las herramientas estrechas en lugar de volver a leer archivos — lo cual varía según el cliente y el modelo. El método es repetible si quieres verificarlo: ejecuta la misma tarea en dos sesiones nuevas, una instruida a usar solo Slimdex y otra instruida a evitarlo, y compara la escritura de caché de /status.
Lo que está realmente verificado
Siendo explícito, ya que el resto de este README es fácil de sobre-leer.
Cubierto por la suite de pruebas unitarias (npm test ejecuta 224 pruebas en 23 archivos):
-
Extracción de símbolos en JS/TS (incl. métodos de clases y literales de objetos), Python, Go, Rust, Java/C#, y omisión de comentarios —
symbols.test.ts -
Extracción de importaciones para JS
import/require/export-from, Python, Rust -
Extracción de bloques, con ámbito por llaves y por sangría, con detección de cadenas/comentarios (comillas, plantillas,
//,/* */,#de línea completa) —extractBlock.test.ts -
Resolución de importaciones, clasificación de módulos externos, dependientes de aristas inversas, emisión de Mermaid y alcance de profundidad BFS desde la raíz —
graph.test.ts -
Formato de coincidencias de búsqueda, paginación sin solapamiento, conteo de ocurrencias por línea, totales exactos, escape/rechazo de expresiones regulares —
search.test.ts -
Reutilización de cursores opacos y rechazo de cursores malformados; respaldo del backend del analizador —
pagination.test.ts -
Detección de declaraciones de esquema vs. flujo de control —
outline.test.ts -
get_symbol_contextmaxLinespresupuesto y aviso de truncamiento -
Enmascaramiento de cadenas/comentarios y seguimiento de profundidad de llaves —
lexer.test.ts -
Extracción por lenguaje para los doce lenguajes compatibles —
languages.test.ts -
La caché del índice devuelve el mismo objeto hasta que el índice se reescribe
-
Carga de
.slimdex.json: cada clave aplicada mediante una construcción de índice real, además de los modos de fallo (JSON inválido, claves desconocidas, tipos incorrectos) que producen cada uno una advertencia visible en lugar de silencio —config.test.ts -
changed_filescontra un repositorio git temporal real: atribución hunk→símbolo, archivos sin seguimiento, refs base explícitos y formato; se omite limpiamente cuando git no está instalado —git.test.ts -
El observador de archivos, con eventos reales del sistema de archivos: un guardado se debouncea, se reindexa y llega al índice en disco —
watch.test.ts -
Aristas del grafo más allá de las importaciones: aristas de referencia de nombre para código sin importaciones (clase→clase usada, interfaz→implementación vía dependientes, disparador→manejador) y aristas de cableado declarativo desde XML del repositorio (enlace de metadatos→clase), con menciones de comentarios/cadenas excluidas y caché por construcción —
apexgraph.test.ts -
La caché de archivos en memoria sirve repeticiones sin releer y siempre sirve contenido fresco después de un cambio en disco —
fscache.test.ts -
Detección de archivos de prueba en convenciones JS/TS/Python/Go/Ruby/Java/C#, con separadores de Windows normalizados y código fuente ordinario (
latest.ts,Contest.java) no marcado incorrectamente —testlink.test.ts -
El lado de escritura: reemplazo del bloque de un símbolo, código final preservado y finales de línea CRLF vs LF mantenidos para que una edición no se reformatee en un diff de todo el archivo —
edit.test.ts -
Obsolescencia de memoria: un hecho se marca como vivo cuando nombra un símbolo/archivo que aún existe, se marca como obsoleto solo cuando cada mención de código desaparece, y se deja sin marcar para prosa — además de composición breve —
brief.test.ts -
Búsqueda por intención: tokenización camelCase/snake_case y clasificación BM25 que muestra un símbolo con nombre diferente por sus palabras de intención mientras puntúa una consulta no relacionada a nada —
intent.test.ts -
Frescura: un archivo más nuevo que su mtime indexado se lee como obsoleto (los números de línea pueden estar desviados), un mtime coincidente se lee como fresco y un archivo faltante nunca grita obsoleto —
freshness.test.ts -
Ensamblaje de
context_pack: encabezado + símbolos clasificados + cuerpos en un solo paquete, el mensaje de sin coincidencias, control de presupuesto de caracteres que aún garantiza el primer cuerpo y el límite máximo de símbolos —pack.test.ts -
El resumen de arquitectura: archivos cubiertos modificados después del resumen se leen como obsoletos, un resumen más nuevo se lee limpio, filtrado por alcance de cobertura y prefijo de directorio, y el veredicto renderizado fresco/obsoleto —
digest.test.ts
Cubierto de extremo a extremo, a través del servidor MCP real (integration.test.ts inicia
el servidor sobre stdio contra un repositorio de fixture temporal y afirma sobre la salida):
index_repo, repo_map, read_lines, get_file_skeleton, outline_file,
get_symbol_context, find_definition, find_references, find_tests (el acierto
y la advertencia de sin cobertura), search_intent (clasificación por intención), context_pack (paquete de una llamada),
digest_save/digest_get (ida y vuelta con veredicto de frescura),
get_context (incluyendo su límite de maxChars),
dep_graph (importaciones + mermaid), batch, search_code, search_symbols,
stats, brief, replace_symbol (ida y vuelta de escritura-luego-consulta y el
rechazo de símbolo desconocido), el ida y vuelta de memory_save/search/list/delete, el
guardia de escape de ruta y las rutas no encontradas.
CI ejecuta la compilación y ambas suites en Ubuntu + Windows, Node 20 y 22.
Advertencia sobre la prueba del observador: fs.watch recursivo es dependiente de la plataforma, por lo que
watch.test.ts se degrada a una omisión registrada en sistemas de archivos que nunca entregan un
evento — mismo comportamiento que el observador en sí. En Windows, macOS y Linux
actual, afirma la ruta completa de guardado→reindexación.
npm run smoke todavía existe pero solo prueba que el pipeline está vivo — las
afirmaciones de corrección viven en integration.test.ts.
Verificado por inspección: src/ no contiene llamadas de red — ningún código sale de
tu máquina. Esto puedes comprobarlo tú mismo:
grep -rE "fetch\(|https?://|axios|http\.request" src/.
Documentación más larga
En docs/:
tool-guide.md— cada herramienta explicada dos veces (técnicamente y en palabras simples) con un ejemplo cada una, el flujo de trabajo combinado y cómo funciona la persistencia basada en mtimetool-guide.html— la misma guía como una página estilizada y autocontenida para el navegadortoken-savings-report.md— la medición A/B original, su método y cómo repetirlaagent-brain.md— la disciplina operativa completa como un documento legibleagent-brain-slim.md— la indicada para colocar en un repositorio como CLAUDE.md / AGENTS.md. Autocontenida y de una página: escalera de ahorros, tabla de pregunta→herramienta, disciplina de memoria, higiene de sesión, límites honestos, perillas de entorno. Misma cobertura que el documento completo con ~30% de la prosa, porque las reglas de herramientas son tablas densas en lugar de párrafos que el servidor ya inyecta.
Cobertura de lenguajes
Dos mediciones, porque los fixtures por sí solos prueban muy poco.
Fixtures — uno por lenguaje, contando las declaraciones a las que un desarrollador
navegaría realmente: 65/65 encontrados, 0 falsos positivos, fijados por
test/languages.test.ts.
Código real de terceros — extracción ejecutada sobre ~11,800 archivos de varios cientos de paquetes reales (React, Babel, Remix, Socket.io, Playwright, Three.js, Emotion, zod, ajv …) y comparada contra una heurística escrita independientemente para lo que cuenta como declaración: 95.9% de recuperación. Reprodúcelo tú mismo:
npm run audit -- ./node_modules # or any directory of code you didn't write
Ese número es un piso, no una calificación — la heurística de verdad cuenta algunas no-declaraciones, por lo que la recuperación real es un poco más alta. Su propósito es detectar regresiones y encontrar la próxima brecha real.
Sobre frameworks
Casi nada que falló la auditoría era específico de un framework. Los frameworks agregan anotaciones, decoradores y convenciones; rara vez inventan sintaxis. Maneja el lenguaje y los frameworks vienen con él — las capas Application/Domain/Selector/ Service/UnitOfWork de fflib se extraen completamente (129 declaraciones) sin una sola regla específica de fflib.
La única excepción genuina son los DSL de prueba. Un archivo vitest/jest/mocha/RSpec a menudo
no tiene declaraciones de nivel superior, por lo que directorios de prueba enteros solían indexarse a
nada. Los títulos de describe/it/test ahora se indexan como tipo test, que es
a lo que realmente navegas en un archivo de prueba.
Las semánticas de frameworks se recuperan dondequiera que la referencia exista en algún lugar del repositorio, a través de dos fuentes de aristas adicionales en el grafo:
- Aristas de referencia de nombre, para lenguajes que no tienen declaración de importación (p. ej.
Apex): si el código de un archivo — con comentarios y cadenas enmascarados — menciona un
tipo de nivel superior definido en otro archivo, eso es una arista. Esto es lo que hace
que
implementssea respondible como "quién implementa esta interfaz", y vincula un disparador a la clase de manejador que instancia. - Aristas de cableado declarativo: enlaces que los frameworks mantienen en configuración
en lugar de código (registros de metadatos personalizados, definiciones de flujo) generalmente viven
en el repositorio como XML con el nombre del tipo como valor de elemento. El XML del repositorio se escanea
para nombres de tipos conocidos — comentarios XML excluidos — y cada acierto se convierte en una
arista de
metadata-file → class, por lo quedependentsresponde "qué conecta esto".
Ambos escaneos se almacenan en caché por construcción de índice y no cuestan nada en repositorios sin tales
archivos. Fijados por apexgraph.test.ts. Lo que ningún lector estático puede ver es un
enlace que existe solo en un sistema en vivo — configurado en una organización o base de datos en ejecución
y nunca recuperado al repositorio. Si no está en el repositorio en ninguna
forma, no hay arista que dibujar; busca el nombre del tipo en su lugar.
| Lenguaje | Extensiones | Lo que se reconoce |
|---|---|---|
| JavaScript / TypeScript | .js .jsx .mjs .cjs .ts .tsx .vue .svelte | clases, interfaces, tipos, enums, funciones, flechas de nivel superior, métodos de clase y literales de objetos |
| Apex | .cls .trigger | clases, clases internas, métodos (incl. @AuraEnabled, global, retornos genéricos), disparadores |
| Java | .java | clases, interfaces, enums, métodos, métodos genéricos con un <T> inicial |
| C# | .cs | clases, interfaces, structs, métodos async y genéricos, miembros virtuales |
| Kotlin | .kt | clases, clases de datos, interfaces, object, fun, suspend fun |
| Swift | .swift | clases, structs, enums, protocolos, func, static func |
| Python | .py | clases, def, async def, métodos dunder y decorados |
| Go | .go | funcs, métodos de receptor, tipos struct e interface |
| Rust | .rs | structs, enums, traits, fn, pub async fn, métodos impl |
| Ruby | .rb | clases, módulos, def, def self.x, attr_accessor/reader/writer |
| PHP | .php | clases, interfaces, traits, métodos, funciones |
| Scala | .scala | clases, clases de caso, traits, objetos, def con modificadores |
| C / C++ / Objective-C | .c .h .cpp .hpp .cc .m .mm | clases, structs, enums, funciones libres (incl. llaves K&R, retornos de puntero), definiciones fuera de clase de Foo::bar, ctors/dtors, namespaces, macros de #define similares a funciones, typedef struct {…} Name, @interface/@implementation/@protocol |
Rendimiento
El índice en frío es un análisis completo; el cálido es una verificación de mtime por archivo. Medido en Windows, Node 24.
| Repo | Archivos | Símbolos | Índice en frío | Índice cálido | Consulta típica |
|---|---|---|---|---|---|
| Organización Salesforce DX | 56 | 344 | 0.1 s | 15 ms | < 10 ms |
| Aplicación Java + React | 356 | 1,713 | 0.42 s | 26 ms | 3–57 ms |
| Estrés sintético | 5,000 | 50,000 | 1.5 s | 0.24 s | 5–22 ms |
El índice se mantiene en memoria y se invalida por el mtime del archivo de índice. Sin esa caché, cada llamada de herramienta releía y reanalizaba todo el índice — alrededor de 20 ms de peso muerto por llamada en el repo de 5,000 archivos, y crecía con el repo.
find_references es la herramienta más lenta a escala porque es un escaneo textual,
no una búsqueda de índice — pero un pre-filtro literal ahora omite la división de líneas y
la regex por línea para cualquier archivo cuyo código fuente crudo no contenga el nombre buscado,
que en un repo típico es la mayoría. Limita con pathPrefix para reducir las
lecturas de archivos restantes cuando sabes aproximadamente dónde buscar.
Los contenidos de archivos también se sirven desde un LRU en memoria con límite de bytes (64 MB,
validado por mtime+tamaño por acierto), por lo que el segundo escaneo de un repo — y la
secuencia skeleton→read_lines→context que los agentes realmente realizan en un archivo —
cuesta un stat() en lugar de una lectura.
Memoria entre sesiones
memory_save escribe en <root>/.slimdex/memory.json, que sobrevive al
proceso — un hecho guardado en un chat es legible en el siguiente, por un cliente
diferente, después de un reinicio. El chat y el editor comparten un solo almacén solo cuando ambos apuntan al
mismo SLIMDEX_ROOT.
Nada se captura automáticamente: el servidor nunca ve tu conversación, por lo que el agente tiene que decidir qué vale la pena conservar. Los instructions incluidos le indican que lea la memoria primero en una nueva sesión y que guarde decisiones, restricciones y trampas a medida que las aprende, pero eso es una guía para el modelo, no una garantía.
Limitaciones conocidas
- La extracción de símbolos es basada en regex y heurística, no un parser o LSP. Puede omitir declaraciones inusuales, y
find_referenceses una coincidencia textual que puede incluir identificadores con el mismo nombre pero no relacionados. - La extracción de símbolos y esquemas ahora se ejecuta sobre una copia enmascarada de cada línea, con el contenido de cadenas y comentarios en blanco, por lo que la prosa con forma de declaración dentro de una plantilla literal ya no se indexa como código. Las declaraciones también son conscientes de la profundidad: un
const x = () => …otype X = …cuenta solo a nivel superior, porque las variables locales dentro de un cuerpo de función no son cosas a las que alguien navegue. Los métodos de clase aún se indexan en su profundidad de anidamiento. - Un comentario en línea de Python
#que contenga una llave aún puede confundir la extracción de bloques (#también es el sigilo de campo privado de JS, por lo que no se puede eliminar a ciegas). changed_filesatribuye un fragmento a la declaración precedente más cercana — correcto para un cuerpo de función normal, aproximado para código entre declaraciones. Trátalo como radio de explosión, no como un grafo de llamadas.search_codeinforma un total exacto pero se detiene en un límite interno de escaneo en conjuntos de resultados muy grandes, imprimiendoN+ (scan cap reached)en lugar de un número incorrecto con confianza.- El soporte de lenguajes es desigual: JS/TS es el mejor cubierto. La familia C y Ruby, antes los más delgados, ganaron reglas dedicadas (funciones libres, definiciones
Foo::bar, macros similares a funciones,attr_*); los puntos débiles restantes son formas avanzadas de C++ — plantillas divididas en líneas, sobrecarga de operadores. - Para precisión de grado LSP, cambiarías el parser por tree-sitter o un servidor de lenguaje.
src/parser.tses la costura: una interfazParserseleccionada porSLIMDEX_PARSER, con el parser regex como la única implementación que se incluye. Un backend de tree-sitter podría insertarse allí sin tocar ninguna herramienta ni el formato de índice. No está construido — las gramáticas por lenguaje sacrifican la propiedad de "se instala al instante, funciona sin conexión, cero configuración".
Deliberadamente no construido
Ideas evaluadas y rechazadas, con razonamiento — son opiniones de diseño, no resultados medidos:
- Diccionarios de ID de símbolo (
S42→ ruta) — MCP no tiene capa de expansión en el cliente, por lo que el modelo recibe un token opaco que debe gastar otra llamada para resolver. - Gestores de presupuesto de tokens / estimadores de coste — las estimaciones de
chars/4no son fiables entre tokenizadores, y la auto-compresión con una mala estimación puede descartar datos que el modelo necesitaba. - Caché delta / "ya enviado, ver respuesta #5" — después de la compactación de contexto, la carga anterior desaparece, por lo que la referencia no resuelve a nada.
- Embeddings / búsqueda semántica — gran huella de dependencias; posible bandera opcional futura, no un valor predeterminado.
- Un backend de parser tree-sitter — este es el que cerraría el ~4% restante, y fue costeado en lugar de descartado a la ligera:
web-tree-sitteres WASM, por lo que no necesita compilación nativa, pero las gramáticas (tree-sitter-wasms) son 51.7 MB descomprimidas frente a ~4.5 MB de toda la instalación actual. Evaluado y rechazado con un recall medido del 95.9%, porque "se instala en un segundo, funciona sin conexión, sin configuración" es la propiedad que este servidor existe para tener.src/parser.tssigue siendo la costura si ese cálculo cambia alguna vez — un backend se inserta allí sin tocar una herramienta ni el formato de índice.
Instalación
Publicado en npm como slimdex-mcp, y listado en el Registro MCP como io.github.Siddhukaushik/slimdex-mcp. Nada que construir — apunta tu cliente a:
npx slimdex-mcp
O desde el código fuente, si quieres modificarlo:
git clone https://github.com/Siddhukaushik/slimdex-mcp
cd slimdex-mcp
npm install
npm run build # produces dist/index.js
npm test # vitest unit suite
Verifica que funcione de extremo a extremo contra un repositorio:
npm run smoke # this repo
node smoke-test.mjs "C:/path/to/some/repo" # any other
Variables de entorno
| Variable | Efecto |
|---|---|
SLIMDEX_ROOT | Repositorio a indexar (o pásalo como primer argumento CLI; por defecto, el directorio actual) |
SLIMDEX_WATCH | Establécelo a 1 para reindexar automáticamente al guardar archivos (observador nativo, sin dependencias) |
SLIMDEX_PARSER | Backend de parser; solo regex existe hoy |
SLIMDEX_PRETTY | Establécelo a 1 para restaurar el renderizado verboso y alineado a humanos: encabezados más largos y relleno de columnas en search_code, find_definition, search_symbols, find_references, repo_map, read_lines, outline_file. El modo conciso es el predeterminado — ese relleno es contexto que el modelo paga en cada turno posterior. SLIMDEX_TERSE=0 hace lo mismo. |
SLIMDEX_PROFILE | lean anuncia 15 herramientas en lugar de 29, reduciendo los esquemas de herramientas reenviados en cada turno de ~22,300 a ~12,600 caracteres. Las otras 14 (get_context, changed_files, find_tests, dep_graph, outline_file, search_symbols, recap, memory_list, memory_search, memory_delete, digest_save, digest_get, snapshot, stats) siguen funcionando y se llaman a través de batch — y las instrucciones del servidor las nombran bajo este perfil, para que el modelo sepa qué es solo por lotes en lugar de descubrirlo. Predeterminado full. |
SLIMDEX_NO_DEDUPE | Establécelo a 1 para deshabilitar la supresión de respuestas repetidas (una segunda llamada idéntica read_lines/get_file_skeleton/outline_file sobre un archivo sin cambios responde con un puntero a la llamada anterior en lugar del cuerpo; una tercera llamada idéntica reemite el contenido completo). |
La caché persistente
Por repositorio, Slimdex escribe en <repo>/.slimdex/:
index.json— el índice de código (invalidado por mtime por archivo, y descartado por completo cuando cambia la versión del formato de índice, por lo que un índice obsoleto construido por un extractor antiguo nunca se reutiliza)memory.json— hechos de memoria guardadosstats.json— contadores de uso por herramienta
El directorio se ignora a sí mismo: se escribe un * .gitignore dentro de él (el truco de node_modules/.cache), por lo que nunca aparece en git status y no tienes que tocar el .gitignore propio del repositorio. Elimina ese archivo interno si quieres confirmar la caché.
Conexión con clientes MCP
MCP es un estándar compartido, por lo que el mismo servidor debería conectarse a cualquier cliente compatible con MCP. La raíz del proyecto se pasa a través de SLIMDEX_ROOT (o como primer argumento CLI).
Solo Claude Code y Claude Desktop se han ejecutado realmente. Los demás a continuación son la forma de configuración estándar para cada cliente, escrita según su formato documentado — no están probados aquí y pueden necesitar ajustes.
Desde 1.0.0, la conexión más simple es npx -y slimdex-mcp — sin clonar, sin compilar, y se mantiene actualizado. Los ejemplos a continuación mantienen la forma node <ABS_PATH> para cualquiera que ejecute desde el código fuente; para usar el paquete publicado en su lugar, intercambia "command": "node", "args": ["<ABS_PATH>"] por "command": "npx", "args": ["-y", "slimdex-mcp"].
Reemplaza <ABS_PATH> con tu salida de compilación, p. ej. C:\path\to\slimdex-mcp\dist\index.js, y <REPO> con el repositorio a indexar.
No se requiere ajuste. Los ahorros importantes están activados por defecto en cada cliente: los hechos de memoria se listan como vistas previas, las respuestas son concisas, una relectura idéntica de un archivo sin cambios responde con un puntero en lugar del cuerpo, y varias ediciones de símbolos van en una sola llamada. Las variables de entorno a continuación son para optar por no participar, o para lean — que intercambia ~8,700 caracteres/turno adicionales por enrutar un tercio de las herramientas a través de batch, por lo que deliberadamente no es el predeterminado.
Claude Code (CLI) — probado
claude mcp add slimdex --env SLIMDEX_ROOT=<REPO> -- npx -y slimdex-mcp
Desde el código fuente en su lugar: -- node <ABS_PATH>.
Claude Desktop — probado
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"slimdex": {
"command": "npx",
"args": ["-y", "slimdex-mcp"],
"env": { "SLIMDEX_ROOT": "<REPO>" }
}
}
}
Codex CLI — probado
~/.codex/config.toml
[mcp_servers.slimdex]
command = 'C:\Program Files\nodejs\node.exe'
args = ['<ABS_PATH>']
startup_timeout_sec = 30
Registrado globalmente así, slimdex se adjunta a cada tarea de Codex y usa el directorio de trabajo de esa tarea como raíz del repositorio — no se necesita SLIMDEX_ROOT. Codex lanza el servidor con un entorno restringido, así que dale a command una ruta absoluta a node en lugar de confiar en PATH.
Cursor — no probado
.cursor/mcp.json (proyecto) o ~/.cursor/mcp.json (global)
{
"mcpServers": {
"slimdex": {
"command": "node",
"args": ["<ABS_PATH>"],
"env": { "SLIMDEX_ROOT": "${workspaceFolder}" }
}
}
}
Windsurf — probado
~/.codeium/windsurf/mcp_config.json — misma forma mcpServers que Cursor.
VS Code (Copilot / MCP) — probado
.vscode/mcp.json
{
"servers": {
"slimdex": {
"command": "node",
"args": ["<ABS_PATH>"],
"env": { "SLIMDEX_ROOT": "${workspaceFolder}" }
}
}
}
Cline (extensión de VS Code) — probado
Configuración de Cline → Servidores MCP → añadir:
{
"slimdex": {
"command": "node",
"args": ["<ABS_PATH>"],
"env": { "SLIMDEX_ROOT": "<REPO>" }
}
}
Zed — probado
settings.json → context_servers
{
"context_servers": {
"slimdex": {
"command": { "path": "node", "args": ["<ABS_PATH>"], "env": { "SLIMDEX_ROOT": "<REPO>" } }
}
}
}
Para clientes que exponen la carpeta de trabajo (Cursor, VS Code),
${workspaceFolder}mantiene a Slimdex apuntando al repositorio que tienes abierto.
Flujo de trabajo típico del agente
index_repouna vez al inicio (más rápido en ejecuciones posteriores), luegobriefpara retomar donde quedaron las sesiones anteriores con notas obsoletas ya marcadas.repo_map→ obtener una visión general.outline_fileen un archivo de interés → elegir rangos de líneas.read_linessolo para esos rangos.find_definition/find_references/dep_graphpara navegar.find_testsantes de editar un símbolo;replace_symbolpara reescribir uno sin reenviar su cuerpo anterior.memory_savedecisiones y trampas para que la próxima sesión comience informada.
Licencia
MIT © 2026 Kael VK Inc. (Número de negocio 751569161 RC0001) — ver LICENCIA.
Se proporciona tal cual, sin garantía ni soporte. Si no compila, no se ejecuta o no funciona en tu configuración, es tu responsabilidad — consulta el descargo de responsabilidad en la licencia.