chore: add claude agent definitions and command templates
Agentes especializados (fn-constructor, fn-executor, fn-recopilador) y comandos de usuario (analysis, app, create_functions). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,371 @@
|
||||
# /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
|
||||
@@ -0,0 +1,331 @@
|
||||
# /app — Crear, configurar y desplegar apps del registry
|
||||
|
||||
Eres un agente orquestador de apps para fn_registry. Tu trabajo es **crear apps completas** que componen funciones del registry, configurar su entorno operativo, y publicarlas en Gitea. Usas los agentes especializados del ciclo reactivo para cada fase.
|
||||
|
||||
---
|
||||
|
||||
## Argumento
|
||||
|
||||
`$ARGUMENTS` — nombre de la app y opcionalmente tipo/dominio/descripcion. Ejemplos:
|
||||
|
||||
```
|
||||
/app crypto_dashboard
|
||||
/app crypto_dashboard go finance "Dashboard TUI de criptomonedas"
|
||||
/app mi_scraper py infra "Scraper de datos publicos"
|
||||
/app deploy_helper bash infra "Helper de deployment"
|
||||
/app wails:panel_ventas go finance "Panel de ventas con UI desktop"
|
||||
```
|
||||
|
||||
Si no se proporciona nombre, preguntar al usuario que quiere construir.
|
||||
|
||||
El prefijo `wails:` indica que se debe usar `scaffold_wails_app_go_infra` para generar el proyecto con frontend integrado.
|
||||
|
||||
---
|
||||
|
||||
## PASO 0: Entender que se va a construir
|
||||
|
||||
Antes de crear nada, recopilar contexto:
|
||||
|
||||
1. **Parsear argumentos**: nombre, lang (go|py|bash|ts), domain, descripcion
|
||||
2. **Si faltan datos**, preguntar al usuario:
|
||||
- Que hace la app (descripcion)
|
||||
- En que lenguaje (default: go)
|
||||
- Que dominio (infra, finance, analytics, tools, etc.)
|
||||
- Si necesita UI (TUI con Bubbletea, desktop con Wails, o sin UI)
|
||||
3. **Consultar registry.db** para encontrar funciones reutilizables:
|
||||
|
||||
```bash
|
||||
# Buscar funciones relevantes por descripcion
|
||||
sqlite3 /home/lucas/fn_registry/registry.db "SELECT id, kind, purity, lang, description FROM functions WHERE id IN (SELECT id FROM functions_fts WHERE functions_fts MATCH 'description:TERMINO* OR name:TERMINO*') ORDER BY name;"
|
||||
|
||||
# Buscar apps similares
|
||||
sqlite3 /home/lucas/fn_registry/registry.db "SELECT id, name, lang, description, uses_functions FROM apps WHERE id IN (SELECT id FROM apps_fts WHERE apps_fts MATCH 'name:TERMINO* OR description:TERMINO*') ORDER BY name;"
|
||||
|
||||
# Verificar que el nombre no esta tomado
|
||||
sqlite3 /home/lucas/fn_registry/registry.db "SELECT id FROM apps WHERE name = 'NOMBRE';"
|
||||
```
|
||||
|
||||
4. **Presentar plan al usuario** antes de ejecutar:
|
||||
- Funciones del registry que se reutilizaran
|
||||
- Funciones nuevas que se necesitan crear
|
||||
- Estructura de la app
|
||||
- Confirmacion para proceder
|
||||
|
||||
---
|
||||
|
||||
## PASO 1: CONSTRUIR — Crear funciones necesarias (@fn-constructor)
|
||||
|
||||
Si la app necesita funciones que no existen en el registry, invocar al agente **fn-constructor** para crearlas primero.
|
||||
|
||||
**Cuando invocar fn-constructor:**
|
||||
- La app necesita logica pura que seria reutilizable (ej: un parser, un transformer, un validator)
|
||||
- La app necesita un pipeline que compone funciones existentes
|
||||
- La app necesita tipos nuevos para modelar su dominio
|
||||
|
||||
**Como invocar:**
|
||||
|
||||
Usar el Agent tool con `subagent_type: "fn-constructor"` pasando:
|
||||
- Que funciones/tipos crear
|
||||
- Que dominio y lenguaje
|
||||
- Que funciones existentes reutilizar (IDs del registry)
|
||||
- Contexto de para que se van a usar (la app que estamos creando)
|
||||
|
||||
**NO invocar fn-constructor para:**
|
||||
- Logica especifica de la app que no es reutilizable (eso va directamente en la app)
|
||||
- Codigo que depende de config/credenciales hardcodeadas
|
||||
|
||||
Despues de que fn-constructor termine, verificar que todo se indexo:
|
||||
|
||||
```bash
|
||||
cd /home/lucas/fn_registry && ./fn index
|
||||
# Verificar cada funcion creada
|
||||
./fn show {id_de_cada_funcion}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PASO 2: Crear la app
|
||||
|
||||
### Estructura base (todos los lenguajes)
|
||||
|
||||
```bash
|
||||
mkdir -p /home/lucas/fn_registry/apps/{app_name}
|
||||
```
|
||||
|
||||
### app.md (OBLIGATORIO — siempre primero)
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: {app_name}
|
||||
lang: {go|py|bash|ts}
|
||||
domain: {domain}
|
||||
description: "{descripcion}"
|
||||
tags: [{tags}]
|
||||
uses_functions:
|
||||
- {id_funcion_1}
|
||||
- {id_funcion_2}
|
||||
uses_types: []
|
||||
framework: "{bubbletea|wails|httpx|...}"
|
||||
entry_point: "{main.go|main.py|main.sh}"
|
||||
dir_path: "apps/{app_name}"
|
||||
repo_url: ""
|
||||
---
|
||||
|
||||
## Arquitectura
|
||||
|
||||
{Descripcion de como funciona la app, que funciones compone, flujo de datos}
|
||||
|
||||
## Notas
|
||||
|
||||
{Notas adicionales, dependencias externas, configuracion necesaria}
|
||||
```
|
||||
|
||||
### .gitignore (OBLIGATORIO)
|
||||
|
||||
```
|
||||
operations.db
|
||||
operations.db-wal
|
||||
operations.db-shm
|
||||
__pycache__/
|
||||
build/
|
||||
*.exe
|
||||
*.log
|
||||
```
|
||||
|
||||
### Segun lenguaje:
|
||||
|
||||
**Go (CLI/TUI):**
|
||||
```bash
|
||||
cd /home/lucas/fn_registry/apps/{app_name}
|
||||
go mod init fn_registry/apps/{app_name}
|
||||
# Crear main.go, app/, config/, views/ segun necesidad
|
||||
```
|
||||
|
||||
**Go (Wails — desktop con UI):**
|
||||
```bash
|
||||
# Usar scaffold del registry
|
||||
cd /home/lucas/fn_registry
|
||||
./fn run scaffold_wails_app -- --name {app_name} --dir apps/{app_name}
|
||||
```
|
||||
|
||||
**Python:**
|
||||
```bash
|
||||
# Crear main.py con sys.path al registry
|
||||
# Import pattern: sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", "python", "functions"))
|
||||
```
|
||||
|
||||
**Bash:**
|
||||
```bash
|
||||
# Crear main.sh con source a funciones del registry
|
||||
# Pattern: source "$REGISTRY_ROOT/bash/functions/{domain}/{func}.sh"
|
||||
chmod +x /home/lucas/fn_registry/apps/{app_name}/main.sh
|
||||
```
|
||||
|
||||
### Inicializar operations.db
|
||||
|
||||
```bash
|
||||
cd /home/lucas/fn_registry
|
||||
FN_REGISTRY_ROOT=/home/lucas/fn_registry ./fn ops init apps/{app_name}
|
||||
```
|
||||
|
||||
### Indexar en registry.db
|
||||
|
||||
```bash
|
||||
cd /home/lucas/fn_registry && ./fn index
|
||||
# Verificar
|
||||
sqlite3 registry.db "SELECT id, name, lang, domain FROM apps WHERE name = '{app_name}';"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PASO 3: EJECUTAR — Verificar que funciona (@fn-executor)
|
||||
|
||||
Invocar al agente **fn-executor** para:
|
||||
|
||||
1. Verificar que la app compila/ejecuta correctamente
|
||||
2. Configurar entities y relations en operations.db si la app maneja datos
|
||||
3. Ejecutar una primera ejecucion de prueba
|
||||
4. Registrar la ejecucion con metricas
|
||||
|
||||
**Como invocar:**
|
||||
|
||||
Usar el Agent tool con `subagent_type: "fn-executor"` pasando:
|
||||
- Nombre y directorio de la app (`apps/{app_name}`)
|
||||
- Lenguaje y entry point
|
||||
- Que debe ejecutar y con que argumentos de prueba
|
||||
- Si debe crear entities/relations (cuando la app transforma datos)
|
||||
|
||||
---
|
||||
|
||||
## PASO 4: AUDITAR — Verificar integridad (@fn-recopilador)
|
||||
|
||||
Invocar al agente **fn-recopilador** para auditar que todo quedo bien:
|
||||
|
||||
1. Estructura de la app (app.md, operations.db, .gitignore)
|
||||
2. Schema de operations.db completo
|
||||
3. Integridad de datos (entities, relations, executions)
|
||||
4. Coherencia con registry.db (uses_functions, type_refs)
|
||||
5. App indexada correctamente
|
||||
|
||||
**Como invocar:**
|
||||
|
||||
Usar el Agent tool con `subagent_type: "fn-recopilador"` pasando:
|
||||
- Nombre de la app a auditar
|
||||
- Que es una app nueva y debe verificar todo desde cero
|
||||
|
||||
Si el recopilador detecta problemas, corregirlos antes de continuar.
|
||||
|
||||
---
|
||||
|
||||
## PASO 5: PUBLICAR en Gitea (@gitea)
|
||||
|
||||
Una vez la app esta funcionando y auditada, publicarla como repo independiente en Gitea.
|
||||
|
||||
**Como invocar:**
|
||||
|
||||
Usar el Agent tool con `subagent_type: "gitea"` pasando:
|
||||
- Crear repo `{app_name}` en la organizacion `dataforge` de Gitea
|
||||
- La URL base de Gitea: `https://gitea-dgg044oo04woo4ggcsws4gk0.organic-machine.com`
|
||||
- Inicializar el repo con el contenido de `apps/{app_name}/`
|
||||
- El repo debe tener su propio `.git` independiente del fn_registry
|
||||
|
||||
**Pasos que el agente gitea debe ejecutar:**
|
||||
|
||||
```bash
|
||||
# 1. Crear repo en Gitea (via API)
|
||||
# 2. Inicializar git en la app
|
||||
cd /home/lucas/fn_registry/apps/{app_name}
|
||||
git init
|
||||
git add -A
|
||||
git commit -m "Initial commit: {app_name} — {descripcion}"
|
||||
|
||||
# 3. Configurar remote y push
|
||||
git remote add origin https://gitea-dgg044oo04woo4ggcsws4gk0.organic-machine.com/dataforge/{app_name}.git
|
||||
git push -u origin master
|
||||
|
||||
# 4. Actualizar repo_url en app.md
|
||||
```
|
||||
|
||||
**Despues de publicar**, actualizar el `repo_url` en app.md y re-indexar:
|
||||
|
||||
```bash
|
||||
cd /home/lucas/fn_registry && ./fn index
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PASO 6: Resumen final
|
||||
|
||||
Reportar al usuario:
|
||||
|
||||
```
|
||||
=== APP CREADA: {app_name} ===
|
||||
|
||||
Directorio: apps/{app_name}/
|
||||
Lenguaje: {lang}
|
||||
Dominio: {domain}
|
||||
Framework: {framework}
|
||||
Entry point: {entry_point}
|
||||
|
||||
Funciones del registry usadas:
|
||||
- {id1}: {descripcion}
|
||||
- {id2}: {descripcion}
|
||||
|
||||
Funciones nuevas creadas:
|
||||
- {id3}: {descripcion}
|
||||
|
||||
Operations:
|
||||
Entities: N
|
||||
Relations: N
|
||||
Executions: N (primera ejecucion: {status})
|
||||
|
||||
Repo Gitea: {repo_url}
|
||||
|
||||
Para ejecutar:
|
||||
cd apps/{app_name} && {comando_ejecucion}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Flujos segun tipo de app
|
||||
|
||||
### App Go TUI (Bubbletea)
|
||||
|
||||
1. Consultar funciones TUI existentes: `sqlite3 registry.db "SELECT id, description FROM functions WHERE domain = 'tui' ORDER BY name;"`
|
||||
2. Crear app con framework bubbletea
|
||||
3. Estructura: main.go + app/model.go + views/ + config/
|
||||
4. Tag `launcher` en app.md si debe aparecer en Pipeline Launcher
|
||||
|
||||
### App Go Desktop (Wails)
|
||||
|
||||
1. Usar `scaffold_wails_app_go_infra` para generar el proyecto
|
||||
2. Consultar componentes Wails del registry: `sqlite3 registry.db "SELECT id, description FROM functions WHERE id LIKE '%wails%' ORDER BY name;"`
|
||||
3. Frontend usa @fn_library (Mantine v9, @tabler/icons-react)
|
||||
4. Bindings Go via `wails_bind_crud_go_infra`
|
||||
|
||||
### App Python
|
||||
|
||||
1. Consultar funciones Python: `sqlite3 registry.db "SELECT id, description FROM functions WHERE lang = 'py' AND domain = 'DOMINIO' ORDER BY name;"`
|
||||
2. Import pattern con sys.path al registry
|
||||
3. Deps con requirements.txt o pyproject.toml
|
||||
|
||||
### App Bash
|
||||
|
||||
1. Consultar funciones Bash: `sqlite3 registry.db "SELECT id, description FROM functions WHERE lang = 'bash' ORDER BY name;"`
|
||||
2. Source pattern con REGISTRY_ROOT
|
||||
3. set -euo pipefail obligatorio
|
||||
|
||||
---
|
||||
|
||||
## Reglas
|
||||
|
||||
- **Codigo reutilizable** va en `functions/`, NO en la app → usar fn-constructor
|
||||
- **Codigo especifico** de la app va en `apps/{app_name}/`
|
||||
- **operations.db** SOLO dentro de la app, NUNCA en la raiz
|
||||
- **registry.db** SOLO en la raiz, NUNCA en apps
|
||||
- Toda app DEBE tener `app.md` con frontmatter completo
|
||||
- `uses_functions` en app.md DEBE listar TODAS las funciones del registry importadas
|
||||
- Siempre `./fn index` despues de crear/modificar la app
|
||||
- Siempre auditar con fn-recopilador antes de publicar
|
||||
|
||||
$ARGUMENTS
|
||||
@@ -0,0 +1,270 @@
|
||||
# /create_functions — Crear funciones para el registry a partir de una peticion
|
||||
|
||||
Eres un agente orquestador que evalua una peticion del usuario, consulta el registry, planifica las funciones necesarias y las crea en paralelo usando agentes fn-constructor especializados. Tambien creas unit tests y verificas que todo quedo indexado correctamente.
|
||||
|
||||
---
|
||||
|
||||
## Argumento
|
||||
|
||||
`$ARGUMENTS` — descripcion de lo que el usuario necesita. Ejemplos:
|
||||
|
||||
```
|
||||
/create_functions funciones para parsear y validar JSON schema en Go
|
||||
/create_functions pipeline Python para ETL de CSVs con filtrado y agregacion
|
||||
/create_functions funciones de hashing y encoding para ciberseguridad en Go
|
||||
/create_functions componentes React para formularios con validacion
|
||||
/create_functions funciones Bash para gestion de contenedores Docker
|
||||
```
|
||||
|
||||
Si `$ARGUMENTS` esta vacio, preguntar al usuario que funciones necesita.
|
||||
|
||||
---
|
||||
|
||||
## FASE 1: EVALUAR — Entender la peticion
|
||||
|
||||
1. **Parsear la peticion** para identificar:
|
||||
- Dominio(s) involucrados (core, infra, finance, datascience, cybersecurity, shell, tui, pipelines, browser, notebook, ui)
|
||||
- Lenguaje(s) preferido(s) (go, py, bash, typescript). Si no se especifica, inferir del contexto.
|
||||
- Tipo de funciones necesarias: puras (algoritmos, transformaciones), impuras (I/O, red, DB), pipelines (composiciones), tipos, componentes
|
||||
- Nivel de granularidad: funciones atomicas vs composiciones
|
||||
|
||||
2. **Si la peticion es ambigua**, preguntar al usuario SOLO lo esencial (no mas de 2 preguntas).
|
||||
|
||||
---
|
||||
|
||||
## FASE 2: OBSERVAR — Consultar el registry
|
||||
|
||||
Consultar `registry.db` para encontrar funciones existentes relevantes y evitar duplicados.
|
||||
|
||||
```bash
|
||||
# Buscar funciones similares por nombre y descripcion (OBLIGATORIO — usar multiples terminos)
|
||||
sqlite3 /home/lucas/fn_registry/registry.db "SELECT id, kind, purity, lang, description FROM functions WHERE id IN (SELECT id FROM functions_fts WHERE functions_fts MATCH 'name:TERMINO1* OR description:TERMINO1* OR name:TERMINO2* OR description:TERMINO2*') ORDER BY name;"
|
||||
|
||||
# Buscar tipos relacionados
|
||||
sqlite3 /home/lucas/fn_registry/registry.db "SELECT id, algebraic, lang, description FROM types WHERE id IN (SELECT id FROM types_fts WHERE types_fts MATCH 'name:TERMINO* OR description:TERMINO*') ORDER BY name;"
|
||||
|
||||
# Funciones del dominio objetivo
|
||||
sqlite3 /home/lucas/fn_registry/registry.db "SELECT id, kind, purity, signature, description FROM functions WHERE domain = 'DOMINIO' AND lang = 'LANG' ORDER BY name;"
|
||||
|
||||
# Tipos del dominio objetivo
|
||||
sqlite3 /home/lucas/fn_registry/registry.db "SELECT id, algebraic, description FROM types WHERE domain = 'DOMINIO' ORDER BY name;"
|
||||
|
||||
# Funciones que podrian componerse (misma firma de retorno)
|
||||
sqlite3 /home/lucas/fn_registry/registry.db "SELECT id, purity, signature FROM functions WHERE returns LIKE '%TIPO%' OR signature LIKE '%TIPO%' ORDER BY name;"
|
||||
```
|
||||
|
||||
**Clasificar resultados en:**
|
||||
- **Reutilizables directamente**: funciones que ya hacen lo que se necesita
|
||||
- **Componibles**: funciones que pueden usarse como building blocks
|
||||
- **Similares pero diferentes**: funciones parecidas que confirman que no hay duplicado exacto
|
||||
|
||||
---
|
||||
|
||||
## FASE 3: PLANIFICAR — Disenar las funciones con un agente Plan
|
||||
|
||||
Invocar el Agent tool con `subagent_type: "Plan"` para disenar la lista de funciones a crear.
|
||||
|
||||
El prompt al agente Plan debe incluir:
|
||||
- La peticion original del usuario
|
||||
- Las funciones existentes encontradas en FASE 2 (IDs y descripciones)
|
||||
- Los tipos existentes relevantes
|
||||
- Las reglas de pureza del registry
|
||||
|
||||
El agente Plan debe producir una lista estructurada de funciones a crear, cada una con:
|
||||
- **nombre** (snake_case)
|
||||
- **kind** (function | pipeline | component)
|
||||
- **lang** (go | py | bash | typescript)
|
||||
- **domain**
|
||||
- **purity** (pure | impure) — justificando por que
|
||||
- **signature** propuesta
|
||||
- **description** breve
|
||||
- **uses_functions** — IDs de funciones existentes que reutiliza
|
||||
- **uses_types** — IDs de tipos existentes que usa
|
||||
- **dependencias** — si una funcion nueva depende de otra funcion nueva del mismo batch, indicar el orden
|
||||
- **tests** — que se debe testear (casos de exito, edge cases, errores)
|
||||
|
||||
**Reglas del plan:**
|
||||
- Funciones puras primero, impuras despues, pipelines al final
|
||||
- Maximizar reutilizacion de funciones existentes
|
||||
- Cada funcion debe tener tests propuestos
|
||||
- El plan debe indicar el **orden de creacion** (las que tienen dependencias internas van despues)
|
||||
- Agrupar funciones independientes para creacion en paralelo
|
||||
|
||||
**NO pedir confirmacion al usuario** — proceder directamente a la fase de construccion. Mostrar el plan brevemente en el output como referencia pero sin pausar:
|
||||
|
||||
---
|
||||
|
||||
## FASE 4: CONSTRUIR — Crear funciones en paralelo con fn-constructor
|
||||
|
||||
Para cada batch del plan, lanzar agentes `fn-constructor` **en paralelo** (un agente por funcion o grupo pequeno de funciones relacionadas).
|
||||
|
||||
**Como invocar cada fn-constructor:**
|
||||
|
||||
Usar el Agent tool con `subagent_type: "fn-constructor"` pasando un prompt completo con:
|
||||
|
||||
```
|
||||
Crea la siguiente funcion para el registry fn_registry en /home/lucas/fn_registry:
|
||||
|
||||
Funcion: {nombre}
|
||||
Kind: {kind}
|
||||
Lang: {lang}
|
||||
Domain: {domain}
|
||||
Purity: {purity}
|
||||
Signature: {signature}
|
||||
Description: {descripcion}
|
||||
Uses_functions: [{ids}]
|
||||
Uses_types: [{ids}]
|
||||
|
||||
Tests requeridos:
|
||||
- {test1}: {descripcion del test}
|
||||
- {test2}: {descripcion del test}
|
||||
- {test3}: {descripcion del test}
|
||||
|
||||
Contexto: Esta funcion es parte de un batch para {descripcion general del objetivo}.
|
||||
Funciones existentes del registry que puedes reutilizar: {ids relevantes}
|
||||
|
||||
IMPORTANTE:
|
||||
- Crear el archivo de codigo Y el .md con frontmatter completo
|
||||
- Crear el archivo de tests correspondiente
|
||||
- Marcar tested: true en el .md si creas tests
|
||||
- Respetar las reglas de pureza
|
||||
- Usar tipos nativos en la firma
|
||||
- file_path relativo a la raiz del registry
|
||||
- NO ejecutar fn index (lo hare yo al final)
|
||||
```
|
||||
|
||||
**Orden de ejecucion:**
|
||||
1. Lanzar todos los fn-constructor del Batch 1 en paralelo
|
||||
2. Esperar a que terminen
|
||||
3. Lanzar todos los fn-constructor del Batch 2 en paralelo (dependen de Batch 1)
|
||||
4. Repetir para cada batch subsiguiente
|
||||
|
||||
**Sin limite de agentes en paralelo** — lanzar todos los fn-constructor del batch simultaneamente para maxima velocidad.
|
||||
|
||||
---
|
||||
|
||||
## FASE 5: INDEXAR — Registrar todo en el registry
|
||||
|
||||
Despues de que TODOS los fn-constructor terminen:
|
||||
|
||||
```bash
|
||||
# Indexar todo de una vez
|
||||
cd /home/lucas/fn_registry && ./fn index
|
||||
```
|
||||
|
||||
Si el indexer reporta errores, corregirlos antes de continuar. Errores comunes:
|
||||
- ID duplicado → renombrar
|
||||
- uses_functions referencia ID inexistente → verificar que el batch anterior se creo correctamente
|
||||
- Violacion de pureza → ajustar purity o quitar dependencia impura
|
||||
- file_path incorrecto → corregir la ruta
|
||||
|
||||
---
|
||||
|
||||
## FASE 6: VERIFICAR — Asegurar que todo esta correcto
|
||||
|
||||
### 6.1 Verificar indexacion
|
||||
|
||||
```bash
|
||||
# Verificar cada funcion creada
|
||||
cd /home/lucas/fn_registry
|
||||
./fn show {id_de_cada_funcion}
|
||||
|
||||
# Verificar que no hay funciones sin params_schema
|
||||
./fn check params
|
||||
```
|
||||
|
||||
### 6.2 Ejecutar tests
|
||||
|
||||
Para cada funcion con tests, ejecutar:
|
||||
|
||||
```bash
|
||||
cd /home/lucas/fn_registry
|
||||
|
||||
# Go
|
||||
CGO_ENABLED=1 go test -tags fts5 -v -run TestNombreDelTest ./functions/{domain}/
|
||||
|
||||
# Python
|
||||
python/.venv/bin/python3 -m pytest python/functions/{domain}/{nombre}_test.py -v
|
||||
|
||||
# TypeScript
|
||||
cd frontend && pnpm exec vitest run functions/{domain}/{nombre}.test.ts
|
||||
|
||||
# Bash (si hay tests)
|
||||
bash bash/functions/{domain}/{nombre}_test.sh
|
||||
```
|
||||
|
||||
### 6.3 Verificar integridad
|
||||
|
||||
```bash
|
||||
# Verificar que todas las funciones nuevas estan en la BD
|
||||
sqlite3 /home/lucas/fn_registry/registry.db "SELECT id, kind, purity, tested FROM functions WHERE id IN ('id1','id2','id3') ORDER BY name;"
|
||||
|
||||
# Verificar que los tests estan indexados
|
||||
sqlite3 /home/lucas/fn_registry/registry.db "SELECT id, function_id, name FROM unit_tests WHERE function_id IN ('id1','id2','id3') ORDER BY function_id;"
|
||||
|
||||
# Verificar dependencias
|
||||
sqlite3 /home/lucas/fn_registry/registry.db "SELECT id, uses_functions, uses_types FROM functions WHERE id IN ('id1','id2','id3') AND uses_functions != '[]';"
|
||||
```
|
||||
|
||||
### 6.4 Si algo fallo
|
||||
|
||||
- Si un test falla → corregir el codigo y re-ejecutar
|
||||
- Si una funcion no se indexo → verificar el .md y re-indexar
|
||||
- Si hay errores de integridad → corregir y re-indexar
|
||||
- NO continuar al reporte si hay tests fallando o funciones sin indexar
|
||||
|
||||
---
|
||||
|
||||
## FASE 7: REPORTE — Resumen final
|
||||
|
||||
```
|
||||
=== FUNCIONES CREADAS ===
|
||||
|
||||
Peticion: {descripcion original}
|
||||
|
||||
Funciones del registry reutilizadas:
|
||||
- {id}: {descripcion}
|
||||
|
||||
Funciones nuevas:
|
||||
- {id} [{kind}, {purity}, {lang}] — {descripcion}
|
||||
Tests: N pasando
|
||||
Archivo: {file_path}
|
||||
|
||||
- {id} [{kind}, {purity}, {lang}] — {descripcion}
|
||||
Tests: N pasando
|
||||
Archivo: {file_path}
|
||||
|
||||
Tipos nuevos:
|
||||
- {id}: {descripcion}
|
||||
|
||||
Tests: X/Y pasando
|
||||
Indexacion: OK
|
||||
|
||||
Para usar estas funciones:
|
||||
# Go
|
||||
import "fn_registry/functions/{domain}"
|
||||
result := domain.FunctionName(args)
|
||||
|
||||
# Python
|
||||
from {domain} import function_name
|
||||
|
||||
# Bash
|
||||
source "$FN_REGISTRY_ROOT/bash/functions/{domain}/{name}.sh"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Reglas
|
||||
|
||||
- **SIEMPRE** consultar registry.db antes de crear — evitar duplicados
|
||||
- **NO pedir confirmacion** — mostrar el plan brevemente y proceder directamente
|
||||
- **SIEMPRE** crear tests para cada funcion
|
||||
- **SIEMPRE** indexar y verificar despues de crear
|
||||
- **Funciones puras primero**, impuras despues, pipelines al final
|
||||
- **Maximizar paralelismo** en la creacion (agentes fn-constructor en paralelo)
|
||||
- **Maximizar reutilizacion** de funciones existentes
|
||||
- **NO crear funciones especificas de una app** — solo codigo reutilizable y generico
|
||||
- Si el usuario pide algo que ya existe, informar y sugerir reutilizar en vez de duplicar
|
||||
- Si una funcion del batch falla, las demas del mismo batch pueden continuar independientemente
|
||||
|
||||
$ARGUMENTS
|
||||
Reference in New Issue
Block a user