Preflight
The Preflight feature is currently in experimental stage. Its behavior is subject to change without notice. To provide feedback, please contact Buildkite's Support team at support@buildkite.com.
Preflight is a subcommand of the Buildkite CLI (bk preflight) that runs your uncommitted local changes against Buildkite Pipelines and monitors failures as they happen. It is designed for use with a coding agent, triggering a build against the changes in your working tree and surfacing failures for the agent to iterate against.
The Preflight (bk preflight) command:
- Snapshots your uncommitted changes (staged, unstaged, and untracked files) as a temporary commit on a new branch, without touching your working tree. Files matched by
.gitignoreare excluded. - Pushes that commit to a branch prefixed with
bk/preflight/on the repository'soriginremote, then triggers a build on your chosen Buildkite pipeline. - Monitors failures in your terminal in real time and exits as soon as the build starts failing.
- Cleans up the temporary branch automatically when the build finishes.
Before you begin
You'll need:
- The Buildkite CLI version 3.40.0 or later.
- A configured API access token with the
read_builds,write_builds, andread_pipelinesscopes. Theread_suitesscope is also required to use Preflight with Test Engine. - Git commit and push access to the repository.
Install or upgrade the Buildkite CLI
To check your current Buildkite CLI version, run:
bk version
To upgrade using Homebrew:
brew upgrade buildkite/buildkite/bk@3
To upgrade using mise:
mise use -g github:buildkite/cli@latest
Install the Preflight skill
To install the Preflight skill into your coding agent:
bk skill add buildkite-preflight
Using the skill requires Buildkite CLI version 3.40.0 or later.
Run a Preflight build
To run a build with Preflight enabled:
bk preflight --pipeline my-org/my-pipeline --watch
The --pipeline flag accepts either {org-slug}/{pipeline-slug} or just {pipeline-slug} if your Buildkite organization is already set in your bk config.
You can omit --pipeline when configuration or repository discovery resolves the pipeline. Pass it explicitly in automation to avoid ambiguous selection. Watching is enabled by default; --no-watch starts the build and exits without waiting or automatically cleaning up its branch.
In --watch mode, Preflight exits with code 0 if all jobs pass, 10 when the build first enters the failing state (the default), or 9 if the build completes with failures. See exit codes for the full list.
Preflight works well with promise job failure. If a running job declares a promised hard failure, Buildkite Pipelines can move the build to failing before the job exits, and Preflight can start reporting the failure earlier while the job continues uploading logs and test results. Reading promised failures from running jobs requires Buildkite CLI version 3.50.0 or later.
The following examples show common variations:
# Start the build and exit immediately (don't wait)
bk preflight --pipeline my-org/my-pipeline --no-watch
# Skip confirmation prompts
bk preflight --pipeline my-org/my-pipeline --watch --yes
# Use plain text output in non-interactive environments
bk preflight --pipeline my-org/my-pipeline --watch --text
# Use JSONL output when another tool needs structured events
bk preflight --pipeline my-org/my-pipeline --watch --json
# Wait up to 30s for Test Engine results after build completion
bk preflight --pipeline my-org/my-pipeline --watch --await-test-results
# Set a custom wait for Test Engine results
bk preflight --pipeline my-org/my-pipeline --watch --await-test-results=10s
# Don't cancel the build or remove the branch on exit
bk preflight --pipeline my-org/my-pipeline --watch --no-cleanup
# Wait for the build to reach a terminal state instead of exiting on the failing state
bk preflight --pipeline my-org/my-pipeline --watch --exit-on build-terminal
Unless you pass --no-cleanup, an early exit while watching can cancel the build before deleting the remote branch. Use --no-cleanup when you want the build to continue after Preflight exits.
Clean up retained branches
For branches left by --no-watch, --no-cleanup, or an interrupted run, preview cleanup before deleting them:
bk preflight cleanup --pipeline my-org/my-pipeline --preflight-uuid UUID --dry-run
bk preflight cleanup --pipeline my-org/my-pipeline --preflight-uuid UUID
Cleanup checks build status only in the selected pipeline. It leaves branches with in-progress builds found in that pipeline untouched, but branches with no build found are eligible for deletion. Without --preflight-uuid, all bk/preflight/* branches on origin are candidates, including branches used by other pipelines.
In repositories shared by multiple pipelines, use --preflight-uuid UUID with the matching --pipeline and inspect --dry-run output before deleting. The UUID limits branch selection; it does not independently verify which pipeline owns the branch. See the Preflight command reference for available flags.
Build summary
On exit, Preflight prints a summary of the jobs that failed. When integrated with Buildkite Test Engine, the summary also includes test results. This integration requires the read_suites scope on your API access token.
A test with at least one passed execution is treated as passed, and a test with only failed executions is treated as failed. Tests that pass on retry are not counted as failures. Tests with only pending, skipped, or unknown executions are excluded from the summary.
Preflight reports up to 10 test failures in the terminal output, and up to 100 test failures in JSON events.
Customizing pipelines for Preflight
Preflight sets the following environment variables on the build, so you can customize pipeline behavior for preflight runs:
-
PREFLIGHT: Set totrue. -
PREFLIGHT_SOURCE_COMMIT: The HEAD commit when Preflight was run. -
PREFLIGHT_SOURCE_BRANCH: The current branch when Preflight was run.
Use these with conditionals and dynamic pipelines to run a subset of a pipeline or otherwise modify its behavior under Preflight.
To skip linting on builds triggered by Preflight:
steps:
- command: ./scripts/lint.sh
label: lints
if: build.env("PREFLIGHT") != "true"
To run a test suite with --fast-fail when Preflight is in use:
steps:
- label: "π§ͺ Tests"
command: |
if [ "$PREFLIGHT" = "true" ]; then
./scripts/test.sh --fast-fail
else
./scripts/test.sh
fi
Exit codes
| Exit code | Meaning |
|---|---|
0 |
Watched build passed, or the build was created successfully with --no-watch
|
1 |
Generic error |
9 |
Build completed with failures |
10 |
Build incomplete β failures already detected |
11 |
Build incomplete β still running or blocked |
12 |
Unknown build state |
130 |
Aborted by user (Ctrl+C) |
Flags
| Flag | Default | Description |
|---|---|---|
--pipeline, -p
|
Inferred | Pipeline slug ({slug} or {org}/{slug}); specify explicitly when inference is ambiguous |
--watch / --no-watch
|
true |
Watch the build until completion or the selected exit condition |
--interval |
2 |
Polling interval in seconds |
--exit-on |
build-failing |
Condition that triggers exit. build-failing exits when the build enters the failing state; build-terminal exits when the build reaches a terminal state. |
--no-cleanup |
false |
Keep the remote preflight branch and leave the build running on early exit |
--await-test-results[=DURATION] |
Disabled | Wait for Test Engine summaries after build completion; without a duration, wait up to 30 seconds |
--text |
false |
Use plain text output |
--json |
false |
Emit one JSON object per event (JSONL) |
--yes, -y
|
false |
Skip confirmation prompts |
--no-input |
false |
Disable all interactive prompts |
--quiet, -q
|
false |
Suppress progress output |
--debug |
false |
Log HTTP API traffic to stderr; bodies can contain sensitive data |