Memoria 100% local para Claude Code — GraphRAG de tus documentos y grafo de tu código, vía MCP. Sin nube, sin claves de API de modelos comerciales.
Dos servidores MCP locales: myrmion-graphrag (documentos) y myrmion-codebase (código).
Myrmion es un ecosistema opensource para adoptar IA corporativa con cultura propia. Myrmion graphRAG es una de sus herramientas: da a Claude Code memoria local sobre tus documentos y tu código sin que nada salga de tu máquina. Se usa por sí sola, sin requerir el resto del ecosistema.
Dos memorias locales, expuestas como dos servidores MCP:
myrmion-graphrag— grafo de conocimiento sobre tus documentos (notas, manuales, papers, decisiones). Motor: LightRAG + Ollama.myrmion-codebase— grafo de tu código: dependencias, "¿a qué afecta esta función?", "¿quién llama a X?", inventario (reutilizable / obligatoria / muerta) e histórico. Parser multi-lenguaje (Python víaast; JS/TS, Java, C# y VB.NET vía tree-sitter; VB6/VBScript y ASP clásico con parser propio).
Todo corre en tu equipo: el indexado (LLM + embeddings vía Ollama) no requiere ninguna clave de API de modelos comerciales (OpenAI, Anthropic, etc.). La única salida a Internet es la que Claude Code hace a Anthropic al razonar tu pregunta — no la provoca esta herramienta.
Otras piezas del ecosistema: myrmion-blackbar-pii-guard (redacción de PII para Claude) · myrmion-AI-factory (SDLC agéntico gobernado) · myrmion-framework (el paraguas).
Claude Code (VS Code) ── cliente MCP
│ stdio │ stdio
┌──────────────▼───────┐ ┌──────▼────────────────┐
│ myrmion-graphrag │ │ myrmion-codebase │
│ mcp_server.py │ │ codebase_server.py │
│ (documentos) │ │ (código) │
└──────────┬───────────┘ └──────┬────────────────┘
HTTP :9621 GraphStore pluggable
┌──────────▼───────────┐ ┌──────▼────────────────────────────┐
│ lightrag-server │ │ filesystem(def) │ neo4j │ postgres │
│ storage PLUGGABLE: │ └────────────────────────────────────┘
│ filesystem/neo4j/pg │
│ /híbrido │
└──────────────────────┘
def= backend por defecto. Ambos servidores usan el mismo tríofilesystem / neo4j / postgres. Para el grafo de código,filesystempersiste el grafo en un JSON enconfig/(sin BD externa, como el filesystem de LightRAG);neo4j/postgresson las opciones profesionales.
| Pieza | Rol | Dónde corre |
|---|---|---|
| Ollama | LLM local (extrae entidades) + embeddings | localhost:11434 |
| LightRAG | Grafo de conocimiento + índice vectorial + API REST | localhost:9621 |
mcp_server.py |
Servidor MCP de documentos (puente a LightRAG) | proceso local (stdio) |
codebase_server.py |
Servidor MCP de código (parser + grafo propio) | proceso local (stdio) |
| Neo4j / PostgreSQL | Backends profesionales (opcionales) | Docker 127.0.0.1 |
- Python 3.11+
- Ollama instalado y en ejecución
- VS Code con la extensión de Claude Code
- ~11 GB de RAM libres para indexar documentos con
qwen2.5:7b - (Opcional, para backends profesionales) Docker + Docker Compose
ollama pull qwen2.5:7b
ollama pull nomic-embed-text./setup.shsetup.sh crea el venv, instala dependencias (requirements.txt + requirements-codebase.txt),
crea tu config personal en config/ (desde las plantillas *.example), genera
config/mcp.json con los dos servidores y sus rutas absolutas, crea los enlaces
.env y .mcp.json en la raíz, copia los scripts locales (db-up.sh, migrate-backend.sh)
y activa el git pre-push hook del inventario.
Toda tu configuración personal vive en config/ (gitignored); el repo solo versiona
las plantillas. Edita config/lightrag.env (rutas, API key, perfil de storage) y
config/codebase.env (raíz del código, backend), y re-ejecuta ./setup.sh.
uv tool install "lightrag-hku[api]" # o: pip install "lightrag-hku[api]"
lightrag-server # otra terminal; lee .env -> config/lightrag.env# Documentos -> myrmion-graphrag
python ingest.py "$INPUT_DIR" --api-key "$LIGHTRAG_API_KEY" --watch
# Código -> myrmion-codebase (desde Claude Code: tool indexar_codebase )Abre el repo en VS Code con Claude Code. El .mcp.json de la raíz hace que Claude Code
descubra ambos servidores. Verifica con /mcp que aparecen conectados:
myrmion-graphrag y myrmion-codebase. Llama a estado_rag y a
estado_indexado para diagnosticar cada uno.
El servidor
myrmion-codebasepuede apuntar a cualquier codebase: pon su ruta enCODEBASE_ROOT(enconfig/codebase.env) y re-ejecuta./setup.sh.
LightRAG usa 4 capas de storage (KV, Vector, Grafo, DocStatus). Eliges un perfil en
config/lightrag.env (bloque de almacenamiento). Caveat: el storage debe elegirse
antes de indexar el primer documento; cambiarlo obliga a re-indexar (usa
./migrate-backend.sh).
| Perfil | Qué usa | Cuándo |
|---|---|---|
| A · filesystem (def.) | Json / Nano / NetworkX | Empezar, corpus pequeño/medio, 100% sin BD |
| B · neo4j | Neo4j (grafo) + resto local | Quieres visualizar/consultar el grafo con Cypher |
| C · postgres | PostgreSQL todo-en-uno (pgvector + AGE) | Unificación y garantía transaccional máxima |
| D · híbrido (recomendado pro) | Postgres (KV/vector/estado) + Neo4j (grafo) | pgvector escalable y grafo nativo/visual |
Levanta los backends con Docker (bind a 127.0.0.1, nada sale de tu máquina):
./db-up.sh neo4j start # Neo4j en :7474 (browser) / :7687 (bolt)
./db-up.sh postgres start # Postgres en :5432
./db-up.sh pro start # HÍBRIDO: ambos a la vezValida la conexión y qué backend está activo:
python -m backends healthcheck neo4j # o postgres
# y desde Claude Code: estado_rag (reporta el backend activo)El inventario de código (myrmion-codebase) usa su propio GraphStore pluggable con el
mismo trío: filesystem (por defecto, grafo persistido en un JSON en config/, sin BD),
neo4j (recomendado para uso pro; puede reutilizar la instancia de LightRAG) o postgres.
El perfil híbrido escribe el grafo en Neo4j y los vectores/KV/estado en Postgres: dos
bases de datos sin transacción distribuida. Para que nunca queden desalineadas,
myrmion-graphrag incluye un supervisor de consistencia (consistency.py):
- Health-gate: no se escribe salvo que Neo4j y Postgres y LightRAG respondan.
- Saga con reintentos automáticos + compensación: cada operación de documento es una saga de pasos idempotentes; si un paso agota reintentos, se compensan los previos.
- Reconciliación: detecta deriva (docs sin grafo/sin vectores, huérfanos) y la repara (reindexar / borrar huérfanos).
Tools MCP (solo aplican al híbrido): verificar_alineacion (dry-run) y
reconciliar(aplicar=True) (repara).
Compromiso honesto: es consistencia fuerte auto-reparable (se detecta y repara toda deriva), no un candado 2PC instantáneo. Si necesitas una garantía transaccional dura sin reconciliación, usa el Perfil C (Postgres todo-en-uno: una sola transacción ACID). El inventario de código va en Neo4j (grafo puro, un solo store → sin deriva posible).
Los backends profesionales suelen correr en hardware potente, donde interesa un Qwen mayor
para maximizar la extracción y la fiabilidad. En config/lightrag.env hay presets:
| Perfil | LLM | Contexto / paralelismo | Hardware |
|---|---|---|---|
| local (def.) | qwen2.5:7b |
NUM_CTX=8192, MAX_ASYNC=1 |
CPU / 24 GB |
| profesional | qwen2.5:32b (o :14b/:72b, qwen3:*) |
NUM_CTX=32768, MAX_ASYNC=4 |
GPU / mucha RAM |
Regla crítica: cambiar LLM_MODEL no obliga a reindexar; cambiar
EMBEDDING_MODEL/EMBEDDING_DIM sí (la dimensión del vector cambia). Descarga el
modelo con ollama pull qwen2.5:32b.
Ajusta config/lightrag.env según CPU/RAM/GPU. Referencia (Q4): 7b≈6GB, 14b≈10GB,
32b≈20GB, 72b≈48GB de VRAM/RAM.
| Escenario | LLM_MODEL |
NUM_CTX |
MAX_ASYNC |
EMBEDDING_BATCH_NUM |
Timeouts | KV cache |
|---|---|---|---|---|---|---|
| CPU-only 16 GB | qwen2.5:3b |
8192 | 1 | 1 | altos | q8_0 |
| CPU-only 24-32 GB | qwen2.5:7b |
8192 | 1 | 4 | altos | q8_0 |
| GPU 8-12 GB VRAM | qwen2.5:7b/14b |
16384 | 2 | 8 | medios | q8_0 |
| GPU 24 GB | qwen2.5:32b |
32768 | 4 | 16 | bajos | f16 |
| GPU 48 GB+ | qwen2.5:72b/qwen3:32b |
32768+ | 6 | 32 | bajos | f16 |
Perillas: MAX_ASYNC = llamadas LLM en paralelo (CPU=1; en GPU sube según VRAM).
OLLAMA_LLM_NUM_CTX = ventana para extracción (32k+ ideal, pero consume RAM/VRAM; 8k en
CPU para evitar swap). OLLAMA_KV_CACHE_TYPE=q8_0 comprime la KV cache. Sube timeouts en
CPU. Ollama usa la GPU automáticamente si está disponible (OLLAMA_NUM_PARALLEL, capas
descargadas según VRAM). Regla de oro: sube modelo/NUM_CTX/MAX_ASYNC solo si el
hardware lo aguanta sin swap; en CPU, prioriza terminar el indexado antes que calidad
máxima.
| Herramienta | Qué hace |
|---|---|
buscar_conocimiento(consulta, modo="mix", solo_contexto=True, top_k=40) |
Recupera contexto del grafo para que tú razones |
anadir_documento(texto, descripcion="") |
Indexa un texto al vuelo (asíncrono) |
sincronizar_documento(ruta, texto="") |
Actualiza un documento tras editarlo sin duplicar y versionado (skip si el hash no cambió; delete + insert/upload si cambió) |
sincronizar_documentos(carpeta="") |
Sincroniza una carpeta entera: added/modified/removed por hash, crea un snapshot |
historico_documento(ruta) |
Evolución versionada del documento (added/modified/removed por commit) |
estado_documentos() |
Nº de documentos rastreados y último snapshot |
estado_rag() |
Salud de LightRAG + backend de storage activo |
verificar_alineacion() / reconciliar(aplicar=False) |
Consistencia Neo4j⇄Postgres (perfil híbrido) |
Modos de búsqueda: mix (recomendado), hybrid, local, global, naive.
| Herramienta | Qué hace |
|---|---|
indexar_codebase(ruta="", incremental=False) |
Indexa/reindexa el codebase |
sincronizar_codigo(rutas) |
Sync incremental idempotente tras editar |
dependencias_de(simbolo, profundidad=1) |
De qué depende (callees) |
quien_llama_a(simbolo, profundidad=1) |
Quién lo llama (callers) |
a_que_afecta(simbolo, profundidad=5) |
Blast radius: qué se afecta si lo cambias |
inventario(filtro="") |
Símbolos con etiquetas reusable/mandatory/dead |
codigo_muerto() |
Funciones/clases sin callers ni export |
arquitectura() |
Lenguajes, módulos, hotspots, reutilizables, muertos |
cambios_desde(git_ref) |
Ficheros cambiados + blast radius de cada símbolo |
anotar_simbolo(simbolo, etiqueta, nota="") |
Anotación persistente (mandatory/reusable/keep/…) |
historico(simbolo) |
Evolución added/modified/removed por commit |
estado_indexado() |
Último snapshot y si el codebase cambió desde entonces |
Cada llamada expone la confianza (exact/heuristic/unresolved) de las aristas para
que valores tú la fiabilidad; nunca se adivina en ambigüedad.
El servidor myrmion-codebase elige el parser por la extensión del fichero. El grafo es
el mismo para todos (nodos Module/Class/Function/Method, aristas DEFINES/IMPORTS/INHERITS/ CALLS/IMPLEMENTS); solo cambia el motor de parseo:
| Lenguaje | Extensiones | Parser | Notas |
|---|---|---|---|
| Python | .py |
ast (stdlib) |
resolución semántica de scopes; cero dependencias |
| JavaScript | .js .jsx .mjs .cjs |
tree-sitter | tree-sitter-javascript |
| TypeScript / TSX | .ts .tsx |
tree-sitter | tree-sitter-typescript |
| Java | .java |
tree-sitter | tree-sitter-java |
| C# | .cs |
tree-sitter | tree-sitter-c-sharp |
| VB.NET | .vb |
tree-sitter | grammar vb de tree-sitter-language-pack: Class/Module/Structure/Interface/Enum, Sub/Function, Imports, llamadas |
| VB5/6 · VBScript | .bas .cls .frm .vbs |
propio (line-oriented) | Sub/Function/Property Get|Let|Set/Class, Implements, Call (sin gramática tree-sitter fiable) |
| ASP clásico | .asp |
preprocesador → VBScript | extrae bloques <% %> y directivas <!--#include--> (→ IMPORTS) |
La resolución de llamadas es heurística en todos los lenguajes (tree-sitter es sintáctico; no hay análisis de tipos): se expone
confidence(exact/heuristic/unresolved) para que valores la fiabilidad. En VB.NET la herencia (Inherits/Implements) se omite por ser poco fiable en la gramática. Nuevos lenguajes tree-sitter se añaden registrando su gramática y extensión. El markup.aspxde ASP.NET queda para fase posterior.
El inventario durable refleja solo la rama main; editar en ramas de feature no lo
muta (si la rama nunca se mergea, no deja símbolos fantasma). Tres capas:
- Instrucciones en
CLAUDE.md: Claude llama asincronizar_codigotras editar. - Hook
PostToolUse(.claude/settings.json→hooks/sync_on_edit.sh): mantiene caliente el overlay de sesión tras cada Edit/Write (nunca el durable). - git
pre-pushhook (hooks/pre-push, activado porsetup.shvíacore.hooksPath): al hacer push amain, reconcilia el inventario canónico con el diff y aborta el push si no queda consistente. Lo ejecuta git, no el modelo → no se puede saltar.
sincronizar_codigo(["ruta"]) (y el CLI python -m codebase_mcp.sync) actualizan el grafo
tras editar, garantizando:
- Sin duplicados:
Node.idestable (kind:qualified_name) + upsert idempotente. - Sin residuos: borra todos los nodos/aristas del fichero antes de re-parsear (los símbolos renombrados/eliminados desaparecen).
- Consistencia cruzada: re-resuelve todas las llamadas, así ninguna arista de otro fichero queda colgando.
- Barato: no-op si el hash del fichero no cambió.
LightRAG guarda solo la versión actual de cada documento y deduplica por nombre
(archiva los duplicados en vez de actualizar): si el contenido cambia pero el nombre no, un
re-upload ingenuo pierde el update. Por encima de LightRAG hay un ledger de documentos
que reutiliza la misma maquinaria que el inventario de código (snapshots + histórico), con la
identidad = basename y el body_hash = hash de contenido/bytes:
- Detección por hash, no por nombre:
sincronizar_documento(ruta)/sincronizar_documentos(carpeta)reindexan solo si el hash cambió (no-op si no), y hacen delete + insert/upload cuando cambió → nunca se pierde un update ni se duplica. Funciona con binarios (pdf/docx: se re-sube el fichero por multipart). - Histórico: cada sync crea un snapshot (etiquetado con el commit git) y registra
added/modified/removed →
historico_documento(ruta)yestado_documentos(), igual que el codebase. - Batch seguro:
python ingest.py "$INPUT_DIR" --syncusa el ledger para saltar lo no cambiado y actualizar (borrar+subir) lo modificado, en vez de dejar que LightRAG archive el duplicado.
El ledger vive en config/docs.json (var DOCS_LEDGER), gitignored.
pip install -r requirements-dev.txt # pytest, pytest-cov, respx, tree-sitter, ...
python -m pytest # cobertura mínima exigida: 80%87 tests, ~87% de cobertura. Todo corre sin servicios externos (HTTP mockeado con
respx, grafo en memoria, git real en tmp_path). Los tests que requieren Neo4j/Postgres
reales van marcados @pytest.mark.integration y se excluyen por defecto.
.
├── mcp_server.py # servidor MCP de documentos (LightRAGClient)
├── codebase_server.py # servidor MCP de código
├── codebase_mcp/ # paquete: parsers, GraphStore, resolver, queries, inventory,
│ # gitutil, history, indexer, sync
├── backends.py # perfiles de storage + healthcheck + modelos (testeable)
├── consistency.py # saga + reconciliación del híbrido (testeable)
├── consistency_readers.py # cableado a Neo4j/Postgres reales (integración)
├── ingest.py # ingesta en lote de documentos
├── docker-compose.yml # Neo4j / Postgres (perfiles)
├── hooks/ # pre-push (gate del inventario) + sync_on_edit (PostToolUse)
├── tests/ # suite pytest + fixtures/mini_codebase
├── pyproject.toml # config de pytest/coverage
├── *.env.example / .mcp.json.example / *.sh.example # PLANTILLAS públicas
└── CLAUDE.md / README.md / LICENSE
# Generado en local, NUNCA versionado (gitignored):
# config/ TU config real (lightrag.env, codebase.env, mcp.json, codebase.json)
# .env .mcp.json enlaces a config/
# db-up.sh migrate-backend.sh venv/ rag_storage/
Este proyecto toma como base y se inspira en:
- HKUDS/LightRAG — motor GraphRAG (grafo + vectores + storage pluggable).
- DeusData/codebase-memory-mcp — concepto del servidor de inteligencia de codebase.
- tree-sitter + gramáticas
tree-sitter-javascript/typescript/java/c-sharpy tree-sitter-language-pack (grammarvbpara VB.NET) — parsing multi-lenguaje. - Ollama y Qwen — modelos locales (LLM y embeddings).
- Model Context Protocol — el estándar que conecta las herramientas con Claude Code.
- Neo4j y PostgreSQL (pgvector + Apache AGE) — backends profesionales.
MIT. Ver LICENSE.
