Manifiesto de proyecto

Archivo HubBound

El archivo HubBound a nivel proyecto — pins exactos más releases nombrados de artifacts y kits. Commitealo para compartir los mismos inputs.

Qué es

El archivo HubBound es hubbound.json dentro del proyecto. Registra los artifacts y kits exactos que necesita el proyecto y, opcionalmente, los paquetes locales que este repo puede publicar.

Para install y upgrade, HubBound encuentra el archivo más cercano caminando desde el directorio actual. Deploy es distinto a propósito: --path debe apuntar al directorio que contiene el manifest, para no elegir accidentalmente uno padre.

Para qué sirve

Usa dependencies para declarar el tooling que espera el proyecto. hubbound install sin argumentos instala todos los dependencies — como npm install leyendo package.json.

Usa deployments para describir los artifacts y kits que hubbound deploy puede publicar. Install lee dependencies; deploy lee deployments. Separar ambos mapas evita que una dependencia del proyecto se convierta en un release solo por estar en el mismo archivo.

Estructura del archivo

Los archivos nuevos usan schema_version 2. hubbound init crea name y un objeto dependencies vacío; agrega deployments si el repo publica artifacts o kits.

{
  "schema_version": 2,
  "name": "my-app",
  "dependencies": {
    "artifacts": {
      "vendor/shared-rule": "1.4.0"
    },
    "kits": {
      "vendor/base-kit": "2.0.0"
    }
  },
  "deployments": {
    "auditor": {
      "kind": "artifact",
      "path": "packages/auditor",
      "tag": "security-auditor",
      "version": "1.2.0",
      "visibility": "public",
      "artifact_type": "SKILL",
      "description": "Security audit skill",
      "content": { "entrypoint": "SKILL.md" },
      "files": ["SKILL.md", "references/**", "scripts/**"]
    },
    "security-kit": {
      "kind": "kit",
      "path": "packages/security-kit",
      "tag": "security-kit",
      "version": "2.0.0",
      "visibility": "public",
      "description": "Security tooling",
      "changelog": "Publish the auditor skill",
      "members": [
        { "deployment": "auditor" },
        { "tag": "vendor/remote-auditor", "version": "1.5.0" }
      ]
    }
  }
}
schema_version Formato del manifiesto. Los archivos de proyecto nuevos usan 2; versiones no soportadas fallan.
name Label del proyecto. Por defecto es el basename del directorio al correr hubbound init. Informativo — no se usa como clave de install.
dependencies Objeto opcional con pins exactos de artifacts y kits bajo dependencies.artifacts y dependencies.kits.
deployments Mapa opcional de nombres locales de deployment. deploy requiere al menos uno y usa estas entradas, no dependencies.
deployment name Selector local, no el tag remoto: 1–64 caracteres, empieza por letra o dígito y después admite letras, dígitos, ., _ o -.
deployment.path Directorio relativo con los archivos del paquete, resuelto desde el directorio del manifest. Default: .; se rechazan paths absolutos, backslashes y traversal al padre.
deployment.tag/version Identidad remota y versión SemVer exacta del release. Los tags usan segmentos lowercase como security-auditor o vendor/security-auditor.
deployment.visibility Uno de private, org o public.
artifact_type/content/files Propiedades solo de artifact. artifact_type es un label no vacío (los tipos del runtime son MCP, SKILL, SUBAGENT, HOOK y RULE); content es JSON opcional; files es una lista no vacía de patrones relativos.
kit.changelog/members Propiedades de composición del kit. members es exactamente una referencia local {deployment} o remota {tag, version}; changelog es texto opcional del kit y no se envía para artifacts.
  • Los pins de dependencies del proyecto deben ser SemVer exactos, como 1.2.0 — latest no es válido en un manifest v2 de proyecto. Los perfiles conservan su semántica histórica separada de latest.
  • Se rechazan campos desconocidos, claves JSON duplicadas, tipos inválidos, miembros duplicados de kits y ciclos de deployments locales.
  • HubBound encuentra el archivo caminando hacia arriba desde el directorio actual.

Archivos legacy y migración

Los manifests viejos con artifacts, kits o publish en el root se aceptan como v1 por compatibilidad y se normalizan en memoria. Las operaciones que escriben serializan la forma canónica v2 bajo dependencies y deployments; hubbound init escribe v2 directamente.

No mezcles artifacts/kits en el root con un documento v2. En v2, dependencies es el único mapa de dependencias y deployments es el único mapa de publicación.

Publicar con hubbound deploy

Un deployment es una receta de release, no un directorio de subida que se adivina desde la shell. Selecciona uno o más nombres de deployment, o no pases nombres para procesar todas las entradas de deployments.

Para un artifact, deploy toma un snapshot de los archivos declarados en files, hashea cada byte, consulta al control plane autenticado qué digests faltan, sube esos bytes a URLs presigned y hace commit del release. Un kit envía su composición exacta por la ruta de kits; los artifacts locales se preparan antes del kit.

$ hubbound auth login

$ hubbound deploy --path . --dry-run --json

$ hubbound deploy auditor --path .

$ hubbound deploy security-kit --path . --allow-dirty

--path <dir> Directorio exacto que contiene hubbound.json. Default: .; deploy no camina a padres para encontrar un manifest.
--allow-dirty Acepta un worktree Git sucio y envía source.dirty=true. Sin el flag, cualquier archivo tracked, untracked o borrado detiene el preflight.
--dry-run Ejecuta solo el preflight del manifest, Git y archivos. Nunca llama prepare, PUT presigned ni commit.
--json Imprime el resumen de deploy en JSON, incluyendo estado, commit SHA, manifest digest si el backend lo devuelve, cantidad de uploads e idempotency key.
--wait-timeout <duration> Tiempo máximo de espera de un watcher configurado del registry público. Default: 5m; por sí solo no vuelve active un release committed.
  • El preflight requiere un worktree Git, remote.origin.url, un remote HTTPS sin credenciales embebidas y un HEAD SHA hexadecimal de 40 o 64 caracteres. Query y fragment se eliminan del repository URL normalizado.
  • Los patrones de artifact son relativos y soportan **. Cada match debe ser un archivo regular, no symlink, de texto UTF-8: máximo 250 archivos, 2 MiB por archivo y 10 MiB de tamaño lógico total.
  • El snapshot excluye .git, hubbound.json, archivos .env, backups y extensiones de claves/certificados (.pem, .key, .crt), y rechaza binarios como imágenes, archives, PDFs, ejecutables y fonts.
  • Las llamadas autenticadas al control plane usan DPoP. El PUT CAS presigned usa los headers exactos del backend y no debe recibir headers Authorization ni DPoP.
  • Un release committed y su proyección en el registry público son estados separados. En el checkout actual el watcher público no está conectado, así que un release público puede quedar committed mientras el comando reporta que no hay status de publicación; verifica release_state y publication_state por separado.

Comandos compatibles

Estos comandos leen y/o escriben el hubbound.json del proyecto.

$ hubbound init

$ hubbound install artifact jane-a1b2c3/my-hook

$ hubbound install

$ hubbound upgrade all

hubbound init Crea hubbound.json en el directorio actual (falla si ya existe).
hubbound install Sin args + manifesto → instala todos los pins. Con args + scope local → instala y registra el pin.
hubbound upgrade En scope local, refresca los pins en hubbound.json después de actualizar (una entidad o all).
hubbound deploy Valida y publica las entradas de deployments; nunca publica los pins de dependencies.
--scope local|global Scope por defecto: local si hay hubbound.json arriba del cwd; si no, global.

vs manifiestos de perfil

Ambos usan hubbound.json, pero el manifest de proyecto y el de perfil tienen responsabilidades distintas.

  • hubbound.json de proyecto → dependencies locales y deployments opcionales; suele ir al repo.
  • profiles/<name>/hubbound.json → pins globales bajo la config de usuario; los perfiles no pueden contener deployments.
  • --profile en install siempre apunta a un archivo de perfil y fuerza scope global.
  • hubbound install pelado requiere un hubbound.json de proyecto (o corré hubbound init antes).