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 local MCP 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 siguiente chat comience informado en lugar de re-derivar el repositorio desde cero.
claude mcp add slimdex -- npx -y slimdex-mcp
~50% menos tokens en el 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 de forma independiente — y
statscuenta caracteres, no tokens. Lee Lo que está realmente verificado antes de confiar en ello.
| Herramienta | Lo que devuelve |
|---|---|
index_repo | Construye/actualiza un índice persistente de símbolos + 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, limitado a 6,000 caracteres por defecto con una línea de continuación; establece maxChars cuando se necesita más |
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 coincidente 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 referenciado 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 aterriza cada fragmento |
dep_graph | imports / dependents / un diagrama Mermaid (BFS de root+depth) |
stats | Conteos de llamadas por herramienta y tamaños de respuesta, en caracteres, más la mezcla 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 compacto: resumen del repositorio + enfoque derivado del diario + conclusiones recientes verificadas contra el índice en vivo (✓ vivo / ⚠ posiblemente desactualizado); detail:"full" expande el resumen y las vistas previas de memoria |
digest_save / digest_get | Almacena una hoja de referencia compacta de la 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 restablecimientos accidentales, no un sustituto para confirmar |
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 de MCP del servidor, para que
los clientes la inyecten en el contexto del modelo automáticamente.
Flujo de agente recomendado
brief primero, al comienzo mismo de una sesión — una llamada que informa qué es el
repositorio, dónde estaban excavando las sesiones recientes, y qué conclusiones guardadas
aún coinciden con el código (las desactualizadas 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 solo 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, ejecuta 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 ubicar 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 supera 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.
Configuración: <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 archivos laterales 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 coincidentes por sufijo se
indexan para búsqueda y alcance de lectura, no para símbolos.
Se fusionan sobre la lista de ignorados integrada (node_modules, dist, .venv,
.svelte-kit, Pods, .pytest_cache, …). Una entrada de ignoreDirs es 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
también ignorará 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
excluye del índice — los empaquetadores 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 paquete 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ática: 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).
Las 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 de get_symbol_context names:[...]. El camino
ingenuo: 313 KB ≈ 78–85k tokens en 3–4 lecturas completas forzadas. Matemática: ~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 llega a punto de equilibrio. 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 ubicarlo. replace_symbol
se dirige por nombre y ese costo desaparece. stats informa esto junto con
la mezcla de lectura, 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 — produciendo 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 en el uso regular diario. 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 entre sesiones en tu IDE para obtener lo mejor de esto.
Trata estos como un punto de datos, no un punto de referencia. Repositorio único, tarea única, una
ejecución A/B cada uno, auto-medido, sin repeticiones o 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 por cliente y modelo. El método es
repetible si quieres verificarlo: ejecuta la misma tarea en dos sesiones nuevas, una
instruida para usar solo Slimdex y otra instruida para 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 objeto), 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 de llaves y de sangría, con conocimiento de cadenas/comentarios (comillas, plantillas,
//,/* */,#de línea completa) —extractBlock.test.ts -
Resolución de importaciones, clasificación de módulos externos, dependientes de arista inversa, emisión de Mermaid, y delimitación 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 -
Round-tripping de cursor opaco y rechazo de cursor malformado; respaldo de backend de analizador —
pagination.test.ts -
Detección de declaraciones de esquema vs. flujo de control —
outline.test.ts -
Presupuesto de
get_symbol_contextmaxLinesy aviso de truncamiento -
Enmascaramiento de cadenas/comentarios y seguimiento de profundidad de llaves —
lexer.test.ts -
Extracción por lenguaje para los doce lenguajes soportados —
languages.test.ts -
La caché del índice devuelve el mismo objeto hasta que el índice se reescribe
-
Carga de
.slimdex.json: cada clave aplicada a través de una construcción de índice real, además de los modos de fallo (JSON inválido, claves desconocidas, tipos incorrectos) cada uno produciendo 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 aterriza en el índice en disco —
watch.test.ts -
Aristas de grafo más allá de 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 erróneamente —testlink.test.ts -
El lado de escritura: reemplazar el 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 archivo completo —
edit.test.ts -
Obsolescencia de memoria: un hecho se marca como vivo cuando nombra un símbolo/archivo que aún existe, se marca obsoleto solo cuando cada mención de código ha desaparecido, y se deja sin marcar para prosa — además de composición breve —
brief.test.ts -
Búsqueda de intención: tokenización camelCase/snake_case, y clasificación BM25 que saca a la superficie 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 desfasados), 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 no coincidencia, 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 de 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 de intención), context_pack (paquete
de una llamada), digest_save/digest_get (round trip 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 (round trip de escribir-luego-consultar y el
rechazo de símbolo desconocido), el round trip 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 propio observador. En Windows, macOS, y Linux
actual afirma la ruta completa de guardar→reindexar.
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 ahorro, tabla de pregunta→herramienta, disciplina de memoria, higiene de sesión, límites honestos, perillas de entorno. Misma cobertura que el documento completo a ~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. Para lo que sirve es para detectar regresiones y encontrar la próxima brecha real.
Sobre frameworks
Casi nada de lo que falló la auditoría era específico de frameworks. Los frameworks añaden anotaciones, decoradores y convenciones; raramente 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 consciente 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.
La semántica de frameworks se recupera 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 — 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 enlaza 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) usualmente viven
en el repositorio como XML con el nombre del tipo como un 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
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 literal de objeto |
| 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 con receptor, tipos struct e interfaz |
| 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, case classes, 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 tipo función #define, typedef struct {…} Name, @interface/@implementation/@protocol |
Rendimiento
El índice frío es un análisis completo; el cálido es una verificación de mtime por archivo. Medido en Windows, Node 24.
| Repositorio | Archivos | Símbolos | Índice 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 re-analizaba todo el índice — alrededor de 20 ms de peso muerto por llamada en el repositorio de 5,000 archivos, y crecía con el repositorio.
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 el
regex por línea para cualquier archivo cuyo código fuente crudo no contenga el nombre buscado,
que en un repositorio típico es la mayoría. Delimita 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 repositorio — y la
secuencia skeleton→read_lines→contexto 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 dato 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 único almacén solo cuando ambos apuntan
al mismo SLIMDEX_ROOT.
Nada se captura automáticamente: el servidor nunca ve tu conversación, así que
el agente tiene que decidir qué vale la pena conservar. Las instructions incluidas le indican
que lea la memoria primero en una sesión nueva y que guarde decisiones, restricciones y
errores a medida que los 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 expresiones regulares y heurística, no un analizador 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 en el nivel superior, porque las variables locales dentro del cuerpo de una función no son algo a lo que alguien navegue. Los métodos de clase todavía 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 impacto, no como un grafo de llamadas.search_codeinforma un total exacto pero se detiene en un límite de escaneo interno en conjuntos de resultados muy grandes, imprimiendoN+ (scan cap reached)en lugar de un número incorrecto con confianza.- El soporte de idiomas es desigual: JS/TS es el mejor cubierto. La familia C y Ruby,
anteriormente 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, sobrecargas de operadores. - Para precisión de nivel LSP, cambiarías el analizador por tree-sitter o un servidor
de lenguaje.
src/parser.tses la costura: una interfazParserseleccionada porSLIMDEX_PARSER, con el analizador de expresiones regulares como la única implementación que se incluye. Un backend de tree-sitter encajaría allí sin tocar ninguna herramienta o el formato del índice. No está construido — las gramáticas por idioma sacrifican la propiedad de "se instala al instante, funciona sin conexión, cero configuración".
Deliberadamente no construido
Ideas evaluadas y rechazadas, con su razonamiento — estas son opiniones de diseño, no resultados medidos:
- Diccionarios de ID de símbolos (
S42→ ruta) — MCP no tiene una capa de expansión del lado del cliente, por lo que el modelo recibe un token opaco que debe gastar otra llamada para resolver. - Gestores de presupuesto de tokens / estimadores de costos — las estimaciones de
chars/4son poco 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 del contexto, la carga útil anterior desaparece, por lo que la referencia se resuelve a nada.
- Embeddings / búsqueda semántica — gran huella de dependencias; posible futuro indicador opcional, no un valor predeterminado.
- Un backend de analizador 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 para toda la instalación actual. Evaluado y rechazado con un 95.9% de recuperación medida, 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 alguna vez cambia — un backend encaja allí sin tocar una herramienta o el formato del í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
| Var | Efecto |
|---|---|
SLIMDEX_ROOT | Repositorio a indexar (o pásalo como primer argumento CLI; por defecto es el directorio actual) |
SLIMDEX_WATCH | Establécelo a 1 para reindexar automáticamente al guardar archivos (observador nativo, sin dependencias) |
SLIMDEX_PARSER | Backend del analizador; solo regex existe hoy |
SLIMDEX_PRETTY | Establécelo a 1 para restaurar la representación verbosa y alineada 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, por lo que al modelo se le dice qué es solo por lotes en lugar de dejarlo que lo descubra. Por defecto full. |
SLIMDEX_NO_DEDUPE | Establécelo a 1 para deshabilitar la supresión de respuestas repetidas (una segunda read_lines/get_file_skeleton/outline_file idéntica en 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 del índice, por lo que un índice obsoleto construido por un extractor más antiguo nunca se reutiliza)memory.json— hechos de memoria guardadosstats.json— contadores de uso por herramienta
El directorio se ignora a sí mismo: un * .gitignore se escribe 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 desde 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, por ejemplo
C:\path\to\slimdex-mcp\dist\index.js, y <REPO> con el repositorio a indexar.
No se requiere ajuste. Los ahorros que importan 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 fuera, o para
lean — que intercambia ~8,700 caracteres adicionales por turno contra enrutar un tercio de las
herramientas a través de batch, por lo que deliberadamente no es el valor 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 de esta manera, 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
inicia el servidor con un entorno restringido, así que dale a command una ruta
absoluta a node en lugar de depender de 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 → agregar:
{
"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 del espacio 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 las sesiones pasadas lo dejaron con notas obsoletas ya marcadas.repo_map→ obtén una visión general.outline_fileen un archivo de interés → elige 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 errores 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 y sin soporte. Si no compila, no funciona, o no funciona en tu configuración, eso es tuyo para cargar — ver el descargo en la licencia.