chore: auto-commit (799 archivos)
- .claude/CLAUDE.md - .claude/commands/subagentes.md - .claude/rules/INDEX.md - .mcp.json - bash/functions/cybersecurity/analyze_dns.md - bash/functions/cybersecurity/audit_http_headers.md - bash/functions/cybersecurity/audit_ssh_config.md - bash/functions/cybersecurity/check_firewall.md - bash/functions/cybersecurity/detect_suspicious_users.md - bash/functions/cybersecurity/encrypt_file.md - ... Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"_": "Paths que fn-orquestador NUNCA debe modificar dentro del worktree auto/<issue>. Issue 0069.",
|
||||
"_format": "Cada entry es una ruta o glob relativa al repo root. La regla puede ser exact|glob|prefix.",
|
||||
"protected": [
|
||||
{"rule": "prefix", "path": ".claude/agents/", "reason": "Self-modification prohibida; el orquestador no se modifica a si mismo ni a otros subagentes en la misma run."},
|
||||
{"rule": "prefix", "path": ".claude/commands/", "reason": "Comandos definidos por humano."},
|
||||
{"rule": "prefix", "path": ".claude/rules/", "reason": "Reglas operativas. Modificar requiere review humano."},
|
||||
{"rule": "prefix", "path": ".claude/scripts/", "reason": "Hooks del repo."},
|
||||
{"rule": "exact", "path": ".claude/CLAUDE.md", "reason": "Memoria del proyecto."},
|
||||
{"rule": "exact", "path": ".claude/settings.json", "reason": "Config persistente."},
|
||||
{"rule": "exact", "path": ".claude/settings.local.json", "reason": "Config local del PC."},
|
||||
{"rule": "exact", "path": ".mcp.json", "reason": "Config MCP."},
|
||||
{"rule": "prefix", "path": "dev/issues/", "reason": "Issues files. Excepcion: el issue del task actual (orquestador puede actualizar status/notas)."},
|
||||
{"rule": "glob", "path": "**/.env*", "reason": "Secrets."},
|
||||
{"rule": "glob", "path": "**/*.key", "reason": "Secrets."},
|
||||
{"rule": "glob", "path": "**/*.pem", "reason": "Secrets."},
|
||||
{"rule": "glob", "path": "**/credentials.json", "reason": "Secrets."},
|
||||
{"rule": "glob", "path": "**/migrations/*.sql", "reason": "Migraciones existentes inmutables. Crear nuevas numeradas — no editar."},
|
||||
{"rule": "exact", "path": "registry.db", "reason": "Indice regenerable, no fuente. Usar fn index."},
|
||||
{"rule": "glob", "path": "**/operations.db", "reason": "Datos vivos. Acceso via fn ops o sqlite_api, no escritura directa de SQL."},
|
||||
{"rule": "exact", "path": "go.mod", "reason": "Cambios de deps requieren review humano (riesgo CVE/licencias)."},
|
||||
{"rule": "exact", "path": "go.sum", "reason": "Bloqueo de deps."},
|
||||
{"rule": "glob", "path": "**/package.json", "reason": "Cambios de deps requieren review humano."},
|
||||
{"rule": "glob", "path": "**/package-lock.json", "reason": "Bloqueo de deps npm."},
|
||||
{"rule": "glob", "path": "**/pnpm-lock.yaml", "reason": "Bloqueo de deps pnpm."},
|
||||
{"rule": "glob", "path": "**/pyproject.toml", "reason": "Cambios de deps Python."},
|
||||
{"rule": "glob", "path": "**/uv.lock", "reason": "Bloqueo deps uv."},
|
||||
{"rule": "exact", "path": ".git/", "reason": "git internals. Operar via git CLI, nunca tocar archivos directo."}
|
||||
],
|
||||
"exceptions": [
|
||||
{
|
||||
"rule": "Single-issue exception",
|
||||
"description": "El orquestador PUEDE modificar dev/issues/<current_task_id>*.md para actualizar estado/notas del propio task. Cualquier otro issue file permanece protegido."
|
||||
},
|
||||
{
|
||||
"rule": "Migrations aditivas",
|
||||
"description": "El orquestador PUEDE crear archivos NUEVOS en cualquier migrations/ (NNN_*.sql) con numero superior al maximo existente. NUNCA editar migrations existentes."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,13 +1,41 @@
|
||||
---
|
||||
id: 0069
|
||||
title: Bucle autonomo de subagentes — completar y mejorar tareas sin intervencion humana
|
||||
status: pending
|
||||
status: ready
|
||||
priority: medium
|
||||
created: 2026-05-09
|
||||
depends_on: [0068]
|
||||
related: [0026, 0027, 0028]
|
||||
related: [0026, 0027, 0028, 0085]
|
||||
---
|
||||
|
||||
## Estado 2026-05-13
|
||||
|
||||
Infra base lista para lanzar el orquestador:
|
||||
|
||||
| Paso | Estado |
|
||||
|---|---|
|
||||
| 1. Migration `006_task_runs.sql` | **hecho** — aplicada via embed.FS, verificada en operations.db nueva |
|
||||
| 2. Subagente `.claude/agents/fn-orquestador/SKILL.md` | **hecho** (preexistente) |
|
||||
| 3. `dev/autonomous_protected_paths.json` | **hecho** — 21 patrones + 2 excepciones documentadas |
|
||||
| 4. Slash `/autonomous-task <issue_id>` | **hecho** — `.claude/commands/autonomous-task.md` |
|
||||
| 5-6. Funciones/tipos auxiliares (`task_run_persist`, `proposal_filter_safe`, ...) | pending (no bloquea piloto si el orquestador inlinea SQL) |
|
||||
| 7-8. Pilotaje en 2 issues reales | pending |
|
||||
| 9. Hardening + tests | pending |
|
||||
| 10. Regla `.claude/rules/autonomous_loop.md` | pending |
|
||||
|
||||
Pre-condiciones verificadas 2026-05-13:
|
||||
- ✓ migration 006_task_runs.sql aplicada (`schema_migrations` v6)
|
||||
- ✓ 6 subagentes presentes
|
||||
- ✓ paths protegidos JSON
|
||||
- ✓ master sync OK
|
||||
- ✓ gh auth OK (gutierenmanuel)
|
||||
- ✓ sin branches `auto/*` colgando
|
||||
|
||||
Listo para piloto: `/autonomous-task <issue_id_simple_y_verificable>`.
|
||||
|
||||
Integracion con issue 0085 (call_monitor): el orquestador puede consultar `function_stats`, `proposals` y `copied_code` antes de cada fase para tomar decisiones informadas; sus invocaciones se loggean automaticamente via hook PostToolUse.
|
||||
|
||||
|
||||
## Contexto
|
||||
|
||||
El issue 0068 cierra el bucle reactivo a nivel **agentes individuales**:
|
||||
|
||||
@@ -139,3 +139,164 @@ Hooks de salida del monitor:
|
||||
- El monitor empieza pasivo (solo loguea). En una fase posterior puede bloquear violaciones criticas (ej. `sqlite3 registry.db` directo aborta con mensaje + sugerencia).
|
||||
- Datos sensibles: el `args_hash` se guarda pero los valores concretos NO. Para queries SQL que contienen secretos por accidente, mantener allowlist de redaccion.
|
||||
- Compatible con el patron de `task_runs` del issue 0069 — comparten el concepto de "ejecucion trazable".
|
||||
|
||||
## Decisiones 2026-05-13
|
||||
|
||||
- **UI**: tab dentro de `registry_dashboard` (proyecto `fn_monitoring`). Reusa C++/ImGui + `sqlite_api`. Razon: pregunta clave "que deprecar" = JOIN entre `functions` y `function_stats`; una sola app gana.
|
||||
- **Plumbing**: `projects/fn_monitoring/apps/call_monitor/` (Go + hook Bash `PostToolUse`). Repo Gitea propio (`dataforge/call_monitor`).
|
||||
- **Hook scope**: solo proyecto (`.claude/settings.local.json`). Captura solo sesiones de fn_registry.
|
||||
- **Orden de sub-issues**: 0085j (docs) → 0085a (schema) → 0085b (hook) → 0085c (wrapper Python).
|
||||
- **0085j hecho** (2026-05-13): seccion "Como invocar funciones del registry (CANONICO)" en `.claude/CLAUDE.md`, regla `.claude/rules/registry_calls.md` (rule #27), entrada `INDEX.md`, memoria `feedback_canonical_registry_calls.md`.
|
||||
- **MCP ampliado**: tool nuevo `fn_proposal` (read-only, list + show by id) en `apps/registry_mcp/tool_proposal.go`. Cierra el gap de `sqlite3 registry.db "SELECT ... FROM proposals"` inline. Rebuild aplicado.
|
||||
|
||||
## Schema extendido — contadores por funcion
|
||||
|
||||
Event-log tables (append-only):
|
||||
|
||||
| Tabla | Captura |
|
||||
|---|---|
|
||||
| `calls` | function_id, tool_used, session_id, duration_ms, success, error_class, error_snippet, args_hash, ts |
|
||||
| `code_writes` | function_id (derivado del path), session_id, lines_added, lines_removed, ts |
|
||||
| `test_runs` | function_id, test_id, passed, duration_ms, output_snippet, ts |
|
||||
| `e2e_runs_fn` | function_id, app_id, check_id, passed, ts (cruza con `apps.uses_functions`) |
|
||||
| `violations` | rule_id, session_id, command_snippet, severity, ts |
|
||||
| `patterns` | pattern_hash, session_ids[], representative_snippet, occurrences, last_seen |
|
||||
| `sessions` | session_id, cwd, started_at, ended_at, health_score, mcp_ratio |
|
||||
|
||||
Vista agregada `function_stats` por `function_id`:
|
||||
|
||||
- **Uso**: `calls_total`, `calls_24h/7d/30d/90d`, `last_used_at`
|
||||
- **Errores**: `errors_total`, `error_rate`, `last_error_class`, `last_error_ts`
|
||||
- **Performance**: `mean_duration_ms`, `p95_duration_ms`
|
||||
- **Codigo**: `writes_count`, `last_write_at`
|
||||
- **Tests**: `tests_total`, `tests_failed`, `test_fail_rate`, `last_test_failed_at`
|
||||
- **E2E**: `e2e_total`, `e2e_failed`, `e2e_fail_rate`, `consumer_apps_count`
|
||||
- **Salud**: `violations_caused`
|
||||
|
||||
Assertions derivadas → proposals automaticas:
|
||||
|
||||
| Regla | Threshold | Proposal |
|
||||
|---|---|---|
|
||||
| Huerfana absoluta | `calls_90d=0 AND writes_count=0` | `deprecate_function` |
|
||||
| Bug prioritario | `error_rate>0.1 AND calls_7d>5` | `improve_function` (bug) |
|
||||
| Regresion performance | `p95_24h > 1.5 * p95_30d` | `improve_function` (perf) |
|
||||
| Test flaky | `test_fail_rate>0.1 AND tests_total>10` | `improve_function` (flaky) |
|
||||
| Wrapper saltado | `violations_caused>3` | `improve_function` (API gap) |
|
||||
| Patron inline sin funcion | `patterns.occurrences>5 AND no match FTS` | `new_function` con snippet |
|
||||
| Blast radius alto | `e2e_fail_rate>0 AND consumer_apps_count>=3` | `improve_function` (critical) |
|
||||
|
||||
Migracion: `projects/fn_monitoring/apps/call_monitor/migrations/001_init.sql` con las 7 tablas + indices sobre `function_id`, `session_id`, `ts`. Vista `function_stats` se construye en `002_function_stats_view.sql` (materializar como TABLE si performance bajo, recalcular cada N min).
|
||||
|
||||
## Cobertura por lenguaje — capas de monitorizacion
|
||||
|
||||
Cada lenguaje del registry tiene un "techo" de lo monitorizable runtime. Las 8 capas de cobertura propuestas, ordenadas por ROI:
|
||||
|
||||
| # | Capa | Lenguaje | Cubre | Esfuerzo | Estado |
|
||||
|---|---|---|---|---|---|
|
||||
| 1 | Hook PostToolUse Bash | universal | mcp__registry__*, `./fn run`, Edit/Write sobre `functions/`, violations | bajo | **hecho (0085b)** |
|
||||
| 2 | Wrapper Python (`registry_telemetry`) activable con `FN_TELEMETRY=1` | py | heredocs Python + notebooks Jupyter + scripts dentro del registry | bajo | pending 0085c |
|
||||
| 3 | Wrapper Bash `bash/lib/telemetry_prelude.sh` (redefine cada funcion del registry con cronograma + log) | bash | heredocs bash + scripts/apps Bash | bajo | pending 0085c-bash |
|
||||
| 4 | Interceptor en `fn run` (binario Go) | go/py/bash/ts | invocaciones via CLI con duration/error real medido | medio | pending 0085d-go |
|
||||
| 5 | `fn doctor copied-code` — fingerprint match registry vs apps | universal (estatico) | codigo copiado/parafraseado sin import | medio | pending 0085k |
|
||||
| 6 | Tabla `function_versions` + snapshot en Edit-hook | universal (estatico) | drift de versiones, forks silenciosos | bajo | pending 0085l |
|
||||
| 7 | Build-tag `telemetry` Go + codegen wrappers | go | runtime de apps Go (parcial, opt-in por build) | alto | futuro |
|
||||
| 8 | Macro `FN_CALL(name, ...)` C++ opt-in | cpp | C++ apps cooperantes | alto | futuro |
|
||||
|
||||
**Reglas duras:**
|
||||
- **Go y C++ compilados:** sin monkey-patch dinamico. Apps que linkean estaticamente la funcion **no se pueden auditar runtime** salvo capas 7/8 con opt-in.
|
||||
- **Solucion realista Go/C++:** medir 3 caminos legitimos — `./fn run`, `mcp_fn_run`, `go test`/`ctest`. Runtime de app en produccion queda fuera.
|
||||
- **Wrapper Python/Bash:** activacion explicita via `FN_TELEMETRY=1`. Si la app no exporta esa env var, no se mide.
|
||||
|
||||
## Drift detection — funciones copiadas y modificadas
|
||||
|
||||
### 5. Codigo copiado en apps (sin `import`)
|
||||
|
||||
Problema: app reescribe el cuerpo de una funcion del registry en vez de importarla. Invisible runtime — el codigo nunca pasa por el registry. Solo se detecta por analisis estatico.
|
||||
|
||||
Tecnicas (ordenadas por precision/coste):
|
||||
|
||||
| Tecnica | Pilla | Limitacion |
|
||||
|---|---|---|
|
||||
| Hash exacto del cuerpo normalizado (strip whitespace + comments) | copy-paste literal | 0 false-positives, miss si renombran 1 var |
|
||||
| AST fingerprint via Tree-Sitter → token sequence → SimHash | copia con renames | requiere parser por lenguaje |
|
||||
| ssdeep / TLSH fuzzy hash sobre cuerpo normalizado | copia con tweaks pequeños | umbral arbitrario ~85% true match |
|
||||
| Embeddings de codigo (Code2Vec, starcoder, etc.) | parafraseado / refactor parcial | costoso, opaco |
|
||||
|
||||
**MVP propuesto:** `fn doctor copied-code` que cruza fingerprints de cada funcion del registry contra cuerpos de funciones declaradas en `apps/`, `projects/*/apps/`. Salida: `{app_id, app_file, app_func_name, matched_registry_id, similarity, kind}`. Severidad:
|
||||
|
||||
- `exact_copy` → critical → proposal `import_instead`
|
||||
- `near_copy` (>0.85 fuzzy) → warning
|
||||
- `partial_match` (>0.6) → info
|
||||
|
||||
Persistencia: tabla nueva `copied_code` en `call_monitor.operations.db`. Aporta a `function_stats` columna `copies_detected`.
|
||||
|
||||
### 6. Versiones modificadas (`function_versions`)
|
||||
|
||||
`registry.db.functions.content_hash` ya existe — `fn index` lo recalcula. Falta historial.
|
||||
|
||||
Schema propuesto (migracion `003_function_versions.sql` en call_monitor):
|
||||
|
||||
```sql
|
||||
CREATE TABLE function_versions (
|
||||
function_id TEXT NOT NULL,
|
||||
content_hash TEXT NOT NULL,
|
||||
version TEXT NOT NULL,
|
||||
snapped_at INTEGER NOT NULL,
|
||||
source TEXT NOT NULL, -- 'index' | 'edit_hook' | 'copy_detected'
|
||||
lines_added INTEGER DEFAULT 0,
|
||||
lines_removed INTEGER DEFAULT 0,
|
||||
PRIMARY KEY (function_id, content_hash)
|
||||
);
|
||||
```
|
||||
|
||||
Llenado:
|
||||
- Cada `fn index` inserta snapshot con `source='index'`.
|
||||
- Hook PostToolUse Edit/Write sobre `functions/...` inserta snapshot con `source='edit_hook'` (ya tenemos `code_writes` — extender o cross-reference).
|
||||
- `fn doctor copied-code` registra version observada en la copia con `source='copy_detected'`.
|
||||
|
||||
Consultas utiles:
|
||||
- Forks silenciosos: app copio version X, registry esta en version Y, app sigue en X.
|
||||
- Velocidad de cambio: funciones con muchas versions en poco tiempo → inestables.
|
||||
- Backport candidates: app tiene version vieja, version nueva resuelve bug → flag.
|
||||
|
||||
## Que se escapa del monitor (boundary explicito)
|
||||
|
||||
| Caso | Capturado? | Capa que lo cubriria |
|
||||
|---|---|---|
|
||||
| `mcp__registry__fn_*` | si | hook PostToolUse |
|
||||
| `./fn run X` desde Bash | si | hook PostToolUse |
|
||||
| Edit/Write sobre `functions/*/*.{go,py,sh,ts}` | si | hook PostToolUse |
|
||||
| Heredoc Python importando registry | parcial (solo `heredoc_py`, no funciones internas) | wrapper Python (0085c) |
|
||||
| Heredoc Bash sourcing registry | parcial | wrapper Bash (0085c-bash) |
|
||||
| Notebook Jupyter (MCP jupyter) ejecutando codigo registry | parcial | wrapper Python (0085c) — el kernel hereda env vars |
|
||||
| Sub-agente (`Agent` tool) | NO transitivo | requiere registrar hooks en cada sub-agente |
|
||||
| **Funcion Go llamada por codigo de app en runtime** | **NO** | capa 7 (build-tag) — futuro |
|
||||
| **Funcion Bash sourceada por otro script en runtime** | **NO** | wrapper Bash (0085c-bash) si se sourcea el prelude |
|
||||
| **Funcion C++ compilada y llamada por app** | **NO** | capa 8 (macro `FN_CALL`) — futuro |
|
||||
| Test automatico que ejecuta funciones | NO si corre fuera de Claude | capa 4 (`fn run` instrumentado captura `go test` via fn) |
|
||||
| Service de produccion (`registry_api.service`) recibe HTTP | **NO** | sin cobertura — runtime sistema, no agente |
|
||||
| Cron / Dagu / systemd timer | **NO** | sin cobertura |
|
||||
| Funcion clonada/copiada (sin `import`) | NO runtime | capa 5 (`fn doctor copied-code`) detecta estatico |
|
||||
|
||||
**Verdad operativa:** monitorizamos al **agente** y a las **invocaciones canonicas** del registry. El runtime de cada app en produccion queda fuera. Compensar con: tests, e2e_checks (capa propia por app, issue 0068), y telemetria de invocacion via `fn run`/MCP.
|
||||
|
||||
## Implementacion por pasos (actualizado 2026-05-13)
|
||||
|
||||
| Paso | Tarea | Sub-issue | Estado |
|
||||
|---|---|---|---|
|
||||
| 1 | Migracion `call_monitor.operations.db` schema (7 tablas event-log + vista `function_stats`) | 0085a | **hecho** |
|
||||
| 2 | Hook Bash `PostToolUse` que parsea tools y escribe `calls`/`code_writes`/`violations` | 0085b | **hecho** |
|
||||
| 3a | Wrapper Python `registry_telemetry` (activable con `FN_TELEMETRY=1`) | 0085c | pending |
|
||||
| 3b | Wrapper Bash `bash/lib/telemetry_prelude.sh` | 0085c-bash | pending |
|
||||
| 3c | Interceptor en `fn run` (binario Go) | 0085d-go | **hecho** |
|
||||
| 4 | Tab "Claude Usage" en `registry_dashboard` (datasource `ops:call_monitor`, KPIs + 3 sub-tabs) | 0085d | **hecho** |
|
||||
| 5 | Top usage, huerfanas, sesiones (vistas UI) | 0085e | pending |
|
||||
| 6 | Clusterizacion heredocs + tabla `patterns` populada | 0085f | pending |
|
||||
| 7 | Reglas violation configurables YAML | 0085g | pending |
|
||||
| 8 | Pipeline `call_monitor propose` (funcion `infra.GenerateProposalsFromTelemetry` + `infra.PersistProposalDrafts`) que escribe a `registry.db.proposals` desde `function_stats` + `copied_code` + `violations`. 4 reglas MVP: copy_detected, orphan, bug, wrapper_skip. INSERT OR IGNORE con id determinista | 0085h | **hecho** |
|
||||
| 9 | `e2e_checks` propios de call_monitor (en `app.md`, ya declarados) | 0085i | parcial (declarado) |
|
||||
| 10 | Documentacion CLAUDE.md + rules (registry_calls.md) | 0085j | **hecho** |
|
||||
| 11 | `fn doctor copied-code` + tabla `copied_code` + subcomando `call_monitor copied-code` | 0085k | **hecho** |
|
||||
| 12 | Tabla `function_versions` + subcomando `call_monitor snapshot` + edit-hook con sha256 file | 0085l | **hecho** |
|
||||
| 13 (futuro) | Go build-tag `telemetry` con codegen | 0085m | futuro |
|
||||
| 14 (futuro) | C++ macro `FN_CALL` opt-in | 0085n | futuro |
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
---
|
||||
id: 0086
|
||||
title: Refactor incremental de CLAUDE.md — delegacion agresiva a fn-constructor + capability groups por tags
|
||||
status: pending
|
||||
priority: high
|
||||
created: 2026-05-13
|
||||
related: [0069, 0085]
|
||||
---
|
||||
|
||||
## Contexto
|
||||
|
||||
`.claude/CLAUDE.md` (proyecto) cubre bien el "que" (BDs, sync, MCP-first, antipatrones) pero NO documenta el bucle que multiplica capacidades de Claude:
|
||||
|
||||
```
|
||||
detectar gap -> spawn fn-constructor -> indexar -> importar -> invocar (mismo turno)
|
||||
```
|
||||
|
||||
Hoy Claude:
|
||||
- Detecta logica reutilizable y la escribe **inline** en el artefacto (o heredoc). No delega.
|
||||
- Cuando si delega, suele hacerlo **secuencial** aunque las funciones sean independientes.
|
||||
- Tras crear funciones nuevas, no las **invoca en el mismo turno** — quedan recien indexadas sin primer uso.
|
||||
- No marca con **tags de grupo** las nuevas funciones, asi que el siguiente turno (o siguiente sesion) no encuentra el cluster facilmente. Resultado: re-descubrimiento via FTS5 cada vez.
|
||||
- No hay **documentacion de capability groups** (ej. "metabase", "android-emu", "deploy", "notebook") — los tags existen sueltos pero sin pagina madre que liste el grupo, su API y ejemplos.
|
||||
|
||||
Issue 0085 ya da la base de telemetria (call_monitor + writes). Falta:
|
||||
|
||||
1. **Doctrina en CLAUDE.md** que obligue al ciclo crear-usar-tagear-documentar en el mismo turno.
|
||||
2. **Capability groups**: tags canonicos + `docs/capabilities/<group>.md` autogenerable que liste funciones, firmas, ejemplos.
|
||||
3. **Loop closure**: paralelizar fn-constructor, auto-verificar con `fn doctor`, usar las nuevas funciones antes de cerrar turno.
|
||||
|
||||
## Objetivo
|
||||
|
||||
Que Claude, en cada turno, **multiplique su capacidad util** registrando funciones nuevas y reusandolas inmediatamente — no acumular funciones huerfanas ni reescribir logica inline.
|
||||
|
||||
Tres entregables:
|
||||
|
||||
1. **Refactor incremental de `.claude/CLAUDE.md`** (no reescritura completa): mantener estructura actual, comprimir secciones referenciales hacia `docs/`, anadir bloque nuevo "Delegacion + Capability Groups" al principio.
|
||||
2. **Sistema de capability groups** basado en tags + `docs/capabilities/<group>.md` generado por `fn doctor capabilities` (nuevo subcomando) o pipeline dedicado.
|
||||
3. **Reglas duras nuevas en `.claude/rules/`** que el hook `PreToolUse`/`UserPromptSubmit` pueda verificar.
|
||||
|
||||
## Diseno
|
||||
|
||||
### Fase 1 — Bloque nuevo en CLAUDE.md (top del archivo)
|
||||
|
||||
Despues del parrafo "fn-registry" y antes de "Dos bases de datos SQLite", insertar bloque dedicado:
|
||||
|
||||
```markdown
|
||||
## Delegacion + Capability Groups (REGLA DURA)
|
||||
|
||||
Claude **multiplica capacidades** delegando creacion de funciones a `fn-constructor`
|
||||
y reusandolas inmediatamente. NO escribir logica reutilizable inline.
|
||||
|
||||
### Cuando un patron es candidato a funcion
|
||||
|
||||
- Aparece >=2 veces en la sesion actual o en heredocs recientes.
|
||||
- Firma es generica (no depende de tipos internos del artefacto).
|
||||
- Tiene 1 responsabilidad clara (CRUD, parse, transform, http call, etc.).
|
||||
|
||||
### Flujo obligatorio (mismo turno)
|
||||
|
||||
1. **Detectar gap**. Si vas a escribir 5+ lineas de logica reutilizable inline -> STOP.
|
||||
2. **Spawn `fn-constructor` inmediato** via `Agent(subagent_type="fn-constructor", ...)`.
|
||||
- Sin preguntar al usuario.
|
||||
- Si hay >1 funcion independiente -> **una sola llamada al Agent tool con N tool_use blocks paralelos**.
|
||||
3. **Tagear con grupo de capacidad**. Cada funcion nueva lleva al menos UN tag de grupo
|
||||
(ej. `metabase`, `android-emu`, `notebook`, `deploy`, `osint`). Ver `docs/capabilities/`.
|
||||
4. **`fn index`** para registrar.
|
||||
5. **Importar y USAR en el mismo turno** — no dejar funcion huerfana recien creada.
|
||||
6. **Auto-verificar**: `fn doctor uses-functions` y `fn doctor unused` para detectar drift.
|
||||
|
||||
### Anti-patrones (auditables)
|
||||
|
||||
| Anti-patron | Consecuencia | Sustituir por |
|
||||
|---|---|---|
|
||||
| Escribir helper inline en artefacto en vez de delegar | Re-invento por sesion | Spawn fn-constructor |
|
||||
| Crear N funciones serialmente cuando son independientes | Latencia x N | Multiples Agent() en mismo mensaje |
|
||||
| Crear funcion y no usarla en el turno | Funcion huerfana, calls_90d=0 desde dia 1 | Importar + invocar antes de cerrar turno |
|
||||
| Crear funcion sin tag de grupo | Imposible descubrir en bloque la siguiente sesion | Anadir tag de capability group |
|
||||
| Reescribir logica inline en heredoc que ya existe como funcion | Capitalizacion perdida | `mcp__registry__fn_search` antes de escribir |
|
||||
|
||||
### Capability groups
|
||||
|
||||
Cada grupo tiene una pagina madre en `docs/capabilities/<group>.md` con:
|
||||
- Lista de funciones (ID + firma corta).
|
||||
- 1-2 ejemplos canonicos de uso.
|
||||
- Que NO hace el grupo (fronteras).
|
||||
|
||||
Generada/actualizada por `fn doctor capabilities --update`. Grupos vigentes:
|
||||
ver `docs/capabilities/INDEX.md`.
|
||||
|
||||
Cuando Claude entra en una tarea de un dominio conocido, lee `docs/capabilities/<grupo>.md`
|
||||
ANTES de buscar funciones sueltas. Eso desbloquea el grupo entero (no funcion a funcion).
|
||||
```
|
||||
|
||||
### Fase 2 — Comprimir secciones referenciales
|
||||
|
||||
Mover de CLAUDE.md a `docs/`:
|
||||
|
||||
| Seccion actual | Destino |
|
||||
|---|---|
|
||||
| Schema rapido (functions/types/unit_tests/pc_locations + FTS5) | `docs/schema.md` |
|
||||
| CLI completa (`fn index`, `fn ops *`, `fn doctor`, `fn run`, `fn sync`, `fn proposal`) | `docs/cli.md` |
|
||||
| Anadir funciones / Anadir tipos (paso a paso) | `docs/contributing.md` |
|
||||
| Analysis (estructura + crear + usar + helpers) | `docs/analysis.md` |
|
||||
| Bucle reactivo 5 fases (detalle `ExecuteAndReact`) | `docs/reactive_loop.md` |
|
||||
|
||||
CLAUDE.md queda como **mapa** (~150-180 lineas): identidad del repo + top reglas + tres patrones canonicos + punteros al INDEX de rules y a docs/.
|
||||
|
||||
### Fase 3 — Capability groups (tags + docs autogeneradas)
|
||||
|
||||
#### 3.1 Tags canonicos de grupo
|
||||
|
||||
Reservar un namespace de tags para "capability groups". Convencion: tag plano (sin prefijo) coincide con el slug del grupo:
|
||||
|
||||
| Grupo | Tag | Cubre |
|
||||
|---|---|---|
|
||||
| metabase | `metabase` | Cliente HTTP, refresh metadata, dashboards, cards |
|
||||
| android-emu | `android-emu` | adb, emulator, input events, screenshots |
|
||||
| deploy | `deploy` | rsync, systemd, gitea webhook, vps setup |
|
||||
| notebook | `notebook` | jupyter discover/read/exec/write/kernel |
|
||||
| osint | `osint` | gliner/glirel, graph_explorer ingestion |
|
||||
| frontend-ui | `frontend-ui` | @fn_library wrappers Mantine |
|
||||
| sqlite-helpers | `sqlite-helpers` | open/migrate/wal/fts5 |
|
||||
| http-server | `http-server` | router, json response, middleware |
|
||||
| ... | ... | ... |
|
||||
|
||||
`fn doctor capabilities` (nuevo subcomando) audita tags vs grupos declarados en `docs/capabilities/INDEX.md`.
|
||||
|
||||
#### 3.2 Pagina madre por grupo
|
||||
|
||||
`docs/capabilities/<grupo>.md` autogenerable. Ejemplo `docs/capabilities/notebook.md`:
|
||||
|
||||
```markdown
|
||||
# Capability: notebook
|
||||
|
||||
Operar Jupyter Lab colaborativo desde cualquier sesion de Claude.
|
||||
|
||||
## Funciones
|
||||
|
||||
| ID | Firma | Que hace |
|
||||
|---|---|---|
|
||||
| jupyter_discover_py_notebook | `discover(host, port) -> JupyterInfo` | Lista instancias + kernels + sesiones |
|
||||
| jupyter_read_py_notebook | `read(path, cell?) -> list[Cell]` | Lee celdas / metadata |
|
||||
| jupyter_exec_py_notebook | `exec(mode, path, code, cell?)` | append/cell/kernel exec |
|
||||
| jupyter_write_py_notebook | `write(action, path, content, cell?)` | append/insert/edit/delete |
|
||||
| jupyter_kernel_py_notebook | `kernel(action, kernel_id?)` | list/start/restart/shutdown |
|
||||
|
||||
## Ejemplo canonico
|
||||
|
||||
\`\`\`bash
|
||||
PY="python/.venv/bin/python3"
|
||||
$PY python/functions/notebook/jupyter_discover.py --json
|
||||
$PY python/functions/notebook/jupyter_exec.py append notebooks/01.ipynb "df.describe()"
|
||||
\`\`\`
|
||||
|
||||
## Fronteras
|
||||
|
||||
NO incluye: ejecutar notebooks via papermill, scheduling, conversion a HTML.
|
||||
Para eso ver `docs/capabilities/scheduling.md` o crear funcion nueva.
|
||||
```
|
||||
|
||||
#### 3.3 Autogeneracion
|
||||
|
||||
Nuevo pipeline `generate_capability_doc_bash_pipelines <grupo>`:
|
||||
- Query a registry.db: `SELECT id, signature, description FROM functions WHERE tags LIKE '%"<grupo>"%'`
|
||||
- Render template Markdown.
|
||||
- Escribir a `docs/capabilities/<grupo>.md` (preservando seccion "Ejemplo canonico" y "Fronteras" si existen — son curated, no autogenerables).
|
||||
|
||||
`fn doctor capabilities`:
|
||||
- Lista grupos en `docs/capabilities/INDEX.md`.
|
||||
- Para cada grupo, cuenta funciones taggeadas vs documentadas.
|
||||
- Avisa de drift: tag sin pagina, pagina sin funciones, funcion sin grupo.
|
||||
|
||||
### Fase 4 — Reglas duras nuevas en `.claude/rules/`
|
||||
|
||||
Crear `.claude/rules/delegation.md`:
|
||||
|
||||
- "Si vas a escribir >=5 lineas de logica reutilizable inline -> STOP -> spawn fn-constructor"
|
||||
- "Funciones independientes -> Agent paralelo en mismo mensaje"
|
||||
- "Funcion creada -> tag de grupo obligatorio -> usar en el mismo turno -> `fn doctor uses-functions`"
|
||||
|
||||
Crear `.claude/rules/capability_groups.md`:
|
||||
|
||||
- Lista de grupos canonicos.
|
||||
- Como crear grupo nuevo (cuando hay >=3 funciones que comparten dominio + no encajan en grupo existente).
|
||||
- Como leer `docs/capabilities/<grupo>.md` antes de buscar funciones sueltas.
|
||||
|
||||
Actualizar `.claude/rules/INDEX.md` con las dos nuevas filas.
|
||||
|
||||
### Fase 5 — Telemetria (reutiliza issue 0085, NO tabla nueva)
|
||||
|
||||
Anadir vista a `call_monitor`:
|
||||
|
||||
```sql
|
||||
-- Funciones creadas + usadas en la misma sesion (multiplicador real)
|
||||
CREATE VIEW IF NOT EXISTS session_capability_growth AS
|
||||
SELECT
|
||||
w.session_id,
|
||||
w.function_id,
|
||||
w.created_at as first_write,
|
||||
MIN(c.ts) as first_call,
|
||||
COUNT(c.id) as calls_in_session
|
||||
FROM code_writes w
|
||||
LEFT JOIN calls c
|
||||
ON c.function_id = w.function_id
|
||||
AND c.session_id = w.session_id
|
||||
AND c.ts >= w.created_at
|
||||
WHERE w.is_creation = 1
|
||||
GROUP BY w.session_id, w.function_id;
|
||||
```
|
||||
|
||||
Dashboard tab "Capability growth": cuantas funciones creo Claude por sesion, cuantas uso, cuantas quedaron huerfanas.
|
||||
|
||||
Hook `UserPromptSubmit` extiende su contexto con:
|
||||
```
|
||||
CAPABILITY-GROWTH: created_this_session=X used=Y orphan=Z. Si orphan>0 -> usa esas funciones o documenta por que no.
|
||||
```
|
||||
|
||||
## Decisiones tomadas (2026-05-14)
|
||||
|
||||
- **Minimo por grupo**: 3-4 funciones para crear pagina madre. Tags con <3 funciones se mantienen sueltos.
|
||||
- **Ubicacion docs**: `docs/capabilities/` (no `.claude/capabilities/`). Asi `documentar`, `init` y resto de agentes los leen igual que el resto de docs/.
|
||||
- **Auto-tagging masivo**: SI. Pasada inicial sobre todas las funciones existentes (clustering por dominio + signature similarity + co-ocurrencia en `uses_functions`). Las nuevas a partir de hoy llevan tag obligatorio.
|
||||
- **Hook CAPABILITY-GROWTH**: **siempre on**. Cada `UserPromptSubmit` inyecta linea `CAPABILITY-GROWTH: created_this_session=X used=Y orphan=Z`, incluso con valores 0/0/0. Razon: presencia constante crea disciplina, el banner muerto (0/0/0) es por si solo signal — recuerda que el bucle existe.
|
||||
|
||||
## Pasos
|
||||
|
||||
1. **Inventario actual** de tags en registry.db (`SELECT tag, COUNT(*) FROM functions_tags GROUP BY tag`) — identificar candidatos a grupo (tags con >=3 funciones).
|
||||
2. **Auto-tagging masivo retroactivo**: pipeline `auto_tag_capabilities_bash_pipelines` que:
|
||||
- Clusteriza funciones por `domain` + signature embedding + co-ocurrencia en `uses_functions`.
|
||||
- Propone tag de grupo para cada cluster con >=3 funciones.
|
||||
- Aplica via `fn proposal add --kind add_tag` (revision humana en bloque) o directo con `--apply` si confianza >0.9.
|
||||
- Idempotente: re-correr no duplica tags.
|
||||
3. Crear `docs/capabilities/INDEX.md` + 1 pagina piloto (ej. `notebook.md`) a mano para fijar formato.
|
||||
4. Implementar `generate_capability_doc_bash_pipelines` + `fn doctor capabilities` (audita drift tag<->doc).
|
||||
5. Refactor incremental de `.claude/CLAUDE.md` (insertar bloque + comprimir + mover a docs/).
|
||||
6. Crear `.claude/rules/delegation.md` + `capability_groups.md` + actualizar INDEX.
|
||||
7. Anadir vista `session_capability_growth` a call_monitor.
|
||||
8. Extender hook `UserPromptSubmit` con linea CAPABILITY-GROWTH (modo a definir).
|
||||
9. Gate post-creacion: hook `PostToolUse` sobre Agent(subagent_type=fn-constructor) que verifica que la funcion creada lleva al menos un tag de grupo antes de cerrar turno.
|
||||
10. Pilotar 3 grupos: `notebook`, `metabase`, `deploy`. Verificar que Claude (siguiente sesion) entra a `docs/capabilities/metabase.md` antes de buscar `metabase_*` sueltas.
|
||||
|
||||
## Criterio de exito
|
||||
|
||||
- CLAUDE.md baja a <=200 lineas, sin perder informacion (movida a docs/).
|
||||
- 5+ capability groups documentados con pagina madre.
|
||||
- En una sesion piloto, Claude crea >=2 funciones nuevas y las invoca en el mismo turno (vista `session_capability_growth` lo confirma).
|
||||
- `fn doctor capabilities` corre sin warnings tras la migracion inicial.
|
||||
- Reduccion medible de patrones inline repetidos (vista `patterns` del call_monitor) tras 1 semana.
|
||||
|
||||
## Riesgos
|
||||
|
||||
- **Sobre-fragmentar en grupos pequenos**: cada grupo con 2 funciones genera ruido. Minimo 3-4 funciones por grupo para crear pagina madre.
|
||||
- **Tags duplicados / drift**: `metabase` vs `mb` vs `metabase-client`. `fn doctor capabilities` debe avisar y proponer normalizacion.
|
||||
- **Funciones nuevas huerfanas pese a la regla**: si el "usar en mismo turno" es solo aspiracional, la regla muere. La vista de telemetria + hook de UserPromptSubmit son el gate real.
|
||||
- **Refactor de CLAUDE.md rompe punteros existentes**: revisar que `.claude/commands/`, `subagentes.md`, etc. no referencien secciones movidas. Dejar redirects breves.
|
||||
|
||||
## Notas
|
||||
|
||||
- Issue 0085 ya provee `call_monitor` + tablas `calls`, `code_writes`, `patterns`, `violations`. Esta issue NO crea tablas nuevas, solo vistas + reglas + docs.
|
||||
- El sistema de capability groups es analogo a "skills" de Claude Code pero a nivel de funciones del registry — un grupo desbloquea un conjunto de capacidades aprendido del codigo ya existente, no externo.
|
||||
+16
-1
@@ -5,10 +5,25 @@
|
||||
| Campo | Valor |
|
||||
|-------|-------|
|
||||
| **ID** | 0062 |
|
||||
| **Estado** | pendiente |
|
||||
| **Estado** | resuelto 2026-05-13 |
|
||||
| **Prioridad** | baja |
|
||||
| **Tipo** | research + policy — `.claude/rules/`, `docs/` |
|
||||
|
||||
## Resolucion (2026-05-13)
|
||||
|
||||
Decision: opcion **2 (deprecar via tag)** — NO se borra, NO se mantiene en limbo. Se marca con `pendiente-usar` para hacer visible "disponible, sin consumidor todavia".
|
||||
|
||||
Implementacion: pipeline `tag_unused_pending_py_pipelines` (Python). Cruza `fn doctor unused --json` con `registry.db.functions.file_path` y modifica el frontmatter YAML del `.md` de cada funcion. Idempotente — re-ejecutar:
|
||||
- Anade el tag a funciones nuevas en la lista de unused.
|
||||
- Retira el tag de funciones que han adquirido un consumer real (mantener coherencia).
|
||||
|
||||
Comando: `python/.venv/bin/python3 python/functions/pipelines/tag_unused_pending.py && ./fn index`.
|
||||
|
||||
Filtro: `mcp__registry__fn_search 'tags:"pendiente-usar"'` o
|
||||
`sqlite3 registry.db "SELECT id FROM functions WHERE tags LIKE '%pendiente-usar%'"`.
|
||||
|
||||
Estado actual: **631 funciones** marcadas `pendiente-usar` (de 1249 totales). El tag persiste mientras `fn doctor unused` las liste; desaparece cuando alguna app/funcion las declare en `uses_functions`.
|
||||
|
||||
## Dependencias
|
||||
|
||||
- `find_unused_functions_go_infra` (existe, lista 704 funciones sin consumidores al 2026-05-07).
|
||||
Reference in New Issue
Block a user