1f93e9d502
Cada projects/<name>/ es ahora su propio repo Gitea con branch master, versionando solo sus docs de nivel-project. apps/*/ y analysis/*/ siguen como sub-repos hijos independientes (excluidos por el .gitignore del project). /full-git-push|pull los manejan via discover_git_repos. Cierra el gap de docs de nivel-project sin versionar. Aplicado a web_scraping, fn_monitoring, message_bus.
510 lines
29 KiB
Markdown
510 lines
29 KiB
Markdown
# fn-registry
|
|
|
|
Registry personal de codigo reutilizable con busqueda FTS. Diseñado para composicion funcional y agentes.
|
|
|
|
## Objetivos del registry (Norte) — Issues 0086 + 0087
|
|
|
|
**4 metricas optimizadas por el bucle reactivo** (visibles en Monitor tab del `registry_dashboard`):
|
|
|
|
1. **MAXIMIZAR `Reg %`** — porcentaje de calls del agente que golpean una funcion del registry (`function_id != ''`). Cada bash inline o heredoc que reescribe logica baja el ratio. Target: subir cada semana.
|
|
2. **MEJORAR uso del registry por Claude** — el agente debe encontrar y usar funciones existentes antes de escribir codigo. Indicadores: `MCP` (mcp/heredoc/fn run) sube; violations baja. Si Claude no encuentra una funcion por busqueda mediocre, mejorar `description`/`tags`/`params_schema` de esa funcion.
|
|
3. **ACELERAR tareas comunes via funciones nuevas** — patrones inline repetidos >2 veces -> `fn-constructor` crea la funcion, Claude la usa el siguiente turno. Velocidad medida en pasos (turnos) por tarea. Pattern detection: tab Monitor + `mcp__registry__fn_proposal action="list"`.
|
|
4. **PROMOVER COMPOSICIONES A PIPELINES** (issue 0087) — el registry no crece inflando funciones, crece **promoviendo secuencias A→B(→C) que se repiten con exito** a pipelines one-shot. Hoy `bank_login + bank_make_transfer` (2 calls). Manana `bank_transfer_oneshot` (1 call). Misma capacidad, mitad de pasos. Detectado por telemetria de secuencias en `call_monitor`. Una funcion que hace bien UNA cosa NO necesita crecer — lo que crece es el catalogo de composiciones probadas.
|
|
|
|
**Auto-discovery zero-second-lookup:** cada `.md` debe ser autosuficiente — `## Ejemplo` lanzable + `## Cuando usarla` + `## Gotchas` (impuras). Descubrir = lanzar, sin segunda lectura. Ver `.claude/rules/function_growth_and_self_docs.md`.
|
|
|
|
Cualquier decision tecnica que choque con estos objetivos esta mal priorizada. Ejemplo: un bash heredoc rapido hoy que reinventa logica = penaliza objetivos 1 y 3 manana.
|
|
|
|
**Dos bases de datos SQLite:**
|
|
- **registry.db** (raiz) — funciones, tipos, proposals, apps, projects, analysis, vaults, pc_locations. Regenerable con `fn index` (excepto proposals y pc_locations).
|
|
- **operations.db** (por app en `apps/*/`) — entities, relations, executions, assertions. Datos vivos.
|
|
|
|
**Sync entre PCs:** `fn sync` sincroniza datos no regenerables (proposals, apps, projects, analysis, vaults, pc_locations) contra `registry_api` en `https://registry.organic-machine.com`. Config: `~/.fn_pc` (identidad del PC), `FN_REGISTRY_API` (URL con basicAuth), `REGISTRY_API_TOKEN` (token).
|
|
|
|
**Sub-repos:** cada app, cada analysis y **cada project** es su propio repo Gitea en `dataforge/<basename>` con branch `master` (ver ADR 0002). `apps/*`, `analysis/*` y `projects/*` estan en el `.gitignore` del repo padre — el codigo de cada app vive en `apps/<name>/.git/`. Cada `projects/<name>/` es a su vez un sub-repo que versiona solo sus docs de nivel-project (`project.md`, `CONVENTIONS.md`, ...) con un `.gitignore` interno que excluye `apps/*/` y `analysis/*/` (sub-repos hijos). Ver `.claude/rules/projects.md`. Los slash commands `/full-git-push` y `/full-git-pull` orquestan push/pull/clone de fn_registry + todos los sub-repos + `fn sync`. `/full-git-push` auto-inicializa apps/analyses sin `.git` via `ensure_repo_synced_bash_infra`. Los `vaults/` y `subrepos/` NO entran en este flujo. **Gotcha worktrees**: si creas una app nueva dentro de un git worktree del repo padre, haz `git init` dentro de `apps/<name>/` ANTES de limpiar el worktree, sino el codigo se pierde (apps/* gitignored). **REGLA DURA**: el repo padre NUNCA trackea contenido de artefactos hijos (apps/analysis/projects) — solo `.gitkeep`. Nada de `git add -f` sobre esos paths: deja el padre permanentemente dirty (doble-tracking). Auditoria + fix en `.claude/rules/apps_subrepo.md`. Ver `.claude/rules/apps_subrepo.md`.
|
|
|
|
**Artefactos:** termino paraguas para apps, analysis, vaults, projects y playgrounds — todo lo que NO es codigo reutilizable. Usa "artefacto" cuando una afirmacion aplica a varios tipos a la vez para no repetir la lista. Ver `.claude/rules/artefactos.md` y `.claude/rules/playgrounds.md`.
|
|
|
|
**Reglas y convenciones:** ver `.claude/rules/INDEX.md`
|
|
|
|
**Slash commands:** `/commands` lista todos los slash commands del repo agrupados por namespace (global + projects). Project commands viven en `projects/<p>/.claude/commands/` y se exponen como `/<project>:<cmd>` via symlink. Ver `.claude/rules/project_commands.md`.
|
|
|
|
**Migraciones SQLite obligatorias:** todo cambio de schema en cualquier `.db` (apps, operations.db, registry.db) va en `migrations/NNN_*.sql` numerado. Aditivo, idempotente, aplicado al arrancar via `embed.FS`. Nunca borrar `.db` ni modificar migraciones existentes. Aplica retroactivamente. Ver `.claude/rules/db_migrations.md`.
|
|
|
|
---
|
|
|
|
## Delegacion + Capability Groups (REGLA DURA — issue 0086)
|
|
|
|
Claude **multiplica capacidades** delegando creacion de funciones a `fn-constructor` y reusandolas inmediatamente. NO escribir logica reutilizable inline.
|
|
|
|
### Flujo obligatorio (mismo turno)
|
|
|
|
1. **Detectar gap**. Si vas a escribir >=5 lineas de logica reutilizable inline -> STOP.
|
|
2. **Spawn `fn-constructor`** via `Agent(subagent_type="fn-constructor", ...)`. Sin preguntar al usuario.
|
|
3. **Paralelo**: si hay >1 funcion independiente -> **una sola llamada al Agent tool con N tool_use blocks paralelos** en mismo mensaje. NO serializar.
|
|
4. **Tag de grupo obligatorio** (`notebook`, `metabase`, `deploy`, etc.). Ver `docs/capabilities/INDEX.md`.
|
|
5. **`fn index`** + **importar + invocar en mismo turno**. No dejar funcion huerfana recien creada.
|
|
6. **Auto-verificar**: `fn doctor uses-functions` + `fn doctor unused` si tocas >=3 funciones nuevas.
|
|
|
|
### Capability groups
|
|
|
|
Cluster de >=3 funciones que comparten dominio operativo. Cada grupo tiene tag plano + pagina madre `docs/capabilities/<grupo>.md` con: lista de funciones, ejemplo canonico end-to-end, fronteras.
|
|
|
|
**Antes de buscar funciones sueltas en una tarea de dominio conocido:** lee `docs/capabilities/<grupo>.md` para cargar el cluster entero en un solo read. Filtro MCP: `mcp__registry__fn_search query="" tag="<grupo>"`.
|
|
|
|
Reglas completas: `.claude/rules/delegation.md` + `.claude/rules/capability_groups.md`.
|
|
|
|
### Telemetria CAPABILITY-GROWTH
|
|
|
|
Cada turno el hook `UserPromptSubmit` inyecta `CAPABILITY-GROWTH: created_this_session=X used=Y orphan=Z`. Si `orphan>0` -> integra la funcion antes de cerrar turno o documenta por que.
|
|
|
|
---
|
|
|
|
## Explorar el registry (OBLIGATORIO)
|
|
|
|
**SIEMPRE** consulta registry.db antes de escribir codigo, crear funciones, o responder sobre el registry. No uses grep/glob sobre archivos .go/.md — la BD es la fuente de verdad.
|
|
|
|
### Usa SIEMPRE el MCP `registry` (regla por defecto)
|
|
|
|
**OBLIGATORIO:** para buscar/leer/inspeccionar el registry usa SIEMPRE las tools del MCP `registry`. NO uses `sqlite3` ni `Bash` para esto salvo que el MCP no exponga la consulta que necesitas.
|
|
|
|
| Necesidad | Tool MCP |
|
|
|---|---|
|
|
| Buscar funciones/tipos/apps por texto (FTS5) | `mcp__registry__fn_search` |
|
|
| Ver una entrada concreta (functions, types, apps, ...) | `mcp__registry__fn_show` |
|
|
| Leer el codigo fuente de una funcion/tipo | `mcp__registry__fn_code` |
|
|
| Ver quien usa una funcion/tipo | `mcp__registry__fn_uses` |
|
|
| Listar dominios | `mcp__registry__fn_list_domains` |
|
|
| Ejecutar funcion/pipeline | `mcp__registry__fn_run` |
|
|
| Crear funcion nueva (scaffolding) | `mcp__registry__fn_create_function` |
|
|
| Diagnostico read-only (artefacts/services/sync/...) | `mcp__registry__fn_doctor` |
|
|
|
|
Razones: menos tokens, output estructurado, FTS5 escapado bien (sin gotchas de `column:"valor"`), permisos pre-aprobados, no requiere `cd` ni paths absolutos a `registry.db`.
|
|
|
|
**La BD contiene el codigo y la documentacion completa** de cada funcion y tipo en los campos `code`, `documentation` y `notes`. Tambien indexados en FTS5 — buscas dentro del codigo directamente. Para leer codigo: `mcp__registry__fn_code <id>`.
|
|
|
|
### Ejemplos MCP (usa estos, NO sqlite3)
|
|
|
|
Cada llamada MCP se registra en `call_monitor` (issue 0085). Cada `sqlite3 registry.db "SELECT ..."` queda fuera del bucle reactivo y dispara el hook PreToolUse.
|
|
|
|
```
|
|
# Busqueda basica por nombre/descripcion (FTS5 detras)
|
|
mcp__registry__fn_search query="slice"
|
|
|
|
# Filtros: kind, purity, domain, lang
|
|
mcp__registry__fn_search query="filter" kind="function" purity="pure" domain="core"
|
|
|
|
# Prefijo FTS5 — encuentra slice/slicing/sliced
|
|
mcp__registry__fn_search query="slic*"
|
|
|
|
# Buscar tipos
|
|
mcp__registry__fn_search query="result" entity="types"
|
|
|
|
# Apps
|
|
mcp__registry__fn_search query="kanban" entity="apps"
|
|
|
|
# Listar dominios
|
|
mcp__registry__fn_list_domains
|
|
|
|
# Ver una entrada concreta (functions, types, apps, analysis, proposals...)
|
|
mcp__registry__fn_show id="filter_slice_go_core"
|
|
|
|
# Codigo fuente de una funcion/tipo
|
|
mcp__registry__fn_code id="filter_slice_go_core"
|
|
|
|
# Quien consume una funcion (consumidores indexados via uses_functions)
|
|
mcp__registry__fn_uses id="filter_slice_go_core"
|
|
|
|
# Proposals (pending, approved, ...)
|
|
mcp__registry__fn_proposal action="list" status="pending"
|
|
mcp__registry__fn_proposal action="show" id="<proposal_id>"
|
|
|
|
# Diagnostico read-only del registry (artefacts/services/sync/uses-functions/unused/cpp-apps)
|
|
mcp__registry__fn_doctor subcommand="artefacts"
|
|
mcp__registry__fn_doctor subcommand="sync"
|
|
```
|
|
|
|
**Escapado FTS5 (gotcha cuando pasas query libre):** valores con `-`, `.`, `:`, espacios rompen el parser FTS5 si los expones como `column:valor`. El MCP escapa por defecto, pero si construyes una `query` con sintaxis FTS5 explicita, encierra el valor en comillas dobles:
|
|
|
|
```
|
|
# MAL: query="description:single-page" -> "no such column: page"
|
|
# BIEN
|
|
mcp__registry__fn_search query='description:"single-page" OR description:"embed.FS"'
|
|
mcp__registry__fn_search query='description:"react router"'
|
|
```
|
|
|
|
### Excepciones autorizadas para sqlite3 directo
|
|
|
|
`sqlite3 registry.db` SOLO es legitimo si el MCP no expone la consulta:
|
|
|
|
- Introspeccion de schema: `.schema`, `.tables`, `PRAGMA table_info(...)`, `PRAGMA index_list(...)`.
|
|
- Agregaciones: `COUNT(*)`, `GROUP BY`, `SUM(...)`, `AVG(...)`.
|
|
- JOINs custom entre tablas (ej. `functions JOIN unit_tests ON ...`) no expuestos por el MCP.
|
|
|
|
Cualquier `SELECT ... FROM functions/types/apps/proposals WHERE ...` plano se hace via MCP. El hook PreToolUse avisa si ve `sqlite3 registry.db "SELECT ..."`.
|
|
|
|
### Schema rapido
|
|
|
|
**functions** — columnas: `id, name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, example, tested, tests, test_file_path, file_path, created_at, updated_at, props, emits, has_state, framework, variant, notes, documentation, code, content_hash, source_repo, source_license, source_file, params_schema`
|
|
- `params_schema`: JSON con semántica de inputs/outputs. Formato: `{"params":[{"name":"x","desc":"..."}],"output":"..."}`. Buscable via FTS5.
|
|
- Enums: `kind`(function|pipeline|component) `purity`(pure|impure) `lang`(go|py|bash|ps)
|
|
- Dominios: core, infra, finance, datascience, cybersecurity, shell, tui, pipelines, browser
|
|
|
|
**types** — columnas: `id, name, lang, domain, version, algebraic, definition, description, tags, uses_types, file_path, created_at, updated_at, examples, notes, documentation, code, content_hash, source_repo, source_license, source_file`
|
|
- Enums: `algebraic`(product|sum)
|
|
|
|
**unit_tests** — columnas: `id, function_id, name, code, file_path, lang, created_at, updated_at`
|
|
- Extraidos automaticamente por `fn index` desde los archivos de test
|
|
- FK: `function_id` → `functions.id`
|
|
|
|
**pc_locations** — columnas: `id, entity_type, entity_id, pc_id, dir_path, status, notes, created_at, updated_at`
|
|
- Mapa de ubicaciones por PC: donde esta cada app/analysis/project/vault en cada maquina
|
|
- `entity_type`: app, analysis, project, vault
|
|
- `status`: active, missing, archived
|
|
- Se puebla con `fn sync`, NO con `fn index`
|
|
- Consultas: `mcp__registry__fn_doctor subcommand="sync"` (drift PC vs disco) o `sqlite3 registry.db "SELECT ... GROUP BY pc_id"` SOLO para agregaciones que el MCP no expone
|
|
|
|
**FTS5 (columnas buscables):**
|
|
- `functions_fts`: id, name, description, tags, signature, domain, example, notes, documentation, code, params_schema
|
|
- `types_fts`: id, name, description, tags, domain, examples, notes, documentation, code
|
|
- `unit_tests_fts`: id, name, code, function_id, lang
|
|
|
|
---
|
|
|
|
## Como invocar funciones del registry (CANONICO)
|
|
|
|
Tres patrones, uno por caso de uso. Toda invocacion del agente se loguea en `projects/fn_monitoring/apps/call_monitor/operations.db` para alimentar el bucle reactivo (issue 0085).
|
|
|
|
| Caso de uso | Patron canonico | Cuando usar |
|
|
|---|---|---|
|
|
| **Inspeccionar** registro (buscar, leer codigo, ver dependencias, dominios) | `mcp__registry__fn_search` / `fn_show` / `fn_code` / `fn_uses` / `fn_list_domains` | SIEMPRE para descubrimiento. Reemplaza `sqlite3 registry.db "SELECT ..."` inline. |
|
|
| **Ejecutar** UNA funcion o pipeline con sus args | `mcp__registry__fn_run <id> [args]` (preferido) o `./fn run <id> [args]` (fallback CLI) | Cuando hay UN id conocido a lanzar. Despacho automatico por lenguaje. Salida estructurada. |
|
|
| **Componer** ad-hoc varias funciones con logica intermedia | Heredoc `python/.venv/bin/python3 - <<'PYEOF' ... PYEOF` IMPORTANDO funciones del registry | Solo cuando hay loops/conditionals/dispatch entre N funciones. Las funciones del registry **se importan**, no se reescriben. |
|
|
|
|
Regla decisiva: antes de cada bloque de codigo, decide caso. Si dudas entre 2 y 3, casi siempre es 2 (un MCP run con args). Si el caso 3 se repite con el mismo shape >5 veces entre sesiones, **es candidato a pipeline** en `python/functions/pipelines/`.
|
|
|
|
### Antipatrones prohibidos
|
|
|
|
| Patron | Por que es malo | Sustituir por |
|
|
|---|---|---|
|
|
| `sqlite3 registry.db "SELECT ..."` para buscar funciones/tipos | Salta MCP, FTS5 gotchas, sin trazabilidad. Hook PreToolUse ya avisa. | `mcp__registry__fn_search` |
|
|
| `python -c "import metabase; print(dir(metabase))"` o `help(metabase)` para descubrir helpers | La fuente de verdad es el registry, no el `__init__.py` | `mcp__registry__fn_search "metabase"` + `mcp__registry__fn_show <id>` |
|
|
| Heredoc que reescribe logica que ya existe como funcion del registry | Reinvento + perdida de capitalizacion | Buscar primero; si falta, delegar a `fn-constructor` (no escribir inline) |
|
|
| `client._http.request(...)` directo cuando hay wrapper en el registry | Salta validacion del wrapper y telemetria | Usar wrapper; si la firma no cubre el caso, proponer extension via `fn proposal add` |
|
|
| Scripts en `temp/` para composiciones que se repiten | Codigo se pierde y no se monitoriza | Pipeline en `python/functions/pipelines/` o pipeline Bash en `bash/functions/pipelines/` |
|
|
| Imports `from <pkg> import *` en heredoc | Imposible saber que funcion del registry se uso | Imports explicitos `from <domain> import <name1>, <name2>` |
|
|
| `claude -p` o `subprocess(["claude", "-p", ...])` para obtener una respuesta del modelo | Lento (cold start ~7-15s, carga MCP + CLAUDE.md), caro, sin control de tools | `ask_llm` (grupo `claude-direct`, API directa, arranque 0). Ver regla `llm_invocation.md` |
|
|
|
|
Excepciones autorizadas para `sqlite3` directo (no requieren MCP): `.schema`, `.tables`, `PRAGMA table_info`, `COUNT(*) GROUP BY`, JOINs custom entre tablas que el MCP no expone.
|
|
|
|
### Trazabilidad y bucle reactivo
|
|
|
|
Hook `PostToolUse` en `.claude/settings.local.json` parsea cada comando Bash + cada `mcp__registry__*` y escribe en la `operations.db` del call_monitor. Datos consumidos por:
|
|
|
|
1. **Tab "Claude usage" en `registry_dashboard`** — top funciones, latencias, error rate, huerfanas con `calls_90d=0`.
|
|
2. **Fase MEJORAR del bucle reactivo** — patrones inline repetidos generan proposals `new_function` con evidencia (session_ids + snippets). Funciones con error_rate alto y muchas llamadas suben en prioridad de bugfix.
|
|
3. **Auditoria de reglas** — assertions sobre `violation_count`, `mcp_ratio`, `heredoc_repetition`. Si fallan critical → proposal "actualizar CLAUDE.md / prompt del agente".
|
|
|
|
Datos sensibles: solo se guarda `args_hash`, NUNCA valores concretos de argumentos.
|
|
|
|
---
|
|
|
|
## Estructura
|
|
|
|
```
|
|
fn-registry/
|
|
functions/{domain}/ # .go + .md por funcion Y tipo Go (core, finance, datascience, cybersecurity)
|
|
functions/pipelines/ # Composiciones, siempre impuras
|
|
types/{domain}/ # Solo .md de tipos (los .go viven en functions/{domain}/)
|
|
python/functions/ # .py + .md por funcion Python
|
|
python/types/ # .py + .md por tipo Python
|
|
bash/functions/ # .sh + .md por funcion Bash (core, infra, io, shell)
|
|
frontend/ # pnpm + vite + react + mantine
|
|
frontend/functions/ # .tsx/.ts + .md (core para TS puro, ui para componentes React)
|
|
frontend/types/ # .ts + .md por tipo
|
|
registry/ # Paquete Go: modelos, SQLite, parser, indexer, validacion, migraciones
|
|
fn_operations/ # Paquete Go: operations database (libreria)
|
|
apps/ # Apps ejecutables (TUIs, CLIs, scripts) — codigo NO reutilizable, cada una con su operations.db
|
|
cpp/apps/ # Apps C++ standalone (sin proyecto). Ej: chart_demo, shaders_lab. Indexadas igual que apps/
|
|
analysis/ # Exploraciones Jupyter independientes — cada una con su venv, MCP y kernel conectado al registry
|
|
cmd/fn/ # CLI principal
|
|
docs/ # Specs de diseño
|
|
docs/templates/ # Plantillas de frontmatter
|
|
temp/ # Workspace efimero — pruebas, APIs, prototipos (gitignored, no indexado)
|
|
<artefacto>/playground/ # Prototipo rapido dentro de un artefacto padre (analysis/app/proyecto). No se indexa
|
|
```
|
|
|
|
---
|
|
|
|
## Build
|
|
|
|
```bash
|
|
CGO_ENABLED=1 go build -tags fts5 -o fn ./cmd/fn/
|
|
CGO_ENABLED=1 go test -tags fts5 ./...
|
|
```
|
|
|
|
---
|
|
|
|
## CLI
|
|
|
|
```bash
|
|
# Registry
|
|
fn index # Regenera registry.db
|
|
fn search "texto" # FTS en functions + types
|
|
fn search -k function -p pure -d core "slice"
|
|
fn list [-d domain] [-k kind]
|
|
fn show <id>
|
|
fn add -k function # Template
|
|
fn check params # Lista funciones sin params_schema
|
|
|
|
# Doctor: diagnostico read-only del registry y artefactos
|
|
fn doctor # Corre todos los checks
|
|
fn doctor artefacts # git/venv/app.md/upstream de cada app y analysis
|
|
fn doctor services # apps tag 'service' + systemctl + puerto
|
|
fn doctor services-spec # audita bloque `service:` del app.md (issue 0105)
|
|
fn doctor sync # drift pc_locations BD vs disco
|
|
fn doctor uses-functions # imports reales vs uses_functions del app.md
|
|
fn doctor unused # funciones del registry sin consumidores
|
|
fn doctor --json # salida JSON (cualquier subcomando)
|
|
# Ver .claude/rules/fn_doctor.md para mapeo subcomando → funcion + acciones derivadas.
|
|
|
|
# Ejecutar funciones y pipelines (fn run)
|
|
fn run <id_or_name> [args...] # Ejecuta por ID o nombre
|
|
fn run init_metabase --project test # Go pipeline (go run .)
|
|
fn run setup_metabase_volume # Bash pipeline (bash <file>)
|
|
fn run metabase_setup_py_infra # Python (python/.venv/bin/python3 <file>)
|
|
fn run my_component_ts_core # TypeScript (frontend/node_modules/.bin/tsx <file>)
|
|
fn run filter_slice_go_core # Go function con tests (go test -v)
|
|
fn run docker_pull_image_go_infra # Go function sin tests (go vet)
|
|
# Despacho por lenguaje:
|
|
# go (con main.go en dir) → go run .
|
|
# go (con tests) → go test -v -count=1 -tags fts5 ./pkg/
|
|
# go (sin tests) → go vet -tags fts5 ./pkg/
|
|
# py → python/.venv/bin/python3 <file>
|
|
# bash → bash <file>
|
|
# ts → frontend/node_modules/.bin/tsx <file>
|
|
# Si el nombre es ambiguo, muestra los IDs para desambiguar.
|
|
|
|
# Proposals
|
|
fn proposal add --kind new_function --title "..." --created-by agent [--target-id <id>]
|
|
fn proposal list [-k kind] [-s status]
|
|
fn proposal show <id>
|
|
fn proposal update <id> --status approved [--reviewed-by lucas]
|
|
|
|
# Sync entre PCs
|
|
fn sync # Push+pull completo contra el servidor
|
|
fn sync status # Estado local: PC, API, conteos
|
|
fn sync locations # Mapa de ubicaciones en todos los PCs
|
|
# Config: ~/.fn_pc (identidad PC), FN_REGISTRY_API (URL), REGISTRY_API_TOKEN (token)
|
|
# URL con basicAuth: export FN_REGISTRY_API="https://user:pass@registry.organic-machine.com"
|
|
|
|
# Operations (desde directorio con operations.db)
|
|
fn ops init [path]
|
|
fn ops entity add|list|show|delete
|
|
fn ops relation add|list|show|delete
|
|
fn ops graph
|
|
fn ops snapshot list|check|update
|
|
fn ops execution add|list|show
|
|
fn ops assertion add|list|show|delete|eval [--react]
|
|
fn ops assertion result add|list
|
|
```
|
|
|
|
`FN_REGISTRY_ROOT` env var permite que `fn ops` acceda a registry.db desde cualquier directorio.
|
|
|
|
### Uso de fn run por agentes
|
|
|
|
`fn run` permite ejecutar directamente funciones y pipelines del registry desde la terminal. Usar para:
|
|
- Lanzar pipelines con sus argumentos: `./fn run init_metabase --project fn_registry`
|
|
- Correr tests de funciones Go: `./fn run filter_slice_go_core`
|
|
- Ejecutar scripts Python/Bash del registry sin montar paths manualmente
|
|
- Verificar que funciones Go compilan correctamente (go vet)
|
|
|
|
Entornos usados automaticamente:
|
|
- Python: `python/.venv/bin/python3` (venv del proyecto)
|
|
- TypeScript: `frontend/node_modules/.bin/tsx` (node del proyecto)
|
|
- Go: `go run .` / `go test` / `go vet` con `CGO_ENABLED=1 -tags fts5`
|
|
- Bash: `bash` del sistema
|
|
|
|
---
|
|
|
|
## Añadir funciones
|
|
|
|
1. `mcp__registry__fn_search query="<nombre|desc>"` para verificar que no existe algo similar
|
|
2. Crea dos archivos segun el lenguaje:
|
|
- Go: `functions/{domain}/{name}.go` + `.md`
|
|
- Python: `python/functions/{domain}/{name}.py` + `.md`
|
|
- Bash: `bash/functions/{domain}/{name}.sh` + `.md`
|
|
- TypeScript: `frontend/functions/{domain}/{name}.ts` + `.md`
|
|
3. Ejecuta `./fn index` y verifica con `./fn show {id}`
|
|
|
|
Frontmatter del .md — ver template completo en `docs/templates/` o con `fn add -k function`.
|
|
|
|
Campos `params` y `output` (obligatorios en frontmatter):
|
|
- `params`: lista de `{name, desc}` con descripción semántica de cada parámetro (qué representa, unidades, rango)
|
|
- `output`: descripción semántica de lo que retorna la función
|
|
- Para componentes: solo `output` (ya tienen `props`)
|
|
- Se indexan como JSON en `params_schema` y son buscables via FTS5
|
|
- `fn check params` lista funciones sin documentar
|
|
|
|
Reglas de integridad (el indexer las valida):
|
|
- Pipeline → siempre impuro + uses_functions no vacio
|
|
- Pure → returns_optional: false + error_type: ""
|
|
- Impure → error_type obligatorio (usar `error_go_core`)
|
|
- tested: true → test_file_path y tests obligatorios
|
|
- uses_functions, uses_types, returns, error_type → IDs existentes
|
|
- Component → framework obligatorio, returns vacio (usar emits)
|
|
- file_path siempre relativa, IDs formato `{name}_{lang}_{domain}`
|
|
- Campo `returns` solo para IDs del registry, NO tipos nativos de Go
|
|
|
|
## Añadir tipos
|
|
|
|
Dos archivos en directorios separados:
|
|
- **Codigo Go:** `functions/{domain}/{name}.go` (junto a las funciones, mismo paquete Go)
|
|
- **Metadata .md:** `types/{domain}/{name}.md` con `file_path` apuntando a `functions/{domain}/{name}.go`
|
|
|
|
Los `.go` de tipos viven en `functions/{domain}/` para que Go los compile en el mismo paquete que las funciones que los usan. Los `.md` se mantienen en `types/{domain}/` para que el indexer los identifique como tipos.
|
|
|
|
Ver template en `docs/templates/`.
|
|
|
|
---
|
|
|
|
## Analysis (exploraciones Jupyter)
|
|
|
|
Carpeta `analysis/` para exploraciones de datos con Jupyter + agentes Claude. Mismo patron que `apps/` — cada analisis es independiente con su propio venv, MCP y kernel.
|
|
|
|
**NO es codigo reutilizable** — son investigaciones ad-hoc. Si algo de un analisis resulta util, se extrae como funcion al registry.
|
|
|
|
### Estructura
|
|
|
|
```
|
|
analysis/
|
|
{tema}/ # Cada analisis es autonomo
|
|
.venv/ # Deps propias (gitignored)
|
|
.mcp.json # MCP jupyter apuntando a SU venv (gitignored)
|
|
.claude/CLAUDE.md # Reglas para agentes en este analisis
|
|
.ipython/profile_default/startup/ # Kernel startup con acceso al registry
|
|
00_fn_registry.py # Autocarga FN_REGISTRY_ROOT, helpers, sys.path
|
|
notebooks/ # Notebooks de exploracion
|
|
data/ # Datos locales (gitignored)
|
|
run-jupyter-lab.sh # Launcher Jupyter colaborativo
|
|
pyproject.toml # Deps gestionadas con uv
|
|
```
|
|
|
|
### Crear un analisis nuevo
|
|
|
|
Un solo comando deja todo listo: carpetas, venv, paquetes, launcher, MCP, kernel startup, `analysis.md` con frontmatter y, si va en un proyecto, `fn index` final.
|
|
|
|
```bash
|
|
# Analisis suelto (analysis/{nombre}/)
|
|
fn run init_jupyter_analysis finanzas
|
|
fn run init_jupyter_analysis ml scikit-learn torch
|
|
|
|
# Analisis dentro de un proyecto (projects/{proyecto}/analysis/{nombre}/)
|
|
fn run init_jupyter_analysis --project aurgi sale_prices --desc "Comprobacion precios"
|
|
fn run init_jupyter_analysis --project fn_monitoring coverage polars --tags "monitoring,coverage"
|
|
```
|
|
|
|
Flags del pipeline:
|
|
- `--project <nombre>` — crea el analisis dentro de `projects/{nombre}/analysis/` y ejecuta `fn index` al final. El proyecto debe existir (`projects/{nombre}/project.md`).
|
|
- `--desc "..."` — descripcion que se escribe en el frontmatter de `analysis.md`.
|
|
- `--tags "a,b,c"` — tags CSV que se escriben en el frontmatter.
|
|
|
|
**NUNCA** uses `mv` para mover un analisis de `analysis/` a `projects/{proyecto}/analysis/` despues de crearlo. Al mover, el `.venv/bin/activate` queda con el path antiguo hardcodeado y el launcher falla con `ERROR: jupyter-collaboration no esta instalado`. Si esto pasa: `rm -rf .venv && uv sync` dentro del directorio nuevo. La forma correcta es siempre crear con `--project` desde el inicio.
|
|
|
|
El pipeline `init_jupyter_analysis_bash_pipelines` (v1.1.0) compone 9 funciones atomicas del registry.
|
|
|
|
### Usar un analisis
|
|
|
|
```bash
|
|
# Terminal 1: lanzar Jupyter
|
|
cd analysis/{tema} && ./run-jupyter-lab.sh
|
|
|
|
# Terminal 2: abrir Claude con MCP jupyter
|
|
cd analysis/{tema} && claude
|
|
|
|
# Navegador: http://localhost:8888
|
|
```
|
|
|
|
### Acceso al registry desde notebooks
|
|
|
|
El kernel startup (`00_fn_registry.py`) se ejecuta automaticamente al abrir cualquier notebook y provee:
|
|
|
|
```python
|
|
# Helpers disponibles sin importar nada:
|
|
fn_search("slice") # Busca funciones y tipos por nombre/descripcion
|
|
fn_query("SELECT ...") # SQL directo sobre registry.db
|
|
fn_code("filter_list_py_core") # Codigo fuente de una funcion
|
|
|
|
# Importar funciones Python del registry directamente:
|
|
from core import filter_list, map_list, reduce_list
|
|
from finance import sma, ema, rsi
|
|
from metabase import MetabaseClient
|
|
|
|
# Variable de entorno disponible:
|
|
import os
|
|
os.environ["FN_REGISTRY_ROOT"] # Raiz del registry
|
|
```
|
|
|
|
### Reglas para agentes en analysis
|
|
|
|
Cada analisis tiene su `.claude/CLAUDE.md` con reglas especificas:
|
|
- Celdas inmutables: nunca modificar celdas existentes, solo anadir nuevas
|
|
- Programacion funcional obligatoria: funciones puras, sin mutacion
|
|
- Usar MCP jupyter para ejecutar codigo, nunca bash
|
|
- Notebooks en `notebooks/`, maximo 50 celdas por notebook
|
|
- Dependencias con `uv add`, nunca pip directo
|
|
|
|
---
|
|
|
|
## Bucle reactivo: CONSTRUIR → EJECUTAR → RECOPILAR → ANALIZAR → MEJORAR
|
|
|
|
### 1. CONSTRUIR
|
|
- Agente consulta registry → recupera funciones testeadas por FTS sobre `name`, `description`, `tags`.
|
|
- Razona sobre composabilidad comparando `returns` con `uses_types`.
|
|
- Prioriza funciones puras para el nucleo, aisla impuras en los bordes.
|
|
- Registra el pipeline en operations como `status: designed → implemented`.
|
|
- **BD:** `registry.db` (functions, types) → `operations.db` (relations, entities)
|
|
|
|
### 2. EJECUTAR
|
|
- Pipeline corre → inserta registro en `executions` con `duration_ms`, `records_in`, `records_out`, `metrics`.
|
|
- `operations.relations.status = running`.
|
|
- Si falla → `execution.status = failure`, `error` capturado.
|
|
- **BD:** `operations.db` (executions, relations)
|
|
|
|
### 3. RECOPILAR
|
|
- Entities se pueblan — `metadata` contiene los valores concretos de los campos del tipo.
|
|
- `types_snapshot` garantiza que `operations.db` es autonomo sin `registry.db`.
|
|
- El agente actualiza `entity.status` segun los datos recibidos.
|
|
- **BD:** `operations.db` (entities, types_snapshot)
|
|
|
|
### 4. ANALIZAR
|
|
- Agente evalua todas las `assertions` activas sobre las entities producidas.
|
|
- Compara `metrics` de la ejecucion actual con `executions` historicas.
|
|
- `critical` falla → `entity.status = corrupted`.
|
|
- `warning` falla → `entity.status = stale`.
|
|
- Resultados en `assertion_results` con `value` concreto para debugging.
|
|
- **BD:** `operations.db` (assertions, assertion_results, entities.status)
|
|
|
|
### 5. MEJORAR
|
|
- Si assertions fallan o metricas degradan → agente escribe en `proposals`.
|
|
- `proposals.evidence` referencia los `assertion_ids` y `execution_ids` que lo justifican.
|
|
- El humano revisa `proposals.status: pending → approved → implemented`.
|
|
- El registry crece de forma controlada y trazable.
|
|
- **BD:** `registry.db` (proposals)
|
|
|
|
Codigo: `ExecuteAndReact()` en `fn_operations/operations.go` ejecuta pasos 2-4.
|
|
CLI: `fn ops assertion eval --entity-id X --react` ejecuta pasos 4-5.
|
|
Las assertion rules son expresiones SQL. Campos sin prefijo se reescriben a `json_extract(metadata, '$.campo')`.
|
|
|
|
---
|
|
|
|
## Fuentes de verdad
|
|
|
|
| Que | Donde |
|
|
|---|---|
|
|
| Codigo | .go / .py / .tsx |
|
|
| Metadata | .md junto al codigo |
|
|
| Schema de BDs | `sqlite3 *.db ".schema"` o `docs/` |
|
|
| Indice | registry.db (`fn index`) |
|
|
| Proposals, entities, executions, assertions | datos vivos en sus BDs |
|