diff --git a/.claude/skills/init-jupyter/SKILL.md b/.claude/skills/init-jupyter/SKILL.md index 3d41164..e081c63 100644 --- a/.claude/skills/init-jupyter/SKILL.md +++ b/.claude/skills/init-jupyter/SKILL.md @@ -1,138 +1,156 @@ --- name: init-jupyter -description: Inicializa o inicia Jupyter Lab via MCP con kernel compartido. Detecta notebooks existentes automáticamente. +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/Iniciar Proyecto Jupyter via MCP +# Inicializar Entorno Jupyter para Data Science -Este skill gestiona entornos Jupyter Lab integrados con Claude via MCP. Detecta automáticamente si ya existe un proyecto configurado. +Skill para preparar cualquier repo para exploración de datos con Jupyter + Claude colaborando en kernel compartido. -## Modo de Colaboración (Kernel Compartido) +## PASO 0: Verificar estado actual del repo -**IMPORTANTE**: Para que las ejecuciones de Claude sean visibles en Jupyter Lab, se debe usar el **mismo kernel** que el notebook abierto. Esto permite: -- Ver las ejecuciones de Claude en tiempo real en Jupyter Lab -- Compartir variables y estado entre Claude y el usuario -- Colaboración real entre ambos en el mismo notebook - -## Flujo de decisión - -### 1. Detectar notebooks existentes - -Buscar archivos `.ipynb` en: -- Raíz del proyecto -- Carpeta `notebooks/` -- Cualquier subcarpeta +**Ejecutar estas comprobaciones primero:** ```bash -find [ruta] -name "*.ipynb" -type f 2>/dev/null | head -5 +# 1. ¿MCP instalado globalmente? +which 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" ``` -### 2. Si HAY notebooks existentes → Conectar o Iniciar +### Resultado: MCP NO instalado -**2a. Verificar que MCP está configurado con kernel compartido** -- Comprobar si existe `.claude/settings.local.json` con configuración de jupyter -- Verificar que incluye `--start-new-runtime false` para colaboración -- Si no existe o falta la configuración, crearlo (ver paso 3f) - -**2b. Verificar que jupyter-mcp-server está instalado** -```bash -which jupyter-mcp-server || uv tool install jupyter-mcp-server -``` - -**2c. Verificar si el script run-jupyter-lab.sh existe** -- Si no existe, crearlo (ver paso 3g) - -**2d. Detectar si Jupyter ya está corriendo** -```bash -# Verificar si hay un servidor Jupyter activo en el puerto esperado -curl -s http://localhost:8888/api/status 2>/dev/null && echo "Jupyter activo" || echo "Jupyter no detectado" -``` - -**2e. Si Jupyter YA está corriendo:** -- **NO arrancarlo de nuevo** -- Informar al usuario: "Jupyter Lab detectado en http://localhost:8888" -- Claude puede conectarse directamente via MCP al kernel existente -- El usuario tiene libertad total para gestionar Jupyter manualmente - -**2f. Si Jupyter NO está corriendo:** -- Preguntar al usuario si quiere que Claude lo arranque o prefiere hacerlo manualmente con `./run-jupyter-lab.sh` -- Si el usuario quiere arrancarlo: -```bash -source .venv/bin/activate 2>/dev/null || true -jupyter lab --no-browser --NotebookApp.token='' --NotebookApp.password='' --NotebookApp.disable_check_xsrf=True -``` - -**2g. Informar al usuario** que puede usar las herramientas MCP de Jupyter desde Claude. - -### 3. Si NO hay notebooks → Inicializar proyecto completo - -Seguir estos pasos: - -**3a. Validar ubicación** -- Si se proporciona `$1`, usar esa ruta -- Si no, usar el directorio actual - -**3b. Inicializar proyecto con uv** (si no existe pyproject.toml) -```bash -cd [ruta] && uv init -``` - -**3c. Crear entorno virtual** -```bash -uv venv -``` - -**3d. Instalar dependencias** -```bash -uv add jupyter jupyter-collaboration -``` - -**3e. Instalar jupyter-mcp-server** ```bash uv tool install jupyter-mcp-server ``` -**3f. Configurar MCP para Claude (con kernel compartido)** -Crear o actualizar `.claude/settings.local.json`: -```json -{ - "mcpServers": { - "jupyter": { - "command": "jupyter-mcp-server", - "args": [ - "--jupyter-url", "http://localhost:8888", - "--start-new-runtime", "false" - ] - } - } -} +Informar: +``` +MCP jupyter-mcp-server instalado. +Ejecuta /exit y vuelve a entrar para recargar. +Después ejecuta /init-jupyter de nuevo. +``` +**DETENER AQUÍ** + +### 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: Repo NO configurado → Continuar con PASO 1 + +--- + +## PASO 1: Detectar ruta de trabajo + +```bash +RUTA="${1:-.}" +cd "$RUTA" +pwd ``` -**Parámetros clave:** -- `--jupyter-url`: URL del servidor Jupyter (por defecto localhost:8888) -- `--start-new-runtime false`: **CRÍTICO** - Conecta al kernel existente en lugar de crear uno nuevo +--- -**3g. Crear script `run-jupyter-lab.sh`** +## 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: -Crear un script ejecutable para que el usuario pueda arrancar Jupyter manualmente: ```bash cat > run-jupyter-lab.sh << 'SCRIPT' #!/bin/bash -# Script para iniciar Jupyter Lab con configuración de colaboración -# El usuario puede arrancarlo manualmente y Claude se conectará al kernel existente +# Jupyter Lab para colaboración Claude + Usuario +# Generado por /init-jupyter -PORT=${1:-8888} +# 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 "Iniciando Jupyter Lab en puerto $PORT..." -echo "Abre http://localhost:$PORT en tu navegador" +echo "══════════════════════════════════════════════════════" +echo " Jupyter Lab iniciando en puerto $PORT" +echo "══════════════════════════════════════════════════════" echo "" -echo "Claude se conectará automáticamente al kernel cuando abras un notebook." +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 \ @@ -140,93 +158,174 @@ jupyter lab \ --NotebookApp.token='' \ --NotebookApp.password='' \ --NotebookApp.disable_check_xsrf=True \ - --ServerApp.allow_origin='*' + --ServerApp.allow_origin='*' \ + --ServerApp.root_dir="$(pwd)" SCRIPT chmod +x run-jupyter-lab.sh ``` -**3h. Crear carpeta notebooks** (opcional) +### 4c. Crear/Actualizar `.claude/settings.local.json` + +Usar el PUERTO detectado: + ```bash -mkdir -p notebooks -``` - -**3i. Iniciar Jupyter via MCP** -```bash -source .venv/bin/activate -jupyter lab --no-browser --NotebookApp.token='' --NotebookApp.password='' --NotebookApp.disable_check_xsrf=True -``` - -## Ejemplos de uso - -**Iniciar/inicializar en directorio actual:** -```bash -/init-jupyter -``` - -**Iniciar/inicializar en ruta específica:** -```bash -/init-jupyter ~/proyectos/mi-analisis -``` - -## Flujo de trabajo colaborativo (Kernel Compartido) - -### Cómo funciona la colaboración - -1. **Usuario inicia Jupyter Lab** (via este skill) -2. **Usuario abre un notebook** en Jupyter Lab → se inicia un kernel -3. **Claude se conecta al MISMO kernel** via MCP con `--start-new-runtime false` -4. **Ambos comparten**: - - El mismo estado de variables - - El mismo historial de ejecución - - Las salidas son visibles para ambos en tiempo real - -### Pasos para colaborar - -**Opción A - Usuario arranca Jupyter manualmente (recomendado):** -1. Ejecutar `./run-jupyter-lab.sh` (o `./run-jupyter-lab.sh 8889` para otro puerto) -2. Abrir el navegador en http://localhost:8888 -3. Abrir o crear el notebook deseado -4. Ejecutar `/init-jupyter` - Claude detectará Jupyter y se conectará al kernel existente -5. **Claude ya puede ejecutar celdas** y el usuario verá las ejecuciones en su Jupyter Lab - -**Opción B - Claude arranca Jupyter:** -1. Ejecutar `/init-jupyter` -2. Si no hay Jupyter corriendo, Claude lo arrancará -3. Abrir el navegador en http://localhost:8888 -4. Abrir o crear el notebook deseado -5. **Claude ya puede ejecutar celdas** - -### Obtener kernel ID específico (opcional) - -Si hay múltiples kernels corriendo, puedes obtener el ID del kernel activo: -```bash -curl -s http://localhost:8888/api/kernels | jq '.[0].id' -``` - -Y configurar MCP con ese kernel específico: -```json +cat > .claude/settings.local.json << EOF { "mcpServers": { "jupyter": { "command": "jupyter-mcp-server", "args": [ - "--jupyter-url", "http://localhost:8888", - "--runtime-id", "KERNEL_ID_AQUI" + "--jupyter-url", "http://localhost:PUERTO", + "--start-new-runtime", "false" ] } } } +EOF ``` -## Notas importantes +(Reemplazar PUERTO por el valor real detectado) -- **Siempre usa MCP**: Jupyter se ejecuta siempre de forma que Claude pueda interactuar via MCP -- **Kernel compartido por defecto**: Con `--start-new-runtime false`, Claude usa el kernel existente -- **Script `run-jupyter-lab.sh`**: Se crea automáticamente para que el usuario pueda arrancar Jupyter cuando quiera -- **Detección automática**: Claude detecta si Jupyter ya está corriendo y no lo arranca de nuevo -- **Libertad del usuario**: El usuario puede gestionar Jupyter manualmente, Claude se adapta -- Si detecta notebooks existentes, NO reinicializa el proyecto, solo conecta o inicia Jupyter -- Si el proyecto ya tiene `pyproject.toml`, no ejecuta `uv init` -- La configuración MCP se guarda en `.claude/settings.local.json` del proyecto -- El servidor MCP permite a Claude crear, editar y ejecutar celdas de notebooks -- **jupyter-collaboration** ya está incluido en las dependencias para sincronización en tiempo real +### 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: + +```bash +source .venv/bin/activate 2>/dev/null || true +uv add jupyter jupyterlab pandas numpy matplotlib 2>/dev/null || pip install jupyter jupyterlab pandas numpy matplotlib +``` + +--- + +## PASO 6: Resumen final al usuario + +Mostrar: + +``` +═══════════════════════════════════════════════════════════════ + Entorno Jupyter configurado en: [RUTA] +═══════════════════════════════════════════════════════════════ + + Puerto asignado: [PUERTO] + + Para empezar: + 1. En otra terminal ejecuta: ./run-jupyter-lab.sh + 2. Abre http://localhost:[PUERTO] en tu navegador + 3. Crea o abre un notebook + 4. Yo me conecto automáticamente al kernel compartido + + Archivos creados/actualizados: + - run-jupyter-lab.sh (lanzador) + - .claude/settings.local.json (config MCP) + - .claude/CLAUDE.md (reglas de trabajo) + +═══════════════════════════════════════════════════════════════ +``` + +--- + +## 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 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..da8e109 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +# Archivos locales de Jupyter (generados por /init-jupyter) +.jupyter-port +run-jupyter-lab.sh + +# Entornos virtuales +.venv/ +venv/ +__pycache__/ + +# Jupyter checkpoints +.ipynb_checkpoints/ + +# Configuración local de Claude +.claude/settings.local.json