## Colaboración en notebooks Jupyter

### Requisito previo

El usuario debe tener Jupyter Lab corriendo en modo colaborativo (`--collaborative`) y el notebook abierto en el browser. Sin esto, los cambios no se ven en tiempo real.

El launcher estándar (`run-jupyter-lab.sh` generado por `init_jupyter_analysis`) ya incluye `--collaborative`.

### Funciones del registry (dominio `notebook`)

| Función | ID | Para qué |
|---|---|---|
| `jupyter_discover` | `jupyter_discover_py_notebook` | Descubrir instancias Jupyter activas, kernels, sesiones, modo colaborativo |
| `jupyter_read` | `jupyter_read_py_notebook` | Leer celdas (todas o una), metadata del notebook |
| `jupyter_exec` | `jupyter_exec_py_notebook` | Ejecutar: append+execute, execute celda existente, o directo al kernel |
| `jupyter_write` | `jupyter_write_py_notebook` | Escribir: append code/markdown, insert, edit, delete celdas |
| `jupyter_kernel` | `jupyter_kernel_py_notebook` | CRUD de kernels: list, start, restart, interrupt, shutdown, sessions |

### Invocación desde cualquier sesión de Claude

```bash
PYTHON="python/.venv/bin/python3"

# 1. Descubrir qué Jupyter está corriendo
$PYTHON python/functions/notebook/jupyter_discover.py --json

# 2. Leer notebook
$PYTHON python/functions/notebook/jupyter_read.py notebooks/01.ipynb --json

# 3. Añadir celda y ejecutar (el usuario la ve en tiempo real)
$PYTHON python/functions/notebook/jupyter_exec.py append notebooks/01.ipynb "df.describe()"

# 4. Ejecutar celda existente
$PYTHON python/functions/notebook/jupyter_exec.py cell notebooks/01.ipynb 3

# 5. Ejecutar en kernel sin tocar notebook
$PYTHON python/functions/notebook/jupyter_exec.py kernel "print(df.shape)"

# 6. Añadir markdown
$PYTHON python/functions/notebook/jupyter_write.py append-markdown notebooks/01.ipynb "## Resumen"

# 7. Gestionar kernels
$PYTHON python/functions/notebook/jupyter_kernel.py list
$PYTHON python/functions/notebook/jupyter_kernel.py sessions
$PYTHON python/functions/notebook/jupyter_kernel.py shutdown <kernel_id>
```

### Reglas de uso

- **SIEMPRE** ejecutar `jupyter_discover` primero para confirmar que Jupyter está activo y el notebook abierto.
- Las funciones resuelven automáticamente el `kernel_id` de la sesión del notebook y el `username` colaborativo via `/api/sessions` y `/api/me`.
- Después de escribir/ejecutar, las funciones mantienen la conexión WebSocket 2 segundos para que Y.js propague los cambios al browser.
- **NO usar MCP jupyter** — estas funciones reemplazan al MCP y funcionan desde cualquier directorio sin registrar nada.
- El token por defecto es vacío (sin auth). Si el server tiene token, pasarlo con `--token`.
- Los paths de notebooks son relativos a la raíz del servidor Jupyter (normalmente `analysis/{tema}/`).
