WP Codebox publishes a reusable GitHub Actions workflow for generic agent tasks:
jobs:
run-agent-task:
uses: Automattic/wp-codebox/.github/workflows/run-agent-task.yml@v0.12.3
with:
wp_codebox_release_ref: v0.12.3
external_package_source: '{"repository":"OWNER/agent-packages","revision":"0123456789abcdef0123456789abcdef01234567","path":"agents/example.agent.json","digest":"sha256-bytes-v1:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"}'
target_repo: Automattic/example-target
prompt: Refresh the configured surface from source evidence.
writable_paths: README.md,docs/**
runner_workspace: '{"enabled":true,"repo":"Automattic/example-target"}'
validation_dependencies: npm ci
verification_commands: '[{"command":"npm test","description":"Run checks"}]'
drift_checks: '["git diff --exit-code"]'
success_requires_pr: true
access_token_repos: Automattic/example-target
allowed_repos: '["Automattic/example-target"]'
output_projections: '{"pr_url":{"path":"outputs.artifact_result.result.outputs.runner_workspace_publication.pull_request.url","required":false}}'
secrets:
EXTERNAL_PACKAGE_SOURCE_POLICY: ${{ secrets.EXTERNAL_PACKAGE_SOURCE_POLICY }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}The workflow checks out the target workspace, fetches and imports the selected public native package, invokes the package-declared agent through the native chat path, runs declared commands in a credential-free verification environment, and returns actual runtime and publication data.
Callers must invoke the reusable workflow from an exact WP Codebox release tag
and pass that same tag as wp_codebox_release_ref. For example, callers use
Automattic/wp-codebox/.github/workflows/run-agent-task.yml@v0.12.3 together
with wp_codebox_release_ref: v0.12.3. The accepted format is exactly
vX.Y.Z; branches, commit SHAs, moving major tags, prereleases, and arbitrary
refs are rejected.
The workflow requires wp_codebox_release_ref to be an exact release tag. It
always checks helpers out from Automattic/wp-codebox, verifies the checked-out
commit equals the remote release tag commit, and verifies the checked-out
package.json version equals the requested tag without its v prefix. The
caller cannot select a different helper repository. GitHub nested workflows
expose the caller's github.workflow_ref, and the running workflow cannot
introspect its own uses: ref, so helper selection relies on the required input
and verified checkout rather than that caller context.
This release-coherence contract fixes #1759.
wp_codebox_release_ref: required exact immutable WP Codebox release tag invX.Y.Zform.external_package_source: immutable descriptor withrepository, full commitrevision, one package-relative.agent.jsonpath, anddigest. Packages are supported only from publicly accessible GitHub repositories, fetched from canonicalhttps://github.com/OWNER/REPOSITORY.gitwithout credentials.digestis exactlysha256-bytes-v1:<lowercase-sha256>over the raw file bytes; filenames and JSON content are UTF-8-safe and are not normalized before hashing.EXTERNAL_PACKAGE_SOURCE_POLICY: required reusable-workflow secret, supplied by the caller's operator-controlled secret configuration. Its strict version 1 JSON shape is{"version":1,"repositories":{"owner/repository":["agents/example.agent.json"]}}. Every entry is an exact standalone.agent.jsonpath. The policy is validated in runner memory, is never part of task input, and is not uploaded.
runtime_sources is an optional versioned JSON array for immutable public runtime dependencies. Git descriptors declare version: 1, role (component, provider_plugin, or bundled_library), repository, a full 40-character revision, exact directory path, optional sha256-git-archive-v1 digest, and role metadata. Every provider-plugin descriptor must declare metadata.providers as a sorted, lowercase, duplicate-free non-empty provider allowlist. The selected non-empty provider/model must be in that allowlist, and the model is passed only with that selected provider to the runtime package turn. Component and provider descriptors may instead declare source: {"type":"https_zip","url":"https://...","sha256":"<64 lowercase hex>","archive_root":"plugin-directory"}. The operator-controlled policy separately authorizes Git sources with runtime_sources and exact ZIP URLs with runtime_artifacts, for example {"version":1,"repositories":{},"runtime_artifacts":[{"url":"https://downloads.wordpress.org/plugin/example.zip","sha256":"<64 lowercase hex>"}]}. Every exact runtime_artifacts URL requires sha256; the descriptor digest must exactly equal that trusted policy digest, so callers cannot authorize mutable current bytes. ZIP downloads require HTTPS, an exact allowlisted URL, a matching descriptor digest, bounded transfer and extraction sizes, and redirects only to another allowlisted URL on the original host. The runner verifies the digest before extraction; rejects traversal, symlink, special-file, encrypted, ZIP64, oversized, and multi-root archives; stages under a private temp root outside the workspace and artifacts; removes the staging root after execution; and strips private materialization paths using the exact mkdtemp root handed from the executor as an ephemeral step output before scanning staged files for leaks. Runtime source descriptors lower into existing component, provider plugin, and runtime overlay inputs; artifacts retain provenance only.
target_repo:OWNER/REPOtarget repository.prompt,writable_paths, provider/model,max_turns,time_budget_ms, callback data, and artifact declarations: native task inputs.runner_workspace: JSON runner-workspace publication request owned by the package.validation_dependencies: optional shell command that installs validation dependencies in the target workspace.verification_commandsanddrift_checks: JSON arrays of non-empty command strings or{command, description}objects. Every entry runs and must pass.success_requires_pr: require a successful, published runner-workspace pull request fortarget_repo.access_token_repos: comma-separated repositories available to the supplied access token.allowed_repos: JSON repository allowlist. It andaccess_token_reposmust explicitly includetarget_repo.expected_artifacts: JSON allowlist and collection metadata. Required runtime artifacts are derived only fromartifact_declarationsentries withrequired: trueand must be declared output artifacts.output_projections: JSON object mapping output names to dot-delimited paths in the native result. A string value remains a required projection for compatibility. A descriptor value has the exact shape{ "path": "result.path", "required": false }; unresolved optional projections are omitted, while unresolved required projections fail the run. Each evaluated projection and the combined projection object must serialize to 8,192 bytes or less. Oversized projections fail before success withwp-codebox.agent-task.output-projection-too-large; declare an artifact and project its artifact-relative reference instead.
For a target equal to the caller repository, the workflow passes the caller's
built-in github.token as GITHUB_TOKEN to native agent execution. An
ACCESS_TOKEN secret is not required in that case. For a target in another
repository, ACCESS_TOKEN is required explicitly and must be scoped by both
access_token_repos and allowed_repos. The caller token is never inferred to
have cross-repository access. The effective token is not serialized into task
input, result, or artifact data. GitHub runner tools
receive the normalized allowed_repos policy explicitly through the runtime and
fail closed for every PR, issue, and comment operation outside that set. The
checkout does not persist credentials. Verification, dependency, and drift
commands run with a clean environment that excludes provider and GitHub secrets.
Known secret values are redacted before result or artifact persistence; captured
stdout/stderr is capped at 32 KiB and workflow outputs at 8,192 bytes.
EXTERNAL_PACKAGE_SOURCE_POLICY is treated as a secret even when it contains
only repository and path metadata. It is redacted from runner output, excluded
from task requests, runtime input, results, and upload artifacts, and is never
passed to the agent. The selected descriptor is authorized against this policy
both before persistence and immediately before host materialization.
The source fetch receives no repository, publication, provider, or GitHub token.
Public package bytes are verified against the immutable descriptor, encoded in
the normal in-memory runtime recipe, and decoded inside Playground. The runtime
re-hashes raw bytes, validates the canonical flat package contract
(schema_version: 1, bundle_slug, and exactly one authoritative
agent.agent_slug), canonically imports it, verifies
that exact slug registered, and passes it explicitly as the agent input to
agents/chat. The descriptor and caller cannot select a different identity.
Only {slug} is carried in task metadata. The importer-only temporary
.agent.json is removed in a try/finally before resolving agent tools. No
package file is mounted into or visible from the agent workspace.
The repository's native-loop and PHP runtime-package tests execute generated PHP with narrow WordPress and native agent-registry shims. The non-skippable deterministic WordPress Playground end-to-end test additionally boots the agent registry and OpenAI provider path with a local HTTP interceptor. Its three-turn fixture reads and edits a seeded sandbox workspace, verifies provider tool outputs, and captures the canonical changed-files manifest and patch without network access or provider billing.
To run the optional cross-repository package coverage, use a Docs Agent checkout
pinned to commit 3da1b8076359db9bf9f4ee7dadcc3932c080ed71, which contains
technical-docs-maintenance-agent.agent.json:
DOCS_AGENT_DIR=/path/to/docs-agent npm run test:external-native-package-materialization
DOCS_AGENT_DIR=/path/to/docs-agent npm run test:agent-no-data-machine-loopWhen success_requires_pr is true, success requires the canonical
wp-codebox/runner-workspace-publication-result/v1 result with success: true,
status: published, and a GitHub pull-request URL for target_repo.
WP Codebox then resolves that pull request through the GitHub API with the
runner token, so a fabricated publication result cannot satisfy the gate.
job_status: normalized terminal status.transcript_json: transcript artifact references when available.transcript_summary: short transcript label.engine_data_json: actual runtime output object.projected_outputs_json: evaluated values fromoutput_projections.credential_mode: redacted credential source classification.declared_artifacts_json: accepted typed artifact declarations.
Every structured workflow output is serialized as complete JSON. When a
system-owned structured value exceeds 8,192 bytes, its workflow output becomes a
wp-codebox/workflow-output-reference/v1 object with an artifact-relative path,
byte count, and SHA-256; the canonical JSON is collected from
.codebox/agent-task-artifacts/workflow-outputs/. The workflow result records
these references in workflow_output_artifacts. User-declared projections are
validated instead of truncated, so a success result never omits or corrupts a
projection.
The result artifact includes the executable task input, normalized runtime
result, evaluated projections, verification records, and runner-owned
publication result. A single canonical codebox-transcript ref from the
normalized runtime result is handled independently of package declarations at
.codebox/agent-task-artifacts/transcript.json. Missing canonical evidence is
recorded as unavailable. Present evidence is verified against its normalized
digest when supplied, then converted from wp-codebox/agent-transcript/v1 into
a compact wp-codebox/reviewer-agent-transcript/v1 projection. The projection
records verified source and output digests in exclusions.json, retains bounded
diagnostic tool and model data, and excludes raw stdout, source trees, secrets,
private paths, setup stacks, and package payloads. Runtime input, result, and diagnostics are uploaded from
workspace/.codebox/ with if: always(), including execution failures. A request
artifact alone is not a successful task result.
contracts/run-agent-task-reusable-workflow-interface.v1.json
is the producer-owned, machine-readable wp-codebox/reusable-workflow-interface/v1
fixture. It records every declared input's required/type/default behavior, every
secret's required behavior, and every workflow output expression.
The offline validator reads only the checkout's fixture and
.github/workflows/run-agent-task.yml; it makes no network calls. External
consumers can contract-test a checked-out version with:
WP_CODEBOX_DIR=/path/to/wp-codebox npm --prefix /path/to/wp-codebox run test:agent-task-workflow-interfaceUpdate the workflow declaration and fixture together when intentionally changing this interface. The contract test rejects either addition, removal, or changed input, secret, or output expectation.
This public-only v1 interface removes support for confidential or private package
bytes and removes the previously exposed external_package_allowed_repositories,
external_package_allowed_paths, runner_recipe, context_repositories,
workspace_contract_checks, actions_artifact_downloads,
success_completion_outcomes, step_budget, and tool_results_key inputs.
They were serialized without a generic WP Codebox execution primitive, so
retaining them would have presented inert data as a supported contract. Callers
must migrate checks to executable validation_dependencies,
verification_commands, or drift_checks; context and artifact preparation
remain caller-workflow responsibilities. This is an intentional exposed-workflow breaking change.
wp_codebox_release_ref is a required v1 input. Existing callers must switch
their uses: reference from a branch or other ref to an exact release tag and
pass that exact release tag through this input. Consumer contract tests can
compare both values where the caller workflow is available; the reusable
workflow itself cannot inspect the caller's uses: declaration at runtime.
The reusable workflow stages every uploaded file through a fail-closed policy. Only regular UTF-8 files of 4 MiB or less are uploaded, after configured secret values are redacted. Symlinks, special files, binary files, and files larger than 4 MiB are excluded from the upload staging directory. This applies to task artifacts and workflow request, input, and result files.
Native task execution, validation-dependency installation, verification, drift checks, and GitHub pull-request validation retain at most 32 KiB from each stdout and stderr stream while continuing to drain both streams. Command results expose stdout_truncated and stderr_truncated when retained output is incomplete. Native agent-task-run structured output is instead read from a controlled .codebox/native-agent-task-result.json file outside the agent-writable target checkout. The executor accepts only a regular, non-symlink JSON file up to 1 MiB with the required result schemas, rejects configured secret values, redacts the accepted record before persistence, and removes the transient native result file after reading it.