{
  "site_config": {
    "name": "Documentación de cosmos",
    "brand": "cosmos",
    "brand_icon": "fas fa-circle-notch",
    "use_logos": true,
    "keep_brand_text": true,
    "license": {
      "text": "Documentación de la plataforma cosmos.",
      "link": "https://thecosmosai.cloud"
    },
    "logos": {
      "navbar_light": "logos/logo-light.svg",
      "navbar_dark": "logos/logo-dark.svg",
      "hero": "logos/logo-hero.svg",
      "icon": "logos/favicon.svg",
      "footer": "logos/logo-footer.svg"
    },
    "default_theme": "dark",
    "show_warning_on_pages": false,
    "exclude_warning_routes": [],
    "warning_message": {
      "title": "Plataforma en evolución",
      "content": "Cosmos está en desarrollo activo. Algunos artefactos documentados aquí son incubaciones sin ruta productiva todavía; su página lo indica.",
      "type": "info"
    },
    "toc": {
      "enabled": true,
      "min_headings": 2,
      "exclude_pages": [
        "home"
      ],
      "exclude_headings": {
        "texts": [],
        "selectors": [
          ".alert h4",
          ".warning-box h4",
          ".note-box h4",
          ".hero-title",
          ".hero-subtitle"
        ]
      }
    },
    "page_titles": {
      "base_title": "cosmos — documentación",
      "separator": " · ",
      "routes": {
        "home": "Inicio",
        "platform": "La plataforma",
        "quickstart": "Empieza en cinco minutos",
        "install": "Instala el CLI",
        "login": "Inicia sesión",
        "tokens": "Tokens de acceso personal",
        "organizations": "Organizaciones e invitaciones",
        "security": "Identidad y seguridad",
        "daily-flow": "El flujo diario",
        "dispatch": "Despacho de trabajo",
        "memory": "Memoria de equipo",
        "autopilot": "El autopiloto",
        "onboarding": "Onboarding",
        "fleet-model": "Anatomía de la flota",
        "platform-agents": "Agentes de plataforma",
        "custom-agents": "Crea tus propios agentes",
        "routing": "Capacidades y ruteo",
        "cli": "cosmos CLI",
        "chat": "cosmos chat",
        "ide": "cosmos IDE",
        "admin": "Back office",
        "artifacts-map": "Mapa de artefactos",
        "eclipse": "eclipse",
        "umbra": "umbra",
        "capcom": "capcom",
        "ephemeris": "ephemeris",
        "cygnus": "cygnus",
        "ignition-airlock": "ignition y airlock",
        "pilot": "pilot",
        "substrate": "substrate",
        "echo": "echo",
        "fusion": "fusion",
        "horizon": "horizon",
        "scaffolds": "Servicios en incubación",
        "packages": "Packages compartidos"
      }
    },
    "navbar": {
      "links": [
        {
          "text": "La plataforma",
          "href": "#platform"
        },
        {
          "text": "Artefactos",
          "href": "#artifacts-map"
        },
        {
          "text": "CLI",
          "href": "#cli"
        }
      ]
    },
    "lang": "es",
    "site_url": "https://docs.thecosmosai.cloud",
    "ui": {
      "nav_guides": "Guías",
      "try_it": "Pruébalo",
      "send": "Enviar",
      "sending": "Enviando…",
      "playground_note": "El navegador ejecuta la petición real. El servidor debe permitir CORS para responder desde el navegador.",
      "playground_error_status": "No pudimos conectar. Revisa tu conexión e inténtalo de nuevo.",
      "playground_error_body": "No se pudo completar la petición. Vuelve a intentarlo en un momento.",
      "authorizations_title": "Autorización",
      "query_params_title": "Parámetros de consulta",
      "body_title": "Cuerpo",
      "responses_title": "Respuestas",
      "required": "requerido",
      "optional": "opcional",
      "example": "Ejemplo",
      "copy_code": "Copiar código",
      "code_examples_title": "Ejemplos de implementación",
      "feedback_q": "¿Te resultó útil esta página?",
      "copy_link": "Copiar enlace",
      "prev": "Anterior",
      "next": "Siguiente",
      "on_this_page": "En esta página",
      "search_label": "Buscar",
      "search_placeholder": "Buscar en la documentación...",
      "search_aria": "Buscar en la documentación",
      "search_empty_title": "Nada para",
      "search_empty_hint": "Revisa la ortografía o prueba con otro término.",
      "search_hint_navigate": "navegar",
      "search_hint_open": "abrir",
      "search_hint_close": "cerrar",
      "page_actions": "Acciones de página",
      "copy_md": "Copiar como Markdown",
      "view_md": "Ver Markdown",
      "open_claude": "Abrir en Claude",
      "open_chatgpt": "Abrir en ChatGPT",
      "see_more": "Ver más",
      "explore": "Explorar",
      "rights": "Todos los derechos reservados.",
      "base_url_label": "URL base",
      "audience_label": "Audiencia",
      "confidentiality_label": "Confidencialidad",
      "not_found_title": "No encontramos esta página",
      "not_found_desc": "Puede que el enlace haya cambiado o ya no exista. Prueba desde el inicio o busca lo que necesitas.",
      "back_home": "Volver al inicio",
      "error_hint": "Los detalles técnicos se registraron en la consola."
    }
  },
  "api": {
    "name": "API de cosmos",
    "version": "v1",
    "description": "Toda la plataforma se opera por el gateway capcom con un JWT emitido por eclipse.",
    "base_url": "https://capcom.thecosmosai.cloud"
  },
  "navigation": [
    {
      "id": "home",
      "title": "Inicio",
      "icon": "fas fa-home",
      "type": "page"
    },
    {
      "id": "platform",
      "title": "La plataforma",
      "icon": "fas fa-layer-group",
      "type": "page"
    },
    {
      "id": "quickstart",
      "title": "Empieza en cinco minutos",
      "icon": "fas fa-bolt",
      "type": "page"
    }
  ],
  "sections": [
    {
      "title": "Conexión y acceso",
      "icon": "fas fa-plug",
      "pages": [
        {
          "id": "install",
          "title": "Instala el CLI",
          "icon": "fas fa-download"
        },
        {
          "id": "login",
          "title": "Inicia sesión",
          "icon": "fas fa-right-to-bracket"
        },
        {
          "id": "tokens",
          "title": "Tokens de acceso personal",
          "icon": "fas fa-key"
        },
        {
          "id": "organizations",
          "title": "Organizaciones e invitaciones",
          "icon": "fas fa-people-group"
        },
        {
          "id": "security",
          "title": "Identidad y seguridad",
          "icon": "fas fa-shield-halved"
        }
      ]
    },
    {
      "title": "Cómo opera cosmos",
      "icon": "fas fa-gears",
      "pages": [
        {
          "id": "daily-flow",
          "title": "El flujo diario",
          "icon": "fas fa-sun"
        },
        {
          "id": "dispatch",
          "title": "Despacho de trabajo",
          "icon": "fas fa-route"
        },
        {
          "id": "memory",
          "title": "Memoria de equipo",
          "icon": "fas fa-brain"
        },
        {
          "id": "autopilot",
          "title": "El autopiloto",
          "icon": "fas fa-plane"
        },
        {
          "id": "onboarding",
          "title": "Onboarding",
          "icon": "fas fa-wand-magic-sparkles"
        }
      ]
    },
    {
      "title": "La flota",
      "icon": "fas fa-rocket",
      "pages": [
        {
          "id": "fleet-model",
          "title": "Anatomía de la flota",
          "icon": "fas fa-diagram-project"
        },
        {
          "id": "platform-agents",
          "title": "Agentes de plataforma",
          "icon": "fas fa-users-gear"
        },
        {
          "id": "custom-agents",
          "title": "Crea tus propios agentes",
          "icon": "fas fa-user-astronaut"
        },
        {
          "id": "routing",
          "title": "Capacidades y ruteo",
          "icon": "fas fa-signs-post"
        }
      ]
    },
    {
      "title": "Clientes",
      "icon": "fas fa-display",
      "pages": [
        {
          "id": "cli",
          "title": "cosmos CLI",
          "icon": "fas fa-terminal"
        },
        {
          "id": "chat",
          "title": "cosmos chat",
          "icon": "fas fa-comments"
        },
        {
          "id": "ide",
          "title": "cosmos IDE",
          "icon": "fas fa-code"
        },
        {
          "id": "admin",
          "title": "Back office",
          "icon": "fas fa-user-shield"
        }
      ]
    },
    {
      "title": "Artefactos",
      "icon": "fas fa-cubes",
      "pages": [
        {
          "id": "artifacts-map",
          "title": "Mapa de artefactos",
          "icon": "fas fa-map"
        },
        {
          "id": "eclipse",
          "title": "eclipse — identidad",
          "icon": "fas fa-circle-half-stroke"
        },
        {
          "id": "umbra",
          "title": "umbra — cliente de auth",
          "icon": "fas fa-id-badge"
        },
        {
          "id": "capcom",
          "title": "capcom — gateway",
          "icon": "fas fa-tower-broadcast"
        },
        {
          "id": "ephemeris",
          "title": "ephemeris — ledger",
          "icon": "fas fa-book"
        },
        {
          "id": "cygnus",
          "title": "cygnus — reconciliador",
          "icon": "fas fa-rotate"
        },
        {
          "id": "ignition-airlock",
          "title": "ignition y airlock",
          "icon": "fas fa-fire-flame-simple"
        },
        {
          "id": "pilot",
          "title": "pilot — daemon local",
          "icon": "fas fa-plane"
        },
        {
          "id": "substrate",
          "title": "substrate — librería común",
          "icon": "fas fa-cubes-stacked"
        },
        {
          "id": "echo",
          "title": "echo — memoria",
          "icon": "fas fa-brain"
        },
        {
          "id": "fusion",
          "title": "fusion — conversión",
          "icon": "fas fa-arrows-rotate"
        },
        {
          "id": "horizon",
          "title": "horizon — gateway Rust",
          "icon": "fas fa-mountain-sun"
        },
        {
          "id": "scaffolds",
          "title": "Servicios en incubación",
          "icon": "fas fa-flask"
        },
        {
          "id": "packages",
          "title": "Packages compartidos",
          "icon": "fas fa-box-open"
        }
      ]
    },
    {
      "title": "API de capcom",
      "icon": "fas fa-tower-broadcast",
      "endpoints": [
        {
          "id": "api-agents-list",
          "method": "GET",
          "path": "/agents",
          "title": "Listar la flota"
        },
        {
          "id": "api-agents-register",
          "method": "POST",
          "path": "/agents",
          "title": "Registrar un agente"
        },
        {
          "id": "api-agents-delete",
          "method": "DELETE",
          "path": "/agents/:name",
          "title": "Quitar un agente"
        },
        {
          "id": "api-agent-capsule",
          "method": "GET",
          "path": "/agents/:name/capsule",
          "title": "Config de capsule"
        },
        {
          "id": "api-manifests-create",
          "method": "POST",
          "path": "/manifests",
          "title": "Crear un manifest"
        },
        {
          "id": "api-manifests-get",
          "method": "GET",
          "path": "/manifests/:id",
          "title": "Estado de un manifest"
        },
        {
          "id": "api-memory-get",
          "method": "GET",
          "path": "/memory/:projectId",
          "title": "Leer memoria de equipo"
        },
        {
          "id": "api-memory-put",
          "method": "PUT",
          "path": "/memory/:projectId",
          "title": "Escribir memoria de equipo"
        },
        {
          "id": "api-tether",
          "method": "GET",
          "path": "/tether",
          "title": "Tether de sesión"
        },
        {
          "id": "api-mail",
          "method": "GET",
          "path": "/mail",
          "title": "Correo de crew"
        },
        {
          "id": "api-waypoint-close",
          "method": "POST",
          "path": "/waypoints/:id/close",
          "title": "Cerrar un waypoint"
        }
      ]
    },
    {
      "title": "API de eclipse",
      "icon": "fas fa-circle-half-stroke",
      "endpoints": [
        {
          "id": "api-auth-register",
          "method": "POST",
          "path": "/api/v1/auth/register",
          "title": "Crear cuenta"
        },
        {
          "id": "api-auth-login",
          "method": "POST",
          "path": "/api/v1/auth/login",
          "title": "Iniciar sesión"
        },
        {
          "id": "api-auth-refresh",
          "method": "POST",
          "path": "/api/v1/auth/refresh",
          "title": "Refrescar sesión"
        },
        {
          "id": "api-device-code",
          "method": "POST",
          "path": "/api/v1/auth/device/code",
          "title": "Device flow: pedir código"
        },
        {
          "id": "api-device-token",
          "method": "POST",
          "path": "/api/v1/auth/device/token",
          "title": "Device flow: canjear token"
        },
        {
          "id": "api-pat-create",
          "method": "POST",
          "path": "/api/v1/tokens",
          "title": "Crear token personal"
        },
        {
          "id": "api-admin-users",
          "method": "GET",
          "path": "/api/v1/admin/users",
          "title": "Admin: listar usuarios"
        }
      ]
    }
  ],
  "pages": {
    "home": {
      "template": "hero",
      "content": {
        "hero": {
          "title": "cosmos",
          "subtitle": "La plataforma que orquesta flotas de agentes multi-tenant y aprende de cada desarrollador. Identidad, gateway, ledger durable, memoria de equipo y una flota que corre con tu propio cómputo.",
          "stats": [
            {
              "number": "5",
              "label": "Capas de plataforma"
            },
            {
              "number": "6",
              "label": "Agentes en la flota base"
            },
            {
              "number": "2",
              "label": "Dominios públicos expuestos"
            }
          ],
          "buttons": [
            {
              "text": "Empieza en cinco minutos",
              "href": "#quickstart",
              "type": "primary",
              "icon": "fas fa-bolt"
            },
            {
              "text": "Explora los artefactos",
              "href": "#artifacts-map",
              "type": "outline",
              "icon": "fas fa-map"
            }
          ]
        },
        "features": {
          "title": "Las piezas de la plataforma",
          "subtitle": "Cinco capas delgadas, cosidas por un solo hilo de confianza",
          "items": [
            {
              "icon": "fas fa-circle-half-stroke",
              "title": "Identidad",
              "description": "eclipse emite JWT RS256 y publica su JWKS. Usuarios, organizaciones, invitaciones y verificación de correo.",
              "link": "#eclipse"
            },
            {
              "icon": "fas fa-tower-broadcast",
              "title": "Gateway",
              "description": "capcom es la única puerta pública: valida el token y proxea flota, memoria y ledger on-behalf-of del tenant.",
              "link": "#capcom"
            },
            {
              "icon": "fas fa-book",
              "title": "Trabajo durable",
              "description": "Continuum convierte cada intención en waypoints en un ledger Dolt. Lo que muere a media tarea se retoma sin repetir pasos.",
              "link": "#dispatch"
            },
            {
              "icon": "fas fa-brain",
              "title": "Memoria de equipo",
              "description": "echo guarda una memoria por tenant y proyecto que hidrata cada sesión y crece con lo que tu equipo aprende.",
              "link": "#memory"
            },
            {
              "icon": "fas fa-rocket",
              "title": "La flota",
              "description": "Agentes HTTP en el servidor y capsule agents que corren con tu claude -p local. La plataforma nunca se casa con una máquina.",
              "link": "#fleet-model"
            },
            {
              "icon": "fas fa-plane",
              "title": "Autopiloto",
              "description": "pilot espeja tus subagentes y tu memoria, y destila tu historial de IA en hechos útiles. Cosmos aprende de ti en segundo plano.",
              "link": "#autopilot"
            }
          ]
        },
        "steps": {
          "title": "De cero a tu primera flota",
          "subtitle": "Tres pasos y cosmos trabaja contigo",
          "items": [
            {
              "number": 1,
              "title": "Conéctate",
              "description": "Instala el CLI e inicia sesión con el flujo de autorización en el navegador. Tu sesión vive en el keychain.",
              "link": "#login"
            },
            {
              "number": 2,
              "title": "Cablea tu repo",
              "description": "cosmos init apunta tu proyecto al gateway y cada sesión arranca hidratada con memoria y trabajo pendiente.",
              "link": "#daily-flow"
            },
            {
              "number": 3,
              "title": "Despacha",
              "description": "cosmos run convierte tu intención en trabajo durable y lo rutea al agente correcto de tu flota.",
              "link": "#dispatch"
            }
          ]
        },
        "quick_start": {
          "title": "Pruébalo ahora",
          "subtitle": "El camino completo, en tu terminal",
          "code": {
            "language": "bash",
            "title": "Primer despacho",
            "file": "config/examples/home.quick-start.sh"
          },
          "response": {
            "language": "text",
            "title": "Resultado",
            "file": "config/examples/home.quick-start-response.txt"
          }
        }
      }
    },
    "platform": {
      "template": "content",
      "content": {
        "title": "La plataforma",
        "description": "Cosmos es un orquestador multi-tenant de agentes que aprende de cada desarrollador. No es una app: es una plataforma de cinco capas delgadas, cosidas por un solo hilo de confianza.",
        "sections": [
          {
            "title": "El modelo mental",
            "content": "Todo cosmos se entiende como cinco capas apiladas. Los clientes hablan con un único gateway público; el gateway valida la identidad y proxea el trabajo hacia un control plane durable; la flota ejecuta. Ninguna capa conoce más de lo que necesita.",
            "cards": [
              {
                "icon": "fas fa-display",
                "title": "Clientes",
                "description": "telescope (el CLI cosmos), cosmos chat, cosmos IDE y el back office. Todos hablan por el gateway.",
                "link": "#cli"
              },
              {
                "icon": "fas fa-circle-half-stroke",
                "title": "Identidad",
                "description": "eclipse emite el JWT RS256 y umbra lo guarda y refresca en cada cliente.",
                "link": "#eclipse"
              },
              {
                "icon": "fas fa-tower-broadcast",
                "title": "Gateway",
                "description": "capcom, la única puerta pública. Valida el token y actúa on-behalf-of del tenant.",
                "link": "#capcom"
              },
              {
                "icon": "fas fa-book",
                "title": "Control plane",
                "description": "Continuum: ephemeris (ledger), cygnus (reconciliador), ignition, airlock y pilot, más echo (memoria).",
                "link": "#dispatch"
              },
              {
                "icon": "fas fa-rocket",
                "title": "La flota",
                "description": "fusion como agente HTTP y la flota creativa como capsule agents que corren con tu claude -p.",
                "link": "#fleet-model"
              }
            ]
          },
          {
            "title": "Los dos principios de diseño",
            "content": "Dos decisiones gobiernan toda la arquitectura y explican por qué cosmos escala sin engordar el servidor.",
            "list": [
              "Control plane delgado y multi-tenant: el servidor solo hospeda identidad, gateway, ledger y memoria. Nada de cómputo pesado de IA del lado de la plataforma.",
              "El cerebro vive con el desarrollador: los agentes con LLM corren como capsules en tu máquina, con tu propio claude -p y tu suscripción. La plataforma nunca se casa con una máquina específica."
            ]
          },
          {
            "title": "El hilo de confianza",
            "content": "Un JWT RS256 emitido por eclipse cose las capas. Cada servicio lo verifica contra el JWKS público de eclipse; el tenantId viaja dentro del token verificado y determina, por construcción, qué datos puede tocar cada request. Ningún servicio interno acepta un tenant por parámetro.",
            "callout": {
              "type": "tip",
              "title": "Profundiza",
              "content": "La página Identidad y seguridad explica la cadena de confianza completa, qué ataques bloquea y cómo se aísla cada tenant."
            }
          },
          {
            "title": "Dominios públicos",
            "content": "Solo dos dominios salen a internet, ambos por Cloudflare Tunnel. El resto de los servicios (ephemeris, echo, fusion) viven en loopback o en la red interna de Docker y se alcanzan únicamente a través del gateway.",
            "table": {
              "headers": [
                "Dominio",
                "Servicio",
                "Función"
              ],
              "rows": [
                [
                  "auth.thecosmosai.cloud",
                  "eclipse",
                  "Identidad: cuentas, organizaciones, tokens, páginas de autorización"
                ],
                [
                  "capcom.thecosmosai.cloud",
                  "capcom",
                  "Gateway: flota, manifests, memoria y ledger on-behalf-of del tenant"
                ]
              ]
            }
          },
          {
            "title": "Qué hace distinta a la plataforma",
            "content": "El trabajo no es una llamada frágil en memoria: cada intención se vuelve waypoints durables en un ledger versionado, y un reconciliador los empuja a hecho aunque un proceso muera a media tarea. Además, cosmos aprende: el autopiloto espeja tus subagentes, tu memoria de proyecto y tu historial de IA hacia la plataforma, para que cada sesión arranque sabiendo lo que tu equipo ya sabe.",
            "cards": [
              {
                "icon": "fas fa-route",
                "title": "Trabajo durable",
                "description": "Manifest, waypoints y reconcile: nada se pierde ni se repite.",
                "link": "#dispatch"
              },
              {
                "icon": "fas fa-brain",
                "title": "Memoria de equipo",
                "description": "Un documento por proyecto que hidrata cada sesión de todos.",
                "link": "#memory"
              },
              {
                "icon": "fas fa-plane",
                "title": "Autopiloto",
                "description": "Cosmos aprende de ti en segundo plano, sin comandos.",
                "link": "#autopilot"
              }
            ]
          }
        ]
      }
    },
    "quickstart": {
      "template": "content",
      "content": {
        "title": "Empieza en cinco minutos",
        "description": "El camino feliz completo: de una terminal vacía a tu primer despacho de trabajo a la flota.",
        "sections": [
          {
            "title": "Antes de empezar",
            "content": "Necesitas tres cosas en tu máquina. La tercera solo importa si vas a ejecutar capsule agents, que es el caso normal.",
            "list": [
              "Node 20 o superior",
              "Una cuenta de cosmos con el correo verificado",
              "Claude Code instalado (el comando claude), porque los capsule agents corren con tu claude -p local"
            ]
          },
          {
            "title": "El camino completo",
            "steps": [
              {
                "number": 1,
                "title": "Instala el CLI",
                "description": "Compila y enlaza el binario cosmos desde el monorepo. La página Instala el CLI tiene el paso a paso."
              },
              {
                "number": 2,
                "title": "Inicia sesión",
                "description": "cosmos login abre el navegador, apruebas y pegas un código de un solo uso. Tu sesión queda en el keychain."
              },
              {
                "number": 3,
                "title": "Cablea tu repo",
                "description": "cosmos init instala los hooks y el servidor MCP: cada sesión de Claude Code arranca hidratada."
              },
              {
                "number": 4,
                "title": "Mira tu flota",
                "description": "cosmos agents lista los agentes de tu organización mezclados con la flota base de la plataforma."
              },
              {
                "number": 5,
                "title": "Despacha",
                "description": "cosmos run convierte tu intención en trabajo durable y lo rutea al agente correcto."
              }
            ]
          },
          {
            "title": "En comandos",
            "code": {
              "language": "bash",
              "title": "De cero a primer despacho",
              "file": "config/examples/quickstart.first-run.sh"
            }
          },
          {
            "title": "Qué acaba de pasar",
            "content": "Detrás de esos comandos se movió toda la plataforma: eclipse emitió tu JWT, capcom lo verificó contra el JWKS y creó un manifest en ephemeris, el ruteo eligió el agente por capacidad, y el resultado cerró el waypoint en el ledger. Si el agente era un capsule, el trabajo corrió en tu máquina con tu claude -p.",
            "callout": {
              "type": "note",
              "title": "Apunta a producción",
              "content": "Los defaults del CLI apuntan a localhost para desarrollo. Para usar la plataforma viva, fija capcomUrl y authUrl en ~/.config/cosmos/config.json o exporta COSMOS_CAPCOM_URL y COSMOS_AUTH_URL con los dominios de producción."
            }
          },
          {
            "title": "Siguientes pasos",
            "cards": [
              {
                "icon": "fas fa-wand-magic-sparkles",
                "title": "cosmos onboard",
                "description": "La experiencia guiada de primer uso: identidad, flota, memoria y primeras tareas sugeridas.",
                "link": "#onboarding"
              },
              {
                "icon": "fas fa-sun",
                "title": "El flujo diario",
                "description": "Cómo se siente trabajar con cosmos todos los días desde Claude Code.",
                "link": "#daily-flow"
              },
              {
                "icon": "fas fa-user-astronaut",
                "title": "Crea tus agentes",
                "description": "Registra tus propios capsule agents y amplía tu flota.",
                "link": "#custom-agents"
              }
            ]
          }
        ]
      }
    },
    "install": {
      "template": "content",
      "content": {
        "title": "Instala el CLI",
        "description": "El binario cosmos lo instala el paquete @cosmos/telescope. Hoy se compila desde el monorepo; no hay todavía un paquete publicado en npm.",
        "sections": [
          {
            "title": "Requisitos",
            "list": [
              "Node 20 o superior (el CLI es TypeScript compilado, sin dependencias externas más allá de umbra)",
              "git, para clonar el monorepo y para que cosmos init derive el projectId de tu repo",
              "Claude Code (el comando claude) si vas a ejecutar capsule agents en tu máquina"
            ]
          },
          {
            "title": "Compila y enlaza",
            "content": "telescope vive en tools/telescope dentro del monorepo de cosmos. Se compila con TypeScript y se enlaza el binario con npm link.",
            "code": {
              "language": "bash",
              "title": "Instalación desde el monorepo",
              "file": "config/examples/install.from-source.sh"
            },
            "callout": {
              "type": "warning",
              "title": "Sin paquete publicado",
              "content": "npm install -g @cosmos/telescope todavía no funciona: el paquete no está publicado en el registro de npm. La instalación es desde el código fuente."
            }
          },
          {
            "title": "Verifica",
            "content": "Si el enlace quedó bien, cosmos responde con su ayuda y su versión.",
            "code": {
              "language": "bash",
              "title": "Comprobación",
              "content": "cosmos --version\ncosmos --help"
            }
          },
          {
            "title": "Configura los destinos",
            "content": "El CLI resuelve sus URLs en este orden: flag explícito, variable de entorno, ~/.config/cosmos/config.json y por último el default local. Para hablar con la plataforma viva conviene fijar el archivo de configuración una sola vez.",
            "code": {
              "language": "json",
              "title": "~/.config/cosmos/config.json",
              "content": "{\n  \"capcomUrl\": \"https://capcom.thecosmosai.cloud\",\n  \"authUrl\": \"https://auth.thecosmosai.cloud\"\n}"
            },
            "table": {
              "headers": [
                "Variable",
                "Qué controla",
                "Default"
              ],
              "rows": [
                [
                  "COSMOS_CAPCOM_URL",
                  "URL de capcom, el gateway de la flota",
                  "http://127.0.0.1:9060"
                ],
                [
                  "COSMOS_AUTH_URL",
                  "URL del servicio de identidad (eclipse)",
                  "http://localhost:3001"
                ],
                [
                  "COSMOS_EPHEMERIS_URL",
                  "URL del ledger para comandos de crew",
                  "http://127.0.0.1:9050"
                ],
                [
                  "COSMOS_ECHO_URL",
                  "URL de la memoria de equipo",
                  "vía capcom"
                ],
                [
                  "COSMOS_ORCHESTRATION",
                  "Ruta de orquestación: capcom u orchestrator (legado)",
                  "capcom"
                ],
                [
                  "COSMOS_CONFIG_DIR",
                  "Carpeta de configuración del CLI",
                  "~/.config/cosmos"
                ]
              ]
            }
          },
          {
            "title": "Siguiente paso",
            "cards": [
              {
                "icon": "fas fa-right-to-bracket",
                "title": "Inicia sesión",
                "description": "Conecta el CLI con tu cuenta: navegador, código de un solo uso y listo.",
                "link": "#login"
              }
            ]
          }
        ]
      }
    },
    "login": {
      "template": "content",
      "content": {
        "title": "Inicia sesión",
        "description": "cosmos login conecta tu terminal con tu cuenta. El flujo por defecto es copiar y pegar un código desde el navegador, al estilo de Claude Code; hay alternativas para cada contexto.",
        "sections": [
          {
            "title": "El flujo por defecto: autoriza y pega el código",
            "content": "Al correr cosmos login sin flags, el CLI abre la página /authorize de eclipse en tu navegador. Ahí apruebas la solicitud con tu sesión web y eclipse te muestra un código de un solo uso; lo copias, lo pegas en la terminal y la sesión queda establecida. El intercambio va protegido con PKCE (S256), así que un código interceptado no sirve sin el verificador que solo tu terminal conoce.",
            "code": {
              "language": "text",
              "title": "Así se ve",
              "file": "config/examples/login.copy-paste.txt"
            },
            "callout": {
              "type": "warning",
              "title": "Correo verificado",
              "content": "La página de autorización exige que tu correo esté verificado antes de aprobar el acceso de una terminal. Si acabas de crear la cuenta, primero confirma el correo con el código OTP que te enviamos."
            }
          },
          {
            "title": "Device flow: aprobar sin pegar nada",
            "content": "Con cosmos login --device el CLI usa el device flow estándar (RFC 8628): te muestra un código corto y una URL (/device), apruebas en el navegador y la terminal se autoriza sola cuando eclipse confirma. Útil cuando pegar en la terminal es incómodo, por ejemplo en una sesión SSH.",
            "code": {
              "language": "bash",
              "title": "Device flow",
              "content": "cosmos login --device"
            }
          },
          {
            "title": "Token personal: para máquinas sin navegador",
            "content": "Genera un token de acceso personal en la página /tokens de auth.thecosmosai.cloud y pégalo directo. Es el camino para servidores, contenedores y CI.",
            "code": {
              "language": "bash",
              "title": "Con un PAT",
              "content": "cosmos login --token <token>"
            },
            "callout": {
              "type": "tip",
              "title": "Más sobre tokens",
              "content": "La página Tokens de acceso personal explica cómo crearlos, revocarlos y protegerlos."
            }
          },
          {
            "title": "Password: para scripts controlados",
            "content": "El flujo clásico con credenciales existe para automatización donde los otros flujos no aplican. Evítalo en terminales compartidas: el default de navegador existe justamente para que tu contraseña nunca pase por la terminal.",
            "code": {
              "language": "bash",
              "title": "Flujo con contraseña",
              "content": "cosmos login --email <correo> [--password <pass>] [--password-flow]"
            }
          },
          {
            "title": "Dónde vive tu sesión",
            "content": "umbra, el cliente de auth compartido, guarda el JWT y el refresh token en el keychain del sistema operativo; si no hay keychain disponible cae a un archivo con permisos 0600 en la carpeta de configuración. La renovación es silenciosa: cuando el access token expira, el CLI lo refresca solo y rota el refresh token; si la renovación falla, limpia la sesión y te pide entrar de nuevo.",
            "list": [
              "cosmos logout cierra la sesión y revoca el refresh token en el servidor",
              "eclipse detecta el reuso de un refresh token robado y revoca la familia completa de sesiones",
              "Cada cliente (CLI, chat, IDE) comparte el mismo camino de login gracias a umbra"
            ]
          },
          {
            "title": "Referencia de flags",
            "table": {
              "headers": [
                "Comando",
                "Cuándo usarlo"
              ],
              "rows": [
                [
                  "cosmos login",
                  "El default: abre /authorize, apruebas y pegas el código"
                ],
                [
                  "cosmos login --device",
                  "Aprobar en el navegador sin pegar nada en la terminal"
                ],
                [
                  "cosmos login --token <token>",
                  "Máquinas sin navegador, con un token personal"
                ],
                [
                  "cosmos login --email <correo> --password-flow",
                  "Scripts y automatización controlada"
                ],
                [
                  "cosmos login --auth-url <url>",
                  "Apuntar a un eclipse distinto (desarrollo local)"
                ],
                [
                  "cosmos logout",
                  "Cerrar la sesión y revocar el refresh token"
                ]
              ]
            }
          }
        ]
      }
    },
    "tokens": {
      "template": "content",
      "content": {
        "title": "Tokens de acceso personal",
        "description": "Un token de acceso personal (PAT) autentica una máquina que no puede abrir un navegador: servidores, contenedores, CI. Funciona como los tokens personales de GitHub.",
        "sections": [
          {
            "title": "Crea tu token",
            "steps": [
              {
                "number": 1,
                "title": "Crea tu cuenta",
                "description": "Regístrate en la plataforma y entra con tu correo y contraseña."
              },
              {
                "number": 2,
                "title": "Verifica el correo",
                "description": "Confirma con el código OTP de seis dígitos que te enviamos. Sin correo verificado no se emiten tokens."
              },
              {
                "number": 3,
                "title": "Genera el token",
                "description": "En auth.thecosmosai.cloud/tokens crea un token nuevo. Se muestra una sola vez: cópialo en ese momento."
              },
              {
                "number": 4,
                "title": "Úsalo en la terminal",
                "description": "Pega el token con cosmos login --token y la máquina queda autenticada."
              }
            ],
            "code": {
              "language": "bash",
              "title": "En la máquina destino",
              "content": "cosmos login --token <token>"
            }
          },
          {
            "title": "Revocación",
            "content": "Desde la misma página /tokens puedes revocar cualquier token en cualquier momento. La revocación es inmediata: la siguiente petición con ese token falla y la máquina tiene que autenticarse de nuevo.",
            "callout": {
              "type": "danger",
              "title": "Si un token se filtra",
              "content": "Revócalo de inmediato en /tokens. Un token filtrado autentica como tú hasta que lo revoques."
            }
          },
          {
            "title": "Buenas prácticas",
            "list": [
              "Un token por máquina o por uso, nunca uno compartido entre varias",
              "Guárdalo en un gestor de secretos o variable de entorno del servidor, nunca en un repositorio",
              "Revoca los tokens de máquinas que ya no existen",
              "Para tu máquina de trabajo diario prefiere cosmos login con navegador: la sesión del keychain se refresca sola"
            ]
          }
        ]
      }
    },
    "organizations": {
      "template": "content",
      "content": {
        "title": "Organizaciones e invitaciones",
        "description": "En cosmos la organización es el tenant: todo lo que existe (agentes, memoria, trabajo) pertenece a una organización y está aislado de las demás por construcción.",
        "sections": [
          {
            "title": "La organización es el tenant",
            "content": "El identificador de tu organización es literalmente tu tenantId: orgId y tenantId son el mismo valor. Por eso cambiar de organización cambia por completo qué flota ves, qué memoria lees y qué trabajo despachas.",
            "callout": {
              "type": "note",
              "title": "Org personal automática",
              "content": "Al primer login, eclipse te aprovisiona una organización personal automáticamente, al estilo de Claude Desktop. No necesitas crear nada para empezar a trabajar."
            }
          },
          {
            "title": "Roles",
            "content": "El acceso dentro de una organización se controla por rol. El rol viaja en el token (claim orgRole) y los servicios lo verifican en cada operación.",
            "table": {
              "headers": [
                "Rol",
                "Qué puede hacer"
              ],
              "rows": [
                [
                  "owner",
                  "Todo, incluida la administración de miembros y la eliminación de la organización"
                ],
                [
                  "admin",
                  "Gestionar miembros, invitaciones y la flota de la organización"
                ],
                [
                  "member",
                  "Trabajar: despachar, leer y escribir memoria, registrar agentes propios"
                ],
                [
                  "viewer",
                  "Solo lectura"
                ]
              ]
            }
          },
          {
            "title": "Invita a tu equipo",
            "content": "Las invitaciones se emiten por correo y con rol explícito. Quien la recibe la acepta con su código; la invitación se consume al entrar y requiere que el invitado tenga el correo verificado.",
            "code": {
              "language": "bash",
              "title": "Invitaciones desde el CLI",
              "content": "cosmos invite ana@equipo.com --role member\ncosmos invite accept <código>"
            }
          },
          {
            "title": "Muévete entre organizaciones",
            "content": "Puedes pertenecer a varias organizaciones y cambiar la activa cuando quieras. El cambio emite un token nuevo con el tenant correcto; no hay estado a medias.",
            "code": {
              "language": "bash",
              "title": "Listar y cambiar",
              "content": "cosmos orgs\ncosmos orgs switch <orgId>"
            }
          },
          {
            "title": "Qué se aísla por organización",
            "list": [
              "La flota: los agentes que registras viven en tu tenant y solo tu organización los ve (además de la flota base de la plataforma)",
              "La memoria de equipo: un documento por proyecto y por tenant en echo",
              "El trabajo: manifests y waypoints viven en un store del ledger físicamente separado por tenant",
              "Las sesiones y la facturación futura"
            ]
          }
        ]
      }
    },
    "security": {
      "template": "content",
      "content": {
        "title": "Identidad y seguridad",
        "description": "Toda la plataforma cuelga de una sola cadena de confianza: un JWT RS256 firmado por eclipse y verificado contra su JWKS público. Esta página explica el diseño completo y qué defiende.",
        "sections": [
          {
            "title": "La cadena de confianza",
            "content": "eclipse firma cada token con su clave privada RS256 y publica solo la clave pública en /.well-known/jwks.json, identificada por kid. capcom y los servicios del control plane verifican la firma contra ese JWKS (con caché). La clave privada nunca sale de eclipse.",
            "steps": [
              {
                "number": 1,
                "title": "eclipse emite",
                "description": "Al hacer login, eclipse firma un JWT RS256 con kid y claims de identidad, incluido tu tenantId."
              },
              {
                "number": 2,
                "title": "umbra guarda",
                "description": "El cliente guarda la sesión en el keychain del sistema y la refresca en silencio."
              },
              {
                "number": 3,
                "title": "capcom verifica",
                "description": "Cada request al gateway valida la firma contra el JWKS público de eclipse. El tenant sale solo del claim verificado."
              },
              {
                "number": 4,
                "title": "Mesh interno",
                "description": "capcom habla con ephemeris y echo con un token mesh por request que lleva la identidad del caller, on-behalf-of del tenant."
              }
            ]
          },
          {
            "title": "Qué defiende este diseño",
            "list": [
              "Confusión de algoritmo: el verificador rechaza tokens con alg inesperado, incluido none",
              "kid desconocido: si el token no referencia una clave del JWKS, se rechaza",
              "Verificador comprometido: un servicio que solo tiene la clave pública no puede forjar tokens",
              "Refresh token robado: eclipse detecta el reuso y revoca la familia de sesiones completa",
              "Suplantación de tenant: ningún servicio acepta tenantId por parámetro; siempre sale del claim firmado"
            ]
          },
          {
            "title": "Los claims del token",
            "content": "Los claims son camelCase. Estos son los que gobiernan la autorización en toda la plataforma.",
            "fields": [
              {
                "name": "userId",
                "type": "string",
                "required": true,
                "description": "Identidad del usuario"
              },
              {
                "name": "tenantId",
                "type": "string",
                "required": true,
                "description": "El tenant efectivo de la sesión; igual al orgId de la organización activa"
              },
              {
                "name": "orgRole",
                "type": "string",
                "required": true,
                "description": "Rol dentro de la organización: owner, admin, member o viewer"
              },
              {
                "name": "sessionId",
                "type": "string",
                "required": true,
                "description": "Sesión concreta; permite revocación granular"
              },
              {
                "name": "aud",
                "type": "string",
                "required": true,
                "description": "Audiencia del token (cosmos-client)"
              },
              {
                "name": "isPlatformAdmin",
                "type": "boolean",
                "required": false,
                "description": "Solo para el back office; se emite únicamente a una allowlist de correos verificados, no desde una columna mutable"
              }
            ]
          },
          {
            "title": "Aislamiento multi-tenant por construcción",
            "content": "El ledger no filtra datos por tenant: los separa físicamente. Cada tenant tiene su propio store Dolt en disco, así que no existe una query que pueda devolver datos de otra organización. La memoria de equipo sigue el mismo principio por tenant y proyecto. Aislar por construcción es más fuerte que aislar por filtrado: la clase entera de bugs de filtro desaparece.",
            "callout": {
              "type": "info",
              "title": "Fail-closed",
              "content": "Los servicios internos rechazan cualquier petición sin token válido (401). No hay modo permisivo."
            }
          },
          {
            "title": "Superficie de exposición mínima",
            "content": "Solo auth.thecosmosai.cloud y capcom.thecosmosai.cloud existen para internet, y ambos salen por Cloudflare Tunnel: el origen no acepta conexiones directas. ephemeris, echo y fusion viven en la red interna y solo capcom los alcanza.",
            "table": {
              "headers": [
                "Servicio",
                "Expuesto",
                "Cómo se alcanza"
              ],
              "rows": [
                [
                  "eclipse",
                  "Sí, vía tunnel",
                  "auth.thecosmosai.cloud"
                ],
                [
                  "capcom",
                  "Sí, vía tunnel",
                  "capcom.thecosmosai.cloud"
                ],
                [
                  "ephemeris",
                  "No",
                  "Solo desde capcom, con token mesh"
                ],
                [
                  "echo",
                  "No",
                  "Solo desde capcom, con token mesh"
                ],
                [
                  "fusion",
                  "No",
                  "Solo desde el control plane"
                ]
              ]
            }
          },
          {
            "title": "Verificación de correo y recuperación",
            "content": "eclipse verifica el correo con un OTP de seis dígitos o un link firmado de un solo uso; la recuperación de contraseña usa un token opaco hasheado y revoca todas las sesiones al cambiarla; el cambio de correo verifica el nuevo y avisa al anterior. Cada evento de seguridad (login nuevo, contraseña cambiada) dispara un correo transaccional."
          }
        ]
      }
    },
    "daily-flow": {
      "template": "content",
      "content": {
        "title": "El flujo diario",
        "description": "Después de cablear tu repo una sola vez, el día a día es simplemente abrir Claude Code: cada sesión arranca sabiendo qué trabajo tienes asignado, qué sabe tu equipo y qué correo te dejaron.",
        "sections": [
          {
            "title": "Cablea el repo una vez",
            "content": "cosmos init escribe tres cosas en tu repositorio, todas con merges idempotentes que respetan lo que ya exista.",
            "list": [
              ".mcp.json: registra el servidor MCP de la flota (cosmos mcp-serve), para que el modelo descubra y despache agentes como herramientas",
              ".claude/settings.json: instala los hooks de ciclo de vida (SessionStart ejecuta cosmos prime --hook; UserPromptSubmit ejecuta cosmos mail --check --inject; Stop ejecuta cosmos prime --checkpoint)",
              ".cosmos/rig.json: el estado del rig (id, crew, URLs del ledger y la memoria); el crew toma por defecto el correo de tu sesión"
            ],
            "code": {
              "language": "bash",
              "title": "Una sola vez por repo",
              "content": "cd mi-proyecto\ncosmos init"
            }
          },
          {
            "title": "El projectId: una identidad por repo",
            "content": "cosmos deriva el projectId como un hash sha256 del remoto git del repositorio. Ese identificador es idéntico en todos los clientes (CLI, cosmos chat, el autopiloto), así que todos leen y escriben el mismo documento de memoria sin configurar nada."
          },
          {
            "title": "Qué hace prime al arrancar",
            "content": "Cuando abres Claude Code en el repo, el hook SessionStart corre cosmos prime --hook, que consulta producción a través del gateway y le inyecta contexto a la sesión antes de tu primer mensaje.",
            "steps": [
              {
                "number": 1,
                "title": "Tether",
                "description": "Tus waypoints abiertos (el trabajo que tienes asignado), con los listos para ejecutar primero."
              },
              {
                "number": 2,
                "title": "Memoria de equipo",
                "description": "El documento de memoria del proyecto desde echo: convenciones, decisiones, gotchas."
              },
              {
                "number": 3,
                "title": "Correo de crew",
                "description": "Mensajes que otros miembros o agentes dejaron para ti; el hook de cada prompt sigue drenando el buzón durante la sesión."
              }
            ],
            "callout": {
              "type": "note",
              "title": "Nunca rompe la sesión",
              "content": "Toda lectura del ledger degrada a vacío si algo falla. Si producción no responde, tu sesión arranca normal, solo que sin contexto inyectado."
            }
          },
          {
            "title": "El ciclo del día",
            "content": "El bucle cotidiano no tiene comandos nuevos que aprender: trabajas en Claude Code con el contexto ya puesto, y cierras trabajo con done cuando terminas un waypoint, lo que automáticamente deja listo lo que dependía de él.",
            "code": {
              "language": "bash",
              "title": "El bucle",
              "content": "claude\ncosmos done <waypointId>"
            }
          },
          {
            "title": "Los hooks en resumen",
            "table": {
              "headers": [
                "Hook",
                "Comando",
                "Qué inyecta"
              ],
              "rows": [
                [
                  "SessionStart",
                  "cosmos prime --hook",
                  "Tether + memoria de equipo + correo, como contexto adicional de la sesión"
                ],
                [
                  "UserPromptSubmit",
                  "cosmos mail --check --inject",
                  "Correo nuevo de tu crew en cada prompt"
                ],
                [
                  "Stop",
                  "cosmos prime --checkpoint",
                  "Registra el checkpoint de la sesión"
                ]
              ]
            }
          }
        ]
      }
    },
    "dispatch": {
      "template": "content",
      "content": {
        "title": "Despacho de trabajo",
        "description": "En cosmos el trabajo no es una llamada HTTP que se pierde si algo muere: es un manifest que se descompone en waypoints durables dentro de un ledger versionado, y un reconciliador que los empuja a hecho.",
        "sections": [
          {
            "title": "Los tres caminos de entrada",
            "content": "Todo despacho entra por el gateway con tu JWT, venga de donde venga.",
            "cards": [
              {
                "icon": "fas fa-terminal",
                "title": "cosmos run",
                "description": "Desde la terminal: una intención en lenguaje natural, con capability opcional para fijar el agente.",
                "link": "#cli"
              },
              {
                "icon": "fas fa-comments",
                "title": "MCP desde el chat o Claude Code",
                "description": "El modelo elige la herramienta mcp_dispatch_task con la intención; el cliente hereda tu sesión.",
                "link": "#chat"
              },
              {
                "icon": "fas fa-tower-broadcast",
                "title": "API directa",
                "description": "POST /manifests contra capcom, para integraciones propias.",
                "link": "#api-manifests-create"
              }
            ]
          },
          {
            "title": "De intención a waypoints",
            "steps": [
              {
                "number": 1,
                "title": "Manifest",
                "description": "capcom valida tu token y crea un manifest durable en ephemeris: la declaración del trabajo, aislada en el store de tu tenant."
              },
              {
                "number": 2,
                "title": "Waypoints",
                "description": "El manifest se descompone en waypoints: pasos concretos con dependencias entre sí. Un waypoint bloqueado no se ejecuta hasta que sus dependencias cierran."
              },
              {
                "number": 3,
                "title": "Ruteo",
                "description": "cygnus descubre la flota de tu tenant mezclada con la de plataforma y empata la intención con la capacidad declarada del mejor agente."
              },
              {
                "number": 4,
                "title": "Ejecución",
                "description": "Si el agente es HTTP se le hace POST /execute; si es capsule, el cliente baja su systemPrompt y lo corre con claude -p en la máquina del desarrollador."
              },
              {
                "number": 5,
                "title": "Cierre",
                "description": "El resultado se escribe al ledger y el waypoint cierra, lo que deja listos los que dependían de él."
              }
            ]
          },
          {
            "title": "Claim-lease: la durabilidad real",
            "content": "Antes de trabajar un waypoint, el ejecutor lo reclama (claim) con un lease. Si el proceso muere a media tarea, el waypoint queda abierto con su claim vencido, y el siguiente tick del reconciliador lo retoma. Los pasos ya cerrados jamás se re-ejecutan: la unidad de reintento es el waypoint, no el manifest completo.",
            "callout": {
              "type": "success",
              "title": "Qué significa en la práctica",
              "content": "Puedes matar el proceso, reiniciar la máquina o perder la red a media campaña: al volver, el trabajo continúa exactamente donde quedó."
            }
          },
          {
            "title": "El linaje: Gas Town y Beads",
            "content": "Continuum adopta el modelo de orquestación durable de Gas Town y Beads, de Steve Yegge, verificado contra el código real y no contra el blog. De ahí vienen las primitivas de oro: el ledger sobre Dolt (base SQL versionada), los IDs por content-hash, las dependencias con is_blocked y el claim-lease. Cosmos decidió no copiar el driver interactivo en tmux: los capsules corren con claude -p headless.",
            "note": "El orquestador viejo (agent-kit) fue retirado; queda una ruta legado seleccionable con COSMOS_ORCHESTRATION=orchestrator, pero el default es capcom."
          },
          {
            "title": "Observa el trabajo",
            "content": "El estado de un manifest se consulta por el gateway en cualquier momento, y cosmos run lo sondea hasta completar cuando despachas desde la terminal.",
            "code": {
              "language": "bash",
              "title": "Despacho y seguimiento",
              "file": "config/examples/dispatch.follow.sh"
            }
          }
        ]
      }
    },
    "memory": {
      "template": "content",
      "content": {
        "title": "Memoria de equipo",
        "description": "echo guarda un documento de memoria por organización y por proyecto: lo que tu equipo sabe de ese repositorio. Cada sesión de cada miembro arranca con ese contexto puesto.",
        "sections": [
          {
            "title": "Un documento por proyecto",
            "content": "La unidad de memoria es un documento markdown identificado por el projectId, el hash sha256 del remoto git del repo. Como todos los clientes derivan el mismo projectId, el CLI, cosmos chat y el autopiloto leen y escriben el mismo documento sin configuración.",
            "list": [
              "Aislado por tenant: la memoria de tu organización jamás se mezcla con otra",
              "Versionado con historial de revisiones",
              "Concurrencia optimista: cada escritura lleva If-Match con la versión que leíste; si alguien escribió antes, la tuya se rechaza y reintentas sobre lo nuevo"
            ]
          },
          {
            "title": "Quién la lee y quién la escribe",
            "table": {
              "headers": [
                "Actor",
                "Rol",
                "Cuándo"
              ],
              "rows": [
                [
                  "cosmos prime",
                  "Lee",
                  "Al arrancar cada sesión de Claude Code, como contexto inyectado"
                ],
                [
                  "cosmos memory push",
                  "Escribe",
                  "Cuando curas la memoria a mano desde el CLI"
                ],
                [
                  "pilot (autopiloto)",
                  "Escribe",
                  "En segundo plano, con redacción de secretos y opt-in de equipo"
                ],
                [
                  "cosmos chat",
                  "Lee y escribe",
                  "Mismo documento, mismo projectId"
                ]
              ]
            }
          },
          {
            "title": "Trabaja con ella desde el CLI",
            "code": {
              "language": "bash",
              "title": "Ver, bajar y subir",
              "content": "cosmos memory show\ncosmos memory pull --out MEMORY.md\ncosmos memory push --file MEMORY.md"
            },
            "content": "show imprime el documento del proyecto actual; pull lo baja a un archivo para editarlo con calma; push lo sube con control de versión. Si el push choca con una escritura concurrente, baja la última versión y reaplica tu cambio."
          },
          {
            "title": "Qué sube y qué no",
            "content": "La memoria de equipo es de equipo: convenciones del proyecto, decisiones de arquitectura, gotchas del repo. Tu memoria personal global (tus preferencias, tu historial) no se sube a un documento compartido; el autopiloto redacta secretos antes de escribir y solo participa si el equipo lo habilitó.",
            "callout": {
              "type": "warning",
              "title": "Nada de secretos",
              "content": "La memoria es un documento compartido por la organización. Las credenciales van en un gestor de secretos, nunca en la memoria."
            }
          },
          {
            "title": "Cómo viaja",
            "content": "echo no está expuesto a internet: el CLI habla con capcom (/memory/:projectId) y capcom proxea a echo con un token mesh que lleva tu identidad. Un solo host público, misma cadena de confianza."
          }
        ]
      }
    },
    "autopilot": {
      "template": "content",
      "content": {
        "title": "El autopiloto",
        "description": "pilot es un daemon que corre en tu máquina, sin comandos, y hace que cosmos aprenda de ti: espeja tus subagentes, cura la memoria de tus proyectos y destila tu historial de IA en hechos útiles.",
        "sections": [
          {
            "title": "Qué es",
            "content": "pilot corre en segundo plano (launchd en macOS) con la sesión de tu keychain, y habla con la plataforma únicamente por el gateway. Cada tick ejecuta tres subsistemas independientes. Es el motor del principio el cerebro vive con el dev: el aprendizaje ocurre en tu máquina, con tu claude -p, y solo el resultado curado viaja a la plataforma."
          },
          {
            "title": "Espejo de subagentes",
            "content": "Lee los subagentes que ya definiste en ~/.claude/agents y los clona como capsule agents en el registro de la flota. Un subagente es en esencia un rol (un system prompt): exactamente lo que un capsule necesita. Tus especialistas de Claude Code se vuelven agentes despachables por toda tu organización sin reescribir nada."
          },
          {
            "title": "Espejo de memoria",
            "content": "Recolecta el CLAUDE.md de cada proyecto, redacta secretos y, con el opt-in del equipo, escribe el resultado a la memoria de equipo en echo. La memoria global personal nunca sube a un documento compartido.",
            "list": [
              "Redacción de secretos antes de cualquier escritura",
              "Opt-in explícito por equipo: sin permiso, no se sube nada",
              "Diff por contenido: solo se escribe lo que cambió"
            ]
          },
          {
            "title": "Lookback: destilar tu historial",
            "content": "El subsistema más ambicioso: toma tu historial de IA previo (sesiones de Claude Code, exports de ChatGPT, historial de Cursor) y lo destila con claude -p a hechos útiles y portables, que guarda en echo. El diff es por contenido: solo re-destila lo que cambió desde la última pasada.",
            "callout": {
              "type": "info",
              "title": "Tu cómputo, tu suscripción",
              "content": "La destilación corre con tu claude -p local. Nada de tu historial crudo viaja a la plataforma; solo los hechos destilados y curados."
            }
          },
          {
            "title": "Límites actuales",
            "content": "El autopiloto está vivo y verificado de extremo a extremo, con pendientes conocidos que no bloquean su uso.",
            "list": [
              "El refresh de token dentro del daemon está pendiente: si la sesión expira, el daemon espera a que vuelvas a hacer login",
              "El registro remoto de subagentes usa el registro de flota vía gateway; el cableado completo desde pilot está en curso",
              "La persistencia remota de tu memoria personal es una decisión de producto aún abierta"
            ]
          }
        ]
      }
    },
    "onboarding": {
      "template": "content",
      "content": {
        "title": "Onboarding",
        "description": "cosmos onboard es la experiencia de primer uso: en una sola pantalla te presenta tu identidad, tu flota y la memoria de tu equipo, te sugiere primeras tareas reales y te guía en cinco pasos.",
        "sections": [
          {
            "title": "Qué hace",
            "content": "El comando hidrata tres cosas de producción con tu sesión (quién eres y en qué organización estás, qué agentes tienes disponibles y qué sabe ya tu equipo del proyecto), y con eso arma una guía personalizada: las primeras tareas que sugiere salen de las capacidades reales de tu flota, no de una lista fija.",
            "code": {
              "language": "bash",
              "title": "Primer contacto",
              "content": "cosmos onboard"
            }
          },
          {
            "title": "Los cinco pasos",
            "steps": [
              {
                "number": 1,
                "title": "welcome",
                "description": "Quién eres: tu cuenta, tu organización activa y el estado de tu sesión."
              },
              {
                "number": 2,
                "title": "hydrate",
                "description": "Cablea tu repo con cosmos init y comprueba que prime inyecta contexto."
              },
              {
                "number": 3,
                "title": "build",
                "description": "Tu primer despacho real, con una tarea sugerida desde las capacidades de tu flota."
              },
              {
                "number": 4,
                "title": "team",
                "description": "Invita a tu equipo y comparte la memoria del proyecto."
              },
              {
                "number": 5,
                "title": "done",
                "description": "El cierre: el resumen de lo que quedó funcionando y a dónde ir después."
              }
            ]
          },
          {
            "title": "Progreso que te sigue",
            "content": "Tu avance se guarda por usuario en echo con la misma concurrencia optimista (If-Match) del resto de la memoria: puedes cerrar la terminal y retomar donde ibas, desde cualquier máquina con tu sesión. cosmos onboard --reset reinicia la guía si quieres recorrerla de nuevo.",
            "callout": {
              "type": "note",
              "title": "Motor portable",
              "content": "El motor del onboarding es lógica pura separada del CLI, pensada para extraerse como paquete y reutilizarse en el chat y el IDE con la misma progresión."
            }
          }
        ]
      }
    },
    "fleet-model": {
      "template": "content",
      "content": {
        "title": "Anatomía de la flota",
        "description": "La flota de cosmos no es un clúster de servidores con GPU: es un registro de manifiestos donde conviven dos especies de agente, y una regla de oro sobre dónde corre el cerebro.",
        "sections": [
          {
            "title": "Dos especies de agente",
            "content": "Todo agente de la flota se describe con un manifiesto (nombre, descripción, capacidades). La diferencia está en cómo se ejecuta: un agente de servicio corre como proceso HTTP con un endpoint /execute al que se le hace POST; un capsule agent no tiene proceso propio, es solo un registro con un systemPrompt que se ejecuta bajo demanda con claude -p en la máquina del desarrollador.",
            "table": {
              "headers": [
                "",
                "Agente HTTP",
                "Capsule agent"
              ],
              "rows": [
                [
                  "Qué es",
                  "Un servicio con endpoint /execute",
                  "Un registro con systemPrompt"
                ],
                [
                  "Dónde corre",
                  "En el servidor (o donde se despliegue)",
                  "En tu máquina, con tu claude -p"
                ],
                [
                  "Costo en reposo",
                  "RAM y CPU del proceso",
                  "Cero: es una fila en el ledger"
                ],
                [
                  "Ejemplo",
                  "fusion (conversión de archivos)",
                  "sirius, magnitude, chroma, azimuth, halo"
                ],
                [
                  "Quién paga el cómputo",
                  "La plataforma",
                  "Cada dev con su suscripción"
                ]
              ]
            }
          },
          {
            "title": "El cerebro vive con el dev",
            "content": "Es una decisión de diseño, no una limitación: los agentes con LLM corren como capsules en la máquina de cada desarrollador, invocando el CLI de Claude en modo headless. Cada quien trae su cómputo y su suscripción, el control plane se mantiene delgado y ningún dato de tu código viaja a un ejecutor central.",
            "code": {
              "language": "bash",
              "title": "Lo que ejecuta un capsule por dentro",
              "content": "claude -p \"<intención>\" --append-system-prompt \"<systemPrompt del agente>\" --output-format json --model sonnet"
            },
            "callout": {
              "type": "warning",
              "title": "Regla de la plataforma",
              "content": "La generación con LLM usa siempre el CLI de Claude (suscripción del dev), nunca la API de pago. Los capsules heredan esta regla por construcción."
            }
          },
          {
            "title": "La flota de plataforma: el tenant cosmos-system",
            "content": "Los agentes que cosmos regala a todos los equipos viven registrados en un tenant de sistema llamado cosmos-system. Cuando pides la flota, capcom mezcla los agentes de tu organización con los de plataforma; cygnus hace la misma mezcla al rutear trabajo. El resultado: toda organización nueva ve una flota útil desde el primer día, sin registrar nada.",
            "list": [
              "Descubrimiento: GET /agents en capcom devuelve tu flota + la de cosmos-system",
              "Ruteo: cygnus considera ambas al elegir agente para un waypoint",
              "Prioridad: si registras un agente con el mismo nombre, el tuyo gana en tu tenant",
              "El systemPrompt se considera configuración de operador: capcom lo quita de las respuestas de descubrimiento"
            ]
          },
          {
            "title": "Registrar y quitar agentes",
            "content": "El registro es un insert en el ledger, aislado por tenant. Registrar no despliega nada; quitar no apaga procesos. Por eso la flota escala sin costo: el servidor solo guarda fichas.",
            "table": {
              "headers": [
                "Operación",
                "Camino",
                "Efecto"
              ],
              "rows": [
                [
                  "Registrar",
                  "POST /agents vía capcom (o cosmos fleet register)",
                  "El agente aparece en el descubrimiento de tu tenant"
                ],
                [
                  "Quitar",
                  "DELETE /agents/:name vía capcom (o cosmos fleet unregister)",
                  "Desaparece del descubrimiento; nada que apagar"
                ],
                [
                  "Listar",
                  "GET /agents (cosmos agents o cosmos fleet list)",
                  "Tu flota + la de plataforma"
                ]
              ]
            }
          },
          {
            "title": "Dónde vive cada pieza",
            "content": "El registro nativo de agentes está en ephemeris (el ledger). capcom lo proxea con la identidad del tenant. La lógica compartida de descubrimiento, ruteo y ejecución (discoverAgents, route, executeAgent, executeCapsuleAgent) vive en substrate, la librería común de Continuum, y la usan tanto cygnus en el servidor como el CLI en tu máquina.",
            "note": "La flota creativa tiene además servicios Python reales (services/sirius y compañía, sobre el package filament) que hoy no se usan: los capsules con systemPrompt resultaron más simples y fieles a la regla del CLI. Portar esa lógica específica es trabajo futuro."
          }
        ]
      }
    },
    "platform-agents": {
      "template": "content",
      "content": {
        "title": "Agentes de plataforma",
        "description": "La flota base que toda organización recibe al entrar: un agente de servicio para archivos y cinco capsules creativos. Cada uno declara capacidades con palabras clave; el ruteo las usa para empatar tu intención.",
        "sections": [
          {
            "title": "La flota viva",
            "cards": [
              {
                "icon": "fas fa-arrows-rotate",
                "title": "fusion",
                "description": "Conversión de archivos e imágenes, documentos a PDF y OCR. Agente HTTP en el servidor.",
                "link": "#fusion"
              },
              {
                "icon": "fas fa-bullhorn",
                "title": "sirius",
                "description": "Estratega de campañas de marca y personas de audiencia sintéticas.",
                "link": "#platform-agents"
              },
              {
                "icon": "fas fa-magnifying-glass-chart",
                "title": "magnitude",
                "description": "Auditorías SEO técnicas y de contenido con mejoras priorizadas.",
                "link": "#platform-agents"
              },
              {
                "icon": "fas fa-palette",
                "title": "chroma",
                "description": "Paletas de color y dirección visual para tu marca.",
                "link": "#platform-agents"
              },
              {
                "icon": "fas fa-object-group",
                "title": "azimuth",
                "description": "Wireframes y flujos de UX para pantallas y features.",
                "link": "#platform-agents"
              },
              {
                "icon": "fas fa-hashtag",
                "title": "halo",
                "description": "Borradores de publicaciones para redes sociales.",
                "link": "#platform-agents"
              }
            ]
          },
          {
            "title": "fusion — el agente que se queda en el servidor",
            "content": "fusion envuelve la API de conversión co-ubicada en el servidor como un agente de cosmos. Es el ejemplo canónico de agente HTTP: expone /execute y /manifest, y cygnus o el CLI le despachan por POST. Al no necesitar LLM, no hay razón para que corra en tu máquina.",
            "table": {
              "headers": [
                "Capacidad",
                "Qué hace"
              ],
              "rows": [
                [
                  "file.convert",
                  "Convierte un archivo de un formato a otro"
                ],
                [
                  "image.convert",
                  "Imágenes: heic, jpg, png, webp, avif, tiff"
                ],
                [
                  "document.convert",
                  "Documentos a PDF: docx, xlsx, pptx"
                ],
                [
                  "pdf.convert",
                  "Rasteriza o comprime PDF"
                ],
                [
                  "ocr.extract",
                  "Extrae texto de imágenes o escaneos"
                ]
              ]
            }
          },
          {
            "title": "La flota creativa — capsules con claude -p",
            "content": "Cinco roles registrados en cosmos-system, cada uno con un systemPrompt en español que define su oficio. No tienen endpoint: cuando el ruteo los elige, tu máquina ejecuta el capsule localmente y el resultado vuelve al ledger.",
            "table": {
              "headers": [
                "Agente",
                "Capacidad",
                "Palabras clave que lo activan"
              ],
              "rows": [
                [
                  "sirius",
                  "campaign.generate",
                  "campaña, marca, marketing, lanzamiento"
                ],
                [
                  "sirius",
                  "audience.persona",
                  "persona, audiencia, segmento, público"
                ],
                [
                  "magnitude",
                  "seo.audit",
                  "seo, auditoría, posicionamiento, keywords, metadatos"
                ],
                [
                  "chroma",
                  "design.palette",
                  "diseño, color, paleta, identidad, branding, visual"
                ],
                [
                  "azimuth",
                  "uiux.wireframe",
                  "ux, ui, wireframe, pantalla, flujo, interfaz"
                ],
                [
                  "halo",
                  "social.draft",
                  "social, redes, post, publicación, instagram, tiktok"
                ]
              ]
            },
            "code": {
              "language": "bash",
              "title": "Despachar a la flota creativa",
              "file": "config/examples/platform-agents.run.sh"
            }
          },
          {
            "title": "En el hangar: construidos pero no desplegados",
            "content": "Dos agentes existen en el repositorio con lógica real y quedaron fuera de la flota viva por decisiones operativas. Se documentan para que sepas qué hay y qué falta.",
            "accordion": [
              {
                "title": "supernova — amplificación de contenido",
                "content": "Convierte grabaciones largas en clips verticales con subtítulos. Necesita Whisper y ffmpeg, demasiado pesados para el droplet actual. Correrá cuando haya un nodo con recursos de media."
              },
              {
                "title": "polaris — capa de guía",
                "content": "Un servidor MCP que expone reglas aprendidas de ti y tus proyectos (rules.search). Funciona como demo de referencia del patrón MCP; no está en la flota de plataforma."
              }
            ]
          },
          {
            "title": "Cómo se siembra la flota de plataforma",
            "content": "Dos scripts idempotentes en continuum/deploy la mantienen: platform-fleet-sync.mjs registra los agentes HTTP leyendo su GET /manifest, y creative-fleet-sync.mjs upserta los cinco capsules con sus systemPrompts. Ambos escriben en el tenant cosmos-system y son seguros de re-ejecutar.",
            "note": "Si un agente de plataforma desaparece del descubrimiento, lo primero es re-ejecutar el sync correspondiente: es un upsert por nombre."
          }
        ]
      }
    },
    "custom-agents": {
      "template": "content",
      "content": {
        "title": "Crea tus propios agentes",
        "description": "Registrar un agente en cosmos es declarar quién es y qué sabe hacer. Para un capsule, eso es todo: sin servidores, sin despliegues, sin costo en reposo.",
        "sections": [
          {
            "title": "Qué es un manifiesto de agente",
            "content": "Toda la flota habla el mismo contrato: un manifiesto con nombre, descripción y una lista de capacidades. Cada capacidad tiene un id (verbo.objeto), una descripción y palabras clave que alimentan el ruteo. Los capsules agregan un systemPrompt; los agentes HTTP agregan un endpoint.",
            "fields": [
              {
                "name": "name",
                "type": "string",
                "required": true,
                "description": "Identificador único del agente en tu tenant (minúsculas)"
              },
              {
                "name": "description",
                "type": "string",
                "required": false,
                "description": "Una línea sobre su oficio; los clientes la muestran en el roster"
              },
              {
                "name": "capabilities",
                "type": "Capability[]",
                "required": true,
                "description": "Lo que sabe hacer: id, description y keywords por capacidad"
              },
              {
                "name": "systemPrompt",
                "type": "string",
                "required": false,
                "description": "El rol del capsule; capcom lo oculta en el descubrimiento"
              },
              {
                "name": "endpoint",
                "type": "string",
                "required": false,
                "description": "URL del servicio si es agente HTTP con /execute"
              }
            ]
          },
          {
            "title": "Camino 1: registrar desde el CLI",
            "content": "cosmos fleet register arma el manifiesto por ti. Las capacidades se declaran con el formato id:palabra1,palabra2. Repite --capability para declarar varias.",
            "code": {
              "language": "bash",
              "title": "Registrar un agente propio",
              "file": "config/examples/custom-agents.register.sh"
            },
            "note": "El registro va al registro de agentes de tu tenant, aislado por construcción: ningún otro tenant ve tus agentes ni puede tocarlos."
          },
          {
            "title": "Camino 2: registrar por la API",
            "content": "El mismo registro por HTTP: POST /agents en capcom con tu JWT. capcom escribe on-behalf-of en el ledger con el tenant de tu token, nunca de un parámetro. DELETE /agents/:name lo quita.",
            "code": {
              "language": "bash",
              "title": "POST /agents vía capcom",
              "file": "config/examples/custom-agents.api.sh"
            }
          },
          {
            "title": "Camino 3: el espejo automático de subagentes",
            "content": "Si ya tienes subagentes de Claude Code definidos en ~/.claude/agents, el daemon pilot los clona como capsule agents de tu flota: mismo rol, mismas instrucciones, ahora despachables por cosmos y visibles para tu equipo. Es la vía sin fricción: defines el agente una vez donde ya trabajas y cosmos lo aprende.",
            "list": [
              "pilot lee ~/.claude/agents en cada tick",
              "Cada subagente se vuelve un manifiesto capsule (el prompt es el systemPrompt)",
              "El espejo es idempotente: cambios en el archivo actualizan el registro"
            ]
          },
          {
            "title": "Buenas prácticas de systemPrompt",
            "content": "El systemPrompt es el oficio del agente, no una conversación. Lo que funciona en la flota de plataforma sirve de plantilla.",
            "list": [
              "Define el rol en segunda persona y en presente: eres el estratega de...",
              "Declara el formato de salida esperado (estructura, idioma, longitud)",
              "Incluye las restricciones duras (sin emojis, español correcto, no inventar datos)",
              "Mantén las palabras clave de las capacidades alineadas con el vocabulario real de tus intenciones",
              "Un agente = un oficio; dos oficios distintos rutean mejor como dos agentes"
            ]
          },
          {
            "title": "Ciclo de vida",
            "steps": [
              {
                "number": 1,
                "title": "Declara",
                "description": "Registra el manifiesto con nombre, capacidades y systemPrompt."
              },
              {
                "number": 2,
                "title": "Verifica",
                "description": "cosmos agents debe listarlo; cosmos run con una intención afín debe rutearlo."
              },
              {
                "number": 3,
                "title": "Itera",
                "description": "Ajusta keywords y prompt según qué intenciones quieres que capture."
              },
              {
                "number": 4,
                "title": "Retira",
                "description": "cosmos fleet unregister --name <agente> cuando deje de tener sentido."
              }
            ]
          }
        ]
      }
    },
    "routing": {
      "template": "content",
      "content": {
        "title": "Capacidades y ruteo",
        "description": "Cosmos no adivina qué agente quieres: empata tu intención contra las capacidades declaradas de la flota con un algoritmo simple y predecible.",
        "sections": [
          {
            "title": "Quién entiende qué",
            "content": "Hay dos niveles de interpretación y conviene no confundirlos. El nivel LLM ocurre en el cliente: el modelo con el que ya conversas (en cosmos chat o Claude Code) decide llamar la herramienta de despacho y redacta la intención. El nivel de ruteo es determinista: esa intención se tokeniza y se compara contra las capacidades de cada agente registrado.",
            "callout": {
              "type": "tip",
              "title": "Por qué importa",
              "content": "El ruteo es depurable: con la misma flota y la misma intención, siempre gana el mismo agente. Si rutea mal, se arregla con keywords, no con suerte."
            }
          },
          {
            "title": "El algoritmo, exacto",
            "content": "La función route de substrate tokeniza la intención (minúsculas, alfanumérico) y puntúa cada capacidad: coincidencia exacta con un token del id o de las keywords suma 2, coincidencia parcial (un término contiene al otro) suma 1. Gana la capacidad con mayor puntaje; empates los resuelve el orden de la flota. Si pasas una capacidad explícita, no hay puntaje: se busca el primer agente que la declare.",
            "code": {
              "language": "text",
              "title": "Ejemplo de puntaje",
              "file": "config/examples/routing.score.txt"
            }
          },
          {
            "title": "Quién rutea en cada camino",
            "table": {
              "headers": [
                "Camino",
                "Quién rutea",
                "Dónde ejecuta"
              ],
              "rows": [
                [
                  "cosmos run \"...\"",
                  "El CLI (routeLocal) contra la flota descubierta por capcom",
                  "Capsule: local con tu claude -p; HTTP: despacho por capcom"
                ],
                [
                  "Manifest por capcom",
                  "cygnus al reconciliar cada waypoint de agente",
                  "Según el agente elegido"
                ],
                [
                  "cosmos chat / IDE",
                  "El modelo elige la herramienta MCP; el despacho rutea igual",
                  "Igual que el CLI"
                ]
              ]
            }
          },
          {
            "title": "Forzar el destino",
            "content": "Cuando sabes exactamente qué capacidad quieres, sáltate el puntaje.",
            "code": {
              "language": "bash",
              "title": "Capacidad explícita",
              "content": "cosmos run \"convierte estas fotos\" --capability image.convert"
            }
          },
          {
            "title": "Si nada empata",
            "content": "Puntaje cero en toda la flota significa que ninguna capacidad comparte vocabulario con tu intención. El CLI lo reporta como error accionable en vez de elegir al azar.",
            "list": [
              "Revisa cosmos agents: la capacidad que esperabas puede no estar registrada",
              "Reformula la intención con el vocabulario de las keywords del agente",
              "O registra la capacidad que falta en tu propio agente"
            ]
          },
          {
            "title": "Diseñar capacidades que ruteen bien",
            "list": [
              "Ids con forma verbo.objeto (seo.audit, campaign.generate): los tokens del id también puntúan",
              "Keywords en el idioma en que tu equipo escribe intenciones (y en ambos si mezclan)",
              "Evita keywords genéricas (crear, hacer): capturan intenciones ajenas",
              "Capacidades específicas ganan a las genéricas porque acumulan coincidencias exactas"
            ],
            "note": "Existe además un ruteo de modelos separado (qué modelo de Claude usa un paso: trivial va al barato) en substrate; es independiente del ruteo de agentes y hoy opera con una política local."
          }
        ]
      }
    },
    "cli": {
      "template": "content",
      "content": {
        "title": "cosmos CLI",
        "description": "El binario cosmos (herramienta telescope del monorepo) es la puerta de entrada a toda la plataforma desde la terminal: sesión, flota, despacho, memoria y el cableado de tu repo.",
        "sections": [
          {
            "title": "Sesión y cuenta",
            "content": "La sesión vive en el keychain del sistema (con fallback a archivo protegido) y se refresca sola. El login por defecto abre el navegador: apruebas, copias un código de un solo uso y lo pegas en la terminal.",
            "accordion": [
              {
                "title": "cosmos login",
                "content": "Abre auth.thecosmosai.cloud/authorize en el navegador (flujo con PKCE); pegas el código y quedas dentro. Variantes: --device para aprobar sin pegar código (RFC 8628), --token <token> para pegar un token personal creado en /tokens, y --email/--password con --password-flow para scripts o CI. --auth-url apunta a otro emisor (desarrollo local)."
              },
              {
                "title": "cosmos logout",
                "content": "Cierra y revoca la sesión local."
              },
              {
                "title": "cosmos orgs [list] / cosmos orgs switch <orgId>",
                "content": "Lista tus organizaciones o cambia la organización activa; el cambio re-emite el token con el tenant nuevo."
              },
              {
                "title": "cosmos invite <correo> [--role owner|admin|member|viewer] [--org <orgId>]",
                "content": "Invita a alguien a tu organización con un rol. cosmos invite accept <código> consume una invitación recibida."
              },
              {
                "title": "cosmos onboard [--reset] [--json]",
                "content": "Recorrido guiado de primer uso: hidrata tu identidad, flota y memoria de equipo, sugiere primeras tareas según las capacidades disponibles y te lleva paso a paso hasta el primer despacho. --reset lo reinicia."
              }
            ]
          },
          {
            "title": "Flota y despacho",
            "accordion": [
              {
                "title": "cosmos agents [--json]",
                "content": "Lista la flota visible de tu tenant (la tuya + la de plataforma) vía capcom. --json para consumo por scripts u otros clientes."
              },
              {
                "title": "cosmos run \"<intención>\" [--capability <id>] [--input <json>]",
                "content": "El despacho completo: crea un manifest durable en capcom, rutea la intención contra la flota y ejecuta. Si el elegido es un capsule, corre local con tu claude -p; si es HTTP, va por el gateway. --capability fuerza el destino; --input pasa datos estructurados al agente."
              },
              {
                "title": "cosmos fleet list / register / unregister / sync",
                "content": "Administración del registro: list muestra manifiestos; register da de alta con --name, --endpoint (si es HTTP) y --capability \"id:kw1,kw2\" repetible; unregister --name quita; sync --from copia agentes desde el orquestador legado."
              },
              {
                "title": "cosmos mcp-serve",
                "content": "Expone tu flota como servidor MCP por stdio: Claude Code (u otro cliente MCP) gana las herramientas de listar agentes y despachar tareas. Es lo que cosmos init cablea en .mcp.json."
              }
            ]
          },
          {
            "title": "Tu repo y el flujo diario",
            "accordion": [
              {
                "title": "cosmos init [--rig <id>] [--crew <alias>]",
                "content": "Cablea el repositorio: escribe el estado del rig (gateway, projectId derivado del remoto git), registra el MCP de la flota en .mcp.json e instala los hooks de ciclo de vida para que cada sesión de Claude Code se hidrate sola. Idempotente: seguro de re-ejecutar."
              },
              {
                "title": "cosmos prime [--hook | --checkpoint]",
                "content": "La hidratación: trae en paralelo tu tether (waypoints asignados), la memoria de equipo del proyecto y el correo de crew, y lo imprime como contexto. --hook emite el formato de SessionStart para Claude Code; --checkpoint es el hook de cierre (los waypoints cerrados son el checkpoint durable, no persiste nada más)."
              },
              {
                "title": "cosmos mail [--check --inject] [--send <crew> --text \"...\"]",
                "content": "El correo del crew: revisa mensajes, inyéctalos a la sesión o envía uno a otro miembro."
              },
              {
                "title": "cosmos done <waypointId>",
                "content": "Cierra un waypoint del ledger: así se reporta trabajo terminado para que el reconciliador no lo re-ejecute."
              }
            ]
          },
          {
            "title": "Memoria de equipo",
            "accordion": [
              {
                "title": "cosmos memory show [--project <id>]",
                "content": "Muestra el documento de memoria del proyecto (por defecto, el del repo actual)."
              },
              {
                "title": "cosmos memory pull [--out <archivo>]",
                "content": "Descarga la memoria a un archivo para editarla con calma."
              },
              {
                "title": "cosmos memory push --file <archivo>",
                "content": "Publica tu versión curada; la concurrencia optimista evita pisar cambios de otros."
              }
            ]
          },
          {
            "title": "Configuración",
            "content": "Todo se resuelve en cascada: flag explícito, luego el rig del repo, luego variables de entorno, luego ~/.config/cosmos/config.json, y al final defaults de desarrollo local.",
            "table": {
              "headers": [
                "Variable",
                "Qué controla",
                "Default"
              ],
              "rows": [
                [
                  "COSMOS_CAPCOM_URL",
                  "URL de capcom, el gateway de la flota",
                  "http://127.0.0.1:9060"
                ],
                [
                  "COSMOS_AUTH_URL",
                  "URL del servicio de identidad (eclipse)",
                  "http://localhost:3001"
                ],
                [
                  "COSMOS_EPHEMERIS_URL",
                  "URL del ledger (desarrollo local)",
                  "http://127.0.0.1:9050"
                ],
                [
                  "COSMOS_ECHO_URL",
                  "URL de la memoria de equipo",
                  "vía gateway"
                ],
                [
                  "COSMOS_ORCHESTRATION",
                  "capcom (default) u orchestrator (legado)",
                  "capcom"
                ],
                [
                  "COSMOS_CONFIG_DIR",
                  "Carpeta de configuración",
                  "~/.config/cosmos"
                ]
              ]
            },
            "note": "En producción no necesitas variables: cosmos init deja el rig apuntando al gateway y el login guarda el emisor. Los flags --capcom-url, --auth-url y compañía existen en casi todos los comandos para entornos de desarrollo."
          },
          {
            "title": "Un día con el CLI",
            "code": {
              "language": "bash",
              "title": "Flujo típico",
              "file": "config/examples/cli.daily.sh"
            }
          }
        ]
      }
    },
    "chat": {
      "template": "content",
      "content": {
        "title": "cosmos chat",
        "description": "El cliente conversacional de la plataforma: un fork de opencode con la flota como compañeros de equipo, la memoria de equipo integrada y un cerebro a tu elección.",
        "sections": [
          {
            "title": "Qué es",
            "content": "cosmos chat es un fork mantenido de opencode (TUI de agentes de código, MIT) con la capa cosmos integrada: el MCP de la flota y el proveedor local se auto-inyectan al arrancar, el tema ember es el default y el onboarding de primer uso te conecta a la plataforma. Se sincroniza a diario con el upstream para heredar mejoras.",
            "note": "El cerebro del chat es el modelo que tú configures: OpenAI, Gemini, DeepSeek u Ollama local. La suscripción de Claude está reservada para los capsules de la flota; no se usa como cerebro del chat."
          },
          {
            "title": "La flota como compañeros",
            "content": "El roster vivo de tu flota se inyecta como agentes mencionables: escribe @sirius y despacha con esa identidad fija. Cada compañero conoce sus capacidades (incluido su inputSchema si lo publica) y las instrucciones de despacho síncrono o asíncrono.",
            "list": [
              "@agente <intención> despacha directo a ese agente",
              "El despacho asíncrono devuelve un taskId al instante y el chat sigue conversando",
              "Un notifier interno vigila la tarea y avisa con un toast cuando termina",
              "Los hilos con un agente conservan contexto multi-turno (sessionId)"
            ]
          },
          {
            "title": "Memoria en dos niveles",
            "content": "El chat mantiene una memoria markdown automática por proyecto (se carga en cada sesión y el modelo la mantiene sin fricción) y además participa de la memoria de equipo de cosmos: el mismo projectId que el CLI, espejo offline-first contra echo y sincronización por el gateway con refresh de token.",
            "table": {
              "headers": [
                "Memoria",
                "Alcance",
                "Dónde vive"
              ],
              "rows": [
                [
                  "Del proyecto (local)",
                  "Tu máquina",
                  "Archivo markdown por projectId"
                ],
                [
                  "De equipo (echo)",
                  "Todo tu tenant",
                  "Documento por proyecto en producción, vía capcom"
                ]
              ]
            }
          },
          {
            "title": "Qué hereda de opencode",
            "content": "Toda la maquinaria de un agente de código moderno ya viene del upstream y no se duplica: modos build/plan, undo y redo, comandos slash propios, skills, plugins, permisos granulares por patrón, subagentes por archivo y modo headless con servidor.",
            "list": [
              "Web search habilitado para todos los proveedores (el upstream lo limitaba a uno)",
              "Config dir propio de cosmos con fallback al de opencode",
              "Update checks con opt-in explícito",
              "Timeout MCP ampliado para despachos largos"
            ]
          },
          {
            "title": "Estado y pendientes",
            "list": [
              "Vivo y verificado E2E con campañas reales de la flota",
              "Sync diario con upstream (merge automático local)",
              "En el backlog: rutinas programadas sobre la flota y workflows multi-agente deterministas"
            ]
          }
        ]
      }
    },
    "ide": {
      "template": "content",
      "content": {
        "title": "cosmos IDE",
        "description": "El entorno gráfico de la familia: un IDE de escritorio con agente integrado y un terminal con la flota a bordo. Es el frente en construcción más activo; esta página es honesta sobre qué existe y qué falta.",
        "sections": [
          {
            "title": "Las tres piezas",
            "cards": [
              {
                "icon": "fas fa-code",
                "title": "cosmos IDE",
                "description": "Editor de escritorio (Tauri + Monaco) con IA contextual, agente con herramientas y git integrado."
              },
              {
                "icon": "fas fa-compass",
                "title": "Pyxis",
                "description": "El agente de terminal: la mente que también se expone como servidor MCP."
              },
              {
                "icon": "fas fa-terminal",
                "title": "Aperture",
                "description": "El cuerpo gráfico del terminal (fork de Wave) que embebe a Pyxis y monta cosmos como widgets."
              }
            ]
          },
          {
            "title": "El IDE por dentro",
            "content": "El frontend se reconstruyó por capas sobre un shell propio, con una estética monocroma disciplinada. Lo funcional ya verificado compilando: IA contextual con menciones de archivos y memoria de sesión, un agente real con herramientas y línea de tiempo, edición inline con diff, búsqueda con ripgrep, operaciones de archivo, terminal persistente, diff de git con stage por archivo, push y pull, persistencia de sesión y un sandbox de sistema de archivos.",
            "note": "Pendiente el build firmado de distribución (requiere Developer ID de Apple). Hoy se ejecuta en modo desarrollo."
          },
          {
            "title": "Aperture: un terminal con la UX de Warp",
            "content": "Sobre la base de Wave (Apache 2.0), Aperture suma la experiencia que hace agradable vivir en el terminal: bloques de comando sobre los prompt markers del shell, paleta de historial multi-shell ordenada por frecuencia, autosuggestions, navegación por palabra y pestañas que se separan a su propia ventana sin matar sesiones tmux.",
            "list": [
              "Los widgets de cosmos (flota, memoria) se montan vía MCP dentro del terminal",
              "Pyxis responde desde cualquier bloque: pregunta sobre el comando que acaba de fallar",
              "La identidad de marca aparece en el build empaquetado (en dev se ve la identidad del bundle de desarrollo)"
            ]
          },
          {
            "title": "Cómo se conecta a la plataforma",
            "content": "El IDE y el terminal hablan con cosmos por el mismo camino que todos los clientes: sesión de umbra en el keychain, flota vía el MCP de telescope y memoria de equipo por el gateway. No hay un camino privilegiado: lo que el IDE puede hacer, tu terminal también.",
            "table": {
              "headers": [
                "Integración",
                "Mecanismo"
              ],
              "rows": [
                [
                  "Flota",
                  "MCP de cosmos (mcp-serve) como en Claude Code"
                ],
                [
                  "Sesión",
                  "umbra (keychain del sistema)"
                ],
                [
                  "Memoria de equipo",
                  "echo vía capcom, projectId unificado"
                ],
                [
                  "Agente de terminal",
                  "Pyxis embebido como servidor MCP en Aperture"
                ]
              ]
            }
          },
          {
            "title": "Estado real",
            "list": [
              "IDE: funcional en desarrollo; falta distribución firmada",
              "Aperture: paridad Warp en curso, verificada con typecheck y tests; iteración en dev continua",
              "Pyxis: renombrado y operativo como agente MCP; un check de compilación depende de una dependencia privada"
            ]
          }
        ]
      }
    },
    "admin": {
      "template": "content",
      "content": {
        "title": "Back office",
        "description": "cosmos-admin es el panel de operación de la plataforma: la vista de Dado Company sobre usuarios, organizaciones, sesiones y seguridad, respaldada por la API admin de eclipse.",
        "sections": [
          {
            "title": "Qué puedes operar hoy",
            "content": "El panel de administración de plataforma tiene tres pestañas reales contra eclipse: usuarios de toda la plataforma (paginado por cursor), organizaciones, y alertas de seguridad recientes. Desde usuarios se listan las sesiones activas de cada quien y se revocan al instante.",
            "cards": [
              {
                "icon": "fas fa-users",
                "title": "Usuarios",
                "description": "Búsqueda y paginado keyset; detalle con sesiones activas y revocación."
              },
              {
                "icon": "fas fa-building",
                "title": "Organizaciones",
                "description": "Las orgs de la plataforma con su membresía."
              },
              {
                "icon": "fas fa-shield-halved",
                "title": "Alertas de seguridad",
                "description": "Eventos recientes: logins nuevos, contraseñas cambiadas, sesiones revocadas."
              }
            ]
          },
          {
            "title": "Quién puede entrar",
            "content": "La autorización no es una columna editable en la base: eclipse emite el claim platformRole=admin solo a una lista blanca de correos configurada en el servicio, y solo si el correo está verificado. Sin ese claim, la API admin responde 403 sin importar qué rol tengas en tu organización.",
            "callout": {
              "type": "info",
              "title": "Dos logins distintos",
              "content": "Entrar al back office es entrar a la plataforma como operador (claim de plataforma), no como miembro de una organización. Son autorizaciones independientes."
            }
          },
          {
            "title": "Arquitectura del cliente",
            "content": "El frontend (React + Vite) habla con un cliente de API intercambiable: modo http contra eclipse real y modo mock con datos sintéticos para desarrollo sin backend. El modo se elige con la variable VITE_ADMIN_API_MODE.",
            "code": {
              "language": "bash",
              "title": "Levantar el admin en local",
              "file": "config/examples/admin.local.sh"
            }
          },
          {
            "title": "Honestidad sobre el estado",
            "content": "El repositorio arrastra páginas heredadas de una era anterior del producto; el plan de renovación las está demoliendo. Lo real y respaldado por eclipse es lo descrito arriba: login, resumen, panel de plataforma (usuarios, organizaciones, seguridad), página de organización e invitaciones. Todo lo demás que encuentres en el código debe asumirse mock hasta que su página diga lo contrario.",
            "warning": "Si una vista del admin muestra datos demasiado perfectos, probablemente es el cliente mock. Verifica el modo antes de sacar conclusiones operativas."
          },
          {
            "title": "Conexiones",
            "table": {
              "headers": [
                "Consume",
                "De",
                "Para"
              ],
              "rows": [
                [
                  "API admin (/api/v1/admin/*)",
                  "eclipse",
                  "Usuarios, orgs, sesiones, eventos de seguridad"
                ],
                [
                  "Login",
                  "eclipse",
                  "JWT con claim platformRole=admin"
                ],
                [
                  "Revocación de sesiones",
                  "eclipse",
                  "Cerrar sesiones comprometidas al instante"
                ]
              ]
            }
          }
        ]
      }
    },
    "artifacts-map": {
      "template": "content",
      "content": {
        "title": "Mapa de artefactos",
        "description": "Todos los artefactos de la plataforma, organizados por capa: qué es cada uno, en qué estado está y dónde vive. Cada nombre es astronómico y deliberado: la metáfora codifica el rol del módulo.",
        "sections": [
          {
            "title": "Las cinco capas",
            "content": "Cosmos es un orquestador multi-tenant de agentes que aprende del usuario. Se lee de abajo hacia arriba: la flota ejecuta, el control plane hace el trabajo durable, el gateway es la única puerta, la identidad firma cada petición y los clientes son la superficie con el desarrollador.",
            "table": {
              "headers": [
                "Capa",
                "Artefactos",
                "Responsabilidad"
              ],
              "rows": [
                [
                  "Clientes",
                  "telescope (CLI), cosmos chat, cosmos IDE, back office",
                  "La superficie con el desarrollador; todos hablan por el gateway"
                ],
                [
                  "Identidad",
                  "eclipse, umbra",
                  "Emitir y verificar la identidad; el JWT RS256 es el hilo de confianza"
                ],
                [
                  "Gateway",
                  "capcom",
                  "Única puerta pública; valida el token y proxea todo on-behalf-of del tenant"
                ],
                [
                  "Control plane (Continuum)",
                  "ephemeris, cygnus, ignition, airlock, pilot, echo",
                  "Trabajo durable, reconciliación, memoria de equipo"
                ],
                [
                  "Flota",
                  "fusion (HTTP), sirius, magnitude, chroma, azimuth, halo (capsules)",
                  "Los agentes que ejecutan; el cerebro corre con el cómputo de cada desarrollador"
                ]
              ]
            },
            "note": "Dos principios gobiernan el diseño: el control plane se mantiene delgado y multi-tenant, y los agentes con LLM corren como capsules en la máquina de cada desarrollador con su propio claude -p, nunca con la API de pago."
          },
          {
            "title": "Identidad y acceso",
            "cards": [
              {
                "icon": "fas fa-circle-half-stroke",
                "title": "eclipse",
                "description": "El emisor de identidad: usuarios, organizaciones, sesiones, tokens RS256 y JWKS público.",
                "link": "#eclipse"
              },
              {
                "icon": "fas fa-id-badge",
                "title": "umbra",
                "description": "El cliente de auth compartido: un solo camino de login, refresh y keychain para todos los clientes.",
                "link": "#umbra"
              }
            ]
          },
          {
            "title": "Gateway y control plane",
            "cards": [
              {
                "icon": "fas fa-tower-broadcast",
                "title": "capcom",
                "description": "La única voz pública entre los clientes y el control plane, como el capsule communicator de mission control.",
                "link": "#capcom"
              },
              {
                "icon": "fas fa-book",
                "title": "ephemeris",
                "description": "El ledger durable sobre Dolt y el registro nativo de la flota; la fuente de verdad, un store por tenant.",
                "link": "#ephemeris"
              },
              {
                "icon": "fas fa-rotate",
                "title": "cygnus",
                "description": "El reconciliador que empuja el trabajo a hecho, como la nave de resuministro que mantiene la estación abastecida.",
                "link": "#cygnus"
              },
              {
                "icon": "fas fa-fire-flame-simple",
                "title": "ignition y airlock",
                "description": "El runtime de capsules y la cola de merge: cómo se ejecuta un paso y cómo aterrizan los cambios.",
                "link": "#ignition-airlock"
              },
              {
                "icon": "fas fa-plane",
                "title": "pilot",
                "description": "El autopiloto local: espeja tus subagentes y tu memoria, y destila tu historial de IA.",
                "link": "#pilot"
              },
              {
                "icon": "fas fa-cubes-stacked",
                "title": "substrate",
                "description": "La librería que capcom, ephemeris, cygnus y pilot comparten: auth, flota, ruteo, memoria.",
                "link": "#substrate"
              }
            ]
          },
          {
            "title": "Memoria y flota",
            "cards": [
              {
                "icon": "fas fa-brain",
                "title": "echo",
                "description": "La memoria de equipo: un documento markdown por tenant y proyecto, con versiones y concurrencia optimista.",
                "link": "#echo"
              },
              {
                "icon": "fas fa-arrows-rotate",
                "title": "fusion",
                "description": "El agente HTTP de conversión de archivos; el patrón de referencia para agentes de servicio.",
                "link": "#fusion"
              },
              {
                "icon": "fas fa-users-gear",
                "title": "Flota creativa",
                "description": "sirius, magnitude, chroma, azimuth y halo: capsule agents de la flota de plataforma.",
                "link": "#platform-agents"
              }
            ]
          },
          {
            "title": "Perímetro e incubación",
            "cards": [
              {
                "icon": "fas fa-mountain-sun",
                "title": "horizon",
                "description": "API gateway Rust de alto rendimiento; el borde que toda petición cruzaría para entrar.",
                "link": "#horizon"
              },
              {
                "icon": "fas fa-flask",
                "title": "Servicios en incubación",
                "description": "aurora, gravity, nebula, parsec, quasar, prism y orbit: scaffolds sin ruta productiva todavía.",
                "link": "#scaffolds"
              },
              {
                "icon": "fas fa-box-open",
                "title": "Packages compartidos",
                "description": "filament, stardust, umbra y lo que queda de agent-kit.",
                "link": "#packages"
              }
            ]
          },
          {
            "title": "Tabla maestra",
            "content": "El estado marcado como vivo es lo desplegado en producción en thecosmosai.cloud; scaffold es código en el repo sin ruta productiva todavía.",
            "table": {
              "headers": [
                "Artefacto",
                "Capa",
                "Dónde vive",
                "Estado"
              ],
              "rows": [
                [
                  "eclipse",
                  "Identidad",
                  "services/eclipse · auth.thecosmosai.cloud",
                  "Vivo"
                ],
                [
                  "umbra / umbra-js",
                  "Identidad (cliente)",
                  "packages/umbra · packages/umbra-js",
                  "Vivo"
                ],
                [
                  "capcom",
                  "Gateway",
                  "continuum/services/capcom · capcom.thecosmosai.cloud · :9060",
                  "Vivo"
                ],
                [
                  "ephemeris",
                  "Control plane",
                  "continuum/services/ephemeris · :9050 interno",
                  "Vivo"
                ],
                [
                  "cygnus",
                  "Control plane",
                  "continuum/services/cygnus · daemon",
                  "Vivo"
                ],
                [
                  "ignition",
                  "Control plane",
                  "continuum/services/ignition",
                  "Construido, no desplegado"
                ],
                [
                  "airlock",
                  "Control plane",
                  "continuum/services/airlock",
                  "Construido, no desplegado"
                ],
                [
                  "pilot",
                  "Control plane (local)",
                  "continuum/services/pilot · launchd en tu máquina",
                  "Vivo (local)"
                ],
                [
                  "substrate",
                  "Librería",
                  "continuum/substrate/src",
                  "Vivo"
                ],
                [
                  "echo",
                  "Memoria",
                  "services/echo · :9040 interno",
                  "Vivo"
                ],
                [
                  "fusion",
                  "Flota (HTTP)",
                  "services/fusion · :9010 interno",
                  "Vivo"
                ],
                [
                  "sirius, magnitude, chroma, azimuth, halo",
                  "Flota (capsules)",
                  "Registro en tenant cosmos-system",
                  "Vivos (ejecución local)"
                ],
                [
                  "horizon",
                  "Perímetro",
                  "services/horizon (Rust)",
                  "Construido, fuera del camino productivo"
                ],
                [
                  "aurora, gravity, nebula, parsec, quasar, prism, orbit",
                  "Incubación",
                  "services/*",
                  "Scaffold"
                ],
                [
                  "filament, stardust",
                  "Packages",
                  "packages/*",
                  "Construidos"
                ],
                [
                  "agent-kit",
                  "Packages",
                  "packages/agent-kit",
                  "Residual tras el retiro del orquestador"
                ]
              ]
            }
          },
          {
            "title": "El hilo de confianza",
            "content": "Lo que cose todas las capas es un JWT RS256 emitido por eclipse y verificado en cada servicio contra el JWKS público. El tenantId viaja dentro del token firmado y determina, por construcción, qué datos puede tocar cada petición. Ningún servicio interno acepta un tenantId por parámetro.",
            "steps": [
              {
                "number": 1,
                "title": "eclipse emite",
                "description": "Al iniciar sesión, eclipse firma un JWT RS256 con kid, tenantId y claims de rol."
              },
              {
                "number": 2,
                "title": "umbra guarda",
                "description": "El cliente guarda la sesión en el keychain del sistema operativo."
              },
              {
                "number": 3,
                "title": "capcom verifica",
                "description": "Cada petición llega al gateway, que valida la firma contra el JWKS de eclipse."
              },
              {
                "number": 4,
                "title": "El mesh propaga",
                "description": "capcom habla con ephemeris y echo usando un token mesh por petición que lleva la identidad del caller."
              }
            ]
          }
        ]
      }
    },
    "eclipse": {
      "template": "content",
      "content": {
        "title": "eclipse — identidad",
        "description": "El emisor de identidad de toda la plataforma. Usuarios, organizaciones, sesiones y tokens: todo lo que cosmos sabe de quién eres y qué puedes tocar nace aquí. El nombre es deliberado: en un eclipse, un cuerpo autoriza qué luz pasa.",
        "sections": [
          {
            "title": "Qué es",
            "content": "eclipse es un servicio Node con Postgres que vive en services/eclipse y atiende en auth.thecosmosai.cloud (puerto interno 3001). Es el único artefacto que conoce contraseñas, sesiones y claves privadas de firma. Todo lo demás verifica contra su JWKS público.",
            "table": {
              "headers": [
                "Dato",
                "Valor"
              ],
              "rows": [
                [
                  "Ruta en el repo",
                  "services/eclipse"
                ],
                [
                  "Dominio público",
                  "auth.thecosmosai.cloud (Cloudflare Tunnel)"
                ],
                [
                  "Puerto interno",
                  "3001 (PORT)"
                ],
                [
                  "Base de datos",
                  "Postgres (DATABASE_URL)"
                ],
                [
                  "Secretos",
                  "Infisical, proyecto cosmos-platform/prod"
                ],
                [
                  "Estado",
                  "Vivo en producción"
                ]
              ]
            }
          },
          {
            "title": "Usuarios, organizaciones y membresías",
            "content": "Al primer inicio de sesión, eclipse auto-provisiona una organización personal, al estilo de Claude Desktop: nadie configura un tenant a mano. La organización ES el tenant: orgId y tenantId son el mismo identificador. Las invitaciones se consumen al entrar y el acceso se gobierna con RBAC por organización.",
            "list": [
              "Registro con verificación de correo obligatoria antes de autorizar clientes.",
              "Organización personal creada automáticamente en el primer login.",
              "Invitaciones a organizaciones, consumidas al aceptarse; el admin recibe aviso.",
              "Roles por organización (orgRole) y permisos en los claims del token."
            ]
          },
          {
            "title": "Emisión de tokens: RS256 con JWKS",
            "content": "eclipse firma el JWT de la plataforma. Con clave privada configurada emite RS256 asimétrico y publica la clave pública en el endpoint JWKS; sin clave cae a HS256, de modo que el despliegue nunca fue un flag day. En producción firma RS256 con kid eclipse-prod-2026a. La clave privada jamás sale de eclipse: un verificador comprometido no puede forjar tokens.",
            "code": {
              "language": "text",
              "title": "Claims del token (camelCase)",
              "content": "userId · email · tenantId · orgId · orgRole · role · permissions · sessionId · isPlatformAdmin · aud=cosmos-client"
            },
            "note": "El JWKS público vive en https://auth.thecosmosai.cloud/.well-known/jwks.json. capcom y ephemeris lo consumen vía la variable ECLIPSE_JWKS_URL."
          },
          {
            "title": "Flujos de sesión",
            "content": "Los flujos clásicos de cuenta viven aquí, con las protecciones que se esperan de un emisor serio.",
            "list": [
              "register y login con contraseña.",
              "refresh con detección de reuso del refresh token: si un token robado se reutiliza, la sesión cae.",
              "logout y revocación de sesiones individuales o de todas.",
              "Recuperación de contraseña con token opaco hasheado y página /reset-password; al cambiarla se revocan todas las sesiones.",
              "Cambio de correo: verifica el nuevo y avisa al anterior.",
              "Verificación de email por OTP de seis dígitos o link firmado de un solo uso."
            ]
          },
          {
            "title": "Autorización de clientes: copia y pega, device flow y PAT",
            "content": "Para que el CLI y las apps inicien sesión sin escribir credenciales en la terminal existen tres caminos, todos con PKCE donde aplica.",
            "tabs": [
              {
                "label": "Copia y pega",
                "content": "El camino por defecto de cosmos login: el navegador abre la página /authorize, apruebas, y copias un código de un solo uso (con PKCE S256) que pegas en la terminal. La página refleja cuando el terminal consume el código. Requiere correo verificado."
              },
              {
                "label": "Device flow",
                "content": "RFC 8628 para máquinas sin navegador: el CLI muestra un código corto, lo apruebas en la página /device desde cualquier dispositivo, y el CLI hace polling hasta canjear el token."
              },
              {
                "label": "Token personal",
                "content": "Tokens de acceso personal al estilo GitHub: generas un token largo en la página /tokens y lo pegas con cosmos login --token. Útil para CI y automatización."
              }
            ]
          },
          {
            "title": "Correos transaccionales y jobs",
            "content": "eclipse envía sus correos por Resend con el dominio thecosmosai.cloud verificado: bienvenida, OTP de verificación, alertas de seguridad (inicio de sesión nuevo, contraseña cambiada), invitación aceptada y cambio de correo. Un job runner declarativo e idempotente cubre los correos disparados por tiempo.",
            "table": {
              "headers": [
                "Categoría",
                "Correos"
              ],
              "rows": [
                [
                  "Cuenta",
                  "Bienvenida, verificación por OTP y link, cambio de correo"
                ],
                [
                  "Seguridad",
                  "Inicio de sesión nuevo, contraseña cambiada"
                ],
                [
                  "Equipos",
                  "Invitación aceptada (aviso al admin)"
                ]
              ]
            }
          },
          {
            "title": "API admin",
            "content": "El back office consume la API admin de eclipse: listar usuarios y organizaciones con paginación por cursor, ver sesiones activas y revocarlas, y leer eventos de seguridad. La autorización usa el claim platformRole=admin, emitido solo a una allowlist de correos (ECLIPSE_PLATFORM_ADMIN_EMAILS) con el correo verificado; no existe una columna mutable de admin en la base.",
            "callout": {
              "type": "tip",
              "title": "Por qué allowlist y no columna",
              "content": "Un atacante con acceso de escritura a la base no puede auto-promoverse: el claim de plataforma nace de la configuración del servicio, no de un dato mutable."
            }
          },
          {
            "title": "Se conecta con",
            "table": {
              "headers": [
                "Artefacto",
                "Dirección",
                "Para qué"
              ],
              "rows": [
                [
                  "capcom",
                  "capcom lee el JWKS",
                  "Verificar cada JWT de cliente contra la clave pública"
                ],
                [
                  "ephemeris",
                  "ephemeris lee el JWKS",
                  "Verificar tokens al recibir tráfico del mesh"
                ],
                [
                  "umbra / umbra-js",
                  "cliente a eclipse",
                  "Login, refresh, device flow y PKCE; es el único que conoce la forma HTTP de esta API"
                ],
                [
                  "Back office",
                  "cliente a eclipse",
                  "Consume la API admin: usuarios, organizaciones, sesiones, eventos"
                ],
                [
                  "Resend",
                  "eclipse a Resend",
                  "Todos los correos transaccionales"
                ],
                [
                  "Infisical",
                  "host a Infisical",
                  "El .env se genera desde cosmos-platform/prod, nunca a mano"
                ]
              ]
            }
          },
          {
            "title": "Variables de entorno clave",
            "fields": [
              {
                "name": "DATABASE_URL",
                "type": "string",
                "required": true,
                "description": "Conexión a Postgres."
              },
              {
                "name": "PORT",
                "type": "number",
                "required": false,
                "description": "Puerto de escucha; 3001 por defecto."
              },
              {
                "name": "ECLIPSE_PLATFORM_ADMIN_EMAILS",
                "type": "string",
                "required": false,
                "description": "Allowlist de correos que reciben el claim platformRole=admin."
              },
              {
                "name": "RESEND_API_KEY",
                "type": "string",
                "required": true,
                "description": "Envío de correos transaccionales."
              },
              {
                "name": "JWT_SECRET",
                "type": "string",
                "required": false,
                "description": "Fallback HS256 cuando no hay clave RS256 configurada."
              }
            ]
          }
        ]
      }
    },
    "umbra": {
      "template": "content",
      "content": {
        "title": "umbra — cliente de auth",
        "description": "La umbra es la sombra que el eclipse proyecta: donde cae, la identidad ya está resuelta. umbra es el cliente de autenticación compartido que todos los clientes de cosmos usan en vez de duplicar lógica de tokens.",
        "sections": [
          {
            "title": "Qué es",
            "content": "Dos implementaciones del mismo contrato: packages/umbra en Rust (para el CLI y los clientes nativos) y packages/umbra-js en TypeScript (para los servicios Node y clientes web). Es el único artefacto de la plataforma que conoce la forma HTTP de la API de identidad de eclipse; para el resto del código, la identidad es una función que devuelve un token válido."
          },
          {
            "title": "De qué se encarga",
            "list": [
              "login: el flujo completo de autorización (copia y pega con PKCE, device flow o token personal).",
              "refresh: renovar la sesión sin intervención del usuario.",
              "switch-org: cambiar de organización activa (y por tanto de tenant).",
              "verify: comprobar que la sesión guardada sigue siendo válida.",
              "Persistencia segura de la sesión."
            ]
          },
          {
            "title": "Dónde vive la sesión",
            "content": "La sesión se guarda en el keychain del sistema operativo; si el keychain no está disponible, cae a un archivo con permisos 0600. Ningún cliente guarda tokens en texto plano en configuración versionable.",
            "callout": {
              "type": "warning",
              "title": "Nunca en el repo",
              "content": "La sesión jamás se escribe en archivos del proyecto. Si un cliente necesita credenciales en CI, el camino es un token personal con alcance limitado, no copiar la sesión."
            }
          },
          {
            "title": "Por qué existe",
            "content": "Sin umbra, cada cliente (telescope, cosmos chat, el IDE, el MCP, el pilot) implementaría su propio manejo de tokens, con sus propios bugs de expiración y sus propios lugares donde guardar secretos. Con umbra hay un solo camino auditado: el mismo login, el mismo refresh y el mismo keychain en todas las superficies."
          },
          {
            "title": "Se conecta con",
            "table": {
              "headers": [
                "Artefacto",
                "Dirección",
                "Para qué"
              ],
              "rows": [
                [
                  "eclipse",
                  "umbra a eclipse",
                  "Todos los flujos de identidad: login, refresh, device, PKCE, verify"
                ],
                [
                  "telescope (CLI)",
                  "telescope usa umbra",
                  "cosmos login/logout y el token de cada comando"
                ],
                [
                  "cosmos chat / IDE",
                  "usan umbra",
                  "La misma sesión del keychain, sin reimplementar auth"
                ],
                [
                  "pilot",
                  "pilot usa umbra",
                  "El daemon habla con capcom usando la sesión ya guardada"
                ]
              ]
            }
          }
        ]
      }
    },
    "capcom": {
      "template": "content",
      "content": {
        "title": "capcom — gateway",
        "description": "CAPCOM, el capsule communicator, es la única voz de mission control hacia la tripulación. capcom es la única puerta pública del control plane: todo cliente le habla a él con su JWT de eclipse, y nada interno se expone a internet.",
        "sections": [
          {
            "title": "Qué es",
            "content": "Un gateway Node minimalista que vive en continuum/services/capcom y atiende en capcom.thecosmosai.cloud (puerto 9060, expuesto solo por Cloudflare Tunnel). Su trabajo es triple: verificar la identidad de cada petición, acotarla al tenant del token, y proxear los servicios internos que nunca se exponen (ephemeris y echo).",
            "table": {
              "headers": [
                "Dato",
                "Valor"
              ],
              "rows": [
                [
                  "Ruta en el repo",
                  "continuum/services/capcom"
                ],
                [
                  "Dominio público",
                  "capcom.thecosmosai.cloud (Cloudflare Tunnel)"
                ],
                [
                  "Puerto",
                  "9060 (publicado solo en loopback del host)"
                ],
                [
                  "Endpoint público sin auth",
                  "/health únicamente"
                ],
                [
                  "Estado",
                  "Vivo en producción"
                ]
              ]
            }
          },
          {
            "title": "Verificación del token",
            "content": "capcom verifica cada JWT contra el JWKS de eclipse (RS256/ES256, vía ECLIPSE_JWKS_URL) con fallback HS256 de mesh durante la transición. El tenantId sale exclusivamente del claim verificado, nunca de un parámetro de la petición: no existe forma de pedirle datos de otro tenant por mucho que se manipule la URL.",
            "callout": {
              "type": "note",
              "title": "Defensa del algoritmo",
              "content": "El verificador rechaza alg=none, confusión de algoritmos y kid desconocidos. La clave privada vive solo en eclipse; capcom únicamente conoce la pública."
            }
          },
          {
            "title": "Descubrimiento y escritura de flota",
            "content": "GET /agents devuelve la flota del tenant mezclada con la flota de plataforma (el tenant de sistema cosmos-system), para que cada organización vea los agentes base junto a los suyos. En la respuesta de descubrimiento capcom quita el systemPrompt: es configuración de operador, no información de cliente. Con POST /agents y DELETE /agents/:name un tenant registra o quita sus propios agentes, siempre on-behalf-of.",
            "code": {
              "language": "bash",
              "title": "Descubrir la flota",
              "file": "config/examples/capcom.discover-fleet.sh"
            }
          },
          {
            "title": "Config de capsule",
            "content": "GET /agents/:name/capsule devuelve el systemPrompt y la configuración de ejecución de un capsule agent, para que un cliente con claude local ejecute el agente en su propia máquina. Este endpoint sí entrega el rol completo, porque quien lo pide va a ejecutarlo."
          },
          {
            "title": "Manifests: el camino Continuum",
            "content": "POST /manifests crea el manifest durable (la declaración de trabajo que se descompone en waypoints) y GET /manifests/:id reporta su estado. El aislamiento es por tenant: pedir el manifest de otra organización responde 404, no 403, para no filtrar existencia.",
            "list": [
              "POST /manifests: crea el manifest y lo persiste en ephemeris.",
              "GET /manifests/:id: estado y resultado de los jobs del manifest."
            ]
          },
          {
            "title": "Gateway de memoria y ledger",
            "content": "capcom proxea a echo (GET y PUT /memory/:projectId) y a ephemeris (GET /tether, GET /mail, POST /mail, POST /mail/drain, POST /waypoints/:id/close) firmando un token mesh por petición que lleva la identidad del caller. Así el cliente usa un solo host para toda la plataforma, y ni echo ni ephemeris necesitan un puerto público.",
            "table": {
              "headers": [
                "Ruta en capcom",
                "Servicio interno",
                "Para qué"
              ],
              "rows": [
                [
                  "GET/PUT /memory/:projectId",
                  "echo",
                  "Memoria de equipo por proyecto"
                ],
                [
                  "GET /tether",
                  "ephemeris",
                  "Los waypoints asignados a tu sesión"
                ],
                [
                  "GET /mail · POST /mail · POST /mail/drain",
                  "ephemeris",
                  "Correo de crew"
                ],
                [
                  "POST /waypoints/:id/close",
                  "ephemeris",
                  "Cerrar un paso terminado"
                ]
              ]
            }
          },
          {
            "title": "Se conecta con",
            "table": {
              "headers": [
                "Artefacto",
                "Dirección",
                "Para qué"
              ],
              "rows": [
                [
                  "eclipse",
                  "lee su JWKS",
                  "Verificar la firma de cada token de cliente"
                ],
                [
                  "ephemeris",
                  "proxy con mesh token",
                  "Registro de flota, manifests, tether, mail, waypoints"
                ],
                [
                  "echo",
                  "proxy con mesh token",
                  "Memoria de equipo"
                ],
                [
                  "telescope / chat / IDE / pilot",
                  "clientes de capcom",
                  "Toda la operación de la plataforma pasa por aquí"
                ],
                [
                  "cloudflared",
                  "el túnel apunta a capcom",
                  "Exposición pública sin abrir puertos del origen"
                ]
              ]
            }
          },
          {
            "title": "Variables de entorno clave",
            "fields": [
              {
                "name": "PORT",
                "type": "number",
                "required": false,
                "description": "Puerto de escucha; 9060 por defecto."
              },
              {
                "name": "EPHEMERIS_URL",
                "type": "string",
                "required": true,
                "description": "URL interna del ledger (http://ephemeris:9050 en el compose)."
              },
              {
                "name": "ECLIPSE_JWKS_URL",
                "type": "string",
                "required": true,
                "description": "JWKS de eclipse para verificar tokens de usuario."
              },
              {
                "name": "MANIFEST_DIR",
                "type": "string",
                "required": false,
                "description": "Volumen donde persisten los manifests."
              }
            ]
          }
        ]
      }
    },
    "ephemeris": {
      "template": "content",
      "content": {
        "title": "ephemeris — ledger",
        "description": "Una efeméride es la tabla que dice dónde está cada cuerpo celeste en cada momento: el registro autoritativo de posición en el tiempo. ephemeris es exactamente eso para el trabajo: la fuente de verdad de cada waypoint, cada agente registrado y cada correo de crew.",
        "sections": [
          {
            "title": "Qué es",
            "content": "El ledger durable de Continuum, construido sobre Beads y Dolt (una base SQL versionada con branch y merge). Vive en continuum/services/ephemeris, escucha en el puerto 9050 publicado solo en loopback, y jamás se alcanza directo desde internet: todo pasa por capcom o por el mesh interno.",
            "table": {
              "headers": [
                "Dato",
                "Valor"
              ],
              "rows": [
                [
                  "Ruta en el repo",
                  "continuum/services/ephemeris"
                ],
                [
                  "Puerto",
                  "9050, publicado en 127.0.0.1 únicamente"
                ],
                [
                  "Backend",
                  "Dolt (EPHEMERIS_BACKEND=dolt), binario bd"
                ],
                [
                  "Almacenamiento",
                  "Volumen ledger-mt, un store por tenant en /data/tenants/<tenantStoreKey>"
                ],
                [
                  "Estado",
                  "Vivo en producción"
                ]
              ]
            }
          },
          {
            "title": "Qué guarda",
            "list": [
              "Trajectories y waypoints: el grafo de trabajo, con dependencias y detección incremental de is_blocked (un waypoint se vuelve ready automáticamente cuando su bloqueador cierra).",
              "El registro nativo de agentes (registry.mjs): POST, GET y DELETE /agents. Esto cortó la última dependencia del orquestador viejo.",
              "El correo de crew (/mail): mensajes entre miembros del equipo de trabajo.",
              "Claims y leases: quién reclamó qué waypoint, con recuperación de workers muertos."
            ]
          },
          {
            "title": "Las primitivas de oro",
            "content": "Las primitivas que hacen durable la orquestación vienen de Beads, adoptadas tras leer su código fuente y no el blog que lo popularizó.",
            "accordion": [
              {
                "title": "IDs por content-hash",
                "content": "El identificador de un waypoint deriva de su contenido, así dos agentes en máquinas distintas no colisionan al crear trabajo en paralelo."
              },
              {
                "title": "is_blocked incremental",
                "content": "El grafo de dependencias se recalcula de forma incremental: cerrar un bloqueador vuelve ready a sus dependientes sin recorrer todo el grafo."
              },
              {
                "title": "Claim y lease",
                "content": "Un worker reclama un waypoint antes de trabajarlo, con un lease renovable. Si el worker muere, el lease expira y otro puede reclamar el trabajo sin duplicarlo."
              }
            ]
          },
          {
            "title": "Aislamiento por construcción",
            "content": "Cada tenant vive en un store Dolt físicamente separado bajo /data/tenants/<tenantStoreKey>. No existe una query que devuelva datos de otro tenant, porque no hay tabla compartida que filtrar: el aislamiento no depende de acordarse de poner un WHERE. La autenticación es fail-closed: sin token válido, 401.",
            "callout": {
              "type": "warning",
              "title": "El gotcha del volumen fresco",
              "content": "El binario bd resuelve su store .beads caminando hacia arriba en el árbol de directorios. Si la raíz del volumen alguna vez fue inicializada con bd init, ese store raíz envenena todos los stores de tenant debajo. Por eso el layout multi-tenant vive en el volumen ledger-mt, cuya raíz nunca fue inicializada; el volumen ledger viejo quedó retenido para migración y no se monta."
            }
          },
          {
            "title": "Se conecta con",
            "table": {
              "headers": [
                "Artefacto",
                "Dirección",
                "Para qué"
              ],
              "rows": [
                [
                  "capcom",
                  "capcom a ephemeris",
                  "Todo el tráfico de clientes llega proxeado con mesh token"
                ],
                [
                  "cygnus",
                  "cygnus a ephemeris",
                  "Leer manifests y waypoints abiertos, reclamar y cerrar"
                ],
                [
                  "eclipse",
                  "lee su JWKS",
                  "Verificar tokens cuando se configura ECLIPSE_JWKS_URL"
                ],
                [
                  "Agentes",
                  "vía capcom",
                  "Registrarse y desregistrarse en el registro nativo"
                ]
              ]
            }
          },
          {
            "title": "Variables de entorno clave",
            "fields": [
              {
                "name": "EPHEMERIS_STORE",
                "type": "string",
                "required": true,
                "description": "Raíz del almacenamiento (/data en el compose)."
              },
              {
                "name": "EPHEMERIS_BACKEND",
                "type": "string",
                "required": false,
                "description": "dolt en producción; el build puro de Go da solo sqlite."
              },
              {
                "name": "EPHEMERIS_JWT_SECRET",
                "type": "string",
                "required": false,
                "description": "Secreto mesh; con él la auth multi-tenant se aplica, sin él corre single-tenant (solo desarrollo)."
              },
              {
                "name": "ECLIPSE_JWKS_URL",
                "type": "string",
                "required": false,
                "description": "Verificación asimétrica de tokens de usuario."
              }
            ]
          }
        ]
      }
    },
    "cygnus": {
      "template": "content",
      "content": {
        "title": "cygnus — reconciliador",
        "description": "Cygnus es la constelación del cisne y la nave de resuministro que mantiene abastecida la estación. cygnus es el daemon que mantiene el trabajo fluyendo: vigila el ledger y empuja cada manifest hacia hecho, sin pausa y sin re-ejecutar lo ya cerrado.",
        "sections": [
          {
            "title": "Qué es",
            "content": "Un reconciliador de código plano (no es un agente Claude) que vive en continuum/services/cygnus y corre como daemon junto a ephemeris. Cada tick (INTERVAL_MS, 2000 ms en producción) busca manifests y waypoints abiertos y los avanza; cuando no hay nada, aplica backoff para no quemar ciclos."
          },
          {
            "title": "El ciclo de reconciliación",
            "steps": [
              {
                "number": 1,
                "title": "Encontrar trabajo listo",
                "description": "Lee ephemeris buscando waypoints ready cuyo bloqueador ya cerró."
              },
              {
                "number": 2,
                "title": "Descubrir la flota",
                "description": "Con un mesh token acotado al tenant del manifest, consulta el registro de agentes y mezcla la flota de plataforma (cosmos-system) con la del tenant."
              },
              {
                "number": 3,
                "title": "Rutear la intención",
                "description": "Elige el agente cuya capacidad mejor empata con la intención del job (substrate/fleet.mjs)."
              },
              {
                "number": 4,
                "title": "Ejecutar",
                "description": "Si el agente es HTTP, hace POST a su /execute; si es capsule, la ejecución corre donde vive el claude del tenant."
              },
              {
                "number": 5,
                "title": "Cerrar y avanzar",
                "description": "El resultado se escribe al ledger, el waypoint cierra y la trayectoria avanza al siguiente paso."
              }
            ]
          },
          {
            "title": "La garantía de durabilidad",
            "content": "Si un proceso muere entre reclamar y cerrar, el waypoint queda abierto con su claim; al expirar el lease, un tick posterior lo retoma. Los pasos cerrados nunca se repiten: cada paso lo ejecuta un modelo no determinista, pero que el paso ocurra y no se pierda es determinista.",
            "callout": {
              "type": "success",
              "title": "Verificado en vivo",
              "content": "La prueba de paridad del cutover mata un capsule a media tarea y comprueba que el trabajo completa en el segundo reconcile sin re-ejecutar el paso cerrado."
            }
          },
          {
            "title": "Se conecta con",
            "table": {
              "headers": [
                "Artefacto",
                "Dirección",
                "Para qué"
              ],
              "rows": [
                [
                  "ephemeris",
                  "cygnus a ephemeris",
                  "Leer trabajo, reclamar, cerrar; descubrir agentes (FLEET_REGISTRY_URL)"
                ],
                [
                  "fusion y agentes HTTP",
                  "cygnus al /execute del agente",
                  "Ejecutar jobs de servicio en la red interna"
                ],
                [
                  "ignition",
                  "cygnus usa ignition",
                  "El runtime que sabe correr un paso de trayectoria"
                ],
                [
                  "eclipse",
                  "lee su JWKS",
                  "Verificación de tokens en el camino multi-tenant"
                ]
              ]
            }
          },
          {
            "title": "Variables de entorno clave",
            "fields": [
              {
                "name": "EPHEMERIS_URL",
                "type": "string",
                "required": true,
                "description": "El ledger a reconciliar."
              },
              {
                "name": "FLEET_REGISTRY_URL",
                "type": "string",
                "required": true,
                "description": "El registro de agentes; hoy apunta al propio ephemeris."
              },
              {
                "name": "INTERVAL_MS",
                "type": "number",
                "required": false,
                "description": "Periodo del tick; 2000 ms en producción."
              },
              {
                "name": "WORK_DIR",
                "type": "string",
                "required": false,
                "description": "Directorio de trabajo para jobs que tocan archivos."
              }
            ]
          }
        ]
      }
    },
    "ignition-airlock": {
      "template": "content",
      "content": {
        "title": "ignition y airlock",
        "description": "ignition es el momento en que empieza el empuje: el runtime que ejecuta cada paso de una trayectoria. airlock es la esclusa que admite un cuerpo a la vez: la cola de merge que aterriza cambios paralelos en main de uno en uno.",
        "sections": [
          {
            "title": "ignition: el runtime de capsules",
            "content": "Vive en continuum/services/ignition (bin.mjs, driver.mjs, runtime.mjs). Dado un tether con trabajo listo, lanza un capsule, le inyecta el contexto del paso actual, registra el resultado con checkpoint y lo relanza desde el estado persistido si se interrumpe. El resume es reconstrucción desde estado, no replay de conversación."
          },
          {
            "title": "Los dos drivers de capsule",
            "tabs": [
              {
                "label": "Headless (default)",
                "content": "Una invocación de claude -p por paso de trayectoria, con el contexto inyectado por append-system-prompt y salida en stream JSON. Sin estado, automatizable y multi-tenant: el ajuste natural para la regla de la casa de shellear el CLI de Claude y nunca la API de pago."
              },
              {
                "label": "Interactivo (tmux)",
                "content": "El diseño contempla una sesión claude viva en un pane de tmux con trabajo inyectado por send-keys, como hace Gas Town. Este driver quedó como idea documentada: cosmos adoptó el headless y el driver interactivo no está construido."
              }
            ],
            "note": "El modelo de cada paso se elige con la política de ruteo de substrate: un paso trivial va al modelo barato, el resto al default, y una petición explícita siempre gana."
          },
          {
            "title": "airlock: la esclusa de cambios",
            "content": "Vive en continuum/services/airlock (airlock.mjs, lander.mjs, git.mjs). Hace fan-out de trabajo a landers (workers efímeros que producen exactamente un cambio en un worktree aislado) y opera el git del aterrizaje: integra los cambios concurrentes en main de uno en uno, detrás de una compuerta de pruebas, con estrategia batch-then-bisect. Un cambio conflictivo rebota de vuelta en lugar de romper la rama."
          },
          {
            "title": "Estado real",
            "content": "Ambos servicios están construidos y probados en el flujo de extremo a extremo del Acto I de Continuum, pero no aparecen en el compose de despliegue: en producción corren ephemeris, capcom y cygnus, y cygnus ejecuta los jobs directamente. ignition y airlock entran al camino productivo cuando se despachen trayectorias multi-paso con aterrizaje de código.",
            "callout": {
              "type": "info",
              "title": "Por qué se documentan",
              "content": "Son la mitad construida del modelo Gas Town: el runtime por pasos y la cola de merge. Entender su contrato explica hacia dónde crece el despacho de trabajo."
            }
          },
          {
            "title": "Se conectan con",
            "table": {
              "headers": [
                "Artefacto",
                "Dirección",
                "Para qué"
              ],
              "rows": [
                [
                  "cygnus",
                  "cygnus a ignition",
                  "Ejecutar el paso actual de una trayectoria"
                ],
                [
                  "ephemeris",
                  "ignition a ephemeris",
                  "Leer el tether, checkpointear y cerrar waypoints"
                ],
                [
                  "airlock",
                  "landers a airlock",
                  "Solicitar el merge de su cambio único"
                ],
                [
                  "git (main)",
                  "airlock a main",
                  "Aterrizar cambios de uno en uno tras la compuerta de pruebas"
                ]
              ]
            }
          }
        ]
      }
    },
    "pilot": {
      "template": "content",
      "content": {
        "title": "pilot — daemon local",
        "description": "El piloto vuela la nave sin que la tripulación se lo pida. pilot es el autopiloto local de cosmos: un daemon en tu máquina que, sin comandos, mantiene la plataforma sincronizada con cómo trabajas de verdad. Es el motor de la promesa de que cosmos aprende de ti.",
        "sections": [
          {
            "title": "Qué es",
            "content": "Un daemon Node que vive en continuum/services/pilot y corre en la máquina del desarrollador como agente launchd en macOS. No es un servicio del servidor: el modelo de producto es un pilot POR desarrollador, cada uno con su propio cómputo y su propia suscripción de Claude, hablando con el control plane multi-tenant de producción.",
            "table": {
              "headers": [
                "Dato",
                "Valor"
              ],
              "rows": [
                [
                  "Ruta en el repo",
                  "continuum/services/pilot (bin, pilot, lookback, memory-mirror, echo-client, keychain)"
                ],
                [
                  "Dónde corre",
                  "Tu máquina, como launchd agent"
                ],
                [
                  "Cómo se autentica",
                  "La sesión de eclipse que ya vive en el keychain"
                ],
                [
                  "Por dónde habla",
                  "Siempre por el gateway capcom, nunca directo a echo"
                ],
                [
                  "Estado",
                  "Vivo (local), verificado de extremo a extremo"
                ]
              ]
            }
          },
          {
            "title": "Los tres subsistemas",
            "accordion": [
              {
                "title": "Espejo de subagentes",
                "content": "Clona los subagentes de Claude Code definidos en ~/.claude/agents como capsule agents en el registro de la flota. Un subagente es en esencia un prompt con nombre: exactamente lo que un capsule agent necesita para existir. Tu roster personal de Claude se convierte en flota de cosmos sin trabajo manual."
              },
              {
                "title": "Espejo de memoria",
                "content": "Recolecta el CLAUDE.md de cada proyecto, redacta secretos antes de que nada salga de tu máquina, y con opt-in de equipo lo escribe a echo. La memoria global personal nunca sube a un documento de equipo: la frontera entre lo tuyo y lo compartido es explícita."
              },
              {
                "title": "Lookback",
                "content": "Destila tu historial de IA previo (las sesiones JSONL de Claude Code, el SQLite de Cursor, el export de ChatGPT) a hechos útiles usando claude -p, y los guarda en echo. Hace diff por contenido: solo re-destila lo que cambió desde el último tick."
              }
            ]
          },
          {
            "title": "Cómo decide qué hacer en cada tick",
            "content": "Cada tick del daemon es idempotente: mira el estado actual (qué subagentes existen, qué memoria cambió, qué historial es nuevo), calcula la diferencia contra lo ya espejado y actúa solo sobre el delta. Matar el daemon en cualquier punto no corrompe nada; el siguiente tick converge."
          },
          {
            "title": "Límites honestos",
            "list": [
              "El refresh del token del daemon aún no está cableado: cuando la sesión expira, pilot espera a que vuelvas a iniciar sesión.",
              "El registro remoto de subagentes usa el POST /agents que ya existe en capcom, pero falta cablearlo de punta a punta en el pilot.",
              "La persistencia remota de la memoria PERSONAL (no de equipo) es una decisión de producto pendiente."
            ]
          },
          {
            "title": "Se conecta con",
            "table": {
              "headers": [
                "Artefacto",
                "Dirección",
                "Para qué"
              ],
              "rows": [
                [
                  "capcom",
                  "pilot a capcom",
                  "Todo su tráfico: memoria, registro de flota"
                ],
                [
                  "echo",
                  "vía capcom",
                  "Escribir la memoria de equipo destilada y espejada"
                ],
                [
                  "umbra / keychain",
                  "pilot lee la sesión",
                  "Autenticarse sin pedir credenciales"
                ],
                [
                  "claude -p local",
                  "pilot lo invoca",
                  "Destilar historial en el lookback; nunca la API de pago"
                ],
                [
                  "~/.claude/agents",
                  "pilot lo lee",
                  "Espejar subagentes como capsule agents"
                ]
              ]
            }
          }
        ]
      }
    },
    "substrate": {
      "template": "content",
      "content": {
        "title": "substrate — librería común",
        "description": "El código que capcom, ephemeris, cygnus y pilot comparten. substrate no es un servicio: es la caja de herramientas de Continuum, y leerla es la forma más rápida de entender cómo se implementan la confianza, el ruteo y la memoria.",
        "sections": [
          {
            "title": "Qué es",
            "content": "Un paquete de módulos ES en continuum/substrate/src. Cada módulo tiene una responsabilidad única y los servicios los importan directo. Si un comportamiento aparece en dos servicios de Continuum, vive aquí."
          },
          {
            "title": "Módulo por módulo",
            "accordion": [
              {
                "title": "auth.mjs — firmar y verificar",
                "content": "signJwt y verifyJwt (HS256 de mesh), signJwtAsymmetric y verifyJwtAsymmetric (RS256/ES256), makeVerifier (el verificador combinado JWKS más HMAC que usan los servicios), authenticate (extraer y validar el bearer de los headers) y tenantStoreKey (derivar la clave de store del tenant desde los claims, con saneo del path). Defiende contra alg=none, confusión de algoritmos y kid desconocido."
              },
              {
                "title": "jwks.mjs — cliente JWKS",
                "content": "createJwksClient: descarga y cachea el JWKS de eclipse (TTL de una hora, refetch mínimo de diez segundos), convierte cada JWK a clave verificable y resuelve por kid. Es la pieza que permite verificar sin compartir secretos."
              },
              {
                "title": "fleet.mjs — la flota",
                "content": "discoverAgents (consultar el registro), route (elegir agente por capacidad e intención), executeAgent (POST al /execute de un agente HTTP), executeCapsuleAgent (correr un capsule con claude -p y su systemPrompt) y dispatchToFleet (el camino completo: descubrir, rutear, ejecutar). Lo usan cygnus y el CLI."
              },
              {
                "title": "routing.mjs — política de modelos",
                "content": "policyRoute: un paso trivial va al modelo barato, el resto al default y una petición explícita siempre gana. LocalRouter aplica la política pura; RemoteOrbitRouter es la costura hacia orbit cuando el router de modelos esté vivo."
              },
              {
                "title": "memory.mjs — memoria en contexto",
                "content": "EchoClient (hablar con echo vía el gateway), teamMemoryBlock (formatear la memoria de equipo como bloque inyectable) e injectContext (componer el system prompt de un capsule con la memoria del proyecto)."
              },
              {
                "title": "capsule-config.mjs — config de ejecución",
                "content": "resolveCapsuleConfig: resuelve cómo se ejecuta un capsule para un tenant (binario de claude, overrides), separando la política de la mecánica."
              },
              {
                "title": "claude-agents.mjs — subagentes",
                "content": "parseSubagent, toCapsuleAgent y loadSubagents: leer los subagentes de ~/.claude/agents y convertirlos al formato de capsule agent del registro. Es la base del espejo del pilot."
              },
              {
                "title": "actionable.mjs — errores accionables",
                "content": "actionable y renderActionable: cada error del CLI y el daemon dice qué pasó, qué impacto tiene y cómo remediarlo, con severidad y auditoría (cosmos doctor). Un error que no dice qué hacer es un bug."
              }
            ]
          },
          {
            "title": "Quién usa qué",
            "table": {
              "headers": [
                "Consumidor",
                "Módulos"
              ],
              "rows": [
                [
                  "capcom",
                  "auth, jwks (verificar tokens y firmar mesh)"
                ],
                [
                  "ephemeris",
                  "auth (verificación fail-closed, tenantStoreKey)"
                ],
                [
                  "cygnus",
                  "auth, fleet, routing (descubrir, rutear, ejecutar)"
                ],
                [
                  "ignition",
                  "routing, capsule-config (elegir modelo y driver)"
                ],
                [
                  "pilot",
                  "claude-agents, memory, actionable, auth"
                ],
                [
                  "telescope (CLI)",
                  "fleet y actionable a través del camino local de cosmos run"
                ]
              ]
            }
          }
        ]
      }
    },
    "echo": {
      "template": "content",
      "content": {
        "title": "echo — memoria",
        "description": "Un eco devuelve lo que el equipo dijo. echo es la memoria de equipo de cosmos: un documento markdown por tenant y proyecto que hidrata cada sesión, crece con lo aprendido y es el mismo para el CLI, el chat y el autopiloto.",
        "sections": [
          {
            "title": "Qué es",
            "content": "Un servicio Node pequeño en services/echo que escucha en el puerto 9040, interno únicamente: se alcanza solo a través de capcom. Expone GET y PUT /memory/:projectId con concurrencia optimista e historial de revisiones.",
            "table": {
              "headers": [
                "Dato",
                "Valor"
              ],
              "rows": [
                [
                  "Ruta en el repo",
                  "services/echo"
                ],
                [
                  "Puerto",
                  "9040, solo red interna"
                ],
                [
                  "Modelo de datos",
                  "Un documento markdown por tenant y projectId, con versiones"
                ],
                [
                  "Acceso",
                  "Exclusivamente vía capcom (proxy /memory con mesh token)"
                ],
                [
                  "Estado",
                  "Vivo en producción"
                ]
              ]
            }
          },
          {
            "title": "El projectId compartido",
            "content": "El projectId es el sha256 del remoto git del repositorio, calculado igual en todos los clientes. Eso garantiza que telescope, cosmos chat y el pilot direccionen el mismo documento sin coordinarse: el repo ES la clave.",
            "code": {
              "language": "text",
              "title": "Derivación",
              "content": "projectId = sha256(url del remoto git normalizada)"
            }
          },
          {
            "title": "Concurrencia optimista",
            "content": "Cada lectura devuelve la versión del documento; cada escritura la manda de vuelta en el header If-Match. Si otro cliente escribió en medio, el PUT responde conflicto y el llamador reintenta sobre la versión fresca. Con varios agentes y humanos escribiendo memoria, el último no pisa al resto en silencio.",
            "callout": {
              "type": "note",
              "title": "Historial de revisiones",
              "content": "Las versiones anteriores se conservan: la memoria de equipo se puede auditar y recuperar, no solo sobrescribir."
            }
          },
          {
            "title": "Quién la alimenta y quién la consume",
            "list": [
              "cosmos prime la inyecta al arrancar cada sesión de Claude Code (hook SessionStart).",
              "cosmos memory show, pull y push la leen y curan desde el CLI.",
              "El pilot escribe lo destilado del lookback y el espejo de CLAUDE.md (con opt-in).",
              "cosmos chat comparte el mismo documento vía el projectId unificado."
            ]
          },
          {
            "title": "No confundir con nebula",
            "content": "nebula es un servicio Rust de memoria y retrieval con recall citado, en incubación y con flags apagados. echo es la memoria viva de producción. Comparten tema, no código ni estado.",
            "warning": "La mejora pendiente de echo es verificar JWKS nativo; hoy verifica el HS256 del mesh que capcom firma por petición."
          },
          {
            "title": "Se conecta con",
            "table": {
              "headers": [
                "Artefacto",
                "Dirección",
                "Para qué"
              ],
              "rows": [
                [
                  "capcom",
                  "capcom a echo",
                  "Todo el tráfico llega proxeado con la identidad del caller"
                ],
                [
                  "telescope",
                  "vía capcom",
                  "prime y cosmos memory"
                ],
                [
                  "pilot",
                  "vía capcom",
                  "Espejo de memoria y lookback"
                ],
                [
                  "cosmos chat",
                  "vía capcom",
                  "El mismo documento de equipo por projectId"
                ]
              ]
            }
          }
        ]
      }
    },
    "fusion": {
      "template": "content",
      "content": {
        "title": "fusion — conversión",
        "description": "La fusión convierte un elemento en otro. fusion es el agente de conversión de archivos: el agente HTTP vivo del servidor y el patrón de referencia de cómo un servicio se vuelve un agente de la flota.",
        "sections": [
          {
            "title": "Qué es",
            "content": "Un servicio Node en services/fusion (puerto 9010, interno) que envuelve la API de transmuta co-ubicada en el mismo host y la expone como agente de cosmos con el contrato de flota: un manifest con capacidades y un endpoint /execute. Es el agente no-LLM que se queda en el servidor: no necesita claude, así que no hay razón para que corra en tu máquina."
          },
          {
            "title": "Capacidades",
            "table": {
              "headers": [
                "Capacidad",
                "Qué hace"
              ],
              "rows": [
                [
                  "file.convert",
                  "Convertir un archivo de un formato a otro"
                ],
                [
                  "image.convert",
                  "Imágenes: heic, jpg, png, webp, avif, tiff"
                ],
                [
                  "document.convert",
                  "Documentos a PDF: docx, xlsx, pptx"
                ],
                [
                  "pdf.convert",
                  "Rasterizar o comprimir PDF"
                ],
                [
                  "ocr.extract",
                  "Extraer texto de imágenes o escaneos"
                ]
              ]
            }
          },
          {
            "title": "El patrón de referencia",
            "content": "Para convertir cualquier servicio en un agente de la flota se copia la forma de fusion: declarar un manifest con nombre, descripción y capacidades con keywords, implementar execute(task) que recibe la intención y los inputs, y registrarse en el registro de la flota. El ruteo de cygnus y del CLI funciona contra ese contrato, no contra el servicio concreto.",
            "code": {
              "language": "typescript",
              "title": "La forma del manifest",
              "file": "config/examples/fusion.manifest.ts"
            }
          },
          {
            "title": "Se conecta con",
            "table": {
              "headers": [
                "Artefacto",
                "Dirección",
                "Para qué"
              ],
              "rows": [
                [
                  "transmuta",
                  "fusion a transmuta",
                  "La conversión real; co-ubicados en el mismo host"
                ],
                [
                  "cygnus",
                  "cygnus a fusion",
                  "POST /execute cuando un job rutea a una capacidad de conversión"
                ],
                [
                  "ephemeris",
                  "fusion en el registro",
                  "Su manifest vive en el registro nativo de la flota"
                ]
              ]
            }
          }
        ]
      }
    },
    "horizon": {
      "template": "content",
      "content": {
        "title": "horizon — gateway Rust",
        "description": "El horizonte es la frontera que cruzas para entrar. horizon es el API gateway de alto rendimiento escrito en Rust: el borde diseñado para terminar el tráfico externo cuando la escala lo pida.",
        "sections": [
          {
            "title": "Qué es",
            "content": "Un gateway en services/horizon (Rust) con una suite de 59 pruebas. Termina tráfico, autentica contra el servicio de identidad y reenvía hacia adentro. Su diseño es drop-in: la URL del servicio de auth se inyecta con AUTH_SERVICE_URL, así el emisor de identidad se puede reemplazar sin tocar el código."
          },
          {
            "title": "Validación de tokens real",
            "content": "horizon valida los JWT de eclipse de verdad, con la interop verificada contra el JWKS: los claims camelCase (userId, tenantId, orgRole) y la audiencia cosmos-client que emite eclipse son exactamente lo que horizon espera. Esa verificación cruzada Rust-Node fue un hito: dos stacks distintos acordando el mismo contrato de token."
          },
          {
            "title": "Estado real",
            "content": "Construido y probado, pero fuera del camino productivo de hoy: en producción la única puerta es capcom detrás del Cloudflare Tunnel, y no hay una capa horizon delante. Su lugar natural es el borde de una topología con más tráfico y más servicios públicos, donde un gateway Rust con presupuesto de latencia mínimo pague su lugar.",
            "callout": {
              "type": "info",
              "title": "Cuándo entra",
              "content": "Cuando haya más de una superficie pública o se necesite rate limiting y filtrado en el borde, horizon es la pieza que ya está lista para ese trabajo."
            }
          },
          {
            "title": "Se conecta con",
            "table": {
              "headers": [
                "Artefacto",
                "Dirección",
                "Para qué"
              ],
              "rows": [
                [
                  "eclipse",
                  "AUTH_SERVICE_URL + JWKS",
                  "Validar identidad en el borde"
                ],
                [
                  "capcom",
                  "horizon reenviaría a capcom",
                  "En la topología objetivo, Continuum vive detrás del borde"
                ]
              ]
            }
          }
        ]
      }
    },
    "scaffolds": {
      "template": "content",
      "content": {
        "title": "Servicios en incubación",
        "description": "Código real en el repo sin ruta productiva todavía. Se documentan con honestidad: qué pretende ser cada uno, qué hay hoy y qué les falta. Ninguno bloquea operar la plataforma.",
        "sections": [
          {
            "title": "Cómo leer esta página",
            "content": "Cosmos mantiene el control plane deliberadamente delgado; estas piezas existen porque marcan la dirección de crecimiento, y cada una entra al camino productivo cuando su problema se vuelve real. Hasta entonces, son scaffolds: contratos y código base, no servicios vivos.",
            "note": "Estado verificado contra el repositorio; si una página del resto de la documentación menciona uno de estos servicios, remite aquí para el estado."
          },
          {
            "title": "aurora — telemetría y observabilidad",
            "content": "Una aurora es actividad interna hecha visible. aurora (Rust) pretende ser la capa de telemetría y observabilidad de la plataforma. Hoy es un scaffold; la observabilidad de producción se cubre con healthchecks de Docker y logs de los servicios. Le falta: pipeline de métricas, trazas y un panel."
          },
          {
            "title": "gravity — consenso",
            "content": "La gravedad enlaza cuerpos en un sistema. gravity (Rust) explora consenso BFT para coordinar nodos distribuidos. Es el scaffold más lejano al producto actual: no hay hoy un problema de consenso multi-nodo en cosmos. Se conserva como investigación."
          },
          {
            "title": "nebula — memoria y retrieval",
            "content": "Una nebulosa almacena material del que nacen estrellas. nebula (Rust) apunta a memoria con retrieval y recall citado: responder con fuentes en lugar de solo texto. Está detrás de feature flags apagados. No confundir con echo, que es la memoria de equipo viva; nebula sería la capa de recuperación semántica encima. Le falta: indexación, embeddings y el camino de citas.",
            "warning": "El nombre nebula está tomado por este servicio Rust. La memoria de producción es echo."
          },
          {
            "title": "parsec — NLP de código",
            "content": "Un parsec es distancia astronómica y un juego con parse. parsec pretende análisis semántico de código: entender repositorios a nivel de símbolos para dar mejor contexto a los agentes. Scaffold temprano; le falta todo el pipeline de análisis."
          },
          {
            "title": "quasar — capa de proveedores de IA",
            "content": "Un cuásar es la fuente de energía más luminosa. quasar sería el gateway unificado de proveedores de modelos con ruteo y caché, la fuente única de inferencia del lado servidor. Hoy la regla de la casa lo hace innecesario: los capsules corren con el claude -p de cada desarrollador. Cobra sentido si algún día hay inferencia server-side multi-proveedor."
          },
          {
            "title": "prism — gestión de prompts",
            "content": "Un prisma da forma a la luz. prism pretende ser la gestión de prompts con plantillas y versionado. Hoy los prompts de los agentes viven en el registro de la flota (el systemPrompt del capsule); prism entraría cuando haga falta versionado y revisión editorial de prompts a escala."
          },
          {
            "title": "orbit — router de modelos",
            "content": "La órbita correcta es la trayectoria correcta. orbit elige el modelo por costo, calidad y latencia. Es el caso especial de esta lista: el orbit real es un workspace Rust que vive en su propio repositorio (cosmos-ai-cloud/orbit) y se consume como dependencia git versionada; el directorio services/orbit del monorepo es su rastro histórico. La costura para usarlo ya existe en substrate (RemoteOrbitRouter); falta desplegarlo y apuntar la política a él."
          },
          {
            "title": "supernova y polaris — los que salieron del compose",
            "content": "supernova (amplificación de contenido: grabaciones largas a clips verticales con subtítulos, necesita Whisper y ffmpeg) y polaris (capa de guía como MCP server con reglas aprendidas) siguen en el repo pero salieron del despliegue cuando se retiró el orquestador viejo: eran agentes de demostración de aquel contrato. supernova además es pesado para el droplet actual. Cualquiera de los dos puede volver registrándose contra el registro nativo, como fusion.",
            "table": {
              "headers": [
                "Servicio",
                "Qué es",
                "Qué le falta para volver"
              ],
              "rows": [
                [
                  "supernova",
                  "Video largo a clips verticales con subtítulos",
                  "Un host con Whisper y ffmpeg, y registrarse en el registro nativo"
                ],
                [
                  "polaris",
                  "Guía y reglas aprendidas expuestas por MCP",
                  "Decidir su lugar en el producto; técnicamente solo re-registrarse"
                ]
              ]
            }
          }
        ]
      }
    },
    "packages": {
      "template": "content",
      "content": {
        "title": "Packages compartidos",
        "description": "Las librerías del monorepo: el código que los servicios comparten sin duplicar. Aquí también se documenta lo residual, porque saber qué ya no es la espina dorsal evita arqueología.",
        "sections": [
          {
            "title": "filament — el chasis del growth cluster",
            "content": "Un filamento es la estructura que conecta galaxias. filament (Python, packages/filament) es el chasis sobre el que se construyó la flota creativa: define el contrato de agente, el runner, un motor de IA plugable, el flujo de aprobación humana y el panel de revisión. Los servicios Python de la flota creativa (sirius, magnitude, chroma, azimuth) se construyeron sobre él.",
            "note": "Hoy los agentes creativos desplegados son capsules (claude -p con systemPrompt), más simples y fieles a la regla de la casa; la lógica específica de los servicios filament (por ejemplo mimesis en sirius) es material para portar, no código muerto."
          },
          {
            "title": "stardust — utilidades comunes",
            "content": "El polvo de estrellas está en todo. stardust (packages/stardust) son las utilidades TypeScript compartidas entre servicios Node: helpers pequeños sin peso de framework."
          },
          {
            "title": "umbra y umbra-js — el cliente de auth",
            "content": "El cliente de autenticación compartido, en Rust y TypeScript. Tiene página propia por su peso en la arquitectura.",
            "cards": [
              {
                "icon": "fas fa-id-badge",
                "title": "umbra — cliente de auth",
                "description": "Login, refresh, keychain y device flow para todos los clientes.",
                "link": "#umbra"
              }
            ]
          },
          {
            "title": "agent-kit — el residuo del orquestador",
            "content": "agent-kit fue la espina dorsal de la orquestación síncrona: el orquestador central que despachaba a los agentes. En el Acto III de Continuum se retiró: el orquestador se apagó en producción, se demostró que un job completaba por capcom con el orquestador muerto, y el paquete se redujo a tres módulos que otros aún usan: auth.ts, session-store.ts y task-store.ts.",
            "callout": {
              "type": "warning",
              "title": "No construir sobre agent-kit",
              "content": "El contrato real de la flota es el registro nativo de ephemeris y el patrón de fusion. agent-kit es residual y se seguirá encogiendo."
            }
          },
          {
            "title": "cluster — obsoleto",
            "content": "Un directorio vacío que quedó de una etapa anterior. No contiene código; pendiente de limpieza."
          },
          {
            "title": "Dónde viven los contratos",
            "table": {
              "headers": [
                "Contrato",
                "Dónde vive hoy"
              ],
              "rows": [
                [
                  "Agente de flota (manifest + /execute)",
                  "El patrón de fusion (agent-protocol.ts espejado por servicio)"
                ],
                [
                  "Capsule agent (systemPrompt + capacidades)",
                  "El registro nativo de ephemeris"
                ],
                [
                  "Auth de mesh y verificación",
                  "continuum/substrate/src/auth.mjs"
                ],
                [
                  "Cliente de identidad",
                  "packages/umbra y packages/umbra-js"
                ]
              ]
            }
          }
        ]
      }
    }
  },
  "endpoints": {
    "api-agents-list": {
      "method": "GET",
      "path": "/agents",
      "title": "Listar la flota",
      "description": "Devuelve la flota visible para tu organización: tus propios agentes mezclados con la flota de plataforma (tenant cosmos-system). El tenant sale exclusivamente del claim verificado del JWT; no existe parámetro para consultar otra organización. El systemPrompt de los capsules es configuración de operador y se remueve de la respuesta; si dos agentes comparten nombre, el tuyo gana sobre el de plataforma.",
      "authentication": true,
      "request": {
        "headers": [
          {
            "name": "Authorization",
            "value": "Bearer TU_TOKEN",
            "required": true,
            "description": "JWT de eclipse emitido para tu organización activa."
          }
        ]
      },
      "responses": {
        "200": {
          "description": "Flota del tenant",
          "examples": {
            "success": {
              "summary": "Flota propia + flota de plataforma",
              "value": {
                "agents": [
                  {
                    "name": "fusion",
                    "description": "Conversión de archivos e imágenes",
                    "capabilities": [
                      "file.convert",
                      "image.convert",
                      "document.convert",
                      "pdf.convert",
                      "ocr.extract"
                    ],
                    "endpoint": "http://fusion:9010",
                    "kind": "service",
                    "lastSeen": 1752096000000
                  },
                  {
                    "name": "sirius",
                    "description": "Estratega de campañas de marca y personas sintéticas",
                    "capabilities": [
                      "campaign.generate",
                      "audience.persona"
                    ],
                    "endpoint": "",
                    "kind": "capsule",
                    "lastSeen": 1752096000000
                  }
                ]
              }
            }
          }
        },
        "401": {
          "description": "No autorizado",
          "examples": {
            "error": {
              "summary": "Token ausente, inválido o expirado",
              "value": {
                "error": "unauthorized"
              }
            }
          }
        },
        "502": {
          "description": "Registro no disponible",
          "examples": {
            "error": {
              "summary": "ephemeris no respondió",
              "value": {
                "error": "registry unavailable"
              }
            }
          }
        }
      },
      "code_examples": [
        {
          "id": "agents-list-curl",
          "tech": "curl",
          "name": "cURL",
          "language": "bash",
          "title": "Listar la flota",
          "description": "Petición con cURL desde la terminal.",
          "file": "config/examples/agents-list.curl.sh"
        },
        {
          "id": "agents-list-js",
          "tech": "javascript",
          "name": "JavaScript",
          "language": "javascript",
          "title": "Listar la flota",
          "description": "Petición con la API fetch de JavaScript.",
          "file": "config/examples/agents-list.fetch.js"
        }
      ]
    },
    "api-agents-register": {
      "method": "POST",
      "path": "/agents",
      "title": "Registrar un agente",
      "description": "Registra (o actualiza, es un upsert por nombre) un agente en la flota de tu organización. capcom proxea la escritura a ephemeris con un token mesh que lleva tu tenantId, así que solo puedes tocar tu propia flota. Un agente de servicio declara endpoint HTTP con /execute; un capsule declara systemPrompt y se ejecuta con claude -p en la máquina del desarrollador.",
      "authentication": true,
      "request": {
        "headers": [
          {
            "name": "Authorization",
            "value": "Bearer TU_TOKEN",
            "required": true,
            "description": "JWT de eclipse emitido para tu organización activa."
          }
        ],
        "body": {
          "type": "json",
          "schema": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string",
                "description": "Nombre único del agente dentro del tenant",
                "example": "review-bot"
              },
              "description": {
                "type": "string",
                "description": "Qué hace el agente",
                "example": "Revisa pull requests con foco en seguridad"
              },
              "capabilities": {
                "type": "array",
                "description": "Capacidades que anuncia para el ruteo de intenciones",
                "example": [
                  "code.review"
                ]
              },
              "kind": {
                "type": "string",
                "description": "service (endpoint HTTP) o capsule (claude -p local)",
                "example": "capsule"
              },
              "endpoint": {
                "type": "string",
                "description": "URL del servicio con POST /execute; solo para kind service",
                "example": ""
              },
              "systemPrompt": {
                "type": "string",
                "description": "Rol del capsule; solo para kind capsule",
                "example": "Eres un revisor de código especializado en seguridad..."
              },
              "model": {
                "type": "string",
                "description": "Modelo sugerido para ejecutar el capsule",
                "example": "sonnet"
              }
            },
            "required": [
              "name"
            ]
          }
        }
      },
      "responses": {
        "200": {
          "description": "Agente registrado",
          "examples": {
            "success": {
              "summary": "Upsert aplicado",
              "value": {
                "registered": "review-bot"
              }
            }
          }
        },
        "401": {
          "description": "No autorizado",
          "examples": {
            "error": {
              "summary": "Token ausente, inválido o expirado",
              "value": {
                "error": "unauthorized"
              }
            }
          }
        }
      },
      "code_examples": [
        {
          "id": "agents-register-curl",
          "tech": "curl",
          "name": "cURL",
          "language": "bash",
          "title": "Registrar un agente",
          "description": "Petición con cURL desde la terminal.",
          "file": "config/examples/agents-register.curl.sh"
        },
        {
          "id": "agents-register-js",
          "tech": "javascript",
          "name": "JavaScript",
          "language": "javascript",
          "title": "Registrar un agente",
          "description": "Petición con la API fetch de JavaScript.",
          "file": "config/examples/agents-register.fetch.js"
        }
      ]
    },
    "api-agents-delete": {
      "method": "DELETE",
      "path": "/agents/:name",
      "title": "Quitar un agente",
      "description": "Elimina un agente del registro de tu organización. Solo alcanza tu propia flota: el tenant viene del claim del token, nunca de la URL. Los agentes de plataforma (cosmos-system) no se pueden borrar desde un tenant.",
      "authentication": true,
      "request": {
        "headers": [
          {
            "name": "Authorization",
            "value": "Bearer TU_TOKEN",
            "required": true,
            "description": "JWT de eclipse emitido para tu organización activa."
          }
        ]
      },
      "responses": {
        "200": {
          "description": "Resultado de la eliminación",
          "examples": {
            "success": {
              "summary": "Agente eliminado",
              "value": {
                "unregistered": true
              }
            },
            "missing": {
              "summary": "El agente no existía",
              "value": {
                "unregistered": false
              }
            }
          }
        },
        "401": {
          "description": "No autorizado",
          "examples": {
            "error": {
              "summary": "Token ausente, inválido o expirado",
              "value": {
                "error": "unauthorized"
              }
            }
          }
        }
      },
      "code_examples": [
        {
          "id": "agents-delete-curl",
          "tech": "curl",
          "name": "cURL",
          "language": "bash",
          "title": "Quitar un agente",
          "description": "Petición con cURL desde la terminal.",
          "file": "config/examples/agents-delete.curl.sh"
        },
        {
          "id": "agents-delete-js",
          "tech": "javascript",
          "name": "JavaScript",
          "language": "javascript",
          "title": "Quitar un agente",
          "description": "Petición con la API fetch de JavaScript.",
          "file": "config/examples/agents-delete.fetch.js"
        }
      ]
    },
    "api-agent-capsule": {
      "method": "GET",
      "path": "/agents/:name/capsule",
      "title": "Config de capsule",
      "description": "Devuelve la configuración de ejecución de un capsule agent visible para tu organización (propio o de plataforma), incluido su systemPrompt. Es el endpoint que usa un cliente con claude -p para ejecutar el capsule localmente: el cerebro corre en tu máquina, no en el servidor. Los agentes HTTP no exponen capsule y responden 404.",
      "authentication": true,
      "request": {
        "headers": [
          {
            "name": "Authorization",
            "value": "Bearer TU_TOKEN",
            "required": true,
            "description": "JWT de eclipse emitido para tu organización activa."
          }
        ]
      },
      "responses": {
        "200": {
          "description": "Configuración del capsule",
          "examples": {
            "success": {
              "summary": "Listo para claude -p",
              "value": {
                "name": "sirius",
                "systemPrompt": "Eres sirius, estratega de campañas de marca...",
                "capabilities": [
                  "campaign.generate",
                  "audience.persona"
                ],
                "model": null
              }
            }
          }
        },
        "401": {
          "description": "No autorizado",
          "examples": {
            "error": {
              "summary": "Token ausente, inválido o expirado",
              "value": {
                "error": "unauthorized"
              }
            }
          }
        },
        "404": {
          "description": "No es un capsule o no existe",
          "examples": {
            "error": {
              "summary": "Agente HTTP o nombre desconocido",
              "value": {
                "error": "unknown capsule"
              }
            }
          }
        }
      },
      "code_examples": [
        {
          "id": "agent-capsule-curl",
          "tech": "curl",
          "name": "cURL",
          "language": "bash",
          "title": "Config de capsule",
          "description": "Petición con cURL desde la terminal.",
          "file": "config/examples/agent-capsule.curl.sh"
        },
        {
          "id": "agent-capsule-js",
          "tech": "javascript",
          "name": "JavaScript",
          "language": "javascript",
          "title": "Config de capsule",
          "description": "Petición con la API fetch de JavaScript.",
          "file": "config/examples/agent-capsule.fetch.js"
        }
      ]
    },
    "api-manifests-create": {
      "method": "POST",
      "path": "/manifests",
      "title": "Crear un manifest",
      "description": "Convierte una declaración de trabajo en waypoints durables del ledger. Un manifest agrupa tres tipos de job: trajectories (secuencias de pasos encadenados por dependencias), changes (cambios de archivo que aterriza airlock) y agents (intenciones despachadas a la flota, ejecutadas durablemente por cygnus). Si un proceso muere a media tarea, el siguiente reconcile retoma sin repetir los pasos cerrados.",
      "authentication": true,
      "request": {
        "headers": [
          {
            "name": "Authorization",
            "value": "Bearer TU_TOKEN",
            "required": true,
            "description": "JWT de eclipse emitido para tu organización activa."
          }
        ],
        "body": {
          "type": "json",
          "schema": {
            "type": "object",
            "properties": {
              "trajectories": {
                "type": "array",
                "description": "Secuencias de pasos: [{jid, steps: [{title}]}]",
                "example": [
                  {
                    "jid": "plan",
                    "steps": [
                      {
                        "title": "Investigar competencia"
                      },
                      {
                        "title": "Redactar propuesta"
                      }
                    ]
                  }
                ]
              },
              "changes": {
                "type": "array",
                "description": "Cambios de archivo: [{jid, file, op, text}]",
                "example": []
              },
              "agents": {
                "type": "array",
                "description": "Jobs de agente: [{jid, intent, capability, input}]",
                "example": [
                  {
                    "jid": "campaign",
                    "intent": "genera una campaña para el lanzamiento",
                    "capability": "campaign.generate"
                  }
                ]
              },
              "execution": {
                "type": "object",
                "description": "Preferencias de ejecución de capsules para este manifest: {driver, model}",
                "example": {
                  "model": "sonnet"
                }
              }
            },
            "required": []
          }
        }
      },
      "responses": {
        "201": {
          "description": "Manifest creado",
          "examples": {
            "success": {
              "summary": "Trabajo durable en el ledger",
              "value": {
                "manifest": "a1b2c3d4",
                "trajectories": 1,
                "changes": 0
              }
            }
          }
        },
        "401": {
          "description": "No autorizado",
          "examples": {
            "error": {
              "summary": "Token ausente, inválido o expirado",
              "value": {
                "error": "unauthorized"
              }
            }
          }
        }
      },
      "code_examples": [
        {
          "id": "manifests-create-curl",
          "tech": "curl",
          "name": "cURL",
          "language": "bash",
          "title": "Crear un manifest",
          "description": "Petición con cURL desde la terminal.",
          "file": "config/examples/manifests-create.curl.sh"
        },
        {
          "id": "manifests-create-js",
          "tech": "javascript",
          "name": "JavaScript",
          "language": "javascript",
          "title": "Crear un manifest",
          "description": "Petición con la API fetch de JavaScript.",
          "file": "config/examples/manifests-create.fetch.js"
        }
      ]
    },
    "api-manifests-get": {
      "method": "GET",
      "path": "/manifests/:id",
      "title": "Estado de un manifest",
      "description": "Recalcula el estado de un manifest contra el ledger: qué jobs terminaron y el resultado de cada job de agente. Un manifest solo es visible para su propio tenant; un id de otra organización responde 404 (no 403) para no filtrar su existencia.",
      "authentication": true,
      "request": {
        "headers": [
          {
            "name": "Authorization",
            "value": "Bearer TU_TOKEN",
            "required": true,
            "description": "JWT de eclipse emitido para tu organización activa."
          }
        ]
      },
      "responses": {
        "200": {
          "description": "Estado del manifest",
          "examples": {
            "success": {
              "summary": "Manifest en progreso",
              "value": {
                "id": "a1b2c3d4",
                "complete": false,
                "trajectories": [
                  {
                    "jid": "plan",
                    "done": true
                  }
                ],
                "changes": [],
                "agents": [
                  {
                    "jid": "campaign",
                    "done": false,
                    "state": "open",
                    "result": null
                  }
                ]
              }
            }
          }
        },
        "401": {
          "description": "No autorizado",
          "examples": {
            "error": {
              "summary": "Token ausente, inválido o expirado",
              "value": {
                "error": "unauthorized"
              }
            }
          }
        },
        "404": {
          "description": "Desconocido para tu tenant",
          "examples": {
            "error": {
              "summary": "No existe o es de otra organización",
              "value": {
                "error": "unknown manifest"
              }
            }
          }
        }
      },
      "code_examples": [
        {
          "id": "manifests-get-curl",
          "tech": "curl",
          "name": "cURL",
          "language": "bash",
          "title": "Estado de un manifest",
          "description": "Petición con cURL desde la terminal.",
          "file": "config/examples/manifests-get.curl.sh"
        },
        {
          "id": "manifests-get-js",
          "tech": "javascript",
          "name": "JavaScript",
          "language": "javascript",
          "title": "Estado de un manifest",
          "description": "Petición con la API fetch de JavaScript.",
          "file": "config/examples/manifests-get.fetch.js"
        }
      ]
    },
    "api-memory-get": {
      "method": "GET",
      "path": "/memory/:projectId",
      "title": "Leer memoria de equipo",
      "description": "Lee el documento de memoria compartida de un proyecto. capcom proxea a echo con un token mesh que lleva tu identidad; echo nunca se expone a internet. El projectId es el sha256 del remoto git del repositorio, así todos los clientes (CLI, chat, pilot) direccionan el mismo documento. Aislado por tenant: solo ves la memoria de tu organización.",
      "authentication": true,
      "request": {
        "headers": [
          {
            "name": "Authorization",
            "value": "Bearer TU_TOKEN",
            "required": true,
            "description": "JWT de eclipse emitido para tu organización activa."
          }
        ]
      },
      "responses": {
        "200": {
          "description": "Documento de memoria",
          "examples": {
            "success": {
              "summary": "Memoria con su versión",
              "value": {
                "content": "# Memoria del equipo\n\n- El deploy se hace por git pull, nunca rsync.\n- La API de pagos usa idempotency keys.",
                "version": 7,
                "updatedAt": 1752096000000,
                "updatedBy": "usr_9f2c"
              }
            }
          }
        },
        "401": {
          "description": "No autorizado",
          "examples": {
            "error": {
              "summary": "Token ausente, inválido o expirado",
              "value": {
                "error": "unauthorized"
              }
            }
          }
        },
        "404": {
          "description": "Sin memoria todavía",
          "examples": {
            "error": {
              "summary": "El proyecto no tiene documento",
              "value": {
                "error": "memory not found"
              }
            }
          }
        }
      },
      "code_examples": [
        {
          "id": "memory-get-curl",
          "tech": "curl",
          "name": "cURL",
          "language": "bash",
          "title": "Leer memoria de equipo",
          "description": "Petición con cURL desde la terminal.",
          "file": "config/examples/memory-get.curl.sh"
        },
        {
          "id": "memory-get-js",
          "tech": "javascript",
          "name": "JavaScript",
          "language": "javascript",
          "title": "Leer memoria de equipo",
          "description": "Petición con la API fetch de JavaScript.",
          "file": "config/examples/memory-get.fetch.js"
        }
      ]
    },
    "api-memory-put": {
      "method": "PUT",
      "path": "/memory/:projectId",
      "title": "Escribir memoria de equipo",
      "description": "Escribe el documento de memoria con concurrencia optimista: el header If-Match lleva la última versión conocida (0 para crear un documento nuevo). Si alguien escribió antes que tú, recibes 409 con el documento vigente para fusionar y reintentar. Cada escritura guarda una revisión consultable en /memory/:projectId/revisions.",
      "authentication": true,
      "request": {
        "headers": [
          {
            "name": "Authorization",
            "value": "Bearer TU_TOKEN",
            "required": true,
            "description": "JWT de eclipse emitido para tu organización activa."
          },
          {
            "name": "If-Match",
            "value": "7",
            "required": true,
            "description": "Última versión conocida del documento; 0 si aún no existe."
          }
        ],
        "body": {
          "type": "json",
          "schema": {
            "type": "object",
            "properties": {
              "content": {
                "type": "string",
                "description": "El documento markdown completo",
                "example": "# Memoria del equipo\n\n- Nueva convención de commits."
              }
            },
            "required": [
              "content"
            ]
          }
        }
      },
      "responses": {
        "200": {
          "description": "Escritura aplicada",
          "examples": {
            "success": {
              "summary": "Nueva versión",
              "value": {
                "version": 8
              }
            }
          }
        },
        "401": {
          "description": "No autorizado",
          "examples": {
            "error": {
              "summary": "Token ausente, inválido o expirado",
              "value": {
                "error": "unauthorized"
              }
            }
          }
        },
        "409": {
          "description": "Conflicto de versión",
          "examples": {
            "error": {
              "summary": "Otro cliente escribió primero; se devuelve el documento vigente",
              "value": {
                "content": "# Memoria del equipo\n\n- El deploy se hace por git pull, nunca rsync.\n- La API de pagos usa idempotency keys.",
                "version": 7,
                "updatedAt": 1752096000000,
                "updatedBy": "usr_9f2c"
              }
            }
          }
        },
        "412": {
          "description": "Falta If-Match",
          "examples": {
            "error": {
              "summary": "Header requerido",
              "value": {
                "error": "if-match header with the last known version is required"
              }
            }
          }
        }
      },
      "code_examples": [
        {
          "id": "memory-put-curl",
          "tech": "curl",
          "name": "cURL",
          "language": "bash",
          "title": "Escribir memoria de equipo",
          "description": "Petición con cURL desde la terminal.",
          "file": "config/examples/memory-put.curl.sh"
        },
        {
          "id": "memory-put-js",
          "tech": "javascript",
          "name": "JavaScript",
          "language": "javascript",
          "title": "Escribir memoria de equipo",
          "description": "Petición con la API fetch de JavaScript.",
          "file": "config/examples/memory-put.fetch.js"
        }
      ]
    },
    "api-tether": {
      "method": "GET",
      "path": "/tether",
      "title": "Tether de sesión",
      "description": "Devuelve tu tether: los waypoints abiertos asignados a ti, marcando ready los que no tienen bloqueos pendientes (esos van primero). Es lo que cosmos prime usa para arrancar cada sesión sabiendo qué sigue. capcom lo proxea a ephemeris on-behalf-of de tu tenant.",
      "authentication": true,
      "request": {
        "headers": [
          {
            "name": "Authorization",
            "value": "Bearer TU_TOKEN",
            "required": true,
            "description": "JWT de eclipse emitido para tu organización activa."
          }
        ],
        "query_params": [
          {
            "name": "assignee",
            "type": "string",
            "description": "Identidad de crew cuyos waypoints quieres; el CLI usa crew/<userId>",
            "example": "crew/usr_9f2c"
          }
        ]
      },
      "responses": {
        "200": {
          "description": "Waypoints asignados",
          "examples": {
            "success": {
              "summary": "Un waypoint listo y uno bloqueado",
              "value": {
                "tether": [
                  {
                    "id": "bd-041",
                    "title": "campaign: genera una campaña para el lanzamiento",
                    "status": "open",
                    "labels": [
                      "mf:a1b2c3d4",
                      "kind:agent"
                    ],
                    "ready": true
                  },
                  {
                    "id": "bd-042",
                    "title": "Publicar resultados",
                    "status": "open",
                    "labels": [
                      "mf:a1b2c3d4"
                    ],
                    "ready": false
                  }
                ]
              }
            }
          }
        },
        "401": {
          "description": "No autorizado",
          "examples": {
            "error": {
              "summary": "Token ausente, inválido o expirado",
              "value": {
                "error": "unauthorized"
              }
            }
          }
        }
      },
      "code_examples": [
        {
          "id": "tether-curl",
          "tech": "curl",
          "name": "cURL",
          "language": "bash",
          "title": "Tether de sesión",
          "description": "Petición con cURL desde la terminal.",
          "file": "config/examples/tether.curl.sh"
        },
        {
          "id": "tether-js",
          "tech": "javascript",
          "name": "JavaScript",
          "language": "javascript",
          "title": "Tether de sesión",
          "description": "Petición con la API fetch de JavaScript.",
          "file": "config/examples/tether.fetch.js"
        }
      ]
    },
    "api-mail": {
      "method": "GET",
      "path": "/mail",
      "title": "Correo de crew",
      "description": "Lee (sin consumir) los mensajes no leídos de un miembro del crew. El correo es durable: vive junto al ledger y sobrevive reinicios. Para enviar, haz POST /mail con {to, from, text}; para consumir marcando como leído, POST /mail/drain con {to}. cosmos prime lo incluye en la hidratación y cosmos mail lo muestra en la terminal.",
      "authentication": true,
      "request": {
        "headers": [
          {
            "name": "Authorization",
            "value": "Bearer TU_TOKEN",
            "required": true,
            "description": "JWT de eclipse emitido para tu organización activa."
          }
        ],
        "query_params": [
          {
            "name": "to",
            "type": "string",
            "description": "Buzón a leer; el CLI usa crew/<userId>",
            "example": "crew/usr_9f2c"
          }
        ]
      },
      "responses": {
        "200": {
          "description": "Mensajes sin leer",
          "examples": {
            "success": {
              "summary": "Un mensaje pendiente",
              "value": {
                "messages": [
                  {
                    "id": "m8k2p1q9",
                    "to": "crew/usr_9f2c",
                    "from": "cygnus",
                    "text": "El waypoint bd-041 se completó: la campaña está en el ledger.",
                    "ts": 1752096000000,
                    "read": false
                  }
                ]
              }
            }
          }
        },
        "401": {
          "description": "No autorizado",
          "examples": {
            "error": {
              "summary": "Token ausente, inválido o expirado",
              "value": {
                "error": "unauthorized"
              }
            }
          }
        }
      },
      "code_examples": [
        {
          "id": "mail-curl",
          "tech": "curl",
          "name": "cURL",
          "language": "bash",
          "title": "Correo de crew",
          "description": "Petición con cURL desde la terminal.",
          "file": "config/examples/mail.curl.sh"
        },
        {
          "id": "mail-js",
          "tech": "javascript",
          "name": "JavaScript",
          "language": "javascript",
          "title": "Correo de crew",
          "description": "Petición con la API fetch de JavaScript.",
          "file": "config/examples/mail.fetch.js"
        }
      ]
    },
    "api-waypoint-close": {
      "method": "POST",
      "path": "/waypoints/:id/close",
      "title": "Cerrar un waypoint",
      "description": "Marca un waypoint como cerrado en el ledger de tu tenant. Es el paso final del ciclo claim-lease: un agente (o tú, con cosmos done) reclama un waypoint, trabaja, y lo cierra al terminar. Los waypoints cerrados nunca se re-ejecutan en un reconcile.",
      "authentication": true,
      "request": {
        "headers": [
          {
            "name": "Authorization",
            "value": "Bearer TU_TOKEN",
            "required": true,
            "description": "JWT de eclipse emitido para tu organización activa."
          }
        ],
        "body": {
          "type": "json",
          "schema": {
            "type": "object",
            "properties": {
              "actor": {
                "type": "string",
                "description": "Quién cierra el waypoint",
                "example": "crew/usr_9f2c"
              }
            },
            "required": []
          }
        }
      },
      "responses": {
        "200": {
          "description": "Waypoint cerrado",
          "examples": {
            "success": {
              "summary": "Cierre registrado",
              "value": {
                "closed": "bd-041"
              }
            }
          }
        },
        "401": {
          "description": "No autorizado",
          "examples": {
            "error": {
              "summary": "Token ausente, inválido o expirado",
              "value": {
                "error": "unauthorized"
              }
            }
          }
        }
      },
      "code_examples": [
        {
          "id": "waypoint-close-curl",
          "tech": "curl",
          "name": "cURL",
          "language": "bash",
          "title": "Cerrar un waypoint",
          "description": "Petición con cURL desde la terminal.",
          "file": "config/examples/waypoint-close.curl.sh"
        },
        {
          "id": "waypoint-close-js",
          "tech": "javascript",
          "name": "JavaScript",
          "language": "javascript",
          "title": "Cerrar un waypoint",
          "description": "Petición con la API fetch de JavaScript.",
          "file": "config/examples/waypoint-close.fetch.js"
        }
      ]
    },
    "api-auth-register": {
      "method": "POST",
      "path": "/api/v1/auth/register",
      "title": "Crear cuenta",
      "base_url": "https://auth.thecosmosai.cloud",
      "description": "Crea un usuario y auto-provisiona su organización personal (el orgId es tu tenantId). Devuelve la sesión completa: access token RS256, refresh token opaco y el bootstrap con tus organizaciones. El correo llega con un código de verificación; varias operaciones (tokens personales, invitaciones) exigen correo verificado.",
      "authentication": false,
      "request": {
        "body": {
          "type": "json",
          "schema": {
            "type": "object",
            "properties": {
              "email": {
                "type": "string",
                "description": "Correo del usuario",
                "example": "dev@equipo.mx"
              },
              "name": {
                "type": "string",
                "description": "Nombre para mostrar",
                "example": "Dev"
              },
              "password": {
                "type": "string",
                "description": "Contraseña",
                "example": "una-frase-larga-y-unica"
              }
            },
            "required": [
              "email",
              "password"
            ]
          }
        }
      },
      "responses": {
        "201": {
          "description": "Cuenta creada",
          "examples": {
            "success": {
              "summary": "Sesión emitida con organización personal",
              "value": {
                "accessToken": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImVjbGlwc2UtcHJvZC0yMDI2YSJ9…",
                "refreshToken": "N3f…base64url…Qk",
                "expiresIn": 900,
                "bootstrap": {
                  "user": {
                    "id": "usr_9f2c",
                    "email": "dev@equipo.mx",
                    "name": "Dev",
                    "emailVerified": true
                  },
                  "organizations": [
                    {
                      "org": {
                        "id": "org_personal_9f2c",
                        "name": "Dev (personal)"
                      },
                      "role": "owner"
                    }
                  ],
                  "activeOrg": {
                    "org": {
                      "id": "org_personal_9f2c",
                      "name": "Dev (personal)"
                    },
                    "role": "owner"
                  }
                }
              }
            }
          }
        },
        "400": {
          "description": "Datos inválidos",
          "examples": {
            "error": {
              "summary": "Revisa los datos e inténtalo de nuevo.",
              "value": {
                "error": {
                  "code": "invalid_input",
                  "message": "Revisa los datos e inténtalo de nuevo."
                }
              }
            }
          }
        },
        "429": {
          "description": "Demasiados intentos",
          "examples": {
            "error": {
              "summary": "Demasiados intentos. Espera un momento.",
              "value": {
                "error": {
                  "code": "too_many_requests",
                  "message": "Demasiados intentos. Espera un momento."
                }
              }
            }
          }
        }
      },
      "code_examples": [
        {
          "id": "auth-register-curl",
          "tech": "curl",
          "name": "cURL",
          "language": "bash",
          "title": "Crear cuenta",
          "description": "Petición con cURL desde la terminal.",
          "file": "config/examples/auth-register.curl.sh"
        },
        {
          "id": "auth-register-js",
          "tech": "javascript",
          "name": "JavaScript",
          "language": "javascript",
          "title": "Crear cuenta",
          "description": "Petición con la API fetch de JavaScript.",
          "file": "config/examples/auth-register.fetch.js"
        }
      ]
    },
    "api-auth-login": {
      "method": "POST",
      "path": "/api/v1/auth/login",
      "title": "Iniciar sesión",
      "base_url": "https://auth.thecosmosai.cloud",
      "description": "Autentica con correo y contraseña y devuelve la sesión: access token RS256 de vida corta, refresh token de rotación y el bootstrap de organizaciones. Si inicias sesión desde un dispositivo nuevo recibirás una alerta de seguridad por correo.",
      "authentication": false,
      "request": {
        "body": {
          "type": "json",
          "schema": {
            "type": "object",
            "properties": {
              "email": {
                "type": "string",
                "description": "Correo del usuario",
                "example": "dev@equipo.mx"
              },
              "password": {
                "type": "string",
                "description": "Contraseña",
                "example": "una-frase-larga-y-unica"
              }
            },
            "required": [
              "email",
              "password"
            ]
          }
        }
      },
      "responses": {
        "200": {
          "description": "Sesión emitida",
          "examples": {
            "success": {
              "summary": "Tokens + bootstrap",
              "value": {
                "accessToken": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImVjbGlwc2UtcHJvZC0yMDI2YSJ9…",
                "refreshToken": "N3f…base64url…Qk",
                "expiresIn": 900,
                "bootstrap": {
                  "user": {
                    "id": "usr_9f2c",
                    "email": "dev@equipo.mx",
                    "name": "Dev",
                    "emailVerified": true
                  },
                  "organizations": [
                    {
                      "org": {
                        "id": "org_personal_9f2c",
                        "name": "Dev (personal)"
                      },
                      "role": "owner"
                    }
                  ],
                  "activeOrg": {
                    "org": {
                      "id": "org_personal_9f2c",
                      "name": "Dev (personal)"
                    },
                    "role": "owner"
                  }
                }
              }
            }
          }
        },
        "401": {
          "description": "Credenciales inválidas",
          "examples": {
            "error": {
              "summary": "Correo o contraseña incorrectos.",
              "value": {
                "error": {
                  "code": "invalid_credentials",
                  "message": "Correo o contraseña incorrectos."
                }
              }
            }
          }
        },
        "429": {
          "description": "Demasiados intentos",
          "examples": {
            "error": {
              "summary": "Demasiados intentos. Espera un momento.",
              "value": {
                "error": {
                  "code": "too_many_requests",
                  "message": "Demasiados intentos. Espera un momento."
                }
              }
            }
          }
        }
      },
      "code_examples": [
        {
          "id": "auth-login-curl",
          "tech": "curl",
          "name": "cURL",
          "language": "bash",
          "title": "Iniciar sesión",
          "description": "Petición con cURL desde la terminal.",
          "file": "config/examples/auth-login.curl.sh"
        },
        {
          "id": "auth-login-js",
          "tech": "javascript",
          "name": "JavaScript",
          "language": "javascript",
          "title": "Iniciar sesión",
          "description": "Petición con la API fetch de JavaScript.",
          "file": "config/examples/auth-login.fetch.js"
        }
      ]
    },
    "api-auth-refresh": {
      "method": "POST",
      "path": "/api/v1/auth/refresh",
      "title": "Refrescar sesión",
      "base_url": "https://auth.thecosmosai.cloud",
      "description": "Canjea el refresh token por un access token nuevo. Los refresh tokens rotan en cada uso y eclipse detecta el reuse: si un token ya rotado vuelve a presentarse, la sesión completa se revoca por seguridad (posible robo). Guarda siempre el refresh token más reciente.",
      "authentication": false,
      "request": {
        "body": {
          "type": "json",
          "schema": {
            "type": "object",
            "properties": {
              "refreshToken": {
                "type": "string",
                "description": "El refresh token vigente de la sesión",
                "example": "N3f…base64url…Qk"
              }
            },
            "required": [
              "refreshToken"
            ]
          }
        }
      },
      "responses": {
        "200": {
          "description": "Sesión renovada",
          "examples": {
            "success": {
              "summary": "Tokens rotados",
              "value": {
                "accessToken": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImVjbGlwc2UtcHJvZC0yMDI2YSJ9…",
                "refreshToken": "N3f…base64url…Qk",
                "expiresIn": 900,
                "bootstrap": {
                  "user": {
                    "id": "usr_9f2c",
                    "email": "dev@equipo.mx",
                    "name": "Dev",
                    "emailVerified": true
                  },
                  "organizations": [
                    {
                      "org": {
                        "id": "org_personal_9f2c",
                        "name": "Dev (personal)"
                      },
                      "role": "owner"
                    }
                  ],
                  "activeOrg": {
                    "org": {
                      "id": "org_personal_9f2c",
                      "name": "Dev (personal)"
                    },
                    "role": "owner"
                  }
                }
              }
            }
          }
        },
        "401": {
          "description": "Token inválido, expirado o reusado",
          "examples": {
            "error": {
              "summary": "Tu sesión expiró. Inicia sesión de nuevo.",
              "value": {
                "error": {
                  "code": "invalid_refresh",
                  "message": "Tu sesión expiró. Inicia sesión de nuevo."
                }
              }
            }
          }
        }
      },
      "code_examples": [
        {
          "id": "auth-refresh-curl",
          "tech": "curl",
          "name": "cURL",
          "language": "bash",
          "title": "Refrescar sesión",
          "description": "Petición con cURL desde la terminal.",
          "file": "config/examples/auth-refresh.curl.sh"
        },
        {
          "id": "auth-refresh-js",
          "tech": "javascript",
          "name": "JavaScript",
          "language": "javascript",
          "title": "Refrescar sesión",
          "description": "Petición con la API fetch de JavaScript.",
          "file": "config/examples/auth-refresh.fetch.js"
        }
      ]
    },
    "api-device-code": {
      "method": "POST",
      "path": "/api/v1/auth/device/code",
      "title": "Device flow: pedir código",
      "base_url": "https://auth.thecosmosai.cloud",
      "description": "Inicia una autorización de dispositivo (RFC 8628) con PKCE opcional: el CLI manda un code_challenge S256 y guarda el verifier. Devuelve el device_code (secreto del cliente), el user_code humano y la URL de aprobación en el navegador. El código expira en 30 minutos.",
      "authentication": false,
      "request": {
        "body": {
          "type": "json",
          "schema": {
            "type": "object",
            "properties": {
              "client_id": {
                "type": "string",
                "description": "Cliente que pide la autorización",
                "example": "cosmos-cli"
              },
              "code_challenge": {
                "type": "string",
                "description": "Reto PKCE derivado del code_verifier",
                "example": "E9Mel…S256…u1o"
              },
              "code_challenge_method": {
                "type": "string",
                "description": "Método del reto; usa S256",
                "example": "S256"
              }
            },
            "required": []
          }
        }
      },
      "responses": {
        "200": {
          "description": "Autorización iniciada",
          "examples": {
            "success": {
              "summary": "Código listo para aprobar en el navegador",
              "value": {
                "device_code": "dvc_k8s…secreto…",
                "user_code": "QK7M-PW2R",
                "verification_uri": "https://auth.thecosmosai.cloud/device",
                "verification_uri_complete": "https://auth.thecosmosai.cloud/device?code=QK7M-PW2R",
                "interval": 5
              }
            }
          }
        },
        "429": {
          "description": "Demasiados intentos",
          "examples": {
            "error": {
              "summary": "Demasiados intentos. Espera un momento.",
              "value": {
                "error": {
                  "code": "too_many_requests",
                  "message": "Demasiados intentos. Espera un momento."
                }
              }
            }
          }
        }
      },
      "code_examples": [
        {
          "id": "device-code-curl",
          "tech": "curl",
          "name": "cURL",
          "language": "bash",
          "title": "Device flow: pedir código",
          "description": "Petición con cURL desde la terminal.",
          "file": "config/examples/device-code.curl.sh"
        },
        {
          "id": "device-code-js",
          "tech": "javascript",
          "name": "JavaScript",
          "language": "javascript",
          "title": "Device flow: pedir código",
          "description": "Petición con la API fetch de JavaScript.",
          "file": "config/examples/device-code.fetch.js"
        }
      ]
    },
    "api-device-token": {
      "method": "POST",
      "path": "/api/v1/auth/device/token",
      "title": "Device flow: canjear token",
      "base_url": "https://auth.thecosmosai.cloud",
      "description": "El cliente sondea este endpoint con el device_code (y el code_verifier si inició con PKCE) hasta que el usuario aprueba en el navegador. Los errores hablan el shape OAuth plano de RFC 8628: authorization_pending mientras no hay decisión, slow_down si sondeas más rápido que el interval, access_denied si el usuario negó (o el PKCE no cuadra) y expired_token pasados 30 minutos. El código es de un solo uso: al canjearse queda consumido.",
      "authentication": false,
      "request": {
        "body": {
          "type": "json",
          "schema": {
            "type": "object",
            "properties": {
              "device_code": {
                "type": "string",
                "description": "El device_code recibido al iniciar el flujo",
                "example": "dvc_k8s…secreto…"
              },
              "code_verifier": {
                "type": "string",
                "description": "El verifier PKCE original; obligatorio si el flujo inició con code_challenge",
                "example": "0Zt…43-128-chars…pQ"
              }
            },
            "required": [
              "device_code"
            ]
          }
        }
      },
      "responses": {
        "200": {
          "description": "Aprobado: sesión emitida",
          "examples": {
            "success": {
              "summary": "Access token del tenant elegido; el refresh viaja en cookie HttpOnly",
              "value": {
                "tokens": {
                  "accessToken": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImVjbGlwc2UtcHJvZC0yMDI2YSJ9…",
                  "expiresIn": 900
                },
                "user": {
                  "email": "dev@equipo.mx",
                  "tenantId": "org_personal_9f2c",
                  "role": "owner"
                }
              }
            }
          }
        },
        "400": {
          "description": "Estados del sondeo (RFC 8628)",
          "examples": {
            "pending": {
              "summary": "El usuario aún no decide",
              "value": {
                "error": "authorization_pending"
              }
            },
            "slow_down": {
              "summary": "Sondeo más rápido que el interval",
              "value": {
                "error": "slow_down"
              }
            },
            "denied": {
              "summary": "Negado o PKCE inválido",
              "value": {
                "error": "access_denied"
              }
            },
            "expired": {
              "summary": "Código expirado o ya consumido",
              "value": {
                "error": "expired_token"
              }
            }
          }
        }
      },
      "code_examples": [
        {
          "id": "device-token-curl",
          "tech": "curl",
          "name": "cURL",
          "language": "bash",
          "title": "Device flow: canjear token",
          "description": "Petición con cURL desde la terminal.",
          "file": "config/examples/device-token.curl.sh"
        },
        {
          "id": "device-token-js",
          "tech": "javascript",
          "name": "JavaScript",
          "language": "javascript",
          "title": "Device flow: canjear token",
          "description": "Petición con la API fetch de JavaScript.",
          "file": "config/examples/device-token.fetch.js"
        }
      ]
    },
    "api-pat-create": {
      "method": "POST",
      "path": "/api/v1/tokens",
      "title": "Crear token personal",
      "base_url": "https://auth.thecosmosai.cloud",
      "description": "Crea un token de acceso personal estilo GitHub (prefijo cosmos_pat_) para iniciar sesión sin navegador: pégalo con cosmos login --token o cámbialo por una sesión en POST /api/v1/auth/token. El valor completo solo se muestra una vez; eclipse guarda únicamente su hash. Requiere correo verificado. Expiración opcional hasta 365 días. GET lista tus tokens (id, nombre, prefijo, fechas) y DELETE /api/v1/tokens/:id lo revoca.",
      "authentication": true,
      "request": {
        "headers": [
          {
            "name": "Authorization",
            "value": "Bearer TU_TOKEN",
            "required": true,
            "description": "Sesión del usuario que crea el token (correo verificado)."
          }
        ],
        "body": {
          "type": "json",
          "schema": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string",
                "description": "Nombre para reconocer el token",
                "example": "laptop-personal"
              },
              "expiresInDays": {
                "type": "number",
                "description": "Días de vida; omite para que no expire (máximo 365)",
                "example": 90
              }
            },
            "required": []
          }
        }
      },
      "responses": {
        "201": {
          "description": "Token creado",
          "examples": {
            "success": {
              "summary": "Guarda el valor: no vuelve a mostrarse",
              "value": {
                "token": "cosmos_pat_Qm93…solo-una-vez…Zx",
                "id": "tok_5c1a",
                "userId": "usr_9f2c",
                "name": "laptop-personal",
                "prefix": "cosmos_pat_Qm93…",
                "createdAt": "2026-07-22T16:00:00.000Z",
                "expiresAt": "2026-10-20T16:00:00.000Z"
              }
            }
          }
        },
        "401": {
          "description": "No autorizado",
          "examples": {
            "error": {
              "summary": "Inicia sesión para continuar.",
              "value": {
                "error": {
                  "code": "unauthorized",
                  "message": "Inicia sesión para continuar."
                }
              }
            }
          }
        },
        "403": {
          "description": "Correo sin verificar",
          "examples": {
            "error": {
              "summary": "Verifica tu correo para continuar.",
              "value": {
                "error": {
                  "code": "email_not_verified",
                  "message": "Verifica tu correo para continuar."
                }
              }
            }
          }
        }
      },
      "code_examples": [
        {
          "id": "pat-create-curl",
          "tech": "curl",
          "name": "cURL",
          "language": "bash",
          "title": "Crear token personal",
          "description": "Petición con cURL desde la terminal.",
          "file": "config/examples/pat-create.curl.sh"
        },
        {
          "id": "pat-create-js",
          "tech": "javascript",
          "name": "JavaScript",
          "language": "javascript",
          "title": "Crear token personal",
          "description": "Petición con la API fetch de JavaScript.",
          "file": "config/examples/pat-create.fetch.js"
        }
      ]
    },
    "api-admin-users": {
      "method": "GET",
      "path": "/api/v1/admin/users",
      "title": "Admin: listar usuarios",
      "base_url": "https://auth.thecosmosai.cloud",
      "description": "Lista los usuarios de la plataforma con paginación por cursor keyset (estable ante altas nuevas). Exclusivo del back office: exige el claim platformRole=admin, que eclipse emite solo a una allowlist de correos verificados, nunca desde una columna mutable. Filtros: q busca por correo o nombre, emailVerified filtra por estado de verificación.",
      "authentication": true,
      "request": {
        "headers": [
          {
            "name": "Authorization",
            "value": "Bearer TU_TOKEN",
            "required": true,
            "description": "Sesión con claim platformRole=admin."
          }
        ],
        "query_params": [
          {
            "name": "limit",
            "type": "integer",
            "description": "Tamaño de página, 1 a 100",
            "example": "50"
          },
          {
            "name": "cursor",
            "type": "string",
            "description": "Cursor opaco devuelto en nextCursor",
            "example": "eyJjcmVhdGVkQXQi…"
          },
          {
            "name": "q",
            "type": "string",
            "description": "Búsqueda por correo o nombre",
            "example": "equipo.mx"
          },
          {
            "name": "emailVerified",
            "type": "boolean",
            "description": "true o false para filtrar por verificación",
            "example": "true"
          }
        ]
      },
      "responses": {
        "200": {
          "description": "Página de usuarios",
          "examples": {
            "success": {
              "summary": "Primera página con cursor",
              "value": {
                "users": [
                  {
                    "id": "usr_9f2c",
                    "email": "dev@equipo.mx",
                    "name": "Dev",
                    "emailVerified": true,
                    "platformAdmin": false,
                    "language": "es",
                    "createdAt": "2026-06-01T12:00:00.000Z",
                    "lastLoginAt": "2026-07-22T09:12:00.000Z",
                    "orgCount": 2
                  }
                ],
                "nextCursor": "eyJjcmVhdGVkQXQi…"
              }
            }
          }
        },
        "401": {
          "description": "No autorizado",
          "examples": {
            "error": {
              "summary": "Inicia sesión para continuar.",
              "value": {
                "error": {
                  "code": "unauthorized",
                  "message": "Inicia sesión para continuar."
                }
              }
            }
          }
        },
        "403": {
          "description": "Sin rol de plataforma",
          "examples": {
            "error": {
              "summary": "No tienes acceso a esta sección.",
              "value": {
                "error": {
                  "code": "forbidden",
                  "message": "No tienes acceso a esta sección."
                }
              }
            }
          }
        }
      },
      "code_examples": [
        {
          "id": "admin-users-curl",
          "tech": "curl",
          "name": "cURL",
          "language": "bash",
          "title": "Admin: listar usuarios",
          "description": "Petición con cURL desde la terminal.",
          "file": "config/examples/admin-users.curl.sh"
        },
        {
          "id": "admin-users-js",
          "tech": "javascript",
          "name": "JavaScript",
          "language": "javascript",
          "title": "Admin: listar usuarios",
          "description": "Petición con la API fetch de JavaScript.",
          "file": "config/examples/admin-users.fetch.js"
        }
      ]
    }
  },
  "theme": {
    "colors": {
      "primary": "#ff8a24",
      "secondary": "#ffd166",
      "success": "#10b981",
      "warning": "#ffb347",
      "error": "#e6350f",
      "info": "#ffd166"
    }
  },
  "features": {
    "syntax_highlighting": true,
    "code_copy": true,
    "dark_mode": true,
    "search": true,
    "mobile_responsive": true
  }
}