# /analysis — Trabajar con analisis Jupyter y notebooks del registry

Eres un agente de analisis de datos. Tienes acceso a funciones Python del fn_registry para **crear, gestionar y operar analisis Jupyter** completos: descubrir instancias, crear notebooks, escribir celdas, ejecutar codigo, leer resultados y gestionar kernels. Usa estas funciones directamente — no uses MCP jupyter ni manipules archivos .ipynb a mano.

---

## Como ejecutar funciones

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

# Ejecutar codigo inline
$PYTHON -c "
import sys; sys.path.insert(0, 'python/functions')
from notebook import jupyter_discover
print(jupyter_discover.jupyter_discover())
"

# O via CLI (cada funcion tiene su propio CLI)
$PYTHON python/functions/notebook/jupyter_discover.py --json
$PYTHON python/functions/notebook/jupyter_write.py create notebooks/01.ipynb
$PYTHON python/functions/notebook/jupyter_exec.py append notebooks/01.ipynb "print('hola')"
$PYTHON python/functions/notebook/jupyter_kernel.py list

# Pipelines con fn run
./fn run init_jupyter_analysis mi_analisis
./fn run init_jupyter_analysis ml scikit-learn torch
./fn run export_analysis_pdfs mi_analisis
```

---

## CREAR UN ANALISIS NUEVO

```bash
# Basico (crea venv, launcher, MCP, reglas Claude, kernel startup)
./fn run init_jupyter_analysis nombre_analisis

# Con paquetes extra
./fn run init_jupyter_analysis nombre_analisis pandas scikit-learn matplotlib

# Despues de crear:
cd analysis/nombre_analisis && ./run-jupyter-lab.sh  # Terminal 1: lanzar Jupyter
cd analysis/nombre_analisis && claude                 # Terminal 2: abrir Claude
# Navegador: http://localhost:8888
```

Estructura generada:
```
analysis/nombre_analisis/
  .venv/                             # Deps propias (gitignored)
  .mcp.json                          # MCP jupyter (gitignored)
  .claude/CLAUDE.md                  # Reglas para agentes
  .ipython/profile_default/startup/
    00_fn_registry.py                # Helpers fn_search, fn_query, fn_code
  notebooks/                         # Notebooks aqui
  data/                              # Datos locales (gitignored)
  run-jupyter-lab.sh                 # Launcher colaborativo
  pyproject.toml                     # Deps con uv
```

---

## DISCOVER — Descubrir instancias Jupyter

```python
from notebook.jupyter_discover import jupyter_discover

# Descubrir todas las instancias activas
instances = jupyter_discover()
# [{"url": "http://localhost:8888", "status": "running", "collaborative": true,
#   "root_dir": "/home/user/fn_registry/analysis/mi_analisis",
#   "analysis_name": "mi_analisis", "kernels": 2, "sessions": 1, "pid": 12345}]

# Con registry_root explicito
instances = jupyter_discover(registry_root="/home/user/fn_registry")
```

```bash
$PYTHON python/functions/notebook/jupyter_discover.py --json
```

**SIEMPRE ejecutar discover primero** para confirmar que Jupyter esta activo antes de operar sobre notebooks.

---

## WRITE — Escribir en notebooks

Las funciones append y batch **crean el notebook automaticamente** si no existe. No es necesario abrir el notebook en el navegador primero.

```python
from notebook.jupyter_write import (
    jupyter_create_notebook,    # Crear notebook vacio (REST)
    jupyter_append_code,        # Anadir celda de codigo al final
    jupyter_append_markdown,    # Anadir celda markdown al final
    jupyter_insert_cell,        # Insertar celda en posicion especifica
    jupyter_edit_cell,          # Sobrescribir contenido de celda
    jupyter_delete_cell,        # Eliminar celda
    jupyter_batch_write,        # Anadir N celdas en una conexion
)

# Crear notebook y poblar celdas (una sola llamada)
jupyter_batch_write("notebooks/01.ipynb", [
    {"type": "markdown", "source": "# Analisis exploratorio"},
    {"type": "code", "source": "import pandas as pd\nimport matplotlib.pyplot as plt"},
    {"type": "code", "source": "df = pd.read_csv('data/dataset.csv')\ndf.head()"},
])
# {"action": "batch", "cells_added": 3, "notebook": "notebooks/01.ipynb"}

# Crear notebook explicitamente (si se necesita control)
jupyter_create_notebook("notebooks/02.ipynb", kernel_name="python3")
# force=True para sobreescribir

# Anadir celdas individuales
jupyter_append_code("notebooks/01.ipynb", "df.describe()")
jupyter_append_markdown("notebooks/01.ipynb", "## Resultados")

# Insertar en posicion 2
jupyter_insert_cell("notebooks/01.ipynb", 2, "x = 42", cell_type="code")

# Editar celda existente
jupyter_edit_cell("notebooks/01.ipynb", 0, "# Titulo actualizado")

# Eliminar celda
jupyter_delete_cell("notebooks/01.ipynb", 3)
```

```bash
# CLI
$PYTHON python/functions/notebook/jupyter_write.py create notebooks/01.ipynb
$PYTHON python/functions/notebook/jupyter_write.py append-code notebooks/01.ipynb "print('hola')"
$PYTHON python/functions/notebook/jupyter_write.py append-markdown notebooks/01.ipynb "## Titulo"
$PYTHON python/functions/notebook/jupyter_write.py insert notebooks/01.ipynb 2 "x = 42" --type code
$PYTHON python/functions/notebook/jupyter_write.py edit notebooks/01.ipynb 0 "# Nuevo titulo"
$PYTHON python/functions/notebook/jupyter_write.py delete notebooks/01.ipynb 3

# Batch desde JSON
echo '[{"type":"code","source":"import pandas as pd"},{"type":"markdown","source":"## Datos"}]' | \
  $PYTHON python/functions/notebook/jupyter_write.py batch notebooks/01.ipynb
```

---

## EXEC — Ejecutar codigo en notebooks

`jupyter_append_execute` **crea el notebook y arranca un kernel automaticamente** si no existen. No es necesario abrir el notebook manualmente.

```python
from notebook.jupyter_exec import (
    jupyter_append_execute,   # Anadir celda + ejecutar (auto-init)
    jupyter_execute_cell,     # Ejecutar celda existente por indice
    jupyter_kernel_execute,   # Ejecutar en kernel sin tocar notebook
)

# Crear notebook + kernel + ejecutar celda (todo automatico)
result = jupyter_append_execute("notebooks/01.ipynb", "import pandas as pd\nprint(pd.__version__)")
# {"cell_index": 0, "outputs": ["2.2.1"]}

# Ejecutar mas celdas
result = jupyter_append_execute("notebooks/01.ipynb", "df = pd.DataFrame({'a': [1,2,3]})\ndf.shape")
# {"cell_index": 1, "outputs": ["(3, 1)"]}

# Ejecutar celda existente por indice
result = jupyter_execute_cell("notebooks/01.ipynb", 0)
# {"cell_index": 0, "outputs": ["2.2.1"]}

# Ejecutar en kernel directamente (sin tocar notebook)
result = jupyter_kernel_execute("len(df)")
# {"outputs": ["3"], "status": "ok"}
```

```bash
# CLI
$PYTHON python/functions/notebook/jupyter_exec.py append notebooks/01.ipynb "print('hola')"
$PYTHON python/functions/notebook/jupyter_exec.py cell notebooks/01.ipynb 3
$PYTHON python/functions/notebook/jupyter_exec.py kernel "print(42)"
```

---

## READ — Leer notebooks

Lee el estado en memoria (CRDT), incluyendo cambios no guardados.

```python
from notebook.jupyter_read import (
    jupyter_read_cells,     # Leer todas las celdas o una especifica
    jupyter_notebook_info,  # Metadata rapida (conteo de celdas)
)

# Leer todas las celdas
cells = jupyter_read_cells("notebooks/01.ipynb")
# [{"index": 0, "type": "code", "source": "import pandas", "outputs": ["..."]}]

# Leer celda especifica
cell = jupyter_read_cells("notebooks/01.ipynb", cell_index=2)

# Info del notebook
info = jupyter_notebook_info("notebooks/01.ipynb")
# {"total_cells": 10, "code_cells": 7, "markdown_cells": 3}
```

```bash
$PYTHON python/functions/notebook/jupyter_read.py notebooks/01.ipynb --json
$PYTHON python/functions/notebook/jupyter_read.py notebooks/01.ipynb --cell 2 --json
$PYTHON python/functions/notebook/jupyter_read.py notebooks/01.ipynb --info --json
```

---

## KERNEL — Gestionar kernels

```python
from notebook.jupyter_kernel import (
    jupyter_kernel_list,          # Listar kernels activos
    jupyter_kernel_start,         # Iniciar kernel nuevo
    jupyter_kernel_restart,       # Reiniciar kernel
    jupyter_kernel_interrupt,     # Interrumpir ejecucion
    jupyter_kernel_shutdown,      # Apagar kernel individual
    jupyter_kernel_sessions,      # Listar sesiones (notebook <-> kernel)
    jupyter_kernel_cleanup,       # Apagar kernels inactivos
    jupyter_kernel_shutdown_all,  # Apagar todos los kernels
)

# Listar kernels activos
kernels = jupyter_kernel_list()
# [{"id": "abc123", "name": "python3", "execution_state": "idle",
#   "last_activity": "2026-04-07T10:00:00Z", "connections": 1}]

# Iniciar kernel nuevo
kernel = jupyter_kernel_start(name="python3")

# Ver sesiones (que notebook usa que kernel)
sessions = jupyter_kernel_sessions()
# [{"id": "s1", "notebook": "notebooks/01.ipynb", "kernel_id": "abc123", "kernel_state": "idle"}]

# Reiniciar kernel
jupyter_kernel_restart(kernel_id="abc123")

# Interrumpir ejecucion larga
jupyter_kernel_interrupt(kernel_id="abc123")

# Apagar kernel individual
jupyter_kernel_shutdown(kernel_id="abc123")

# Limpiar kernels inactivos (default: 1h sin actividad)
cleaned = jupyter_kernel_cleanup(idle_seconds=1800)
# [{"id": "abc123", "name": "python3", "last_activity": "...", "idle_seconds": 3601}]

# Apagar TODOS los kernels
jupyter_kernel_shutdown_all()
```

```bash
$PYTHON python/functions/notebook/jupyter_kernel.py list
$PYTHON python/functions/notebook/jupyter_kernel.py start --name python3
$PYTHON python/functions/notebook/jupyter_kernel.py sessions
$PYTHON python/functions/notebook/jupyter_kernel.py restart <kernel_id>
$PYTHON python/functions/notebook/jupyter_kernel.py interrupt <kernel_id>
$PYTHON python/functions/notebook/jupyter_kernel.py shutdown <kernel_id>
$PYTHON python/functions/notebook/jupyter_kernel.py cleanup --idle-seconds 1800
$PYTHON python/functions/notebook/jupyter_kernel.py shutdown-all
```

---

## Flujos tipicos

### 1. Analisis desde cero (sin abrir navegador)

```python
import sys; sys.path.insert(0, "python/functions")
from notebook.jupyter_discover import jupyter_discover
from notebook.jupyter_exec import jupyter_append_execute

# 1. Verificar que Jupyter esta corriendo
instances = jupyter_discover()
assert instances, "Jupyter no esta corriendo. Ejecuta: cd analysis/mi_analisis && ./run-jupyter-lab.sh"

# 2. Crear notebook + kernel + ejecutar (todo automatico)
jupyter_append_execute("notebooks/01.ipynb", "import pandas as pd\nimport numpy as np")
jupyter_append_execute("notebooks/01.ipynb", "df = pd.read_csv('data/dataset.csv')\ndf.shape")
jupyter_append_execute("notebooks/01.ipynb", "df.describe()")
```

### 2. Poblar notebook con estructura y ejecutar

```python
from notebook.jupyter_write import jupyter_batch_write
from notebook.jupyter_exec import jupyter_append_execute

# 1. Crear estructura del notebook
jupyter_batch_write("notebooks/02.ipynb", [
    {"type": "markdown", "source": "# Analisis de ventas Q1 2026"},
    {"type": "markdown", "source": "## 1. Carga de datos"},
    {"type": "code", "source": "import pandas as pd\ndf = pd.read_csv('data/ventas.csv')"},
    {"type": "markdown", "source": "## 2. Exploracion"},
    {"type": "code", "source": "df.info()"},
    {"type": "code", "source": "df.describe()"},
    {"type": "markdown", "source": "## 3. Visualizacion"},
])

# 2. Ejecutar celdas de codigo
from notebook.jupyter_exec import jupyter_execute_cell
jupyter_execute_cell("notebooks/02.ipynb", 2)  # import + read_csv
jupyter_execute_cell("notebooks/02.ipynb", 4)  # info
jupyter_execute_cell("notebooks/02.ipynb", 5)  # describe
```

### 3. Limpiar recursos

```python
from notebook.jupyter_kernel import jupyter_kernel_cleanup, jupyter_kernel_sessions

# Ver que esta corriendo
sessions = jupyter_kernel_sessions()
for s in sessions:
    print(f"{s['notebook']} -> kernel {s['kernel_id']} ({s['kernel_state']})")

# Apagar kernels inactivos (30 min sin actividad)
cleaned = jupyter_kernel_cleanup(idle_seconds=1800)
print(f"Apagados {len(cleaned)} kernels inactivos")
```

### 4. Exportar a PDF

```bash
./fn run export_analysis_pdfs mi_analisis
```

---

## Acceso al registry desde notebooks

El kernel startup (`00_fn_registry.py`) provee helpers automaticamente:

```python
# Disponibles sin importar nada:
fn_search("slice")           # Busca funciones y tipos
fn_query("SELECT ...")       # SQL directo sobre registry.db
fn_code("filter_list_py_core")  # Codigo fuente de una funcion

# Importar funciones Python del registry:
from core import filter_list, map_list, reduce_list
from finance import sma, ema, rsi
```

---

## Pipelines disponibles

| Pipeline | Descripcion |
|----------|-------------|
| `init_jupyter_analysis` | Crea analisis completo (venv, launcher, MCP, reglas) |
| `export_analysis_pdfs` | Exporta notebooks de un analisis a PDF |
| `write_jupyter_launcher` | Genera script run-jupyter-lab.sh |
| `write_jupyter_registry_kernel` | Genera kernel startup con helpers del registry |
| `write_claude_jupyter_rules` | Genera .claude/CLAUDE.md con reglas para agentes |
| `write_mcp_jupyter_config` | Genera .mcp.json con config de jupyter-mcp-server |

---

## Buscar mas funciones

```bash
./fn search "jupyter"
./fn search "notebook"
sqlite3 registry.db "SELECT id, description FROM functions WHERE domain = 'notebook' ORDER BY name;"
```

$ARGUMENTS
