Agent Runtime Package Contract

Agent runtime packages live under agent-runtimes/<runtime-id>/. They expose provider commands that Homeboy can invoke without encoding backend-specific knowledge in core or in domain extensions.

This contract is intentionally backend-neutral. A browser sandbox runtime or a CLI agent runtime can satisfy the same request and outcome schemas.

Package Layout

Each runtime package should include:

  • <runtime-id>.json: package manifest.
  • README.md: runtime-specific operator notes and provider setup.
  • Runnable provider command files referenced by the manifest.
  • Tests or fixtures proving the manifest and provider command contract.

The package may include implementation libraries. Homeboy selects runtimes through the manifest and provider command contract exported by the runtime package.

Manifest Fields

The manifest root must declare:

  • schema: runtime manifest schema, currently homeboy/agent-runtime-manifest/v1.
  • id: stable runtime package id. For standalone installs, Homeboy treats the containing directory name as authoritative and may override this value.
  • name: human-readable runtime name.
  • version: runtime package contract version.
  • description: one-sentence runtime summary.
  • agent_task_executors: non-empty list of provider declarations.

Each agent_task_executors[] entry must declare:

  • schema: provider declaration schema, currently homeboy/agent-task-executor-provider/v1.
  • id: stable provider id. Use a namespaced id such as runtime-id.provider-id.
  • label: human-readable provider label.
  • backend: backend selector value used by requests, for example codebox or opencode.
  • command: shell command Homeboy runs after interpolation.
  • request_schema: accepted request schema, currently homeboy/agent-task-request/v1.
  • outcome_schema: emitted outcome schema, currently homeboy/agent-task-outcome/v1.
  • request_required_fields: request paths the provider requires before execution.
  • outcome_statuses: statuses the provider may emit.
  • failure_classifications: normalized failure classes used for diagnostics.
  • redacted_metadata_keys: metadata keys that must never expose secret values.
  • capabilities: explicit capabilities orchestration may rely on.
  • runner_readiness: executable, path, or environment checks operators can inspect before dispatch.
  • role_aliases: mappings from provider-native artifact/output names to generic Homeboy roles.
  • workspace_materialization: workspace shape required by the provider.
  • secret_requirements and secret_env_requirements: secret names or groups the provider may need. Core lists and resolves explicitly requested env names; runtime packages own provider-specific default selection.
  • provider_defaults: provider-specific defaults such as model names, secret env names, and source hints.
  • diagnostics: diagnostic artifacts and metadata the provider writes or returns.
  • status: lifecycle state, usually active, experimental, or deprecated.
  • integration_contract: higher-level contract name when the provider serves a domain extension.

Runtime-specific fields are allowed when they are additive. The public manifest fields give Homeboy core the information it needs to invoke the provider.

Generic runner specs must declare executor.backend explicitly. Runtime-specific planners may provide their own defaults, but the shared contract does not assume any particular backend.

Runtime ids are canonical package ids. Compatibility aliases may resolve for existing callers, but resolvers should return explicit deprecation metadata with a replacement id and quarantine name. New callers should select canonical runtime ids directly, for example wp-codebox instead of the legacy codebox alias. Compatibility aliases are not extension points; new runtime packages and docs should publish canonical ids only.

runtime_path Interpolation

Provider commands should reference runtime-local files with {{runtime_path}}:

json
{
  "command": "node {{runtime_path}}/scripts/agent/example-agent-task-executor.cjs"
}

Homeboy owns interpolation and replaces {{runtime_path}} with the installed runtime package directory before execution. Runtime packages should keep command paths relative to that directory so linked installs, extracted installs, and remote runners resolve the same files.

Provider commands may use normal shell syntax, but portable single-executable commands are preferred. Avoid commands that depend on the monorepo checkout layout unless that layout is part of the package contract.

Provider Command Contract

A provider command must:

  • Read one JSON request from stdin.
  • Validate schema, task_id, executor.backend, and the fields declared in request_required_fields.
  • Execute using only the request, environment variables, and files under the materialized workspace/runtime paths.
  • Write one JSON outcome to stdout.
  • Write human diagnostics to stderr only when useful; stderr must not contain secrets.
  • Exit 0 after emitting a well-formed terminal outcome, including normalized failure outcomes.
  • Exit non-zero only for command-level failures where no valid outcome can be produced.

The emitted outcome must use outcome_schema and one of outcome_statuses. Failure outcomes should include a normalized classification from failure_classifications plus enough diagnostic context for Homeboy to route the result without parsing backend-native logs.

Runtime Command Provider Boundary

TODO: Add a generic runtime-command provider only after the selected runtime owns a stable command substrate that accepts and returns backend-neutral shapes. The provider manifest should advertise a separate capability such as runtime_command_execution; agent-task providers currently advertise agent-task execution through the request and outcome schemas above.

The generic request shape needs these caller-owned inputs:

  • runtime_package: runtime package id/ref and optional version or checkout ref.
  • recipe: recipe pack/name/path/ref inputs to materialize the runtime.
  • command_id: stable command id selected by the caller.
  • args: JSON object or array passed to the command without shell expansion.
  • env_names: declared environment variable names the runtime may read; values are resolved by Homeboy and never embedded in manifests or diagnostics.
  • workspace, limits, and artifacts: materialization, timeout, and expected output declarations.

The provider command should emit homeboy/agent-task-outcome/v1 with normalized status, failure_classification, summary, diagnostics, artifacts, evidence_refs, outputs, and redacted metadata. Backend-native logs and recipe artifacts may be attached as artifacts, but Homeboy should not parse them to determine the terminal outcome.

Runtime packages forward package-owned command, args, and env-name declarations through their executable contract and return stable result envelopes. Product semantics belong to callers or runtime packages.

Homeboy Contract Adapter

Extension runtime packages and reusable CI callers should consume generic Homeboy contract constants through agent-task-contracts. That shared package owns schema identifiers, the default provider fields, secret-env requirement selectors, redacted metadata keys, artifact/evidence reference projection helpers, and homeboy/agent-task-runner-spec/v1 validation/projection into the generic request fields consumed by executor providers. Extension-specific exports should re-export the shared package instead of copying schema and lifecycle validation logic; legacy runtime-CI, agent-runtimes, and extension-specific paths remain compatibility shims only.

Runtime packages may add backend-specific capabilities, secret names, role aliases, and metadata keys, but should extend the adapter output instead of copying schema strings or selector paths into each backend. Domain policy, such as project-specific defaults, belongs in the caller/runtime package and not in the generic adapter.

Host Orchestration Contract

The published Homeboy core fixture is agent-runtimes/fixtures/homeboy-agent-task-core-contract.json. It is the cross-repo handoff contract for durable host orchestration and runtime package execution. Homeboy core owns durable queueing, fanout, progress, retries, artifacts, and promotion. Runtime packages own the executor command and backend translation behind the provider manifest.

This fixture is a generated artifact, not a hand-maintained mirror. Its core region is consumed directly from Homeboy core’s published contract via homeboy agent-task contract --format json (core’s agent_task_core_contract()), and the extensions-owned fanout/reconcile + orchestration overlay below is derived from the runtime’s own JS constant modules. Regenerate it with node agent-runtimes/fixtures/generate-homeboy-agent-task-core-contract.cjs (or npm run fixture:agent-task-core-contract from wordpress/). The agent-task-core-contract-drift test asserts byte-for-byte equality between the committed fixture and the generator output whenever the homeboy binary is available, so the fixture can never silently drift from core.

Generic fanout/reconcile schemas are part of that fixture:

  • homeboy/generic-fanout-reconcile-config/v1
  • homeboy/fanout-reconcile-plan/v1
  • homeboy/fanout-reconcile-run/v1
  • homeboy/generic-fanout-reconcile-result/v1
  • homeboy/generic-fanout-reconcile-reconciliation/v1
  • homeboy/generic-finding-packet-fanout-config/v1

When a host fanout lane executes agent-task providers, record status is the host orchestration status and outcome status remains the provider terminal status. The canonical bridge is:

Agent-task outcome statusFanout record status
succeededcompleted
no_opcompleted
unable_to_remediatefailed
provider_errorfailed
timeoutfailed
failedfailed
follow_up_issuefailed
cancelledfailed

Fanout runners may also emit missing_record for a planned task with no returned execution record. The run status vocabulary is incomplete, completed, and failed. Backend-native statuses should be preserved inside provider outcome metadata or diagnostics, not promoted into host orchestration status fields.

Secret Requirements

Runtime manifests should declare secret inputs by name, never by value:

json
{
  "secret_requirements": [
    {
      "name": "EXAMPLE_RUNTIME_TOKEN",
      "required": false,
      "purpose": "Authenticates optional provider calls."
    }
  ]
}

Provider commands receive secret values through environment variables or the request’s secret-name declarations. They must redact secret-like metadata in outcomes and diagnostics. If a runtime adds a secret-bearing metadata key, it must add that key to redacted_metadata_keys, preferably with extendRedactedMetadataKeys() from the adapter.

Capability Declarations

Capabilities are selection and orchestration promises. Declare a capability only when the provider can satisfy it for every request accepted by that provider.

Use stable, backend-neutral names where possible, such as:

  • workspace_materialization
  • structured_outcome
  • diagnostic_artifacts
  • patch_artifacts
  • verification_artifacts
  • browser_runtime
  • ability_execution
  • agent_bundle_execution
  • workflow_execution

Backend-specific capabilities are acceptable when they are intentionally part of selection, but they should not replace the generic capability when a generic one applies.

Runtime Execution Contracts

Providers that can execute generic runtime descriptors should declare runtime_execution_contracts on the executor provider. Each key is a generic runtime_execution.kind; each value maps that kind to a provider-specific runtime-profile field and the capabilities required to use it:

json
{
  "runtime_execution_contracts": {
    "bundle": {
      "ability_field": "runtime_bundle_ability",
      "required_capabilities": ["agent_bundle_execution"]
    },
    "workflow": {
      "ability_field": "runtime_workflow_ability",
      "required_capabilities": ["workflow_execution"]
    }
  }
}

Caller configs can then use runtime_execution: { "kind": "bundle", ... } without embedding a provider-specific ability string. The selected adapter maps the generic kind to its own runtime-profile ability field and fails closed when the provider does not advertise the required capability. Direct ability execution remains explicit: callers supply the ability they intend to invoke.

Workspace Materialization

workspace_materialization declares what the provider expects before it starts. Common fields:

  • cwd: working-directory mode, such as git_checkout, runtime_package, or request_workspace.
  • requires_git: whether the workspace must be a git checkout.
  • write_scope: where the provider may write, such as workspace, artifacts, or none.
  • artifact_paths: relative paths the provider may create or update.

The provider must not infer workspace shape from any current runtime unless that shape is declared here.

Caller-owned wrappers should pass domain-specific runtime requirements explicitly. For example, a caller can supply its ability provider, runtime components, workspace-tool, and ability-policy defaults before invoking the generic WP Codebox provider.

Outcome And Diagnostic Contracts

Provider outcomes should include:

  • schema: the outcome schema.
  • task_id: copied from the request.
  • status: terminal status from outcome_statuses.
  • summary: concise human-readable result.
  • diagnostics: structured diagnostics suitable for logs, PR comments, and issue routing.
  • artifacts: typed artifact references when files are produced.
  • metadata: redacted provider metadata.

Diagnostics should distinguish provider setup failures, request validation failures, execution failures, timeouts, and successful no-op outcomes. Backend native logs can be attached as artifacts, but the normalized outcome is the contract Homeboy consumes.

Default-Backend Policy Ownership

Runtime packages declare what they can do. They do not decide which backend is the default for a domain workflow.

Default-backend policy belongs to the caller that understands the domain and deployment context, for example a Homeboy extension, workflow, component config, or operator-supplied setting. One workflow may choose a browser sandbox by default; a different workflow may choose another runtime with the same generic capabilities. Homeboy core should route explicit requests and evaluate declared capabilities, not hard-code a global default backend.

Static Contract Fixture

tests/fixtures/agent-runtime-manifest.json is the smallest reference fixture for this contract. It is intentionally outside agent-runtimes/ so it validates the generic manifest shape without advertising a smoke-test runtime as an installable adapter.