Arc OS — Arquitectura

Resumen

Arc OS reemplaza 11.321 líneas de infraestructura personalizada en Python/JS con las herramientas nativas de Claude Code. El agente de IA ES el backend.

Arquitectura del Sistema (Fase 52.1)

graph TB
    User[👤 Usuario Browser :18888]
    TG[📱 Telegram]
    Local[💻 IDE Local]

    subgraph "Edge"
      Nginx[Nginx :18888<br/>basic-auth + deny-list]
      FE[React CRM + Phaser<br/>contenedor frontend]
    end

    subgraph "Master Bot Bun :19210 — solo 127.0.0.1"
      ApiSrv[api-server.ts<br/>196 LOC]
      Routes[master-bot/routes/<br/>auth · internal · cli · websocket]
      Router[shared/routes/router.ts<br/>373 LOC dispatcher]

      subgraph "19 Módulos de Dominio — Fase 48"
        D1[auth · projects · workers]
        D2[skills · sage · chat]
        D3[wiki · files · onboarding]
        D4[billing · invites · analytics]
        D5[+ 7 más]
      end
    end

    subgraph "Bots Federados"
      Master[Master Bot<br/>orquestrador]
      Child[Child Bots<br/>por proyecto]
      Claude[claude -p CLI]
    end

    subgraph "Capa de Inteligencia"
      Eval[Binary Evals]
      Ctx[Context Router top-5]
      Learn[Inyección de Learnings]
      Karp[Karpathy Loop nocturno]
    end

    NB[NotebookLM Bridge<br/>FastAPI :19213 localhost]
    Google[(Google NotebookLM)]

    DB[(SQLite WAL<br/>21+ tablas<br/>migraciones 001-021)]
    Vault[(AES-256-GCM Vault<br/>config/vault.json)]
    Bridge[Local Bridge CLI<br/>relay WebSocket]

    User -->|HTTPS| Nginx
    Nginx --> FE
    Nginx -->|/api/crm/*| ApiSrv
    Nginx -->|/api/sse/*| ApiSrv
    Nginx -->|/ws/terminal| ApiSrv
    ApiSrv --> Routes
    Routes --> Router
    Router --> D1 & D2 & D3 & D4 & D5

    TG --> Master
    TG --> Child
    Master -.lanza via tmux.-> Child
    Child --> Claude
    Claude --> Eval & Ctx & Learn

    Router -.consulta.-> NB
    Child -.auto-sync.-> NB
    NB --> Google

    Router --> DB
    Router --> Vault
    Child --> Vault

    Local --> Bridge
    Bridge -.ws relay.-> ApiSrv
    Karp -.nocturno.-> DB

Datos clave:

LEGACY (v1):
Usuario → Bot Telegram (Python 111KB) → HybridEngine → command_queue.json
       → bridge_processor.sh → Claude → command_responses.json
       → FastAPI EventBus → WebSocket → UI Phaser

V2 (NATIVE-FIRST):
Usuario → Canal Telegram Oficial → Sesión Claude Code
       ↓                                ↓
       reply/edit_message          Agent Teams (TaskCreate/SendMessage)
                                        ↓
                                   Escribe estado → archivos JSON
                                        ↓
                                   Arc OS Bridge MCP → HTTP/SSE → UI Phaser

Reducción: 11.321 líneas → ~3.700 líneas (67% menos código)

Componentes

1. Sesión Claude Code (El Cerebro)

La sesión Claude Code reemplaza:

Toda la orquestación ocurre nativamente a través de Agent Teams.

2. Arc OS Bridge MCP Server (Adaptador de Estado)

Servidor MCP TypeScript (Bun) que conecta el estado de Claude Code con el frontend.

MCP Tools (lado Claude Code):

Tool Dirección Descripción
get_office_state lectura Lee state/office-state.json
update_agent_state escritura Actualiza posición, estado, burbuja del agente
get_tasks lectura Lee archivos de tareas de Agent Teams
get_knowledge lectura Lee índice de conocimiento

HTTP API (lado Frontend):

Endpoint Método Descripción
/api/state GET Estado completo de la oficina
/api/tasks GET Lista de tareas
/api/knowledge GET Índice de conocimiento
/api/events GET Stream SSE

3. Frontend Phaser (Capa Visual)

Phaser 3.80 + Vite. Se conecta al servidor MCP vía HTTP/SSE.

Diferencia clave respecto a v1: sin WebSocket — reemplazado por SSE del servidor MCP. Sin interfaz de entrada de comandos — Telegram es la interfaz de control.

4. Interfaz de Comandos Telegram (Capa UI Táctica — Fase 21.0)

Telegram es el panel de control principal de todo Arc OS. Dos niveles de bots:

Master Bot (@citadel_ceo_bot):

Child Bots (@cv2_pt_bot, etc.):

Integración CRM (desarrollo):

CRM_BASE_URL = http://62.171.128.248:18888  (dev)
               https://crm.citadel.v2       (prod futuro)

Todos los layouts de teclado definidos en shared/ui_templates.ts — única fuente para cambios de UI.

Protocolo de datos de callback: acción:objetivo (máx. 64 bytes)

Flujo de Datos

1. Usuario envía "/status" via Telegram
2. La sesión Claude Code lo recibe via Canal Telegram
3. Rick lee state/office-state.json + TaskList()
4. Rick responde via Telegram (edit_message para actualizaciones en vivo)
5. Rick llama a update_agent_state() via MCP
6. El servidor MCP escribe en state/office-state.json
7. El file watcher detecta el cambio → envía evento SSE
8. El frontend recibe SSE → actualiza sprites de agentes

Gestión de Estado

Todo el estado vive en archivos JSON bajo state/:

Archivo Esquema Actualizado por Leído por
office-state.json Posiciones, estados, burbujas de agentes Claude (via MCP) Frontend (via HTTP)
knowledge.json Metadatos de archivos indexados Agente Squanchy Frontend, Beth
reports/*.json Salida de análisis Beth, Summer Frontend

Las tareas de Agent Teams son gestionadas nativamente por Claude Code en ~/.claude/tasks/citadel-v2/.

Agentes (6)

Agente Rol Modelo Activación
Rick CEO/Orquestrador opus-4.6 Siempre activo (líder del equipo)
Morty SRE/Monitoreo haiku-4.5 Health checks, cron
Summer Memoria/Revisión sonnet-4.5 Code review, seguridad
Jerry Mantenimiento haiku-4.5 Limpieza, docs
Squanchy Archivero haiku-4.5 Indexación de archivos
Beth Analista sonnet-4.5 Investigación, análisis

Supply Chain

CEO → Rick (descomponer) → Agent Team (ejecutar)
                        → Cross-Review (Summer valida)
                        → Rick (sintetizar)
                        → CEO (resultado final)

Aplicado a través de:

Stack Tecnológico

Capa v1 v2
Backend FastAPI + Python 3.12 Sesión Claude Code
Base de datos SQLite (8 tablas) Archivos JSON + Agent Teams
Mensajería WebSocket + EventBus Agent Teams SendMessage
Estado SQLite + JSON bridge Archivos JSON (state/)
Frontend Phaser 3.86 + WebSocket Phaser 3.80 + SSE
Telegram Bot personalizado (111KB) Plugin de Canal Oficial
Bridge bash + jq (19,6KB) Eliminado
MCP Ninguno Arc OS Bridge (TypeScript)
Deploy Docker Compose Docker Compose

Lifecycle Hooks

Los hooks de Claude Code (~/.claude/settings.json) sincronizan automáticamente el estado del agente:

Evento SubagentStop → subagent-stop.sh → office-state.json (agent=idle)
                                              ↓
                                   StateManager (fs.watch) → SSE → UI Phaser

Evento Stop → session-end.sh → latest_wrapup.txt + all agents=idle

Scripts: scripts/citadel-hooks/subagent-stop.sh, scripts/citadel-hooks/session-end.sh

Campos clave: subagentName (SubagentStop), stopReason (Stop), cwd (ambos).

NotebookLM Bridge (Fase 36.3)

Búsqueda semántica real via Google NotebookLM, reemplazando las subidas manuales de archivos:

Cloud PM Chat → Bun Master Bot (:19210)
                    │
         executeAskNotebooklm()
                    │
         HTTP → FastAPI Bridge (:19213, solo localhost)
                    │
              notebooklm-py async client
                    │
              Google NotebookLM (búsqueda semántica gratuita)

         Fallback: búsqueda local por palabras clave (código existente)

La exportación basada en archivos heredada (/citadel-wrapup, /citadel-recall) sigue funcionando como fallback.

Política de Enrutamiento de Datos y Tareas

Sistema de tres niveles. Cada nivel tiene un propósito estricto. Mezclar niveles = caos.

┌─────────────────────────────────────────────────────────────────┐
│  NIVEL 1: Memoria de Trabajo (Caliente)                         │
│  office-state.json + state/tasks/                               │
│  CLI: /citadel-task, /citadel-status                            │
│                                                                 │
│  Tareas diarias de agentes. Vive durante la sesión. Muere tras  │
│  ella. Tarea completada → /citadel-wrapup → Nivel 3.           │
├─────────────────────────────────────────────────────────────────┤
│  NIVEL 2: Backlog Estratégico (Tibio)                           │
│  GitHub Issues (repos Claude-CEO + citadel-v2)                  │
│                                                                 │
│  Solo epics: Fase 20, Fase 21, bugs globales.                   │
│  Sin tareas diarias. Sin issues de "corregir typo".             │
│  Un Issue = una iniciativa de varias semanas o defecto crítico. │
├─────────────────────────────────────────────────────────────────┤
│  NIVEL 3: Memoria a Largo Plazo (Frío)                          │
│  docs/library-export/ → Google Drive → NotebookLM              │
│  CLI: /citadel-wrapup, /citadel-recall                          │
│                                                                 │
│  Enciclopedia. Resultados de sesiones, decisiones               │
│  arquitectónicas, RAG. Solo lectura. Sin tareas activas.        │
└─────────────────────────────────────────────────────────────────┘

Reglas de Enrutamiento

Tipo de Dato Nivel Ejemplo
"Arreglar script de deploy" 1 — Memoria de Trabajo /citadel-task "Arreglar script de deploy"
"Fase 20: SaaS Multi-Tenant" 2 — GitHub Issues gh issue create --title "Fase 20: ..."
"Resumen de sesión: hooks implementados" 3 — Library /citadel-wrapup → NotebookLM
"Decisión arquitectónica: elegimos SSE sobre WS" 3 — Library Archivado en wrapup tras sesión
"Bug: SSE se cae en VPS" 2 — GitHub Issues Solo si es cross-sesión o bloqueante
"Rick está trabajando en hooks" 1 — Memoria de Trabajo Estado del agente en office-state.json

Ciclo de Vida

CEO da tarea → Nivel 1 (agente trabaja en ella)
                     ↓ completada
                 /citadel-wrapup → Nivel 3 (archivada)
                     ↓ si es estratégica
                 gh issue create → Nivel 2 (rastreada a largo plazo)

Antipatrones (NO HACER)

Infraestructura (Fase 20.5)

Logging Estructurado (shared/logger.ts)

Formato JSONL, salida dual (archivo + consola), división diaria de archivos por categoría.

/var/log/citadel/
├── master/
│   ├── system-2026-04-02.log   ← ciclo de vida, config, health
│   ├── dialog-2026-04-02.log   ← (no usado por master)
│   └── error-2026-04-02.log    ← errores (también en system)
├── citadel-v2/
│   ├── system-2026-04-02.log
│   ├── dialog-2026-04-02.log   ← mensajes usuario ↔ Claude
│   └── error-2026-04-02.log
└── <nombre-proyecto>/          ← por proyecto incorporado

Rotación de logs: config/logrotate-citadel.conf/etc/logrotate.d/citadel (diario, retención 7 días).

Secrets Vault (shared/vault.ts)

Almacenamiento cifrado AES-256-GCM para tokens de bots.

Fuente de clave: env SECRET_ENCRYPTION_KEY → archivo config/vault-key → autogenerado
Almacenamiento:  config/vault.json (escrituras atómicas: tmp + mv)
Caché:           En memoria tras initVault() — sin I/O de disco por getSecret()
Fallback:        getSecret("FOO") → caché vault → process.env.FOO
Nomenclatura:    child:<nombre-proyecto>:token

El token del Master permanece en .env (el vault carga dentro del proceso master).

Watchdog Auto-Curativo (master-bot/watchdog.ts)

Monitor en segundo plano para child bots. Corre dentro del proceso del master bot.

Cada 30s: health check HTTP → /api/child/health (timeout 5s)
  Saludable → reiniciar contador de fallos
  No saludable → incrementar fallos
  3+ fallos + backoff transcurrido → auto-reinicio (matar tmux → iniciar nuevo con token vault)
  Backoff: 30s → 1m → 5m → 15m → 60m (tope)
  10 fallos consecutivos → desactivar permanentemente + notificar al CEO

Estado persistido en config/watchdog-state.json (sobrevive reinicios del master). Notificaciones al CEO via Telegram: primer reinicio, fallo de reinicio, desactivación permanente. Comando /watchdog: estado en tiempo real de todos los hijos.

Protocolo de Eliminación de Proyectos (Fases 20.4 + 21.0)

/remove_project <name> → triple confirmación → limpieza completa:

1. Matar sesión tmux: child-<name>
2. Matar procesos fantasma: ps aux | grep child-<name> → kill -9 todos los PIDs
3. Verificar puerto: ss -tlnp | grep :<port> → forzar liberación si ocupado
4. Eliminar de bot_registry.json + recarga en memoria
5. Eliminar /opt/repos/<name>/ (seguridad: la ruta debe estar bajo /opt/repos/, mín. 3 segmentos)
6. Eliminar /var/log/citadel/<name>/

Nombres protegidos: citadel-v2, citadel, claude-ceo, claude-CEO — eliminación bloqueada.

Problema de procesos fantasma (lección aprendida): tras matar tmux, procesos bun huérfanos pueden ocupar puertos. El kill masivo + verificación de puerto previene "bots fantasma" que responden a health checks pero ignoran Telegram.

Gestión de Skills (Fase 21.0)

Los child bots cargan skills de dos fuentes al arrancar, con deduplicación via Set:

Fuente 1: MANIFEST.md (JSON)
  → manifest.skills[]          (coincidentes durante el onboarding)
  → manifest.library_skills[]  (archivos .md de library coincidentes)

Fuente 2: directorio skills/
  → archivos *.md → nombre de archivo sin extensión

Merge: Set<string>(manifest.skills + manifest.library_skills + skills/*.md)

Ejemplo (proyecto PT): 5 de manifest + 7 de skills/ = 12 skills únicos.

Los skills aparecen como:

Seguridad (Fase 42 — Auditoría Sentinel 2026-04-23, 4 pasadas, 13 parches)

Resumen completo: SECURITY.md. Informe de auditoría: security/audit-2026-04-23.md.

Secretos y almacenamiento:

Auth:

Multi-tenancy (Fase 42):

Perímetro de red:

Seguridad de entradas y rutas:

Cobertura de regresión: scripts/vps-sync.sh ejecuta 7+ smoke tests post-deploy tras cada deploy (bind loopback, path traversal, validación de chat/save, canary de proxy, SSE ?token=, validación fail-closed, bloqueo SSRF si CEO_TOKEN configurado).

Módulos del Master Bot (Fase 25 — Resolución de DEBT-1)

El master bot está organizado en módulos enfocados:

master-bot/
├── bot.ts               ← Bootstrap: vault, registry, context, todo conectado (106 líneas)
├── context.ts           ← Tipo MasterContext + interfaces de dominio
├── api-server.ts        ← Bun.serve() — HTTP, WebSocket, SSE, rutas CRM
├── tg-api.ts            ← Wrapper de Telegram Bot API (sendMessage, getUpdates, etc.)
├── child-state.ts       ← Lee estado del child bot, health, heartbeat, tmux, bridge
├── telegram-commands.ts ← Todos los manejadores /comando, manejador de callback query, router de mensajes
├── telegram.ts          ← Loop de polling slim + re-exports para compatibilidad hacia atrás
├── watchdog.ts          ← Monitor auto-curativo del child bot
└── onboarding.ts        ← Asistente interactivo de creación de proyectos

bot.ts importa solo desde telegram.ts y api-server.ts. Todos los demás módulos son detalles de implementación internos.

Bridge CLI (Fase 25 — Local Gateway)

bridge/
├── bin/citadel-bridge.ts    ← Entrada CLI (commander.js): connect, pull, push, status, disconnect
├── src/
│   ├── auth.ts              ← Validación JWT contra CRM
│   ├── config.ts            ← Persistencia ~/.citadel/bridge.json
│   ├── inject.ts            ← Marcadores <!-- CITADEL:START/END --> en CLAUDE.md
│   ├── sync.ts              ← Pull skills-bundle + learnings, push learnings locales
│   └── heartbeat.ts         ← Reportador de actividad de sesión
├── package.json
└── tsconfig.json

Endpoints de CRM API (50+ en total)

CRM Principal (Fase 22)

Endpoint Método Propósito
/api/master/health GET Health del master bot (público)
/api/crm/projects GET Listar todos los proyectos + health en vivo
/api/crm/projects/:name GET Detalle del proyecto
/api/crm/projects/:name/logs GET Tail de logs JSONL
/api/crm/projects/:name/files GET Listado de directorio seguro
/api/crm/projects/:name/files/upload POST Subir archivos
/api/crm/projects/:name/files/mkdir POST Crear carpeta
/api/crm/projects/:name/files/create POST Crear archivo
/api/crm/projects/:name/files/delete DELETE Eliminar archivo/carpeta
/api/crm/projects/:name/files/clone POST Clonar repo git
/api/crm/projects/:name/files/read GET Leer contenido de archivo
/api/crm/projects/:name/wiki/tree GET Listar archivos .md de wiki
/api/crm/projects/:name/wiki/file GET Leer contenido de archivo wiki
/api/crm/projects/:name/skills GET Skills instalados
/api/crm/projects/:name/metrics GET Timeseries de calidad
/api/crm/projects/:name/restart POST Reiniciar child bot
/api/crm/projects/:name/specs GET Listar specs
/api/crm/projects/:name/specs/:id/approve POST Aprobar spec
/api/crm/projects/:name/specs/:id/reject POST Rechazar spec
/api/crm/projects/:name/active-role GET/POST Rol del agente
/api/crm/projects/:name/message POST Encolar mensaje al worker
/api/crm/projects/:name/workers GET/POST CRUD del registro de workers
/api/crm/projects/:name/workers/:id PUT/DELETE Actualizar/eliminar worker
/api/crm/projects/:name/workers/generate-prompt POST Generar prompt de sistema con IA
/api/crm/projects/:name/skills-bundle GET Skills + evals para bridge
/api/crm/projects/:name/learnings GET/POST Sincronización de learnings
/api/sse/logs/:name GET Stream SSE de logs (?category=)

Dashboard y Wiki (Fase 32)

Endpoint Método Propósito
/api/crm/projects/:name/wiki/save PUT Guardar/crear página wiki
/api/crm/projects/:name/skills/save PUT Guardar archivo de skill
/api/crm/projects/:name/skills/delete DELETE Eliminar archivo de skill

Multi-Tenant (Fase 33)

Endpoint Método Propósito
/api/crm/account/settings GET/PUT Claves API a nivel de cuenta
/api/crm/projects/create POST Creación ligera de proyectos
/api/crm/onboarding/setup POST Asistente completo de onboarding

MCP y CLI (Fase 34)

Endpoint Método Propósito
/api/mcp/issues/:project POST/GET CRUD de issues
/api/mcp/issues/:project/:id PUT Actualizar issue
/api/mcp/wiki/:project PUT Sincronización de wiki via MCP
/api/mcp/roadmap/:project GET/PUT Lectura/sincronización de roadmap
/api/cli/init/:project/:mode GET Contexto cloud para CLI
/api/mcp/skills/:project/:skill GET Obtener skill para MCP
/api/mcp/report/:project POST Informe de misión
/api/mcp/learnings/:project GET Obtener learnings para MCP

Terminal en Vivo (Fase 35)

Endpoint Método Propósito
/api/crm/projects/:name/terminal/log POST Recibir JSONL de terminal desde ARC CLI

Cloud PM y Conocimiento (Fase 36)

Endpoint Método Propósito
/api/crm/projects/:name/chat POST Proxy de chat SSE a API de Anthropic
/api/crm/projects/:name/skills/generate POST Generador Neural de Skills (NotebookLM)
/api/crm/projects/:name/notebooks GET Notebooks NotebookLM vinculados

Auth y OAuth (Fase 37)

Endpoint Método Propósito
/api/auth/register POST Registro con email/contraseña
/api/auth/login POST Login con email/contraseña
/api/auth/google GET Redirección OAuth Google
/api/auth/callback/google GET Callback OAuth Google
/api/auth/github GET Redirección OAuth GitHub
/api/auth/callback/github GET Callback OAuth GitHub
/api/auth/providers GET Proveedores OAuth disponibles

Notas Fijadas (Fase 41.8)

Endpoint Método Propósito
/api/crm/projects/:name/pins GET Listar notas fijadas (más recientes primero)
/api/crm/projects/:name/pins POST Fijar un mensaje de worker al Context Rail (body: worker_id, body, title opcional, author)
/api/crm/projects/:name/pins/:id DELETE Eliminar pin

Backend: migración 009 (tabla pinned_notes), pinnedNoteQueries en shared/db.ts. Frontend: ContextRail.jsx carga al montar, escucha el evento personalizado crm-pin-created, DELETE optimista.

Capa de Protección de Datos (Fase 45)

Cifrado híbrido en reposo — base de criptografía del lado del cliente + cifrado en reposo del lado del servidor.

Lado del Cliente (Browser)

Lado del Servidor (Bun + SQLite)

Headers de Seguridad

Sanitización de PII

Endpoints de Clave de Recuperación

Endpoint Método Propósito
/api/crm/account/recovery POST Crear clave de recuperación (almacena clave maestra cifrada)
/api/crm/account/recovery GET Listar claves de recuperación activas
/api/crm/account/recovery DELETE Revocar clave(s) de recuperación
/api/crm/account/recovery/restore GET Recuperar clave maestra cifrada para recuperación

Detalles completos de seguridad: docs/SECURITY.md, docs/architecture/PHASE_45_E2EE.md.