Component Schema

Component configuration defines buildable and deployable units stored in components/<id>.json.

Schema

json
{
  "id": "string",
  "name": "string",
  "local_path": "string",
  "remote_path": "string",
  "build_artifact": "string",
  "deploy_together": ["component-id"],
  "artifact_inputs": [
    {
      "component": "string",
      "artifact": "string",
      "target": "string",
      "sha256": "string"
    }
  ],
  "extract_command": "string",
  "version_targets": [
    {
      "file": "string",
      "pattern": "string",
      "artifact_path": "string"
    }
  ],
  "changelog_target": "string",
  "hooks": {
    "pre:version:bump": ["shell command"],
    "post:version:bump": ["shell command"],
    "post:release": ["shell command"],
    "post:deploy": ["shell command"]
  },
  "scripts": {
    "lint": ["shell command"],
    "test": ["shell command"],
    "build": ["shell command"],
    "bench": ["shell command"],
    "trace": ["shell command"]
  },
  "env": {
    "KEY": "value"
  },
  "extensions": {},
  "release": {}
}

Fields

Required Fields

  • id (string): Unique component identifier, derived from local_path directory name (lowercased)
  • local_path (string): Absolute path to local source / git checkout directory, ~ is expanded
  • remote_path (string): Remote path relative to project base_path (the deploy target)
  • build_artifact (string): Build artifact path relative to local_path, must include filename

Important: local_path must point to a git repository / source checkout, not the production deploy target. The deploy target is derived from project.base_path + component.remote_path. If local_path points to the deployed directory, builds will run inside production and uncommitted-changes checks will fail (the directory isn’t a git repo). This is a common misconfiguration after server migrations.

Optional Fields

  • name (string): Human-readable component name, defaults to id
  • extract_command (string): Command to execute after artifact upload, runs inside target directory
    • Supports template variables: {artifact}, {targetDir}
  • version_targets (array): List of version detection patterns
    • file (string): Path to file containing version (relative to local_path). This is the source path that the version bump writes to.
    • pattern (string): Regex pattern to extract version (first capture group)
  • changelog_target (string): Path to changelog file (relative to local_path)
  • extensions (object): Extension-specific settings
    • Keys are extension IDs (e.g., "wordpress", "rust")
    • Values are flat extension setting objects; version is reserved for extension version constraints
  • scripts (object): Component-owned shell commands for extension-shaped capabilities
    • Supported keys: lint, test, build, bench, trace
    • Each value is an array of shell commands run sequentially in local_path
    • Resolution order is scripts.<capability> first, then linked extension support, then not-applicable
    • Scripts receive the same runner env paths (HOMEBOY_COMPONENT_ID, HOMEBOY_COMPONENT_PATH, HOMEBOY_RUN_DIR and sidecar file vars when relevant) as extension runners, with HOMEBOY_EXTENSION_ID=component-script
    • Use scripts.build, not build_command; build_command is still only a diagnostic output field.
  • env (object): Component-scoped environment variables applied to Homeboy-managed capability runs for the component
    • Applies to component scripts and extension runners for managed build/test/lint/bench/trace/deps-style capability execution.
    • Per-run environment variables supplied by command workflows are applied after component config and win on key conflicts.
    • homeboy review build reports configured keys as active_env_keys so cache/debug configuration is visible without exposing values.
    • Example: set "CARGO_TARGET_DIR": "/path/to/shared/rebuildable/cargo-target" for a Rust component without adding Rust-specific Homeboy behavior.
  • artifact_inputs (array): Producer artifacts to resolve and compose into this component’s build artifact after this component builds
    • component (string): Producer component ID to build before composition
    • artifact (string): Producer artifact path or glob, resolved relative to the producer local_path
    • target (string): Relative path where the producer artifact is placed inside the consumer artifact
    • sha256 (string, optional): Expected producer artifact SHA-256; comparison is case-insensitive
    • The resolved input metadata is generic (component, resolved artifact, target, sha256). The current writer implementation supports ZIP consumer artifacts and writes each input at target inside the ZIP.
  • deploy_together (array): Component IDs that must be deployed in the same operation as this component
    • Use this when separately tracked components form one runtime contract, such as a WordPress plugin and theme that must stay in sync.
    • Deploy planning fails closed when a selection includes only part of a declared group. Select all coupled components explicitly or use --all for the project.
  • release (object): Component-scoped release configuration
    • enabled (boolean): Whether release pipeline is enabled
    • steps (array): Release step definitions
    • settings (object): Release pipeline settings

Runtime Requirements

Important: local_path must point to a git repository / source checkout, not the production deploy target. The deploy target is derived from project.base_path + component.remote_path. If local_path points to the deployed directory, builds will run inside production and uncommitted-changes checks will fail (the directory isn’t a git repo). This is a common misconfiguration after server migrations.

json
{
  "command": "component.env",
  "id": "example",
  "extension": "example-extension",
  "runtimes": {
    "php": { "version": "8.2", "source": "component" },
    "node": { "version": "22", "source": "extension:example-extension" }
  }
}

Important: local_path must point to a git repository / source checkout, not the production deploy target. The deploy target is derived from project.base_path + component.remote_path. If local_path points to the deployed directory, builds will run inside production and uncommitted-changes checks will fail (the directory isn’t a git repo). This is a common misconfiguration after server migrations.

Hook Fields

  • Supports template variables: {artifact}, {targetDir}

local_path vs remote_path

local_path (source)                          remote_path (deploy target)
┌──────────────────────────┐                ┌──────────────────────────────────────────┐
│ ~/repos/extrachill-api/  │  ── build ──▶  │ /var/www/site/wp-content/plugins/        │
│ (git checkout, builds    │    deploy      │ extrachill-api/                          │
│  run here)               │                │ (project.base_path + remote_path)        │
└──────────────────────────┘                └──────────────────────────────────────────┘
  • file (string): Path to file containing version (relative to local_path). This is the source path that the version bump writes to.
  • pattern (string): Regex pattern to extract version (first capture group)

homeboy component env reports runtime requirements in a generic runtimes map:

Example

json
{
  "id": "extrachill-api",
  "name": "Extra Chill API",
  "local_path": "/Users/dev/extrachill-api",
  "remote_path": "wp-content/plugins/extrachill-api",
  "build_artifact": "build/extrachill-api.zip",
  "extract_command": "unzip -o {{artifact}} && rm {{artifact}}",
  "version_targets": [
    {
      "file": "composer.json",
      "pattern": ""version":\s*"([^"]+)""
    }
  ],
  "changelog_target": "CHANGELOG.md",
  "hooks": {
    "pre:version:bump": [
      "./scripts/verify-generated-sources"
    ],
    "post:version:bump": [
      "./scripts/refresh-versioned-artifacts"
    ],
    "post:release": [
      "echo 'Release complete!'"
    ]
  },
  "env": {
    "SHARED_BUILD_CACHE": "/path/to/shared/rebuildable-cache"
  },
  "extensions": {
    "wordpress": {
      "php_version": "8.1"
    }
  },
  "release": {
    "enabled": true,
    "steps": [
      {
        "id": "preflight.test",
        "type": "preflight.test",
        "label": "Run Tests"
      }
    ]
  }
}

Version Target Format

Runtime IDs are extension-owned strings. source is component for component config or detector output and extension:<id> for extension-provided defaults. Component extension settings and detector output must use the canonical runtimes map with object values containing version.

Setting local_path to the same directory as the deploy target is a misconfiguration — builds would run in production and homeboy deploy would fail uncommitted-changes checks.

  • Keys are extension IDs (e.g., "wordpress", "rust")
  • Values are flat extension setting objects; version is reserved for extension version constraints

Extract Command Context

Version targets use regex to extract semantic versions from files. The pattern must include a capture group for the version string.

  • Supported keys: lint, test, build, bench, trace
  • Each value is an array of shell commands run sequentially in local_path
  • Resolution order is scripts.<capability> first, then linked extension support, then not-applicable
  • Scripts receive the same runner env paths (HOMEBOY_COMPONENT_ID, HOMEBOY_COMPONENT_PATH, HOMEBOY_RUN_DIR and sidecar file vars when relevant) as extension runners, with HOMEBOY_EXTENSION_ID=component-script
  • Use scripts.build, not build_command; build_command is still only a diagnostic output field.

Common patterns:

  • Applies to component scripts and extension runners for managed build/test/lint/bench/trace/deps-style capability execution.
  • Per-run environment variables supplied by command workflows are applied after component config and win on key conflicts.
  • homeboy review build reports configured keys as active_env_keys so cache/debug configuration is visible without exposing values.
  • Example: set "CARGO_TARGET_DIR": "/path/to/shared/rebuildable/cargo-target" for a Rust component without adding Rust-specific Homeboy behavior.

Storage Location

The extract_command runs inside the target directory after artifact upload. The working directory is:

  • component (string): Producer component ID to build before composition
  • artifact (string): Producer artifact path or glob, resolved relative to the producer local_path
  • target (string): Relative path where the producer artifact is placed inside the consumer artifact
  • sha256 (string, optional): Expected producer artifact SHA-256; comparison is case-insensitive
  • The resolved input metadata is generic (component, resolved artifact, target, sha256). The current writer implementation supports ZIP consumer artifacts and writes each input at target inside the ZIP.
  • Use this when separately tracked components form one runtime contract, such as a WordPress plugin and theme that must stay in sync.
  • Deploy planning fails closed when a selection includes only part of a declared group. Select all coupled components explicitly or use --all for the project.