Files
fn_registry/.claude/CLAUDE.md
T
egutierrez ab6ce8f822 feat(registry): index cpp/apps/* + e2e test infrastructure
registry/indexer.go ahora escanea <lang>/apps/*/app.md ademas de apps/ y
projects/*/apps/. cpp/apps/chart_demo y cpp/apps/shaders_lab pasan a estar
en registry.db con sus manifests.

Infraestructura de tests e2e (opt-in con -DFN_BUILD_TESTS=ON):
- vendor de Dear ImGui Test Engine (personal/open-source license).
- chart_demo_tests target con tests/chart_demo_tests.cpp.
- /e2e-cpp slash command para crear y ejecutar tests e2e.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 11:51:38 +02:00

18 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, 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 y cada analysis es su propio repo Gitea en dataforge/<basename> con branch master (ver ADR 0002). 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.

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;"

# FTS5 por semantica de params (composabilidad)
sqlite3 registry.db "SELECT id, json_extract(params_schema, '$.output') FROM functions WHERE id IN (SELECT id FROM functions_fts WHERE functions_fts MATCH 'params_schema:retornos');"

# 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, 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_idfunctions.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: SELECT * FROM pc_locations WHERE pc_id = 'home-wsl'

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

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)

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
fn check params                     # Lista funciones sin params_schema

# 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. 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.

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.

# 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

# 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 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