Instalación y uso de Graphify (Linux / WSL)
(Contenido creado con IA)
Guía paso a paso para instalar Graphify una vez en el
entorno (máquina/WSL) y luego activarlo en cada proyecto. Basada en la instalación real hecha en
drupal (ver sección 8 para las particularidades de ese proyecto).
Graphify convierte una carpeta de código/config/docs en un grafo de conocimiento consultable
(graph.json, graph.html, GRAPH_REPORT.md) y puede integrarse con Claude Code para que
consulte ese grafo antes de rastrear todo el código.
1. Qué es global y qué es por-proyecto
| Elemento | Alcance | Cuándo se instala |
|---|---|---|
uv (gestor de Python) |
Global, una vez por máquina | Sección 2 |
graphifyy (el CLI graphify) |
Global, una vez por máquina | Sección 2 |
| API key del backend LLM | Global (variable de entorno / .env) |
Sección 3 |
graphify-out/ (graph.json, graph.html, GRAPH_REPORT.md) |
Por proyecto — es el dato generado a partir de ESE código | Sección 5 |
.claude/settings.json (hook), .claude/skills/graphify/, sección en CLAUDE.md
|
Por proyecto | Sección 6 |
No hace falta reinstalar uv/graphify en cada repo. Lo único que se repite por proyecto es
generar su grafo y activar la integración con Claude Code.
2. Instalar Graphify en el entorno (una vez)
Requisitos: Python 3.10+ (ya viene en la mayoría de distros/WSL) y curl.
# 1. Instalar uv (gestiona su propio Python, no depende del venv del sistema)
curl -LsSf https://astral.sh/uv/install.sh | sh
source "$HOME/.local/bin/env" # o reinicia la shell; añade ~/.local/bin al PATH
# 2. Instalar graphify como herramienta global
uv tool install graphifyy
# 3. Comprobar
graphify --version
graphify --help
Nota WSL/Debian/Ubuntu: si en algún momento usas
python3 -m venvdirectamente y falla con
No module named ensurepippidiendoapt install python3.X-venv(requiere sudo), no lo
instales para esto: usauv, que no depende del módulovenvdel sistema. Así es como lo
resolvimos endrupal.
2.1 Instalar el soporte del backend LLM que vayas a usar
El extractor semántico necesita un paquete de cliente extra según el backend. Instálalo con el
extra correspondiente (si no sabes cuál usarás, all los trae todos):
uv tool install "graphifyy[gemini]" # Google Gemini
uv tool install "graphifyy[anthropic]" # Claude
uv tool install "graphifyy[openai]" # OpenAI
uv tool install "graphifyy[ollama]" # modelo local, sin API key
# o directamente:
uv tool install "graphifyy[all]"
Si lo instalaste sin el extra y graphify extract falla con the 'openai'/'anthropic' package is, reinstala con
required for this backend--force y el extra correcto:
uv tool install "graphifyy[gemini]" --force
(Esto nos pasó la primera vez: el backend gemini usa internamente el cliente openai, y no se
instala por defecto.)
3. Configurar la API key
Solo hace falta si vas a extraer contenido semántico (docs, config, PDFs, imágenes). El parsing de
código puro (--code-only) no requiere key.
| Backend | Variable de entorno |
|---|---|
| Gemini |
GEMINI_API_KEY o GOOGLE_API_KEY
|
| Claude | ANTHROPIC_API_KEY |
| OpenAI | OPENAI_API_KEY |
| DeepSeek | DEEPSEEK_API_KEY |
| Kimi | MOONSHOT_API_KEY |
| Ollama (local) | ninguna |
| Bedrock | credenciales AWS/IAM |
export GEMINI_API_KEY="tu-clave"
Cuidado con las comillas: si la clave está en un
.envcomoGEMINI_API_KEY="AQ.xxx", un
cut -d'=' -f2-se lleva las comillas literales dentro del valor y Gemini responde
Please pass a valid API key. Al extraer el valor de un.env, quítalas explícitamente:val="$(grep '^GEMINI_API_KEY=' .env | cut -d'=' -f2-)" val="${val%\"}"; val="${val#\"}" export GEMINI_API_KEY="$val"Límites del tier gratuito: el tier gratuito de Gemini (
gemini-3-flash) tiene límites bajos
(5 peticiones/min, 250k tokens/min). Sigraphify extractfalla con errores429, repite con
RESOURCE_EXHAUSTED--max-concurrency 1(más lento pero no satura la cuota). El
caché interno evita reprocesar lo que ya se extrajo con éxito.
4. Decidir el alcance del grafo en un proyecto
Dos formas de usarlo:
A) Graficar todo el repo (proyectos pequeños, sin vendor/, node_modules/, dumps de BD, etc.
mezclados con el código):
cd mi-proyecto
graphify extract .
B) Graficar solo unas rutas concretas (recomendado en proyectos con dependencias de terceros,
builds, backups SQL, sites/default/files, etc. que no aportan nada al grafo y disparan coste/
ruido). Se crea una copia física de solo esas rutas y se extrae sobre la copia:
cd mi-proyecto
mkdir -p graphify/source/<misma-estructura-de-carpetas>
cp -r ruta/a/incluir-1 graphify/source/ruta/a/incluir-1
cp -r ruta/a/incluir-2 graphify/source/ruta/a/incluir-2
# ... una copia por cada ruta a incluir, preservando la ruta relativa
Añade graphify/ a .gitignore para que esta copia y las herramientas no se comiteen:
echo '/graphify/' >> .gitignore
Esto es lo que se hizo en drupal: ver sección 8 para el ejemplo completo con
config/sync, módulos y temas custom/contrib concretos.
5. Generar el grafo
# Extracción completa (AST + semántica vía LLM)
graphify extract <ruta> --backend gemini
# Si el backend gratuito da 429, repetir más despacio:
graphify extract <ruta> --backend gemini --max-concurrency 1
# Generar/regenerar GRAPH_REPORT.md + graph.html con nombres de comunidad
graphify cluster-only <ruta> --backend gemini --max-concurrency 1 --batch-size 100
Flags útiles:
-
--no-gitignore: procesa también archivos que estén en.gitignore(útil si<ruta>es una copia aislada como en el método B, o si hay config versionada que normalmente se ignora). -
--code-only: solo AST determinista, sin LLM, sin API key. -
--force: fuerza re-extracción completa ignorando caché.
Resultado en <ruta>/graphify-out/:
-
graph.json— datos completos del grafo (nodos, edges, comunidades) -
graph.html— visualización interactiva -
GRAPH_REPORT.md— resumen en lenguaje natural + preguntas sugeridas
Es normal que algunos archivos de configuración muy simples (YAML triviales, toggles) no
generen nodo semántico propio — el modelo decide que no aportan nada nuevo más allá del AST. No
es un fallo; el resto del grafo (código, relaciones) sigue siendo válido.
6. Integrar con Claude Code en el proyecto
Si <ruta> del paso anterior es la raíz del proyecto, el grafo ya queda en
./graphify-out/graph.json, la ubicación por defecto que espera Graphify (hook, skill y comandos
sin --graph explícito).
Si usaste el método B (copia aislada, p. ej. graphify/source/), el grafo se genera por defecto
dentro de graphify/source/graphify-out/, no en la raíz. Muévelo una vez a la raíz (ubicación
que espera el resto de la integración):
mv graphify/source/graphify-out ./graphify-out
A partir de ahí, cualquier extract/update que vuelvas a lanzar sobre graphify/source debe
llevar la variable GRAPHIFY_OUT apuntando a esa ruta absoluta, o volverá a escribir dentro de
graphify/source/graphify-out (duplicando el grafo en vez de actualizar el de la raíz):
export GRAPHIFY_OUT="$(pwd)/graphify-out"
graphify update graphify/source # o extract, con --backend
Una alternativa más simple si no te importa el symlink es dejar
graphify-outcomo
ln -s graphify/source/graphify-out graphify-out: las lecturas (query, el hook,graph.html)
y las siguientes escrituras deextract/update graphify/source(que escriben en
graphify/source/graphify-out, el destino real del enlace) siguen funcionando igual sin tocar
GRAPHIFY_OUT. Mover el directorio de verdad a la raíz (como se hizo arriba) es preferible por
tenerlo en la ubicación canónica sin depender de un enlace, pero ambas opciones son válidas.
Instala la integración oficial (hook + skill + nota en CLAUDE.md), sin --strict:
graphify claude install --project
Esto crea/actualiza:
-
.claude/settings.json— hooksPreToolUse(advisory, nunca bloqueante sin--strict): avisan antes de ungrep/Bash/Grepo de leer un archivo de código, sugiriendographify queryprimero. -
.claude/skills/graphify/— skill del comando/graphify. -
CLAUDE.md— sección## graphifycon las reglas de cuándo consultar el grafo.
Revisa la sección añadida a
CLAUDE.md: por defecto dicegraphify update .para
refrescar el grafo tras cambios de código. Si usaste el método B (copia aislada), eso es
incorrecto —.es la raíz real del proyecto, no la copia, y lanzaría una extracción sin
acotar sobre todo el repo. Corrígelo a mano porgraphify update graphify/source(o la ruta de
tu copia).
--strictes opcional y no se activó por defecto: bloquearía la primera lectura de código
por sesión hasta consultar el grafo. Con un grafo que no cubre todo el repo (método B), eso
puede bloquear tareas legítimas fuera del alcance graficado — se dejó desactivado.
7. Mantenimiento
-
Tras cambiar código dentro de las rutas graficadas:
graphify update <ruta>(solo AST, sin coste de API). Si usaste copia aislada, primero hay que reflejar el cambio dentro degraphify/source/(copiando el archivo modificado) y luego correrupdatesobre esa copia conGRAPHIFY_OUTapuntando algraphify-out/real (ver sección 6):
export GRAPHIFY_OUT="$(pwd)/graphify-out"
graphify update graphify/source
-
Re-extracción semántica completa (por ejemplo tras añadir muchas rutas nuevas):
graphify extract <ruta> --backend <backend> --force. -
Desinstalar de un proyecto:
graphify uninstall --project(quita hook, skill y sección deCLAUDE.md; con--purgeborra tambiéngraphify-out/).
8. Limitaciones conocidas (comprobadas en la práctica)
-
Cobertura parcial: el grafo solo "sabe" de las rutas que se graficaron. Para cualquier otra
parte del proyecto, hay que seguir buscando en el código directamente — decídselo explícitamente
a Claude Code en
CLAUDE.mdsi usas el método B. -
El hook de lectura (
Read/Glob) no se dispara para cualquier extensión: solo para un listado fijo de extensiones "genéricas" (.php,.js,.ts,.md, etc. — ver_HOOK_SOURCE_EXTSen el código de Graphify). En un proyecto Drupal, por ejemplo, no se dispara para.module,.install,.yml,.themeni.twig, que es donde vive buena parte del código/config. El aviso de búsqueda (Bash|Grep) sí se dispara siempre que exista el grafo, independientemente de la extensión. -
Coste y cuotas: la extracción semántica consume tokens del backend elegido. El tier
gratuito de Gemini es fácil de agotar en proyectos con muchos archivos de config; usar
--max-concurrency 1lo evita a costa de tardar más. - El grafo es un punto de partida para orientarse, no la fuente de verdad — conviene verificar siempre en el código real antes de editar.
9. Ejemplo real: drupal
En este proyecto se usó el método B (copia aislada) porque el repo mezcla Drupal core, vendor/,
sites/default/files, dumps SQL, etc. junto al código propio. Solo interesaba graficar:
config/sync/**
web/modules/custom/*
web/modules/contrib/quiz
web/themes/custom/*
web/themes/contrib/bootstrap_barrio
Pasos aplicados (resumen; ver CLAUDE.md del proyecto para el resultado final):
# 0. Instalación global (una vez en la máquina/WSL)
curl -LsSf https://astral.sh/uv/install.sh | sh
uv tool install "graphifyy[gemini]" # ~/.local/bin ya estaba en el PATH
# 1. Copia aislada de solo las rutas a graficar
mkdir -p graphify/source/config graphify/source/web/modules/custom \
graphify/source/web/modules/contrib graphify/source/web/themes/custom \
graphify/source/web/themes/contrib
cp -r config/sync graphify/source/config/sync
cp -r web/modules/custom/. graphify/source/web/modules/custom/
cp -r web/modules/contrib/quiz graphify/source/web/modules/contrib/quiz
cp -r web/themes/custom/. graphify/source/web/themes/custom/
cp -r web/themes/contrib/bootstrap_barrio graphify/source/web/themes/contrib/bootstrap_barrio
# 2. Extracción (config/sync son YAML "contenido/conocimiento", no solo código -> --no-gitignore)
export GEMINI_API_KEY="..."
graphify extract graphify/source --backend gemini --no-gitignore --max-concurrency 1
graphify cluster-only graphify/source --backend gemini --max-concurrency 1 --batch-size 100
# 3. Mover el grafo a la raíz (ubicación canónica) e integrar con Claude Code
mv graphify/source/graphify-out ./graphify-out
graphify claude install --project
# (y corregir a mano el "graphify update ." -> ver sección 6/7, con GRAPHIFY_OUT, en CLAUDE.md)
Resultado final: ./graphify-out/graph.json (directorio real en la raíz, ~1600 nodos / ~2850
edges / ~296 comunidades), graphify instalado en global (~/.local/bin/graphify), copia
aislada del código en graphify/source/ (usada solo como entrada para futuras
extract/update), y el hook + la nota en CLAUDE.md activos para ese subconjunto de rutas.
Top comments (0)