Arquitectura de Inteligencia Evolutiva

Fases 21.5–40.12 — Sistema de skills auto-mejorante para Arc OS. Estado: Listo para producción. Sage Worker (mejora autónoma) + benchmarks (pruebas A/B) + Marketplace Discovery + búsqueda semántica NotebookLM.


Resumen

Arc OS opera una arquitectura de bots federados donde los child bots actúan como proxy de mensajes de usuario hacia Claude CLI. La Fase 21.1 introdujo el seguimiento de calidad (logs de ejecución, botones de feedback). La Fase 21.5 cierra el ciclo: el sistema ahora valida su propia salida, recuerda las correcciones, enfoca el contexto y propone mejoras de forma autónoma.

Siete pilares forman la capa de inteligencia:

Mensaje del Usuario
    │
    ├─► Context Router ──► SKILLS_HINT (top 5 skills relevantes)
    │
    ├─► Learnings ──► bloque LEARNINGS (correcciones pasadas)
    │
    ▼
buildGsdPrompt() ──► Claude CLI ──► Respuesta
                                        │
                                        ├─► Binary Evals ──► Notas de advertencia
                                        │
                                        └─► Quality Tracker ──► Métricas
                                                                   │
                                                          Nightly Improve ──► Aprobación CEO

Pilar 1: Motor de Binary Evals

Módulo: shared/evals.ts Archivos de spec: skills/<name>/<name>.evals.json

Qué hace

Cada skill puede declarar reglas de validación en un archivo JSON. Tras generar una respuesta, el motor de evals la comprueba contra todas las reglas aplicables. Los fallos producen notas de advertencia no bloqueantes que se añaden al mensaje de Telegram.

Tipos de reglas

Tipo Verifica Ejemplo de uso
string_contains La respuesta incluye una cadena literal Verificar que la salida JSON tiene el campo "verdict"
string_not_contains La respuesta NO incluye una cadena Bloquear --force en instrucciones de git
regex_match La respuesta coincide con un patrón regex Asegurar que la auditoría del sistema menciona disk/RAM/CPU
regex_not_match La respuesta NO coincide con un regex Prevenir patrones de filtración de credenciales
max_length Longitud de la respuesta <= N caracteres Mantener la salida concisa
min_length Longitud de la respuesta >= N caracteres Garantizar respuestas sustanciales

Niveles de severidad

Cómo afectan las evals a las métricas

Los resultados de las evals se registran junto a los eventos de calidad. Cuando el loop de mejora nocturna detecta un skill con baja tasa de éxito, los patrones de fallo de las evals ayudan a identificar la causa raíz sin necesidad de análisis con IA.

Ejemplo de archivo de evals

{
  "version": 1,
  "skill": "code-review",
  "rules": [
    { "id": "cr-001", "name": "Must return JSON verdict", "type": "string_contains", "value": "\"verdict\"", "severity": "warning" },
    { "id": "cr-002", "name": "No console.log debug", "type": "regex_not_match", "pattern": "console\\.log\\(", "severity": "warning" }
  ]
}

Principio de diseño

Inspirado en el framework de evals de Anthropic's Skill Creator: aserciones declarativas sobre salidas, sin IA en el bucle de validación. El pass/fail binario elimina la ambigüedad.


Pilar 2: Context Router

Módulo: shared/context-router.ts Fuente de datos: skills/_registry.json (campos triggers + keywords)

Qué hace

Antes de construir el prompt GSD, el router puntúa cada skill registrado contra el mensaje del usuario. Los 5 mejores coincidentes se inyectan como bloque SKILLS_HINT, orientando a Claude hacia las capacidades relevantes.

Algoritmo de puntuación

Para cada skill:
  puntuación = 0
  para cada trigger:   si el mensaje contiene trigger  → puntuación += 2
  para cada keyword:   si el mensaje contiene keyword  → puntuación += 1

Ordenar por puntuación DESC → tomar los top 5

Las coincidencias de triggers puntúan más porque los triggers son señales de invocación explícitas (ej. "review", "deploy"). Las keywords ofrecen coincidencia semántica más amplia (ej. "OWASP", "Docker").

Por qué es consultivo, no filtrante

El router es solo consultivo. Claude CLI sigue cargando todos los skills via CLAUDE.md. Razones:

  1. Seguridad: El filtrado duro via --allowedTools o mutaciones de symlinks puede romper la sesión si el router clasifica mal un mensaje.
  2. Estabilidad: Sin mutaciones del sistema de archivos en un proceso en ejecución.
  3. Degradación elegante: Si el router falla, Claude sigue teniendo acceso completo a los skills.

Economía de la ventana de contexto

Sin el router, los 23 skills compiten por atención en el prompt. El bloque SKILLS_HINT le dice a Claude "enfócate en estos 3-5" — reduciendo la activación de skills irrelevantes y manteniendo las respuestas centradas. Es priming de contexto, no reducción de contexto.


Pilar 3: Reflect Loop (Learnings Persistentes)

Módulo: shared/learnings.ts Almacenamiento: {PROJECT_CWD}/learnings.md

Qué hace

Cuando el CEO presiona "Fix It" o "👎", el sistema captura una regla de aprendizaje y la persiste en un archivo markdown. En cada mensaje posterior, los learnings acumulados se inyectan en el prompt GSD como bloque LEARNINGS.

Pipeline Evento → Aprendizaje

CEO presiona 🛠️ Fix It
    │
    ├─► addLearning(source: "fixit", rule: "Fix requested for: <context>")
    │
    └─► projectLearnings recargados desde disco

CEO presiona 👎
    │
    ├─► addLearning(source: "negative", rule: "Negative feedback on: <context>")
    │
    └─► qualityTracker.logFeedback(positive: false)

Formato del archivo de learnings

# Learnings

> Auto-generado. Inyectado en el prompt GSD al inicio de la sesión.

## Rules

- [2026-04-03T14:22:00Z] [fixit] Always use t-call for translations in Odoo QWeb
- [2026-04-03T15:10:00Z] [negative] Avoid sudo in deployment scripts

Inyección en el prompt

La función formatForPrompt() toma los learnings más recientes (hasta 2000 caracteres), los invierte (más nuevo primero) y los formatea como:

LEARNINGS (past corrections — follow these rules):
- Avoid sudo in deployment scripts
- Always use t-call for translations in Odoo QWeb

Principio de diseño

Inspirado en el Claude Reflect System: las correcciones no solo arreglan la respuesta actual — se convierten en reglas persistentes que previenen la regresión. El sistema construye "memoria inmune" con el tiempo.


Pilar 4: Karpathy Loop (Auto-Mejora Nocturna)

Módulo: scripts/nightly-improve.ts Horario: Diariamente a las 03:00 UTC via cron Estado: mcp-server/state/improvement-proposals.json

Qué hace

  1. Lee config/bot_registry.json para enumerar todos los child bots
  2. Para cada hijo: lee quality-metrics.json de su directorio de estado
  3. Llama a findUnderperformingSkills() — filtra skills donde:
    • applied_count >= 3 (tamaño mínimo de muestra)
    • Y success_rate < 80% O feedback_negative > feedback_positive
  4. Lee learnings.md para patrones de corrección relacionados
  5. Genera propuestas basadas en plantillas (deterministas, sin IA involucrada)
  6. Envía informe de resumen al CEO via Telegram
  7. Envía tarjetas de propuesta individuales con botones inline de Aprobar/Rechazar

Flujo de aprobación del CEO

Script nocturno ──► Telegram: Tarjeta de Propuesta
                        │
           ┌────────────┼────────────┐
           ▼                         ▼
    ✅ Aprobar                  ❌ Rechazar
           │                         │
    Backup skill.md              Marcar rechazado
    como skill.v1.md             en proposals.json
    (máx. 3 versiones)
           │
    Marcar aprobado
    en proposals.json

Versionado de skills

Al aprobar, el master bot crea copias de seguridad con versión:

Principio de diseño

Inspirado en el AutoResearch Loop de Karpathy: modificar → verificar → mantener/descartar → repetir. La diferencia crítica: las propuestas son basadas en plantillas y requieren aprobación humana. Sin reescritura autónoma de skills — el CEO sigue siendo la autoridad final.


Fase 36+ — Capa Semántica NotebookLM

La Fase 36.3 añadió un quinto canal de feedback: Google NotebookLM como memoria semántica a largo plazo.

Eventos CRM (cierre de issue, actualización de wiki)
    │
    └─► POST fire-and-forget al bridge /sync
                                    │
                                    ▼
                          NotebookLM Bridge (:19213)
                            ├── SyncWorker (asyncio.Queue, 3 reintentos)
                            └── notebooklm-py → Google NotebookLM
                                    │
                                    ▼
                          Notebook actualizado con nueva fuente
                                    │
              ┌─────────────────────┤
              ▼                     ▼
    tool ask_notebooklm      Neural Skill Generator
    (chat Cloud PM, 15s)     (POST /skills/generate, 30s)
              │                     │
              ▼                     ▼
    Respuesta semántica en   Skill Markdown para
    contexto del proyecto    revisión + guardar (Fase 36.6)

La Fase 36.6 añadió el Neural Skill Generator: el CEO define un objetivo de extracción, el bridge consulta NotebookLM con un prompt estructurado de AI Architect, y devuelve un Rulebook Markdown estricto que puede guardarse como skill.

La Fase 36.7 expuso los notebooks en la UI del sidebar (punto de estado verde/rojo, contador de fuentes, enlace externo).


Pilar 6: Sage Worker (Fase 40.11c)

Módulo: shared/sage.ts Disparador: POST /api/crm/sage/analyze o scripts/nightly-improve.ts

Qué hace

Sage es un motor autónomo de mejora de skills. Analiza los skills usando métricas de calidad + feedback del usuario (learnings), luego genera contenido mejorado concreto via API de Anthropic (modelo Haiku por eficiencia de costos). Los resultados se almacenan como skill_update_requests (PRs) en la base de datos para revisión del CEO.

Flujo

Solicitud de Análisis Sage
    │
    ├─► Cargar skills activos desde DB (skillQueries)
    ├─► Cruzar referencias con métricas de calidad (readMetrics)
    ├─► Priorizar los de bajo rendimiento (findUnderperformingSkills)
    │
    ▼ Para cada skill objetivo (máx. 5):
    ├─► Cargar contenido del skill + fork (si es de ámbito de proyecto)
    ├─► Cargar métricas de calidad (tasa de éxito, conteos de feedback)
    ├─► Cargar learnings relacionados (correcciones del usuario)
    ├─► Omitir si ya existe un PR pendiente
    ├─► Construir prompt (contenido + métricas + learnings)
    ├─► Llamar a la API de Anthropic (Haiku, timeout 30s)
    ├─► Parsear respuesta (NO_CHANGE = omitir)
    ├─► Insertar skill_update_request (proposed_by: 'sage')
    └─► Ejecutar benchmark automático (Pilar 7) en nuevo PR

Por qué un endpoint CRM y no un worker

Sage necesita acceso directo a la DB (skillQueries, benchmarkQueries) — los workers corren como subprocesos sin conexión a DB. Sage no recibe mensajes del usuario; es un analizador en segundo plano cuya salida = filas de DB, no texto de chat.


Pilar 7: Aprobaciones Basadas en Datos — Benchmarks (Fase 40.11d)

Módulo: shared/sage.ts (runBenchmark()) DB: shared/migrations/005_skill_benchmarks.ts API: POST /api/crm/sage/benchmark, GET /api/crm/skill-updates/:id/benchmarks

Qué hace

Antes de que el CEO apruebe un PR de Sage, el sistema demuestra que el cambio funciona. Genera 3 escenarios de prueba, ejecuta tanto el contenido antiguo como el nuevo del skill a través de ellos (prueba A/B ciega), y usa un juez LLM para determinar cuál es mejor. Puntuación combinada: eval_rules deterministas (60%) + juez LLM (40%).

Flujo del Benchmark

Ejecutar Benchmark (requestId)
    │
    ├─► Cargar skill_update_request (current_content + proposed_content)
    ├─► Cargar eval_rules desde DB
    │
    ▼ Generar 3 escenarios de prueba (Haiku)
    │
    ▼ Para cada escenario:
    ├─► Ejecutar contenido antiguo del skill → old_output
    ├─► Ejecutar contenido nuevo del skill → new_output
    ├─► Aleatorizar orden A/B (prevención de sesgo por posición)
    ├─► Juez LLM puntúa ambos (1-10) + razón
    ├─► Puntuación determinista de eval_rules (si disponible)
    ├─► Puntuación combinada: evals 60% + LLM 40%
    └─► Guardar en tabla skill_benchmarks
    │
    ▼ Actualizar metadatos del PR
    ├─► veredicto: PASSED / FAILED / TIE
    ├─► improvement_pct: ((new_avg - old_avg) / old_avg * 100)
    └─► BenchmarkBadge visible en el header del PR en el frontend

Frontend: Modo Battle

SkillEvolution.jsx → componente BenchmarkReport:


Mapa de Archivos

shared/
├── evals.ts              ← Pilar 1: Motor de Binary Evals
├── context-router.ts     ← Pilar 2: Context Router (routeContextFromDb)
├── learnings.ts          ← Pilar 3: Reflect Loop
├── quality.ts            ← Extendido: findUnderperformingSkills()
├── sage.ts               ← Pilares 6+7: Sage Worker + Benchmarks (runSageAnalysis, runBenchmark)
├── db.ts                 ← SQLite SSOT: skillQueries, benchmarkQueries, chatQueries
├── migrations/
│   ├── 004_skill_system.ts     ← skills_global, forks, evolution_logs, update_requests
│   └── 005_skill_benchmarks.ts ← skill_benchmarks (resultados pruebas A/B)
├── crm-routes.ts         ← CRM API: 55+ endpoints (Sage + benchmarks + evolución de skills)
└── ui_templates.ts       ← Extendido: improvementProposal()

scripts/
├── nightly-improve.ts    ← Pilar 4: Karpathy Loop (ahora usa Sage + DB)
└── migrate-skills-to-db.ts ← Migración nuclear: archivos → DB

clients/
├── arc-cli.ts            ← ARC CLI (Fase 31.5): login, start, projects
└── knowledge-mcp.ts      ← Obsoleto (Fase 38 → subcomandos CLI)

services/
└── notebooklm-bridge/    ← Pilar 5: búsqueda semántica NotebookLM (Fase 36.3)
    ├── main.py           ← FastAPI (:19213), /query, /sync, /notebooks/init, /health
    └── seed_knowledge.py ← Importación masiva de conocimiento existente

frontend/src/crm/pages/
└── SkillEvolution.jsx    ← UI de dos paneles: explorador + detalle (Content/Evals/Evolution/PRs)
                             BenchmarkBadge, BenchmarkReport, Modo Battle, botón de análisis Sage

child-bot/bot.ts          ← Integración: arranque + prompt GSD + notas de evals + /learnings
child-bot/ingest-watcher.ts ← Auto-ingest: fs.watch en raw/ → CRM inbox (Fase 28)
master-bot/bot.ts         ← Integración: trigger cron nocturno de Sage