GraphCodeMap
Um grafo consultável de símbolos, chamadas e fluxo de dados, para agentes de IA entenderem um repositório grande sem reler arquivo atrás de arquivo.
3 min de leitura
Stack
- Python
- tree-sitter
- SQLite
- MCP
- LSP
O problema
Agente de código em repositório grande passa a maior parte do orçamento de contexto relendo arquivo para responder perguntas estruturais. "Quem chama esta função?" e "o que quebra se eu mudar esta assinatura?" não são perguntas de busca textual — são perguntas de grafo.
O GraphCodeMap indexa o repositório com tree-sitter num grafo em SQLite, e expõe isso por três interfaces: biblioteca Python, CLI e servidor MCP.
O princípio que sustenta tudo
O código é a fonte da verdade; o grafo é um cache derivado.
Um índice de código só é útil enquanto está correto, e a maneira mais comum de falhar é envelhecer em silêncio. Aqui cada fato indexado carrega o hash de conteúdo do arquivo de origem, e toda consulta verifica o frescor antes de responder — se o hash mudou, o arquivo é reindexado ali mesmo, no meio da pergunta.
São três camadas de frescor: watchers mantêm o índice quente durante a sessão, uma varredura no boot pega o que mudou com o processo desligado, e a verificação por hash fecha o resto.
Honestidade sobre limites
Análise estática erra. A escolha aqui foi declarar o erro em vez de escondê-lo: toda aresta de chamada carrega uma confiança explícita.
| Confiança | O que significa |
|---|---|
certain | Verificada semanticamente |
inferred | Heurística por nome |
possible | Ambígua |
O comando doctor mostra o estado do índice: o que parseou, a divisão de confiança com a
métrica %certain, quais resolvedores L1 estão ativos e o que está velho.
As camadas
L0 — estrutural. tree-sitter extrai símbolos, imports e arestas de chamada, por extratores específicos de linguagem ou por heurística genérica.
L1 — semântica. Uma camada de resolvedores plugáveis promove arestas a certain usando
language servers: jedi para Python, tsserver para TypeScript e JavaScript, e clientes LSP
genéricos para os demais — gopls, rust-analyzer, jdtls.
L3 — IA. Resumos gerados por LLM para símbolos, módulos e domínios, com cache para controlar custo e uso de tokens reportado por geração.
Cobertura
18 linguagens com extrator dedicado, incluindo Python, TypeScript/TSX, JavaScript,
Rust, Go, Java, Kotlin, C#, C, C++, PHP, Ruby, Swift, Scala e Clojure. Há também HTML e
CSS/SCSS com arestas entre linguagens — um className em TSX ligado à definição na folha
de estilo.
Um nível genérico cobre mais duas dezenas: Zig, PowerShell, Elixir, Dart, Vue, Svelte, Astro, SQL, Bash e outras.
Análise de fluxo de dados e de taint — entrada não confiável até um sink perigoso — funciona nas 18 linguagens dedicadas.
Usando
pip install graphcodemap
pip install "graphcodemap[l1]" # refinamento semântico
pip install "graphcodemap[mcp]" # servidor MCPcodegraph index .
codegraph overview # mapa do repositório por PageRank
codegraph callers auth.TokenService.validate # quem chama
codegraph impact auth.TokenService.validate # o que quebra se eu mudar
codegraph taint --entry handle_request # fluxo de dado não confiávelComo servidor MCP, entra no .mcp.json do agente:
{ "mcpServers": { "codegraph": { "command": "graphcodemap-mcp", "args": ["--root", "."] } } }O que ele não é
O grafo complementa o grep, não substitui. Para achar onde uma string aparece, grep resolve mais rápido e mais barato. O grafo se paga em pergunta estrutural.
A análise de taint é may-taint: superestima, apontando caminhos que podem não acontecer em execução. É insensível a fluxo, embora já seja sensível a campo em Python e JS/TS. E chamada dinâmica ou por reflexão escapa de qualquer análise estática — as respostas dizem isso explicitamente em vez de fingir certeza.
Sobre desempenho: testado em mais de 100 mil arquivos, com pico de 324 MB de memória e indexação em torno de 8 minutos em código bem estruturado.
Estado atual
Alpha, v0.1.0. O roteiro planejado está implementado de ponta a ponta, com cerca de 165 testes de regressão — mas ainda falta rodagem em uso real.
Um detalhe que faço questão de manter no README: o piloto de 15 tarefas do SWE-bench-Lite achou o arquivo alvo em 93% dos casos contra 80% do baseline, e essa margem cabe dentro do ruído. É indicativo, não é prova.