Slimdex
Recuperação estreita de código para agentes de codificação — esboços, corpos de símbolos, grafos de dependência e memória persistente em vez de leituras de arquivos inteiros.
Documentação
slimdex-mcp
Seu agente lê um arquivo de 900 linhas para alterar uma função — e depois paga por esse arquivo novamente a cada turno seguinte. Toda a conversa é reenviada a cada vez, então uma leitura inicial não é um custo único. É um aluguel.
Slimdex é um servidor MCP local que dá aos agentes de codificação recuperação estreita em vez disso: o esboço de um arquivo, o corpo de um símbolo, quem o chama, o que quebra se ele mudar — e memória que sobrevive à sessão, para que o próximo chat comece informado em vez de redescobrir o repositório do zero.
claude mcp add slimdex -- npx -y slimdex-mcp
~50% menos tokens no uso diário — ~55–60% em trabalho pesado de navegação, ~45% em trabalho pesado de saída, e 85–90% no pior caso para o qual foi construído (um arquivo de 6.200 linhas, explorado através de um esqueleto e 12 corpos de símbolos em vez de quatro leituras completas).
Status: 1.1.0, no npm e no Registro MCP. Esses números são automedidos nos repositórios em que foi executado, sessões únicas, não validados de forma independente — e
statsconta caracteres, não tokens. Leia O que está realmente verificado antes de confiar nisso.
| Ferramenta | O que retorna |
|---|---|
index_repo | Constrói/atualiza um índice persistente de símbolos + importações; apenas arquivos alterados são reanalisados |
outline_file | Declarações de um arquivo com números de linha |
get_file_skeleton | Assinaturas com corpos omitidos, aninhamento preservado |
read_lines | Um intervalo de linhas, limitado a 6.000 caracteres por padrão com uma linha de continuação; defina maxChars quando mais for necessário |
get_symbol_context | Um corpo de função/classe ±2 linhas, limitado por maxLines; names:[...] busca vários corpos em uma única chamada |
search_code | path:line:col + a linha correspondente com destaque de cursor; paginação por limit/offset/cursor |
find_definition | Local(is) de definição de um símbolo como path:line:col |
search_symbols | Busca difusa por nome de símbolo, classificada exato→prefixo→substring→subsequência |
search_intent | Consulta em linguagem natural classificada sobre símbolos por BM25 (sem embeddings) — encontre código pelo que ele faz |
context_pack | Uma chamada: classifica os símbolos de um tópico, mostra como eles se conectam e agrupa os principais corpos sob um orçamento — toda a exploração em uma única ida e volta |
find_references | Referências textuais como path:line:col + função delimitadora |
find_tests | Das referências a um símbolo, quais estão em arquivos de teste — ou um aviso de que nenhuma está |
replace_symbol | Sobrescreve o corpo de um símbolo endereçado por nome (sem reenviar código antigo); tira snapshots primeiro, reindexa depois |
get_context | Uma chamada: definição / assinatura / chamadores / importações / dependentes opcionais, com orçamento |
repo_map | Contagens de arquivos/linhas/símbolos no nível de diretório; path: detalha os maiores arquivos de um diretório |
changed_files | Arquivos alterados + em quais símbolos cada trecho de alteração se encaixa |
dep_graph | imports / dependents / um diagrama Mermaid (BFS de root+depth) |
stats | Contagens de chamadas por ferramenta e tamanhos de resposta, em caracteres, além da mistura de leituras e disciplina de escrita |
batch | Executa várias chamadas em uma única solicitação |
recap | Atividade de sessões anteriores, reconstruída automaticamente a partir do diário de chamadas de ferramentas do servidor — funciona mesmo quando nada foi salvo |
brief | Abertura compacta de sessão: resumo do repositório + foco derivado do diário + conclusões recentes verificadas contra o índice ativo (✓ ativo / ⚠ possivelmente desatualizado); detail:"full" expande o resumo e as prévias de memória |
digest_save / digest_get | Armazene uma folha de referência compacta da arquitetura do repositório uma vez; leia-a de volta com um veredito de frescor por arquivo coberto, para que a próxima sessão pule a reexploração |
snapshot | Copia arquivos não confirmados para .slimdex/snapshots/ (também é executado automaticamente a cada hora via index_repo em uma árvore suja) — seguro contra redefinições acidentais, não um substituto para confirmar |
memory_save/search/list/delete | Notas duráveis em .slimdex/memory.json |
As orientações de recuperação abaixo também são enviadas no instructions do servidor MCP, para que
os clientes as injetem automaticamente no contexto do modelo.
Fluxo de agente recomendado
brief primeiro, bem no início de uma sessão — uma chamada que informa o que é o
repositório, onde sessões recentes estavam cavando e quais conclusões salvas ainda
correspondem ao código (as desatualizadas são sinalizadas), para que um novo chat comece informado em vez de
em branco. Depois, get_context("Foo") para responder "o que é isso, quem chama, do que
depende" em uma única resposta. Para entender uma área inteira em vez de um
símbolo, context_pack("how does auth work") executa toda a exploração
no lado do servidor e devolve um único pacote limitado — os símbolos relevantes, como
eles se conectam e os principais corpos — para que você gaste uma chamada e uma entrada
de transcrição em vez de dez. Não sabe o nome, só o que faz? —
search_intent("parse the config file") classifica símbolos por intenção com BM25, sem
embeddings. Desça para get_symbol_context para um corpo (ele se sinaliza se o arquivo
se afastou do índice, para que você não releia para verificar), get_file_skeleton para a
forma de um arquivo e read_lines quando precisar do código-fonte exato. Antes de editar um
símbolo, execute find_tests nele para ver o que o cobre; para
reescrever uma função inteira, use replace_symbol (você envia apenas o novo corpo — o código
antigo não é reenviado apenas para localizar a edição). Use batch para agrupar várias
consultas. Toda ferramenta de busca aceita limit (padrão 20) e offset.
Orçamento de resposta: as seções de get_context são opcionais via include
(padrão: definição, assinatura, chamadores, importações — adicione body ou dependents
explicitamente), os chamadores são limitados por callerLimit e a resposta é limitada
por maxChars (padrão 12.000). Todo limite que estourar imprime um aviso explícito
(showing 3 of 68, truncated at maxChars=...) em vez de descartar dados
silenciosamente. get_symbol_context limita seu intervalo com maxLines da mesma forma, e
memory_list retorna os 50 fatos mais recentes, a menos que seja instruído de outra forma, como
prévias de ~150 caracteres em vez de corpos inteiros (memory_get ids:[...] os expande,
full:true despeja tudo). Em um armazenamento de 18 fatos, essa é a diferença
entre ~4.100 e ~18.600 caracteres na chamada que toda sessão 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 corresponde a um final de nome de arquivo, para tipos de arquivo que uma extensão não consegue identificar.
Arquivos auxiliares de metadados do Salesforce vêm como integrados: AccountSvc.cls-meta.xml,
panel.js-meta.xml e Account.object-meta.xml são indexados, enquanto pom.xml,
web.xml e manifest/package.xml não são — adicionar .xml a extensions
teria puxado todas as árvores de configuração do repositório. Arquivos correspondidos por sufixo são
indexados para alcance de busca e leitura, não para símbolos.
Mesclado sobre a lista de ignorados integrada (node_modules, dist, .venv,
.svelte-kit, Pods, .pytest_cache, …). Uma entrada de ignoreDirs é um
nome simples, correspondendo a qualquer diretório assim chamado em qualquer profundidade, ou um caminho contendo /,
ancorado na raiz do repositório e respeitando limites de diretório (src/gen não
também ignorará src/generated). index_repo ecoa o que carregou e avisa sobre
chaves desconhecidas, tipos errados ou JSON inválido, para que uma configuração com erro de digitação não seja silenciosamente
indistinguível de nenhuma.
A saída de build geralmente não precisa de configuração alguma. Além da lista de diretórios, qualquer
arquivo cujas linhas ultrapassem ~5.000 caracteres é tratado como saída de build minificada e
deixado de fora do índice — bundlers removem quebras de linha, e código-fonte escrito à mão não
se parece com isso. Isso captura o que uma lista de nomes estruturalmente não consegue: um
bundle com nome de hash (index-B7xK2p9q.js) dentro de um diretório chamado assets. assets, public
e static deliberadamente não são ignorados por nome, porque código-fonte real vive neles;
index_repo relata a contagem como skipped(minified build output): N.
Como funciona a economia de tokens
Não há truque de compressão. A economia é comportamental: essas ferramentas permitem que um agente recupere esboços, intervalos e localizações em vez de arquivos inteiros, e o índice persistente significa que consultas repetidas atingem uma consulta em cache em vez de uma releitura.
Duas sessões posteriores, executadas por modelos diferentes em formatos de repositório diferentes, adicionaram números do mundo real ao relatório original:
Aplicativo web de vários arquivos, sessão de correção de bug (GPT-5.3-Codex). 19 créditos relatados com slimdex; a estimativa do próprio modelo para o mesmo escopo sem ele: 45–70 créditos. Matemática: 19/45 → 19/70 ≈ 58–73% mais barato. O contrafactual é a estimativa do modelo, não um A/B medido — direcional.
Arquivo gigante único (folio-app: um app.js de 6.200 linhas, 313 KB).
Estatísticas do próprio Slimdex: ~34.000 caracteres em 8 chamadas ≈ 9–10k tokens — um
esqueleto (213 assinaturas), depois corpos de apenas ~12 funções relevantes, 9 delas
buscadas em uma única chamada de get_symbol_context names:[...]. O caminho
ingênuo: 313 KB ≈ 78–85k tokens em 3–4 leituras completas forçadas. Matemática: ~10k vs
~80k ≈ ~70k tokens economizados, uma redução de 85–90% na exploração. O diagnóstico do
bug (um caminho de exportação sem caminho de importação correspondente) era visível nas
assinaturas do esqueleto antes de um único corpo ser aberto.
Juntos, eles esboçam a lei de escala: a economia escala com quanto código irrelevante o caminho ingênuo arrastaria. Um arquivo gigante é o melhor caso; um repositório normal fica em torno de metade a dois terços mais barato; um repositório de arquivos minúsculos empata. Mesmas ressalvas de sempre: as estatísticas contam caracteres, não tokens (÷3,5–4), e sessões únicas são evidência, não benchmarks.
Ambos os números acima medem apenas leitura, que é a metade mais barata. A saída
custa aproximadamente 4–5× a entrada, então uma edição indisciplinada desperdiça mais do que uma
leitura indisciplinada: reescrever uma função inteira através de uma ferramenta de edição genérica significa
reenviar todo o corpo antigo apenas para que a ferramenta possa localizá-lo. replace_symbol
endereça por nome e esse custo desaparece. stats relata isso junto com
a mistura de leituras, porque o vazamento é invisível de outra forma — o caminho caro
ainda produz uma edição correta, então nada sinaliza que você pagou demais:
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
Edições externas são inferidas a partir de hashes de conteúdo que se movem entre duas execuções de index_repo,
então o número é honesto sobre seus limites: ele vê que os bytes mudaram, nunca
qual ferramenta os mudou, e um humano editando em outra janela também conta.
A faixa realista de fluxo de trabalho completo
Os números acima são números de exploração de cenário único — o melhor caso, onde o caminho ingênuo teria arrastado o máximo de código irrelevante. Em média em um dia de trabalho real inteiro, não apenas na fatia de exploração, a faixa se estabiliza mais baixa:
- ~55–60% em trabalho pesado de navegação — ler e entender uma base de código, onde a recuperação estreita substitui leituras de arquivos inteiros com mais frequência.
- ~45% em trabalho pesado de saída — produzir novo código, onde mais do custo
é geração que o servidor não toca (embora
replace_symbolagora também reduza o lado da escrita). - ~50% em média no uso regular do dia a dia. A economia se acumula quanto mais
sessões passam por ele, porque
briefe memória significam que cada novo chat começa informado em vez de redescobrir o repositório do zero.
Use-o regularmente entre sessões no seu IDE para obter o melhor disso.
Trate estes como um único ponto de dados, não um benchmark. Repositório único, tarefa única, uma
execução A/B cada, automedido, sem repetições ou variância. Seu resultado depende
fortemente de seu agente realmente alcançar as ferramentas estreitas em vez de
cair de volta na leitura de arquivos — o que varia por cliente e modelo. O método é
repetível se você quiser verificar: execute a mesma tarefa em duas sessões novas, uma
instruída a usar apenas Slimdex e outra instruída a evitá-lo, e compare
a escrita de cache de /status.
O que está realmente verificado
Sendo explícito, já que o resto deste README é fácil de ler demais.
Coberto pela suíte de testes unitários (npm test executa 224 testes em 23 arquivos):
-
Extração de símbolos em JS/TS (incl. métodos de classe e objeto-literal), Python, Go, Rust, Java/C#, e pulo de comentários —
symbols.test.ts -
Extração de imports para JS
import/require/export-from, Python, Rust -
Extração de blocos, com escopo por chaves e por indentação, com consciência de strings/comentários (aspas, templates,
//,/* */,#de linha inteira) —extractBlock.test.ts -
Resolução de imports, classificação de módulos externos, dependentes por aresta reversa, emissão de Mermaid, e escopo de profundidade BFS a partir da raiz —
graph.test.ts -
Formato de correspondência de busca, paginação sem sobreposição, contagem de ocorrências por linha, totais exatos, escape/rejeição de regex —
search.test.ts -
Round-trip de cursor opaco e rejeição de cursor malformado; fallback de backend do parser —
pagination.test.ts -
Detecção de declaração de outline vs. fluxo de controle —
outline.test.ts -
Orçamento de
get_symbol_contextmaxLinese aviso de truncamento -
Mascaramento de string/comentário e rastreamento de profundidade de chaves —
lexer.test.ts -
Extração por linguagem para todas as doze linguagens suportadas —
languages.test.ts -
O cache de índice retorna o mesmo objeto até o índice ser reescrito
-
Carregamento de
.slimdex.json: cada chave aplicada através de uma construção de índice real, além dos modos de falha (JSON inválido, chaves desconhecidas, tipos errados) cada um produzindo um aviso visível em vez de silêncio —config.test.ts -
changed_filescontra um repositório git temporário real: atribuição hunk→símbolo, arquivos não rastreados, refs de base explícitas e formatação; pula limpo quando o git não está instalado —git.test.ts -
O observador de arquivos, com eventos reais do sistema de arquivos: um salvamento é debounced, reindexado e chega ao índice em disco —
watch.test.ts -
Arestas de grafo além de imports: arestas de referência de nome para código sem import (classe→classe usada, interface→implementação via dependentes, trigger→handler) e arestas de fiação declarativa de XML do repositório (binding de metadados→classe), com menções em comentários/strings excluídas e cache por construção —
apexgraph.test.ts -
O cache de arquivos em memória atende repetições sem reler e sempre atende conteúdo fresco após uma mudança em disco —
fscache.test.ts -
Detecção de arquivos de teste nas convenções JS/TS/Python/Go/Ruby/Java/C#, com separadores do Windows normalizados e código-fonte comum (
latest.ts,Contest.java) não sinalizado incorretamente —testlink.test.ts -
O lado da escrita: substituição do bloco de um símbolo, código final preservado e finais de linha CRLF vs LF mantidos para que uma edição não seja reformatada em um diff de arquivo inteiro —
edit.test.ts -
Staleness de memória: um fato é marcado como vivo quando nomeia um símbolo/arquivo que ainda existe, sinalizado como obsoleto apenas quando toda menção de código desapareceu, e deixado sem sinalização para prosa — além de composição breve —
brief.test.ts -
Busca por intenção: tokenização camelCase/snake_case, e ranqueamento BM25 que traz à tona um símbolo com nome diferente por suas palavras de intenção enquanto pontua uma consulta não relacionada como nada —
intent.test.ts -
Frescor: um arquivo mais novo que seu mtime indexado é lido como obsoleto (números de linha podem estar errados), um mtime correspondente é lido como fresco, e um arquivo ausente nunca acusa obsoleto —
freshness.test.ts -
Montagem de
context_pack: cabeçalho + símbolos ranqueados + corpos em um único pacote, a mensagem de sem correspondência, controle de orçamento de caracteres que ainda garante o primeiro corpo, e o limite máximo de símbolos —pack.test.ts -
O resumo de arquitetura: arquivos cobertos modificados após o resumo são lidos como obsoletos, um resumo mais novo é lido como limpo, filtragem de escopo de cobertura e prefixo de diretório, e o veredito renderizado de fresco/obsoleto —
digest.test.ts
Coberto de ponta a ponta, através do servidor MCP real (integration.test.ts inicia
o servidor via stdio contra um repositório fixture temporário e verifica a saída):
index_repo, repo_map, read_lines, get_file_skeleton, outline_file,
get_symbol_context, find_definition, find_references, find_tests (o acerto
e o aviso de sem cobertura), search_intent (ranqueamento por intenção), context_pack (pacote
de uma chamada), digest_save/digest_get (round trip com veredito de frescor),
get_context (incluindo seu limite de maxChars),
dep_graph (imports + mermaid), batch, search_code, search_symbols,
stats, brief, replace_symbol (round trip de escrever-depois-consultar e a
recusa de símbolo desconhecido), o round trip de memory_save/search/list/delete, a
proteção de escape de caminho e os caminhos não encontrados.
O CI executa a construção e ambas as suítes no Ubuntu + Windows, Node 20 e 22.
Ressalva sobre o teste do observador: fs.watch recursivo é dependente da plataforma, então
watch.test.ts degrada para um pulo registrado em sistemas de arquivos que nunca entregam um
evento — mesmo comportamento do próprio observador. No Windows, macOS e Linux
atual, ele verifica o caminho completo de salvar→reindexar.
npm run smoke ainda existe, mas prova apenas que o pipeline está vivo — as
verificações de correção vivem em integration.test.ts.
Verificado por inspeção: src/ não contém chamadas de rede — nenhum código sai da sua
máquina. Este você pode verificar você mesmo:
grep -rE "fetch\(|https?://|axios|http\.request" src/.
Documentação mais longa
Em docs/:
tool-guide.md— cada ferramenta explicada duas vezes (tecnicamente e em palavras simples) com um exemplo cada, o fluxo de trabalho combinado e como a persistência baseada em mtime funcionatool-guide.html— o mesmo guia como uma página estilizada e autocontida para o navegadortoken-savings-report.md— a medição A/B original, seu método e como repeti-laagent-brain.md— a disciplina operacional completa como um documento legívelagent-brain-slim.md— o documento para colocar em um repositório como CLAUDE.md / AGENTS.md. Autocontido e de uma página: escada de economia, tabela pergunta→ferramenta, disciplina de memória, higiene de sessão, limites honestos, botões de ambiente. Mesma cobertura do documento completo com ~30% da prosa, porque as regras de ferramentas são tabelas densas em vez de parágrafos que o servidor já injeta.
Cobertura de linguagens
Duas medições, porque apenas fixtures provam muito pouco.
Fixtures — uma por linguagem, contando as declarações que um desenvolvedor
realmente navegaria: 65/65 encontrados, 0 falsos positivos, fixados por
test/languages.test.ts.
Código real de terceiros — extração executada em ~11.800 arquivos de várias centenas de pacotes reais (React, Babel, Remix, Socket.io, Playwright, Three.js, Emotion, zod, ajv …) e comparada com uma heurística escrita independentemente para o que conta como declaração: 95,9% de recall. Reproduza você mesmo:
npm run audit -- ./node_modules # or any directory of code you didn't write
Esse número é um piso, não uma nota — a heurística de verdade conta algumas não-declarações, então o recall real é um pouco maior. Serve para pegar regressões e encontrar a próxima lacuna real.
Sobre frameworks
Quase nada que falhou na auditoria era específico de framework. Frameworks adicionam anotações, decoradores e convenções; raramente inventam sintaxe. Lide com a linguagem e os frameworks vêm junto — as camadas Application/Domain/Selector/ Service/UnitOfWork do fflib extraem completamente (129 declarações) sem uma única regra ciente de fflib.
A única exceção genuína são DSLs de teste. Um arquivo vitest/jest/mocha/RSpec frequentemente
não tem declarações de nível superior, então diretórios de teste inteiros costumavam indexar para
nada. Títulos de describe/it/test agora são indexados como tipo test, que é
o que você realmente navega em um arquivo de teste.
A semântica de framework é recuperada sempre que a referência existe em algum lugar no repositório, através de duas fontes extras de arestas no grafo:
- Arestas de referência de nome, para linguagens que não têm declaração de import (ex.:
Apex): se o código de um arquivo — comentários e strings mascarados — menciona um
tipo de nível superior definido em outro arquivo, isso é uma aresta. É isso que torna
implementsrespondível como "quem implementa esta interface", e liga um trigger à classe handler que ele instancia. - Arestas de fiação declarativa: bindings que frameworks mantêm em configuração
em vez de código (registros de metadados customizados, definições de fluxo) geralmente vivem
no repositório como XML com o nome do tipo como um valor de elemento. O XML do repositório é escaneado
para nomes de tipos conhecidos — comentários XML excluídos — e cada acerto se torna uma
aresta
metadata-file → class, entãodependentsresponde "o que conecta isso".
Ambos os escaneamentos são armazenados em cache por construção de índice e não custam nada em repositórios sem tais
arquivos. Fixados por apexgraph.test.ts. O que nenhum leitor estático pode ver é um
binding que existe apenas em um sistema vivo — configurado em uma org ou banco de dados
em execução e nunca recuperado para o repositório. Se não está no repositório em nenhuma
forma, não há aresta para desenhar; pesquise o nome do tipo em vez disso.
| Linguagem | Extensões | O que é reconhecido |
|---|---|---|
| JavaScript / TypeScript | .js .jsx .mjs .cjs .ts .tsx .vue .svelte | classes, interfaces, tipos, enums, funções, arrows de nível superior, métodos de classe e objeto-literal |
| Apex | .cls .trigger | classes, classes internas, métodos (incl. @AuraEnabled, global, retornos genéricos), triggers |
| Java | .java | classes, interfaces, enums, métodos, métodos genéricos com um <T> inicial |
| C# | .cs | classes, interfaces, structs, métodos async e genéricos, membros virtuais |
| Kotlin | .kt | classes, data classes, interfaces, object, fun, suspend fun |
| Swift | .swift | classes, structs, enums, protocols, func, static func |
| Python | .py | classes, def, async def, métodos dunder e decorados |
| Go | .go | funcs, métodos com receiver, tipos struct e interface |
| Rust | .rs | structs, enums, traits, fn, pub async fn, métodos impl |
| Ruby | .rb | classes, módulos, def, def self.x, attr_accessor/reader/writer |
| PHP | .php | classes, interfaces, traits, métodos, funções |
| Scala | .scala | classes, case classes, traits, objects, def com modificadores |
| C / C++ / Objective-C | .c .h .cpp .hpp .cc .m .mm | classes, structs, enums, funções livres (incl. chaves K&R, retornos de ponteiro), definições fora da classe Foo::bar, ctors/dtors, namespaces, macros #define semelhantes a funções, typedef struct {…} Name, @interface/@implementation/@protocol |
Desempenho
Índice frio é uma análise completa; quente é uma verificação de mtime por arquivo. Medido no Windows, Node 24.
| Repositório | Arquivos | Símbolos | Índice frio | Índice quente | Consulta típica |
|---|---|---|---|---|---|
| Org Salesforce DX | 56 | 344 | 0,1 s | 15 ms | < 10 ms |
| App Java + React | 356 | 1.713 | 0,42 s | 26 ms | 3–57 ms |
| Estresse sintético | 5.000 | 50.000 | 1,5 s | 0,24 s | 5–22 ms |
O índice é mantido em memória e invalidado pelo mtime do arquivo de índice. Sem esse cache, cada chamada de ferramenta releria e reanalisaria o índice inteiro — cerca de 20 ms de peso morto por chamada no repositório de 5.000 arquivos, e crescia com o repositório.
find_references é a ferramenta mais lenta em escala porque é uma varredura textual,
não uma busca de índice — mas um pré-filtro literal agora pula a divisão de linha e o
regex por linha para qualquer arquivo cujo código-fonte bruto não contém o nome pesquisado,
que em um repositório típico é a maioria deles. Escopo com pathPrefix para reduzir as
leituras de arquivo restantes quando você sabe aproximadamente onde procurar.
Os conteúdos de arquivo também são servidos de um LRU em memória com limite de bytes (64 MB,
validado por mtime+tamanho por acerto), então a segunda varredura de um repositório — e a
sequência skeleton→read_lines→contexto que os agentes realmente executam em um arquivo —
custa um stat() em vez de uma leitura.
Memória entre sessões
memory_save grava em <root>/.slimdex/memory.json, que sobrevive ao
processo — um fato salvo em um chat pode ser lido no próximo, por um cliente
diferente, após uma reinicialização. Chat e editor compartilham um único armazenamento apenas quando ambos apontam para o mesmo SLIMDEX_ROOT.
Nada é capturado automaticamente: o servidor nunca vê sua conversa, então
o agente precisa decidir o que vale a pena manter. As instructions incluídas dizem a ele
para ler a memória primeiro em uma nova sessão e salvar decisões, restrições e
armadilhas conforme as aprende — mas isso é orientação para o modelo, não uma garantia.
Limitações conhecidas
- A extração de símbolos é baseada em regex e heurística, não um parser ou LSP. Ela pode
deixar passar declarações incomuns, e
find_referencesé uma correspondência textual que pode incluir identificadores homônimos, mas não relacionados. - A extração de símbolos e esboços agora é executada em uma cópia mascarada de cada linha,
com o conteúdo de strings e comentários removido, para que prosa com formato de declaração
dentro de um template literal não seja mais indexada como código. Declarações também são
sensíveis à profundidade: um
const x = () => …outype X = …conta apenas no nível superior, porque locais dentro do corpo de uma função não são coisas para as quais alguém navega. Métodos de classe ainda são indexados na profundidade de seu aninhamento. - Um comentário inline de
#em Python contendo uma chave ainda pode confundir a extração de blocos (#também é o sigilo de campo privado do JS, então não pode ser removido cegamente). changed_filesatribui um trecho à declaração anterior mais próxima — correto para um corpo de função normal, aproximado para código entre declarações. Trate-o como raio de impacto, não como grafo de chamadas.search_coderelata um total exato, mas para em um limite interno de varredura em conjuntos de resultados muito grandes, imprimindoN+ (scan cap reached)em vez de um número errado e confiante.- O suporte a linguagens é desigual: JS/TS é o mais bem coberto. A família C e Ruby,
antes as mais fracas, ganharam regras dedicadas (funções livres, definições de
Foo::bar, macros semelhantes a funções,attr_*); os pontos fracos restantes são formatos avançados de C++ — templates divididos em várias linhas, sobrecarga de operadores. - Para precisão de nível LSP, você trocaria o parser por tree-sitter ou um servidor
de linguagem.
src/parser.tsé a costura: uma interfaceParserselecionada porSLIMDEX_PARSER, com o parser regex como a única implementação incluída. Um backend tree-sitter poderia ser encaixado ali sem tocar em nenhuma ferramenta ou no formato do índice. Ele não está construído — gramáticas por linguagem abrem mão da propriedade "instala instantaneamente, roda offline, zero configuração".
Deliberadamente não construído
Ideias avaliadas e rejeitadas, com justificativa — estas são opiniões de design, não resultados medidos:
- Dicionários de ID de símbolo (
S42→ caminho) — MCP não tem camada de expansão no lado do cliente, então o modelo recebe um token opaco que precisa gastar outra chamada para resolver. - Gerenciadores de orçamento de tokens / estimadores de custo — estimativas de
chars/4são não confiáveis entre tokenizadores, e a compressão automática com base em uma estimativa ruim pode descartar dados que o modelo precisava. - Cache delta / "já enviado, veja a resposta #5" — após a compactação de contexto, o payload anterior se foi, então a referência resolve para nada.
- Embeddings / busca semântica — grande pegada de dependências; possível futura flag opcional, não um padrão.
- Um backend parser tree-sitter — este é o que fecharia os
~4% restantes, e foi custeado em vez de apenas mencionado:
web-tree-sitteré WASM, então não precisa de compilação nativa, mas as gramáticas (tree-sitter-wasms) têm 51,7 MB descompactadas contra ~4,5 MB para toda a instalação atual. Avaliado e recusado com 95,9% de recall medido, porque "instala em um segundo, roda offline, sem configuração" é a propriedade que este servidor existe para ter.src/parser.tscontinua sendo a costura se esse cálculo mudar — um backend pode ser encaixado ali sem tocar em uma ferramenta ou no formato do índice.
Instalação
Publicado no npm como slimdex-mcp,
e listado no MCP Registry como
io.github.Siddhukaushik/slimdex-mcp. Nada para compilar — aponte seu cliente para:
npx slimdex-mcp
Ou a partir do código-fonte, se quiser fazer alterações:
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
Verifique se ele funciona de ponta a ponta contra um repositório:
npm run smoke # this repo
node smoke-test.mjs "C:/path/to/some/repo" # any other
Variáveis de ambiente
| Var | Efeito |
|---|---|
SLIMDEX_ROOT | Repositório para indexar (ou passe como o primeiro argumento da CLI; o padrão é o diretório atual) |
SLIMDEX_WATCH | Defina como 1 para reindexar automaticamente ao salvar arquivos (observador nativo, sem dependências) |
SLIMDEX_PARSER | Backend do parser; apenas regex existe hoje |
SLIMDEX_PRETTY | Defina como 1 para restaurar a renderização verbosa e alinhada a humanos: cabeçalhos mais longos e preenchimento de colunas em search_code, find_definition, search_symbols, find_references, repo_map, read_lines, outline_file. O formato conciso é o padrão — esse preenchimento é contexto que o modelo paga em cada turno posterior. SLIMDEX_TERSE=0 faz o mesmo. |
SLIMDEX_PROFILE | lean anuncia 15 ferramentas em vez de 29, reduzindo os esquemas de ferramentas reenviados a cada turno de ~22.300 para ~12.600 caracteres. As outras 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) ainda funcionam e são chamadas por meio de batch — e as instruções do servidor as nomeiam neste perfil, então o modelo é informado sobre o que é somente em lote, em vez de descobrir por conta própria. Padrão full. |
SLIMDEX_NO_DEDUPE | Defina como 1 para desativar a supressão de respostas repetidas (uma segunda read_lines/get_file_skeleton/outline_file idêntica em um arquivo inalterado responde com um ponteiro para a chamada anterior em vez do corpo; uma terceira chamada idêntica reemite o conteúdo completo). |
O cache persistente
Por repositório, o Slimdex grava em <repo>/.slimdex/:
index.json— o índice de código (invalidado por mtime por arquivo e descartado completamente quando a versão do formato do índice muda, para que um índice obsoleto criado por um extrator mais antigo nunca seja reutilizado)memory.json— fatos de memória salvosstats.json— contadores de uso por ferramenta
O diretório ignora a si mesmo: um * .gitignore é gravado dentro dele (o
truque do node_modules/.cache), para que nunca apareça em git status e você não
precise tocar no .gitignore do próprio repositório. Exclua esse arquivo interno se você quiser
fazer commit do cache.
Integrando em clientes MCP
MCP é um padrão compartilhado, então o mesmo servidor deve funcionar em qualquer cliente
compatível com MCP. A raiz do projeto é passada via SLIMDEX_ROOT (ou como o primeiro
argumento da CLI).
Apenas Claude Code e Claude Desktop foram realmente executados. Os outros abaixo são o formato de configuração padrão para cada cliente, escrito a partir do formato documentado deles — não foram testados aqui e podem precisar de ajustes.
Desde a versão 1.0.0, a integração mais simples é npx -y slimdex-mcp — sem clone, sem build, e
ela permanece atualizada. Os exemplos abaixo mantêm o formato node <ABS_PATH> para quem
executa a partir do código-fonte; para usar o pacote publicado, troque
"command": "node", "args": ["<ABS_PATH>"] por
"command": "npx", "args": ["-y", "slimdex-mcp"].
Substitua <ABS_PATH> pela sua saída de build, por exemplo,
C:\path\to\slimdex-mcp\dist\index.js, e <REPO> pelo repositório a indexar.
Nenhum ajuste necessário. As economias que importam estão ativadas por padrão em todos os
clientes: fatos de memória listados como prévias, respostas concisas, uma releitura idêntica
de um arquivo inalterado responde com um ponteiro em vez do corpo, e várias
edições de símbolos vão em uma única chamada. As variáveis de ambiente abaixo são para optar fora, ou para
lean — que troca ~8.700 caracteres adicionais por turno por rotear um terço das
ferramentas por meio de batch, então deliberadamente não é o padrão.
Claude Code (CLI) — testado
claude mcp add slimdex --env SLIMDEX_ROOT=<REPO> -- npx -y slimdex-mcp
A partir do código-fonte: -- node <ABS_PATH>.
Claude Desktop — testado
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"slimdex": {
"command": "npx",
"args": ["-y", "slimdex-mcp"],
"env": { "SLIMDEX_ROOT": "<REPO>" }
}
}
}
Codex CLI — testado
~/.codex/config.toml
[mcp_servers.slimdex]
command = 'C:\Program Files\nodejs\node.exe'
args = ['<ABS_PATH>']
startup_timeout_sec = 30
Registrado globalmente assim, o slimdex se anexa a cada tarefa do Codex e usa
o diretório de trabalho dessa tarefa como raiz do repositório — sem SLIMDEX_ROOT necessário. O Codex
inicia o servidor com um ambiente restrito, então dê a command um caminho absoluto
para o node em vez de depender de PATH.
Cursor — não testado
.cursor/mcp.json (projeto) ou ~/.cursor/mcp.json (global)
{
"mcpServers": {
"slimdex": {
"command": "node",
"args": ["<ABS_PATH>"],
"env": { "SLIMDEX_ROOT": "${workspaceFolder}" }
}
}
}
Windsurf — testado
~/.codeium/windsurf/mcp_config.json — mesmo formato mcpServers que o Cursor.
VS Code (Copilot / MCP) — testado
.vscode/mcp.json
{
"servers": {
"slimdex": {
"command": "node",
"args": ["<ABS_PATH>"],
"env": { "SLIMDEX_ROOT": "${workspaceFolder}" }
}
}
}
Cline (extensão do VS Code) — testado
Configurações do Cline → Servidores MCP → adicionar:
{
"slimdex": {
"command": "node",
"args": ["<ABS_PATH>"],
"env": { "SLIMDEX_ROOT": "<REPO>" }
}
}
Zed — testado
settings.json → context_servers
{
"context_servers": {
"slimdex": {
"command": { "path": "node", "args": ["<ABS_PATH>"], "env": { "SLIMDEX_ROOT": "<REPO>" } }
}
}
}
Para clientes que expõem a pasta do workspace (Cursor, VS Code),
${workspaceFolder}mantém o Slimdex apontado para o repositório que você tem aberto.
Fluxo de trabalho típico do agente
index_repouma vez no início (mais rápido em execuções subsequentes), depoisbriefpara retomar de onde as sessões passadas pararam, com notas desatualizadas já sinalizadas.repo_map→ tenha uma visão geral do terreno.outline_fileem um arquivo de interesse → escolha intervalos de linhas.read_linesapenas para esses intervalos.find_definition/find_references/dep_graphpara navegar.find_testsantes de editar um símbolo;replace_symbolpara reescrever um sem reenviar o corpo antigo.memory_savedecisões e armadilhas para que a próxima sessão comece informada.
Licença
MIT © 2026 Kael VK Inc. (Número de Registro 751569161 RC0001) — veja LICENSE.
Fornecido como está, sem garantia e sem suporte. Se não compilar, não executar ou não funcionar na sua configuração, o problema é seu — veja o aviso de isenção na licença.