| name | buildkite-agent-runtime |
| description | This skill should be used when the user asks to "add an annotation", "upload artifacts from a step", "share data between steps", "upload pipeline dynamically", "request an OIDC token inside a step", "acquire a distributed lock", "get or update a step attribute", "redact a secret from logs", "retrieve a cluster secret at runtime", or "debug environment variables in hooks". Also use when the user mentions buildkite-agent annotate, buildkite-agent artifact upload/download, buildkite-agent meta-data set/get, buildkite-agent pipeline upload, buildkite-agent oidc request-token, buildkite-agent step, buildkite-agent lock, buildkite-agent env, buildkite-agent secret get, buildkite-agent redactor add, buildkite-agent tool sign/verify, or any buildkite-agent subcommand used inside a running job step.
|
Buildkite Agent Runtime
The buildkite-agent binary provides subcommands for interacting with Buildkite from within running job steps — creating annotations, uploading artifacts, sharing state between jobs, generating dynamic pipelines, requesting OIDC tokens, and more. This skill covers the command syntax, flags, and patterns for every in-job subcommand.
Quick Start
A step that runs tests, annotates failures, uploads coverage, and stores a result flag for downstream jobs:
steps:
- label: ":test_tube: Tests"
command: |
if ! make test 2>&1 | tee test-output.txt; then
buildkite-agent annotate --style "error" --context "test-failures" < test-output.txt
buildkite-agent meta-data set "tests-passed" "false"
exit 1
fi
buildkite-agent annotate "All tests passed :white_check_mark:" --style "success" --context "test-results"
buildkite-agent artifact upload "coverage/**/*"
buildkite-agent meta-data set "tests-passed" "true"
A downstream step reading that state:
- label: ":rocket: Deploy"
command: |
PASSED=$(buildkite-agent meta-data get "tests-passed")
if [[ "$PASSED" != "true" ]]; then
echo "Tests did not pass, skipping deploy"
exit 0
fi
scripts/deploy.sh
depends_on: "test-step"
Annotations
Surface build results directly on the build page. Annotations support Markdown and HTML.
Creating annotations
buildkite-agent annotate "Deploy completed successfully" --style "success" --context "deploy"
buildkite-agent annotate --style "error" --context "test-failures" < test-output.md
Key flags
| Flag | Short | Default | Description |
|---|
--style | -s | default | Visual style: default, info, warning, error, success |
--context | -c | random UUID | Unique ID — reusing a context replaces the annotation |
--append | — | false | Append to existing annotation with same context instead of replacing |
--priority | — | 3 | Display priority (1-10). Higher numbers appear first |
--job | — | current job | Job ID to annotate (rarely needed) |
Replacing vs appending
- Same
--context without --append replaces the annotation; with --append appends below existing content.
- Always use a stable
--context value so reruns update the same annotation instead of creating duplicates.
For pipeline-level notify: configuration, see the buildkite-pipelines skill.
Artifacts
Upload files as build artifacts, download them in later steps or other builds, and search by glob.
Upload
buildkite-agent artifact upload "pkg/release.tar.gz"
buildkite-agent artifact upload "dist/**/*"
Download
buildkite-agent artifact download "pkg/release.tar.gz" .
buildkite-agent artifact download "dist/*" . --step "build-step"
Search
buildkite-agent artifact search "pkg/*.tar.gz" --build "$BUILDKITE_BUILD_ID"
For complete flag tables, see references/flag-reference.md.
For the declarative artifact_paths: YAML key, see the buildkite-pipelines skill. For bk artifact CLI commands, see the buildkite-cli skill.
Meta-data
A build-wide key-value store for sharing state between jobs. Set a value in one job, read it in any other job in the same build.
Set
buildkite-agent meta-data set "release-version" "1.4.2"
Get
VERSION=$(buildkite-agent meta-data get "release-version")
Use --default to return a fallback value instead of a non-zero exit when the key is missing: buildkite-agent meta-data get "deploy-env" --default "staging".
Check existence
if buildkite-agent meta-data exists "release-version"; then
echo "Version already set"
fi
Common patterns
Block step field values are stored automatically as meta-data. Retrieve them by field key:
RELEASE_NAME=$(buildkite-agent meta-data get "release-name")
Pipeline Upload
Dynamically add steps to a running build. The core mechanism behind dynamic pipelines — generate YAML at runtime and upload it.
Basic usage
buildkite-agent pipeline upload .buildkite/deploy-steps.yml
./scripts/generate-pipeline.sh | buildkite-agent pipeline upload
Replace mode
By default, uploaded steps are appended after the current step. Use --replace to replace the entire remaining pipeline:
buildkite-agent pipeline upload --replace .buildkite/new-pipeline.yml
Key flags
| Flag | Default | Description |
|---|
--replace | false | Replace remaining pipeline steps instead of appending |
--no-interpolation | false | Skip environment variable interpolation in the uploaded YAML |
--dry-run | false | Validate and output the pipeline without uploading |
For pipeline YAML syntax and step types, see the buildkite-pipelines skill.
OIDC Tokens
Request short-lived OpenID Connect tokens from within a job step for authenticating to external services (cloud providers, package registries) without static credentials.
Basic token request
TOKEN=$(buildkite-agent oidc request-token --audience "https://packages.buildkite.com/my-org/my-registry")
Cloud provider authentication
TOKEN=$(buildkite-agent oidc request-token --audience "sts.amazonaws.com")
Key flags
| Flag | Default | Description |
|---|
--audience | Buildkite endpoint | Target service URL — must match the OIDC provider audience configuration |
--lifetime | 600 | Token lifetime in seconds |
--claim | — | Comma-separated optional claims to include (e.g., organization_id,pipeline_id) |
--aws-session-tag | — | Comma-separated claims to map as AWS session tags |
For end-to-end OIDC auth flows, cloud provider setup, and token claim details, see the buildkite-secure-delivery skill.
Step Management
Read or modify step attributes at runtime. Useful for conditional logic within steps and build automation.
Get step attributes
LABEL=$(buildkite-agent step get "label")
STATE=$(buildkite-agent step get "state" --step "deploy-step")
OUTCOME=$(buildkite-agent step get "outcome" --step "test-step")
Update step attributes
buildkite-agent step update "label" ":rocket: Deploying v${VERSION}"
buildkite-agent step update "label" ":hourglass: Waiting..." --step "pending-step"
Cancel a step
buildkite-agent step cancel --step "optional-step"
Key flags
| Flag | Default | Description |
|---|
--step | current step | Step key or UUID to target |
--build | current build | Build UUID (for cross-build operations) |
--format | string | Output format for get |
Available step attributes
| Attribute | Readable | Writable | Description |
|---|
label | yes | yes | Step label displayed in UI |
state | yes | no | Current state (running, passed, failed, etc.) |
outcome | yes | no | Final outcome of the step |
key | yes | no | Step key identifier |
Distributed Locks
Coordinate parallel jobs within a build using distributed mutex locks. Prevents race conditions when multiple jobs access shared resources.
Acquire / release pattern
#!/bin/bash
set -euo pipefail
token=$(buildkite-agent lock acquire "database-migration")
trap 'buildkite-agent lock release "database-migration" "${token}"' EXIT
bundle exec rails db:migrate
Do / done pattern (one-time setup)
Run a setup task exactly once across all parallel jobs:
#!/bin/bash
echo "+++ Setting up shared test environment"
if [[ $(buildkite-agent lock do "test-env-setup") == "do" ]]; then
echo "Downloading test assets..."
curl -o /tmp/test-data.zip https://releases.example.com/data.zip
unzip /tmp/test-data.zip -d /tmp/shared-test-files/
buildkite-agent lock done "test-env-setup"
else
echo "Assets already prepared by another job"
fi
run-tests.sh
Key flags
| Subcommand | Flags | Description |
|---|
lock acquire <name> | --timeout | Maximum wait time in seconds (0 = wait forever) |
lock release <name> <token> | — | Release with the token from acquire |
lock do <name> | — | Returns do if lock acquired, done if already completed |
lock done <name> | — | Mark a do lock as completed |
Environment
Inspect and modify the job's environment variables. Primarily useful for debugging lifecycle hooks and understanding what environment changes hooks made.
buildkite-agent env dump | jq .
buildkite-agent env get "BUILDKITE_BRANCH"
buildkite-agent env set "DEPLOY_TARGET" "production"
Key flags
| Subcommand | Default | Description |
|---|
env dump | JSON to stdout | Dump all environment variables |
env get <keys...> | — | Get one or more specific variables |
env set <key> <value> | — | Set a variable for subsequent phases |
env unset <key> | — | Remove a variable from subsequent phases |
Debugging hooks
The env dump command is particularly useful in lifecycle hooks to see what prior hooks changed:
#!/bin/bash
echo "--- Environment after environment hook:"
buildkite-agent env dump | jq 'keys'
For agent lifecycle hooks and buildkite-agent.cfg configuration, see the buildkite-agent-infrastructure skill.
Secrets
Retrieve cluster secrets at runtime from within job steps. Secrets retrieved this way are automatically added to the log redactor.
Basic usage
SECRET_VAR=$(buildkite-agent secret get "deploy-key")
cli-tool --token "$(buildkite-agent secret get "api-token")"
Key flags
| Flag | Default | Description |
|---|
--format | string | Output format: string (single secret) or env (multiple, KEY="value" pairs) |
--skip-redaction | false | Do not add the secret value to the log redactor |
--job | current job | Job ID context |
By default, secret get automatically registers retrieved values with the log redactor, masking them as [REDACTED] in subsequent output.
For setting up cluster secrets, see the buildkite-agent-infrastructure skill. For the declarative secrets: pipeline YAML key, see the buildkite-pipelines skill.
Log Redaction
Add values to the build log redactor at runtime so they are masked in all subsequent output. Use this for dynamically-retrieved secrets that were not declared via secrets: or buildkite-agent secret get.
Basic usage
DYNAMIC_TOKEN=$(curl -s https://vault.example.com/token)
echo "$DYNAMIC_TOKEN" | buildkite-agent redactor add
echo "Using token: $DYNAMIC_TOKEN"
Multiple values
echo "$SECRET1" | buildkite-agent redactor add
echo "$SECRET2" | buildkite-agent redactor add
When to use redactor vs secret get
| Scenario | Use |
|---|
| Secret stored in Buildkite cluster secrets | buildkite-agent secret get (auto-redacts) |
| Secret from external vault (HashiCorp Vault, AWS SSM, etc.) | Fetch externally, then buildkite-agent redactor add |
| Computed sensitive value (temporary token, derived key) | buildkite-agent redactor add |
Tool Signing
Sign and verify pipeline step definitions for integrity checking. Ensures steps have not been tampered with between definition and execution.
Sign a pipeline
buildkite-agent tool sign --jwks-file /etc/buildkite-agent/signing-key.json \
--step "command=make test" \
--step "plugins=docker#v5.12.0"
Verify a signature
buildkite-agent tool verify --jwks-file /etc/buildkite-agent/verification-key.json \
--step "command=make test"
Key flags
| Flag | Default | Description |
|---|
--jwks-file | — | Path to JWKS key file for signing or verification |
--jwks-key-id | — | Key ID to use from the JWKS file |
--step | — | Step attributes to sign/verify (repeatable) |
For pipeline signing configuration and rollout strategy, see the buildkite-secure-delivery skill.
Common Mistakes
| Mistake | What happens | Fix |
|---|
Missing --context on annotate | Each call creates a new annotation instead of updating | Always pass --context with a stable identifier |
Using --append without matching --context | Append has no effect — creates a new annotation | Ensure --context matches the annotation to append to |
| Forgetting to quote artifact glob patterns | Shell expands globs before buildkite-agent sees them | Always quote: "dist/**/*" not dist/**/* |
Reading meta-data get before the writing job completes | Key does not exist, command fails with non-zero exit | Use depends_on or wait to enforce ordering, or use --default |
Using pipeline upload --replace unintentionally | Removes all remaining steps in the build | Only use --replace when intentionally rebuilding the entire pipeline |
| Not releasing locks on script failure | Lock held indefinitely, blocking other jobs | Use trap ... EXIT to release locks on any exit |
Passing --audience that doesn't match OIDC provider config | Token rejected by the target service | Audience must exactly match the provider's configured audience URL |
Using --skip-redaction with actual secrets | Secret values appear in plain text in build logs | Only use --skip-redaction for non-sensitive configuration values |
Calling env set expecting it to affect the current shell | Variable is set for subsequent hooks/phases, not the current script | Use export VAR=value for current-script variables; env set for cross-phase |
| Passing large values via environment variables | OS-level env size limits cause silent truncation or job failure | Switch to file-based approaches (artifacts, meta-data with files) for payloads larger than a few KB |
Uploading pipeline YAML with unescaped $ in --no-interpolation mode off | Variables interpolated unexpectedly, producing malformed YAML | Use --no-interpolation when YAML contains literal $ characters |
Additional Resources
Reference Files
references/flag-reference.md — Complete flag tables for all subcommands including upload, download, search, shasum, annotate, meta-data, pipeline upload, oidc, step, lock, env, secret, redactor, and tool
references/patterns-and-recipes.md — Advanced multi-subcommand patterns: test failure annotation pipelines, cross-job state machines, OIDC-authenticated Docker push, parallel job coordination with locks, environment debugging
Further Reading