- Migration 007: repo_url on apps table + analysis table with FTS5 - Analysis struct, parser, CRUD, validation, hash computation - Selective purge: remote-only apps/analysis preserved across fn index - CLI: fn app list/clone/pull, fn analysis list/clone/pull - search/show/list now include analysis results - Apps removed from git tracking (content lives in Gitea repos) - .gitkeep for apps/ and analysis/ dirs - Bash functions: jupyter analysis pipeline, shell utilities - Browser domain: CDP functions moved from infra to browser Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
14 KiB
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.
# 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.
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
- 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)
FTS5 (columnas buscables):
functions_fts: id, name, description, tags, signature, domain, example, notes, documentation, codetypes_fts: id, name, description, tags, domain, examples, notes, documentation, code
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
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
Build
CGO_ENABLED=1 go build -tags fts5 -o fn ./cmd/fn/
CGO_ENABLED=1 go test -tags fts5 ./...
CLI
# 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
# 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]
# 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 vetconCGO_ENABLED=1 -tags fts5 - Bash:
bashdel sistema
Añadir funciones
- Consulta la BD para verificar que no existe algo similar
- 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
- Go:
- Ejecuta
./fn indexy 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
returnssolo 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}.mdconfile_pathapuntando afunctions/{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
# Basico
fn run init_jupyter_analysis finanzas
# Con paquetes extra
fn run init_jupyter_analysis ml scikit-learn torch
fn run init_jupyter_analysis duckdb polars duckdb
El pipeline init_jupyter_analysis_bash_pipelines compone 8 funciones atomicas del registry.
Usar un analisis
# 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:
# 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
returnsconuses_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
executionsconduration_ms,records_in,records_out,metrics. operations.relations.status = running.- Si falla →
execution.status = failure,errorcapturado. - BD:
operations.db(executions, relations)
3. RECOPILAR
- Entities se pueblan —
metadatacontiene los valores concretos de los campos del tipo. types_snapshotgarantiza queoperations.dbes autonomo sinregistry.db.- El agente actualiza
entity.statussegun los datos recibidos. - BD:
operations.db(entities, types_snapshot)
4. ANALIZAR
- Agente evalua todas las
assertionsactivas sobre las entities producidas. - Compara
metricsde la ejecucion actual conexecutionshistoricas. criticalfalla →entity.status = corrupted.warningfalla →entity.status = stale.- Resultados en
assertion_resultsconvalueconcreto para debugging. - BD:
operations.db(assertions, assertion_results, entities.status)
5. MEJORAR
- Si assertions fallan o metricas degradan → agente escribe en
proposals. proposals.evidencereferencia losassertion_idsyexecution_idsque 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 |