# fn-registry Registry personal de codigo reutilizable con busqueda FTS. Diseñado para composicion funcional y agentes. **Dos bases de datos SQLite:** - **registry.db** (raiz) — funciones, tipos, proposals. Regenerable con `fn index` (excepto proposals). - **operations.db** (por app en `apps/*/`) — entities, relations, executions, assertions. Datos vivos. **Reglas y convenciones:** ver `.claude/rules/INDEX.md` --- ## 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. **La BD contiene el codigo y la documentacion completa** de cada funcion y tipo en los campos `code`, `documentation` y `notes`. Estos campos tambien estan indexados en FTS5, asi que puedes buscar dentro del codigo y la documentacion directamente. Para leer el codigo de una funcion: `SELECT code FROM functions WHERE id = '...'`. Para leer su documentacion: `SELECT documentation FROM functions WHERE id = '...'`. **Busquedas FTS5 obligatorias:** Usa SIEMPRE la tabla FTS5 para buscar tanto por `name` como por `description`. Esto encuentra coincidencias parciales y similares que una busqueda exacta perderia. Usa operadores FTS5: `OR` para ampliar, `*` para prefijos, `NEAR` para proximidad. ```bash # Busqueda FTS5 por nombre Y descripcion (USAR SIEMPRE ESTE PATRON) sqlite3 registry.db "SELECT id, kind, purity, description FROM functions WHERE id IN (SELECT id FROM functions_fts WHERE functions_fts MATCH 'name:slice OR description:slice') ORDER BY name;" # FTS5 con prefijo (encuentra slice, slicing, sliced...) sqlite3 registry.db "SELECT id, kind, purity, description FROM functions WHERE id IN (SELECT id FROM functions_fts WHERE functions_fts MATCH 'name:slic* OR description:slic*') ORDER BY name;" # FTS5 en tipos sqlite3 registry.db "SELECT id, algebraic, description FROM types WHERE id IN (SELECT id FROM types_fts WHERE types_fts MATCH 'name:result OR description:result') ORDER BY name;" # Por dominio sqlite3 registry.db "SELECT id, purity, signature FROM functions WHERE domain = 'finance' ORDER BY name;" # Puras de un dominio sqlite3 registry.db "SELECT id, signature FROM functions WHERE domain = 'core' AND purity = 'pure' ORDER BY name;" # Tipos por dominio sqlite3 registry.db "SELECT id, algebraic, description FROM types WHERE domain = 'cybersecurity';" # Dependencias sqlite3 registry.db "SELECT id, uses_functions, uses_types FROM functions WHERE uses_functions != '[]';" # Proposals pendientes sqlite3 registry.db "SELECT id, kind, status, title FROM proposals WHERE status = 'pending';" # Schema completo sqlite3 registry.db ".schema" ``` **Regla:** Si necesitas saber si algo existe o hay algo similar, haz la consulta FTS5 sobre la BD. No asumas que no existe sin consultar primero. --- ## 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 + tailwind + shadcn 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 cmd/fn/ # CLI principal docs/ # Specs de diseño docs/templates/ # Plantillas de frontmatter ``` --- ## 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 fn add -k function # Template # Ejecutar funciones y pipelines (fn run) fn run [args...] # Ejecuta por ID o nombre fn run init_metabase --project test # Go pipeline (go run .) fn run setup_metabase_volume # Bash pipeline (bash ) fn run metabase_setup_py_infra # Python (python/.venv/bin/python3 ) fn run my_component_ts_core # TypeScript (frontend/node_modules/.bin/tsx ) 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 # bash → bash # ts → frontend/node_modules/.bin/tsx # Si el nombre es ambiguo, muestra los IDs para desambiguar. # Proposals fn proposal add --kind new_function --title "..." --created-by agent [--target-id ] fn proposal list [-k kind] [-s status] fn proposal show fn proposal update --status approved [--reviewed-by lucas] # 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. Consulta la BD 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`. 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/`. --- ## 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 |