--- name: init-jupyter description: Inicializa entorno Jupyter para exploración de datos con MCP compartido. Autodetecta puerto y configura repo. argument-hint: [ruta-proyecto] disable-model-invocation: true user-invocable: true allowed-tools: Bash, Read, Write, Edit, Glob --- # Inicializar Entorno Jupyter para Data Science Skill para preparar cualquier repo para exploración de datos con Jupyter + Claude colaborando en kernel compartido. ## ⚠️ REGLA CRÍTICA: MCP SIEMPRE LOCAL **NUNCA instalar jupyter-mcp-server globalmente.** Siempre: - Instalar en `.venv/bin/` del proyecto con `uv add jupyter-mcp-server` - Usar ruta ABSOLUTA en `.claude/settings.local.json` - Si existe instalación global (`~/.local/bin/jupyter-mcp-server`), eliminarla con `uv tool uninstall jupyter-mcp-server` ## PASO 0: Verificar estado actual del repo **Ejecutar estas comprobaciones primero:** ```bash # 1. ¿MCP instalado en el venv LOCAL del proyecto? [ -f .venv/bin/jupyter-mcp-server ] && echo "MCP_OK" || echo "MCP_NO" # 2. ¿Repo ya configurado para Jupyter? [ -f .claude/settings.local.json ] && grep -q "jupyter" .claude/settings.local.json && echo "REPO_CONFIG_OK" || echo "REPO_NO_CONFIG" # 3. ¿Jupyter corriendo en este repo? pgrep -af "jupyter" | grep "$(pwd)" && echo "JUPYTER_RUNNING" || echo "JUPYTER_STOPPED" # 4. ¿CLAUDE.md tiene reglas Jupyter? [ -f .claude/CLAUDE.md ] && grep -q "JUPYTER HABILITADO" .claude/CLAUDE.md && echo "RULES_OK" || echo "RULES_NO" # 5. ¿Puerto guardado está sincronizado con Jupyter real? if [ -f .jupyter-port ]; then PORT=$(cat .jupyter-port) if lsof -i:$PORT 2>/dev/null | grep -q jupyter; then echo "PORT_SYNC_OK" else echo "PORT_DESYNC (archivo dice $PORT pero no hay Jupyter ahí)" fi fi # 6. ¿Existe instalación GLOBAL de jupyter-mcp-server? (problemática) [ -f ~/.local/bin/jupyter-mcp-server ] && echo "GLOBAL_MCP_EXISTS (eliminar)" || echo "NO_GLOBAL_MCP" ``` ### Resultado: Instalación GLOBAL detectada (GLOBAL_MCP_EXISTS) **Eliminar inmediatamente para evitar conflictos:** ```bash # Eliminar instalación global uv tool uninstall jupyter-mcp-server 2>/dev/null || pip uninstall -y jupyter-mcp-server 2>/dev/null rm -f ~/.local/bin/jupyter-mcp-server # Verificar eliminación [ -f ~/.local/bin/jupyter-mcp-server ] && echo "ERROR: No se pudo eliminar" || echo "Instalación global eliminada OK" ``` Continuar con instalación local. ### Resultado: MCP NO instalado **IMPORTANTE: NUNCA instalar jupyter-mcp-server globalmente. Siempre en el venv local.** ```bash # Crear venv si no existe [ -d .venv ] || uv venv # Instalar MCP en el venv local del proyecto source .venv/bin/activate uv add jupyter-mcp-server || pip install jupyter-mcp-server # Verificar instalación local exitosa [ -f .venv/bin/jupyter-mcp-server ] && echo "MCP instalado localmente OK" || echo "ERROR: MCP no instalado" ``` Continuar con los siguientes pasos para configurar el MCP local. ### Resultado: Repo YA configurado + Jupyter corriendo Informar: ``` Este repo ya tiene Jupyter configurado y está corriendo. Puedes empezar a trabajar directamente con notebooks via MCP. ``` **DETENER AQUÍ** (no hace falta reconfigurar) ### Resultado: Repo YA configurado + Jupyter NO corriendo Informar: ``` Este repo tiene Jupyter configurado pero no está corriendo. Ejecuta ./run-jupyter-lab.sh en otra terminal para iniciarlo. ``` **DETENER AQUÍ** ### Resultado: Puerto DESINCRONIZADO (PORT_DESYNC) El archivo `.jupyter-port` dice un puerto pero Jupyter no está corriendo ahí. **Opciones:** 1. Si Jupyter está corriendo en otro puerto → actualizar `.jupyter-port` y `.claude/settings.local.json` 2. Si Jupyter no está corriendo → ejecutar `./run-jupyter-lab.sh` (actualizará el puerto automáticamente) ```bash # Buscar en qué puerto está Jupyter realmente pgrep -af "jupyter" | grep -oP 'port[= ]\K\d+' || echo "Jupyter no está corriendo" ``` ### Resultado: Repo NO configurado → Continuar con PASO 1 --- ## PASO 1: Detectar ruta de trabajo ```bash RUTA="${1:-.}" cd "$RUTA" pwd ``` --- ## PASO 2: Verificar si Jupyter ya corre en ESTE repo ```bash # Buscar proceso jupyter con el directorio actual REPO_PATH=$(pwd) pgrep -af "jupyter" | grep -E "(lab|notebook)" | grep "$REPO_PATH" || echo "NO_JUPYTER" ``` - Si encuentra proceso → Informar "Jupyter ya está corriendo en este repo" y saltar a Paso 6 - Si NO encuentra → Continuar --- ## PASO 3: Detectar puerto libre (autodetección) ```bash # Encontrar primer puerto libre entre 8888-8899 for port in 8888 8889 8890 8891 8892 8893 8894 8895 8896 8897 8898 8899; do if ! lsof -i:$port >/dev/null 2>&1; then echo $port break fi done ``` Guardar el puerto detectado para usarlo en los siguientes pasos. --- ## PASO 4: Crear/Actualizar archivos del proyecto ### 4a. Crear estructura si no existe ```bash mkdir -p .claude notebooks ``` ### 4b. Crear `run-jupyter-lab.sh` con puerto autodetectado Crear el archivo con el PUERTO detectado en Paso 3: ```bash cat > run-jupyter-lab.sh << 'SCRIPT' #!/bin/bash # Jupyter Lab para colaboración Claude + Usuario # Generado por /init-jupyter # Autodetectar puerto libre find_free_port() { for port in 8888 8889 8890 8891 8892 8893 8894 8895 8896 8897 8898 8899; do if ! lsof -i:$port >/dev/null 2>&1; then echo $port return fi done echo 8888 } PORT=${1:-$(find_free_port)} # Guardar puerto para que Claude lo lea echo $PORT > .jupyter-port # Activar entorno si existe source .venv/bin/activate 2>/dev/null || true echo "══════════════════════════════════════════════════════" echo " Jupyter Lab iniciando en puerto $PORT" echo "══════════════════════════════════════════════════════" echo "" echo " Abre: http://localhost:$PORT" echo "" echo " Claude se conectará al kernel cuando abras un notebook" echo " Usa Ctrl+C para detener" echo "" echo "══════════════════════════════════════════════════════" jupyter lab \ --port=$PORT \ --no-browser \ --NotebookApp.token='' \ --NotebookApp.password='' \ --NotebookApp.disable_check_xsrf=True \ --ServerApp.allow_origin='*' \ --ServerApp.root_dir="$(pwd)" SCRIPT chmod +x run-jupyter-lab.sh ``` ### 4c. Crear/Actualizar `.claude/settings.local.json` (con MERGE) **IMPORTANTE: Usar ruta ABSOLUTA al ejecutable del venv local.** **IMPORTANTE: Hacer MERGE para preservar otros MCPs existentes.** Usar el PUERTO detectado y la ruta absoluta: ```bash # Obtener ruta absoluta del proyecto PROJECT_PATH=$(pwd) PUERTO=8888 # Reemplazar con el puerto detectado en Paso 3 # Crear config de jupyter como JSON temporal cat > /tmp/jupyter-mcp.json << EOF { "mcpServers": { "jupyter": { "command": "${PROJECT_PATH}/.venv/bin/jupyter-mcp-server", "args": [ "--jupyter-url", "http://localhost:${PUERTO}", "--start-new-runtime", "false" ] } } } EOF # Merge: si existe settings.local.json, combinar; si no, crear nuevo if [ -f .claude/settings.local.json ]; then # Merge profundo: preserva otros MCPs, actualiza/añade jupyter jq -s '.[0] * .[1] | .mcpServers = (.[0].mcpServers // {}) * (.[1].mcpServers // {})' \ .claude/settings.local.json /tmp/jupyter-mcp.json > .claude/settings.local.json.tmp mv .claude/settings.local.json.tmp .claude/settings.local.json echo "settings.local.json actualizado (merge con config existente)" else # No existe, crear nuevo mv /tmp/jupyter-mcp.json .claude/settings.local.json echo "settings.local.json creado" fi rm -f /tmp/jupyter-mcp.json ``` **NOTA:** La ruta absoluta es crítica. Si usas solo `jupyter-mcp-server`, Claude buscará en PATH global y fallará. ### 4d. Añadir/Actualizar instrucciones en `.claude/CLAUDE.md` **IMPORTANTE**: Las reglas de Jupyter deben ir AL PRINCIPIO del archivo para que nuevas conversaciones las vean inmediatamente. **Lógica de inserción:** 1. Verificar si existe `.claude/CLAUDE.md` 2. Si existe: - Leer contenido actual - Si NO contiene "JUPYTER HABILITADO" → prepend (añadir al principio) - Si YA contiene → no modificar 3. Si no existe → crearlo con las reglas **Contenido a insertar AL PRINCIPIO:** ```markdown # JUPYTER HABILITADO EN ESTE REPO Este repositorio está configurado para exploración de datos con Jupyter + Claude. ## Estado del entorno - **Lanzador**: `./run-jupyter-lab.sh` - **Puerto config**: ver `.jupyter-port` o `.claude/settings.local.json` - **MCP**: jupyter-mcp-server configurado ## Reglas OBLIGATORIAS para Claude ### 1. SIEMPRE usar MCP jupyter para ejecutar código Python - Las ejecuciones se ven en tiempo real en Jupyter Lab del usuario - Compartimos variables y estado del kernel - **NUNCA usar bash para ejecutar Python en este repo** ### 2. Verificar Jupyter activo ANTES de ejecutar ```bash pgrep -af "jupyter" | grep "$(pwd)" || cat .jupyter-port 2>/dev/null ``` - Si no está activo → pedir al usuario: "Ejecuta `./run-jupyter-lab.sh` en otra terminal" ### 3. Gestión de notebooks - Si un notebook tiene >50 celdas → crear uno nuevo - Nombrar descriptivamente: `01_exploracion.ipynb`, `02_limpieza.ipynb` - Mantener notebooks enfocados en una tarea ### 4. Antes de código pesado - Avisar al usuario - Usar `%%time` o `tqdm` para progreso --- ``` **Comando bash para prepend:** ```bash # Si CLAUDE.md existe y NO tiene las reglas if [ -f .claude/CLAUDE.md ]; then if ! grep -q "JUPYTER HABILITADO" .claude/CLAUDE.md; then # Prepend: crear temp con reglas + contenido original cat > .claude/CLAUDE.md.tmp << 'JUPYTER_RULES' [CONTENIDO DE REGLAS AQUÍ] JUPYTER_RULES cat .claude/CLAUDE.md >> .claude/CLAUDE.md.tmp mv .claude/CLAUDE.md.tmp .claude/CLAUDE.md fi else # Crear nuevo cat > .claude/CLAUDE.md << 'JUPYTER_RULES' [CONTENIDO DE REGLAS AQUÍ] JUPYTER_RULES fi ``` --- ## PASO 5: Inicializar entorno Python si no existe ### 5a. Si no existe `pyproject.toml`: ```bash uv init 2>/dev/null || true uv venv 2>/dev/null || true ``` ### 5b. Instalar dependencias de Jupyter (incluyendo MCP): **IMPORTANTE: jupyter-mcp-server SIEMPRE se instala en el venv local, NUNCA global.** ```bash source .venv/bin/activate 2>/dev/null || true uv add jupyter jupyterlab jupyter-mcp-server pandas numpy matplotlib 2>/dev/null || pip install jupyter jupyterlab jupyter-mcp-server pandas numpy matplotlib # Verificar que MCP quedó instalado localmente [ -f .venv/bin/jupyter-mcp-server ] && echo "MCP instalado en venv local OK" || echo "ERROR: MCP no instalado" ``` --- ## PASO 6: Resumen final al usuario Mostrar: ``` ═══════════════════════════════════════════════════════════════ Entorno Jupyter configurado en: [RUTA] ═══════════════════════════════════════════════════════════════ Puerto asignado: [PUERTO] MCP: .venv/bin/jupyter-mcp-server (LOCAL al proyecto) ┌─────────────────────────────────────────────────────────┐ │ PASOS PARA ACTIVAR (orden importante): │ │ │ │ 1. SALIR de Claude Code: /exit o Ctrl+C │ │ (necesario para que cargue el nuevo MCP) │ │ │ │ 2. En OTRA terminal, ejecuta: │ │ cd [RUTA] && ./run-jupyter-lab.sh │ │ │ │ 3. Volver a entrar a Claude: │ │ cd [RUTA] && claude │ │ (ahora detectará el MCP de Jupyter) │ │ │ │ 4. Abre en navegador: http://localhost:[PUERTO] │ │ │ │ 5. Crea o abre un notebook y empieza a trabajar │ └─────────────────────────────────────────────────────────┘ Archivos creados/actualizados: ✓ run-jupyter-lab.sh (lanzador con autodetección de puerto) ✓ .claude/settings.local.json (config MCP - merge con existente) ✓ .claude/CLAUDE.md (reglas de trabajo al principio) ✓ .venv/bin/jupyter-mcp-server (ejecutable MCP local) Verificación rápida del MCP: $ ls -la .venv/bin/jupyter-mcp-server Si el MCP no funciona después de reiniciar Claude: 1. Verifica que Jupyter está corriendo: pgrep -af jupyter 2. Verifica puerto: cat .jupyter-port 3. Verifica MCP existe: ls .venv/bin/jupyter-mcp-server 4. Revisa config: cat .claude/settings.local.json ═══════════════════════════════════════════════════════════════ ``` --- ## Comandos útiles post-inicialización ```bash # Ver puerto actual cat .jupyter-port # Verificar Jupyter corriendo pgrep -af jupyter # Listar kernels activos curl -s http://localhost:$(cat .jupyter-port)/api/kernels | jq # Listar notebooks abiertos curl -s http://localhost:$(cat .jupyter-port)/api/sessions | jq ``` --- ## Notas para uso frecuente - El script `run-jupyter-lab.sh` autodetecta puerto cada vez que se ejecuta - El archivo `.jupyter-port` siempre tiene el puerto actual - Si cambias de puerto, actualiza `.claude/settings.local.json` o recarga Claude - Las reglas en `CLAUDE.md` se mantienen entre sesiones