Files
headquarter/docs/tool-manifest-spec.md
T
alex 62640daf36 docs: update all documentation for OpenCode and deployment
- Update architecture.md with spawn service and auth proxy sections
- Update deployment.md with production stack details
- Update development.md with spawn workflow documentation
- Update mvp-scope.md, project-brief.md, tool-manifest-spec.md
- Update conversation-handoff.md with current status
- Replace all RunFusion references with OpenCode
2026-05-14 17:30:03 +02:00

8.8 KiB
Raw Blame History

Tool Manifest Specification

Canonical schema reference for Headquarter's manifest-driven tool registry. Version: 1.0.0 — aligned with FN-003.

Overview

Headquarter is a manifest-driven platform: every containerized tool (OpenCode, code-server, and future tools) is declared by a YAML manifest. The orchestration backend reads these manifests to generate Docker Compose services, Traefik routing labels, volume mounts, and resource constraints.

Design goal: Adding a new standard container tool requires only a YAML manifest—no backend code changes.

Manifest File Format

Manifests are YAML files with a single top-level mapping. They are validated on load by Pydantic v2 models.

Built-in location

Built-in manifests live in apps/api/app/tools/manifests/*.yml and are loaded automatically on API startup.

Minimal valid manifest

id: my-tool
name: My Tool
image: my-org/my-tool:latest
ports:
  - container_port: 8080
    primary: true
traefik:
  enabled: false

Field Reference

ToolManifest (top level)

Field Type Required Default Description
id string yes Lowercase slug with hyphens only (^[a-z0-9\-]+$). Used as the registry key.
name string yes Human-readable tool name.
description string no "" Short description of the tool.
version string no "1.0.0" Manifest version (semver-ish).
image string yes Docker image reference.
runtime_command string[] | null no null Override the container default command.
runtime_entrypoint string[] | null no null Override the container entrypoint.
runtime_user string | null no null User to run as inside the container.
runtime_working_dir string | null no null Working directory inside the container.
ports PortConfig[] no [] Exposed ports.
workspace_mounts MountConfig[] no [] Workspace volume mounts (project-scoped).
config_mounts MountConfig[] no [] Config volume mounts (user or tool-scoped).
env dict<string, string> no {} Static environment variables.
secrets SecretRef[] no [] Secrets injected as environment variables.
health_check HealthCheckConfig | null no null Health check definition.
resource_limits ResourceLimits | null no null CPU and memory constraints.
executable ExecutableConfig | null no null Node.js runtime metadata for executable environments.
traefik TraefikConfig | null no null Traefik routing configuration.

PortConfig

Field Type Required Default Description
container_port int yes Port inside the container. Range: 165535.
protocol "tcp" | "udp" no "tcp" Transport protocol.
name string | null no null Logical name, e.g. "http", "websocket".
primary bool no false The port used for default routing and health checks.

MountConfig

Field Type Required Default Description
type "volume" | "bind" no "volume" Mount type.
source_pattern string yes Template pattern resolved at spawn time, e.g. "{project_repo}".
target string yes Absolute path inside the container. Must start with /.
read_only bool no false Mount read-only.

SecretRef

Field Type Required Default Description
name string yes Secret identifier in the secret store.
env_var string yes Name of the environment variable injected into the container.
required bool no true Whether the tool fails to start if the secret is missing.

HealthCheckConfig

Field Type Required Default Description
type "http" | "tcp" | "command" no "http" Health check mechanism.
path string | null no null HTTP path. Required when type == "http".
command string[] | null no null Command to execute. Required when type == "command".
port int | null no null Override port; defaults to the primary port if unset.
interval_seconds int no 10 Check interval. ≥ 1.
timeout_seconds int no 5 Check timeout. ≥ 1.
retries int no 3 Retries before marking unhealthy. ≥ 1.
start_period_seconds int no 5 Grace period before checks count. ≥ 0.

ResourceLimits

Field Type Required Default Description
cpus float | null no null CPU limit. If set, ≥ 0.01.
memory_mb int | null no null Memory limit in MiB. If set, ≥ 16.
memory_swap_mb int | null no null Swap limit in MiB. -1 disables swap limit.

ExecutableConfig

Field Type Required Default Description
node_version string | null no null Expected Node.js version, e.g. "22", "lts".
npm_version string | null no null Expected npm version.
package_manager "npm" | "pnpm" | "yarn" | "bun" no "npm" Preferred package manager.
bootstrap_commands string[] no [] One-time setup commands run on first start.
install_commands string[] no [] Commands run before the main command.

TraefikConfig

Field Type Required Default Description
enabled bool no true Whether Traefik routing is generated for this tool.
subdomain_prefix string | null no null Subdomain prefix. Defaults to the tool id.
port int | null no null Container port to route traffic to.
middlewares string[] no [] Traefik middleware names to apply.
strip_prefix bool no false Strip path prefix before forwarding.
entrypoint string | null no null Override the environment default Traefik entrypoint.
cert_resolver string | null no null Override the environment default cert resolver.

Validation Rules

  1. id must match ^[a-z0-9\-]+$ (lowercase, digits, hyphens only).
  2. MountConfig.target must be an absolute path (starts with "/").
  3. When health_check.type == "http", path must be set and non-empty.
  4. When health_check.type == "command", command must be set and non-empty.
  5. container_port must be between 1 and 65535.
  6. cpus, if set, must be ≥ 0.01.
  7. memory_mb, if set, must be ≥ 16.
  8. If traefik.enabled is true, at least one port must have primary: true.

Example: OpenCode Manifest

id: opencode
name: OpenCode
description: AI-powered terminal-based development environment with web interface.
version: "1.0.0"
image: ghcr.io/opencode-ai/opencode:latest
runtime_working_dir: /workspace
ports:
  - container_port: 3000
    protocol: tcp
    name: http
    primary: true
workspace_mounts:
  - type: volume
    source_pattern: "{project_repo}"
    target: /workspace
    read_only: false
config_mounts:
  - type: volume
    source_pattern: "{user_config}/opencode"
    target: /root/.config/opencode
    read_only: false
env:
  TERM: xterm-256color
  FORCE_COLOR: "1"
health_check:
  type: http
  path: /
  port: 3000
  interval_seconds: 10
  timeout_seconds: 5
  retries: 3
  start_period_seconds: 15
resource_limits:
  cpus: 2.0
  memory_mb: 4096
  memory_swap_mb: -1
traefik:
  enabled: true
  subdomain_prefix: opencode
  port: 3000
  middlewares: []
  strip_prefix: false

Extension Guide: Adding a New Tool

To add a new standard container tool:

  1. Create a new YAML file in apps/api/app/tools/manifests/{tool-id}.yml.
  2. Populate all required fields (id, name, image, ports).
  3. Set traefik.enabled: true and mark one port as primary: true if the tool needs HTTP routing.
  4. Declare workspace_mounts and config_mounts as needed.
  5. Restart the API (or call registry.load_builtin_manifests()).

No backend code changes are required for standard containers that expose an HTTP port and need volume mounts.

Registry API

The in-memory registry exposes FastAPI routes under /api/v1/tools:

  • GET /api/v1/tools — list all registered manifests.
  • GET /api/v1/tools/{id} — retrieve a single manifest.
  • POST /api/v1/tools — register a new manifest (returns 409 if id already exists).

Built-in manifests are loaded automatically on application startup via the FastAPI lifespan context manager.