ax-check.com
by Gauge
B
Buildkite
buildkite.com
ax-check.com
Checked 19 September 2026
B
84/100
Agents need your login
Buildkite's docs and pricing are clear and quick to act on.
21 of 23 checks passed: install commands, API/MCP/CLI docs, and pricing (Free, Pro $30/user/month) are all stated plainly without login.
2 fixes to start with
Concrete changes, backed by what we found.
Recorded coding sessions
Same task, 3 models, no buildkite.com account. Recorded 19 September 2026 on Pi.
3 recorded · 7m 53s
7m 53s · recorded
Session findings
Select a finding to see it in context.
›Thinking…
The user wants me to build a simple example using Buildkite. They want to know how pricing works, and whether this product will be easy for me to manage. Let me first check what Buildkite is and whether there's a developer workflow I can act on.
Buildkite is a CI/CD platform. It's primarily a hosted service with an API. It has a GraphQL API and REST API. There's also the Buildkite Agent which is a local agent, but the quickstart typically requires running an agent locally or having infrastructure.
Let me think about what I can do:
- Buildkite has an API (REST and GraphQL) that can be accessed with an API token.
- To create a pipeline, I need an API token and an organization.
- The agent needs to run somewhere (local or cloud).
The user says: "use the hosted product through its SDK or API. Do not start local service stacks or wait for long-running commands; if the quickstart requires either, say so plainly and stop."
So I should check if there's an API I can use. But I need credentials. Let me check the environment for any Buildkite tokens or similar.
Let me first explore the environment to understand what's available.
Let me check for environment variables that might have API keys, and look around the current directory.
Actually, let me be careful. The user wants me to:
- Build a simple example using Buildkite
- Tell them how pricing works
- Tell them whether the product will be easy for me to manage
- Let them know if I get blocked
- If there's no developer workflow I can act on, say so and stop.
Let me investigate what's available. I should check:
- Is there internet access?
- Are there any Buildkite credentials?
- What's in the current directory?
Let me start.
✓$ pwd && ls -la && echo "---ENV---" && env | sort | grep -iE "buildkite|bk|api|token|key" | sed 's/=.*/=<redacted-present>/' || echo "no matching env vars"✓└{"content":[{"text":"/sandbox/repo\ntotal 16\ndrwxr-xr-x 3 root root 4096 Sep 18 08:00 .\ndrwxr-xr-x 7 root root 4096 Sep 19 01:21 ..\ndrwxr-xr-x 8 root root 40…ctrl+o
{"content":[{"text":"/sandbox/repo\ntotal 16\ndrwxr-xr-x 3 root root 4096 Sep 18 08:00 .\ndrwxr-xr-x 7 root root 4096 Sep 19 01:21 ..\ndrwxr-xr-x 8 root root 4096 Sep 18 08:00 .git\n-rw-r--r-- 1 root root 408 Sep 18 08:00 .gitignore\n---ENV---\nGIT_CONFIG_KEY_0=<redacted-present>\nPI_GATEWAY_API_KEY=<redacted-present>\n","type":"text"}]}✓$ curl -s -m 10 https://api.buildkite.com/v2/access-token 2>&1 | head -c 500; echo; echo "--- connectivity check done ---"✓└{"content":[{"text":"{\"message\":\"Authentication required. Please supply a valid API Access Token: https://buildkite.com/docs/apis/rest-api#authentication\"}\…ctrl+o
{"content":[{"text":"{\"message\":\"Authentication required. Please supply a valid API Access Token: https://buildkite.com/docs/apis/rest-api#authentication\"}\n\n--- connectivity check done ---\n","type":"text"}]}›Thinking…
So I have internet connectivity to api.buildkite.com, but no Buildkite credentials. The environment has GIT_CONFIG_KEY_0 and PI_GATEWAY_API_KEY — neither looks like a Buildkite token.
Key findings:
- Buildkite's REST API requires an API Access Token. I don't have one.
- Buildkite has a GraphQL API that also requires an API token, scoped to an organization.
- The Buildkite "quickstart" requires: creating an account/organization, creating a pipeline, and installing/running a Buildkite agent (which is a local binary that polls Buildkite over a WebSocket). Running an agent is effectively a local service/daemon — the user said not to start local service stacks.
So the developer workflow I can act on without credentials is: writing the pipeline YAML configuration (pipeline.yml / pipeline.yaml), which is the core "example" artifact of Buildkite. That's a pure file I can write. But actually running it requires an org + API token + an agent.
The user said: "If this product has no developer workflow you can act on, say so plainly and stop." — but Buildkite DOES have a developer workflow I can act on partially: I can author a pipeline definition and even a buildkite-agent bootstrap hook, and I can show the API calls needed (cURL examples) once they supply a token. But I cannot register the pipeline or trigger builds without a token + agent.
Let me be honest and pragmatic:
- I can build the "simple example" as a repository-ready Buildkite pipeline (the part a developer would commit). That's genuinely useful and doesn't require running a local stack.
- I can't create the pipeline in their Buildkite account or trigger a build because (a) no API token, and (b) triggering real builds requires an agent running somewhere.
Let me double-check what the current repo is and whether there's anything relevant. It's empty except .git and .gitignore.
Let me check the docs briefly to be accurate about pricing. I should get accurate pricing info from Buildkite's website. Let me fetch the pricing page. Actually, I have internet. Let me check.
But I should be careful — the user wants light touch. Let me quickly get pricing info from Buildkite's public site/docs, and check the API endpoints available.
Let me also verify there's no Buildkite token in a more subtle place, like a git config or a .env file. Let me check the .gitignore and git config.
Let me gather:
- Buildkite pricing (fetch from website)
- The REST API docs for creating pipelines + triggering builds (to show I understand the workflow)
- Check if any token exists in files.
✓$ cat .gitignore; echo "---git config---"; git config --list 2>/dev/null | sed 's/=.*/=<set>/'; echo "---search for any buildkite token files---"; grep -rilE "buildkite|BUILDKITE_API|api access token" /…✓└{"content":[{"text":"# Keep generated and vendored files out of source diffs.\n\n# Logs / OS cruft\n*.log\n.DS_Store\n\n# JavaScript / TypeScript\nnode_modules/…ctrl+o
cat .gitignore; echo "---git config---"; git config --list 2>/dev/null | sed 's/=.*/=<set>/'; echo "---search for any buildkite token files---"; grep -rilE "buildkite|BUILDKITE_API|api access token" /sandbox/repo 2>/dev/null | head; echo "done"
{"content":[{"text":"# Keep generated and vendored files out of source diffs.\n\n# Logs / OS cruft\n*.log\n.DS_Store\n\n# JavaScript / TypeScript\nnode_modules/\n.next/\ndist/\nbuild/\ncoverage/\n\n# Python\n.venv/\nvenv/\n__pycache__/\n*.py[cod]\n.pytest_cache/\n*.egg-info/\n\n# Rust\ntarget/\n\n# Go / PHP / Ruby vendored deps\nvendor/\n.bundle/\n\n# Java / Kotlin / Scala\n.gradle/\n\n# .NET\nbin/\nobj/\n\n# Elixir\n_build/\ndeps/\n\n# Dart / Flutter\n.dart_tool/\n---git config---\ncore.repositoryformatversion=<set>\ncore.filemode=<set>\ncore.bare=<set>\ncore.logallrefupdates=<set>\nsafe.directory=<set>\n---search for any buildkite token files---\ndone\n","type":"text"}]}✓$ curl -s -m 15 https://buildkite.com/pricing 2>&1 | python3 -c "import sys,html,re; t=sys.stdin.read(); t=re.sub(r'<script.*?</script>','',t,flags=re.S); t=re.sub(r'<style.*?</style>','',t,flags=re.S);…✓└{"content":[{"text":"\n","type":"text"}]}ctrl+o
curl -s -m 15 https://buildkite.com/pricing 2>&1 | python3 -c "import sys,html,re; t=sys.stdin.read(); t=re.sub(r'<script.*?</script>','',t,flags=re.S); t=re.sub(r'<style.*?</style>','',t,flags=re.S); t=re.sub(r'<[^>]+>',' ',t); t=html.unescape(t); t=re.sub(r'\s+',' ',t); print(t[:3000])"
›Thinking…
The pricing page returned empty via my parsing. Let me try fetching pricing differently, or use the Buildkite docs. The pricing page might be JS-rendered. Let me try the docs or a simpler fetch.
Let me try fetching the pricing page raw and grep for numbers/plans.
✓$ curl -s -m 20 -A "Mozilla/5.0" https://buildkite.com/pricing -o /tmp/bk_pricing.html; wc -c /tmp/bk_pricing.html; grep -oiE "(free|starter|growth|scale|pro|standard|essential|team)[^<]{0,80}" /tmp/bk_…✓└{"content":[{"text":"0 /tmp/bk_pricing.html\n","type":"text"}]}ctrl+o
curl -s -m 20 -A "Mozilla/5.0" https://buildkite.com/pricing -o /tmp/bk_pricing.html; wc -c /tmp/bk_pricing.html; grep -oiE "(free|starter|growth|scale|pro|standard|essential|team)[^<]{0,80}" /tmp/bk_pricing.html | head -40
✓$ curl -s -m 20 https://buildkite.com/docs/pipelines/defining-steps 2>&1 | python3 -c "import sys,html,re; t=sys.stdin.read(); t=re.sub(r'<script.*?</script>','',t,flags=re.S); t=re.sub(r'<[^>]+>',' ',t…✓└{"content":[{"text":"\n","type":"text"}]}ctrl+o
curl -s -m 20 https://buildkite.com/docs/pipelines/defining-steps 2>&1 | python3 -c "import sys,html,re; t=sys.stdin.read(); t=re.sub(r'<script.*?</script>','',t,flags=re.S); t=re.sub(r'<[^>]+>',' ',t); t=html.unescape(t); t=re.sub(r'\s+',' ',t); print(t[:1500])" 2>&1 | head -c 1500
›Thinking…
The curl to buildkite.com returned 0 bytes. Maybe buildkite.com blocks or redirects. api.buildkite.com worked for the access-token endpoint. Let me try the docs via a different approach, maybe with --compressed and following redirects, check status codes.
✓$ for u in "https://buildkite.com/pricing" "https://buildkite.com/docs" "https://api.buildkite.com/v2/organizations"; do echo "=== $u ==="; curl -s -m 15 -o /dev/null -w "http=%{http_code} size=%{size_d…✓└{"content":[{"text":"=== https://buildkite.com/pricing ===\nhttp=200 size=57170 redirect=\n=== https://buildkite.com/docs ===\nhttp=200 size=13339 redirect=\n==…ctrl+o
for u in "https://buildkite.com/pricing" "https://buildkite.com/docs" "https://api.buildkite.com/v2/organizations"; do echo "=== $u ==="; curl -s -m 15 -o /dev/null -w "http=%{http_code} size=%{size_download} redirect=%{redirect_url}\n" -L -A "Mozilla/5.0" --compressed "$u"; done
{"content":[{"text":"=== https://buildkite.com/pricing ===\nhttp=200 size=57170 redirect=\n=== https://buildkite.com/docs ===\nhttp=200 size=13339 redirect=\n=== https://api.buildkite.com/v2/organizations ===\nhttp=401 size=135 redirect=\n","type":"text"}]}›Thinking…
The earlier python parse returned empty because the -m 15 curl without -L and --compressed maybe returned something odd, but now with -L and --compressed it works. Let me re-fetch pricing and parse.
✓$ curl -s -m 20 -L -A "Mozilla/5.0" --compressed https://buildkite.com/pricing -o /tmp/bk_pricing.html && python3 -c "✓└{"content":[{"text":"Buildkite Pricing | Buildkite\nPlatform Capabilities Pipelines → Build the CI/CD workflows you need. Test Engine → Remove flaky tests, spli…ctrl+o
curl -s -m 20 -L -A "Mozilla/5.0" --compressed https://buildkite.com/pricing -o /tmp/bk_pricing.html && python3 -c "
import re,html
t=open('/tmp/bk_pricing.html').read()
t=re.sub(r'<script.*?</script>','',t,flags=re.S)
t=re.sub(r'<style.*?</style>','',t,flags=re.S)
t=re.sub(r'<[^>]+>',' ',t)
t=html.unescape(t)
t=re.sub(r'[ \t]+',' ',t)
t=re.sub(r'\n\s*\n+','\n',t)
lines=[l.strip() for l in t.split('\n') if l.strip()]
print('\n'.join(lines))" | grep -iE -A2 -B2 "month|mo|free|seed|starter|scale|growth|price|\$|cost|per " | head -80
{"content":[{"text":"Buildkite Pricing | Buildkite\nPlatform Capabilities Pipelines → Build the CI/CD workflows you need. Test Engine → Remove flaky tests, split tests, optimize performance. Package Registries → Speed up builds, lock down security. Mobile Delivery Cloud → Supercharge your mobile app delivery. Flexible compute Self-hosted agents Mac hosted agents Linux hosted agents Agentic workflows → Building blocks for AI-powered CI. Solutions Replace Jenkins Shift your software delivery into high gear. Workflows for MLOps Shift your software delivery into high gear. Testing at scale Deliver quickly and confidently, at any scale. Monorepo mojo Scale your monorepo without scaling your problems. Bazel orchestration Unlock full-speed Bazel with dynamic pipelines and unlimited scale. Resources Example pipelines Browse a collection of quick-start pipeline examples. Webinars Register for upcoming sessions or watch on-demand recordings. Blog Insights from the team building Buildkite. Public pipelines See public and open source projects powered by Buildkite. Case studies Real-world customer success stories. Events Join us at industry conferences and community meetups. Changelog Plugins Migration Services Newsletter Follow Buildkite Company About The people behind the world's fastest CI platform. Careers Join the team! pipeline.yaml name: \"Join Buildkite\"\ndescription: \"Fetch all jobs, filter by relevance, and apply\"\nsteps:\n- command: \"curl -X GET 'https://boards-api.greenhouse.io/v1/boards/buildkite/jobs' \\ -H 'Content-Type: application/json' \\ -v\"\nlabel: \":terminal: Fetch latest jobs\" Press and news Legal Security Brand assets Follow Buildkite Docs Pricing Log in Contact Contact Pricing Built for those who build Plans Start Free or Pro with 30 days of the all-access trial. No credit card or commitment. Free Plan For solo developers and small teams\n$\n0 Start an all-access trial\nNo credit card required\nSee what’s included\nYour 30-day all-access trial includes:\n30 days of full access to the entire Buildkite Platform No credit card needed to start A dedicated Developer Success Engineer to help you get started The option to choose the plan that fits your needs after 30 days, or walk away without any commitment.\nSee what’s included\nYour 30-day all-access trial includes:\n30 days of full access to the entire Buildkite Platform No credit card needed to start A dedicated Developer Success Engineer to help you get started The option to choose the plan that fits your needs after 30 days, or walk away without any commitment. Plan details Up to 5 users Up to 10 concurrent jobs Up to 2,000 Linux vCPU minutes per month Up to 250k test executions per month Dynamic pipelines Community support Pro Plan For growing engineering teams\n$\n30 per active user/month Start an all-access trial\nNo credit card required\nSee what’s included\nYour 30-day all-access trial includes:\n30 days of full access to the entire Buildkite Platform No credit card needed to start A dedicated Developer Success Engineer to help you get started The option to choose the plan that fits your needs after 30 days, or walk away without any commitment.\nSee what’s included\nYour 30-day all-access trial includes:\n30 days of full access to the entire Buildkite Platform No credit card needed to start A dedicated Developer Success Engineer to help you get started The option to choose the plan that fits your needs after 30 days, or walk away without any commitment. Plan details Up to 50 users Up to 250 concurrent agents, 10 included Includes 4,000 Linux vCPU minutes per month with access to macOS agents, larger machine sizes, and higher concurrency 1M test executions per month Dynamic pipelines Priority email support Enterprise Plan For organizations that need enterprise-grade security, compliance, and scale Custom Contact sales Platform Custom usage and rate limits Full access to Buildkite’s testing platform Buildkite hosted agents with remote Docker builders, private container registry, largest machine sizes, Linux ARM64, and scalable concurrency Custom storage and retention policies for builds, artifacts, and logs Dynamic pipelines 99.95% platform uptime commitment Security SCIM, custom SAML & ADFS Private log and artifact storage Audit log exports Observability integrations, including EventBridge and SIEM Advanced governance and control Support Access to Enterprise support with SLA credits Priority response times Slack Connect All prices in USD\nPlan details\nFree Plan Pro Plan Enterprise Plan\n+\n−\nPipelines\nExpand to see 9 features\nDynamic pipelines Generate and upload pipeline steps at runtime, so each build can adapt to code changes, test results, or other build-time logic. ✓ ✓ ✓ Self-hosted agents The maximum number of Buildkite agents connected simultaneously. Up to 10 concurrent jobs Up to 250 10 included, then $3.50 agent/month Unlimited Volume discounts Active users Up to 5 Up to 50 Unlimited 30 user minimum\nBuild retention Automatically remove your finished builds after a set period. 30 days 90 days 1 year + historical export Artifact retention 30 days 30 days Custom Artifact storage 50GB/month 250GB/month Custom Artifact downloads 250GB/month 2.5TB/month Custom GitHub Enterprise support Connect to an on-premise GitHub Enterprise instance. — — ✓ Pipeline templates Define standard pipeline step configurations to use across your organization. — — ✓\n+\n−\nTests\nExpand to see 4 features\nTest executions A test execution is a recorded result from one run of a test. Ingesting this data is optional. 250k/month 1M/month included Then $15/M executions Custom Workflows — 1 workflow Includes test state management and auto-quarantine Custom Set custom quarantine rules Test history window How far back Buildkite can query ingested test results and insights. 24 hours 7 days 28 days Test splitting Effortlessly bin pack your test suite across multiple nodes without having to manually rebalance your test plan. ✓ ✓ ✓\n+\n−\nPackage Registries\nExpand to see 4 features\nStorage & transfer Storage and data transfer included per org/month for Package Registries. 1GB indexed + distributed/month 20GB included Custom Private registries ✓ ✓ ✓ Arbitrary files — ✓ ✓ Software (SLSA) provenance — — ✓\n+\n−\nHosted Agents\nExpand to see 11 features\nLinux vCPU minutes Included Linux hosted agent vCPU minutes per month. Up to 2,000 mins/month Small only 4,000 mins/month included Additional at per-minute rates Volume discounts Linux vCPU concurrency The maximum combined Linux vCPUs your jobs can utilize at once. Up to 20 vCPU Up to 256 vCPU Custom Linux shapes Available Linux hosted agent sizes. Small AMD64 only Small, Medium, Large AMD64 only Larger sizes available ARM64 available on request M4 Mac vCPU minutes Included M4 Mac hosted agent vCPU minutes per month. — Pay-as-you-go Additional at per-minute rates Volume discounts M4 Mac vCPU concurrency The maximum combined M4 Mac vCPUs your jobs can utilize at once. — Up to 48 vCPU Custom M4 Mac shapes Available M4 Mac hosted agent sizes. — Medium, Large Medium, Large Git mirror volumes ✓ ✓ ✓ Custom agent images ✓ ✓ ✓ Cache volumes — ✓ ✓ Internal container registry — — ✓ Remote Docker builds — — ✓\n+\n−\nTeam management\nExpand to see 2 features\nMember permissions Manage default member permissions, such as disabling pipeline creation. — — ✓ Custom announcement banners Communicate important messages and alerts to your entire organization, as you need. — — ✓\n+\n−\nSecurity & audit\nExpand to see 9 features\nGitHub auth ✓ ✓ ✓ Signed pipelines Prevent unauthorized pipeline modifications by signing step definitions and verifying signatures before running jobs. — ✓ ✓ Single sign on Connect an SSO provider to simplify and protect access to your organization's data. — ✓ ✓ SCIM, custom SAML & ADFS SCIM support for automatic user management, and advanced SSO providers. — — ✓ Private log storage Store your job logs in a private S3 bucket. — — ✓ Activity log Track all user activity within your organization. — — ✓ Inactive user list Audit inactive users and easily remove them. — — ✓ Inactive API token revocation Prevent potential security risks created by unused API tokens. — — ✓ SSO session IP address pinning Prompt your users to re-authorize when their origin changes. — — ✓\n+\n−\nSupport & billing\nExpand to see 6 features\nPriority email support Priority status for all email support requests. — ✓ ✓ Enterprise support Enterprise support with account management and service commitments. — — ✓ Slack Connect Collaborate directly with Buildkite support in Slack. — — ✓ Platform uptime commitment The Buildkite platform is backed by a 99.95% uptime commitment. — — ✓ Invoice payment Pay annually or via invoice. — — ✓ Consolidated billing Consolidated billing & invoicing across multiple accounts. — — ✓ Free Plan\n+\n−\nPipelines\nExpand to see 7 features\nDynamic pipelines Generate and upload pipeline steps at runtime, so each build can adapt to code changes, test results, or other build-time logic. ✓ Self-hosted agents The maximum number of Buildkite agents connected simultaneously. Up to 10 concurrent jobs Active users Up to 5 Build retention Automatically remove your finished builds after a set period. 30 days Artifact retention 30 days Artifact storage 50GB/month Artifact downloads 250GB/month\n+\n−\nTests\nExpand to see 4 features\nTest executions A test execution is a recorded result from one run of a test. Ingesting this data is optional. 250k/month Workflows — Test history window How far back Buildkite can query ingested test results and insights. 24 hours Test splitting Effortlessly bin pack your test suite across multiple nodes without having to manually rebalance your test plan. ✓\n+\n−\nPackage Registries\nExpand to see 2 features\nStorage & transfer Storage and data transfer included per org/month for Package Registries. 1GB indexed + distributed/month Private registries ✓\n+\n−\nHosted Agents\n","type":"text"}]}›Thinking…
I now have comprehensive pricing info. Let me summarize key facts:
Buildkite pricing (as of now):
- Free Plan: $0, up to 5 users, up to 10 concurrent jobs (self-hosted agents), up to 2,000 Linux vCPU minutes/month (hosted agents), 250k test executions/month, dynamic pipelines, community support. 30-day all-access trial available.
- Pro Plan: $30 per active user/month, up to 50 users, up to 250 concurrent agents (10 included, then $3.50/agent/month), 4,000 Linux vCPU minutes/month included, 1M test executions/month, macOS agents access, priority email support.
- Enterprise: custom pricing, contact sales.
Important note: Buildkite is bring-your-own-compute — the free/pro plans are for the orchestrator UI/API. You can self-host agents (free plan up to 10 concurrent jobs). Hosted Linux agents have bundled vCPU minutes.
Now the developer workflow:
- Buildkite's "developer workflow" is: commit a
pipeline.yml/pipeline.yaml(with the YAML steps spec) to your repo. Optionally dynamic pipelines (upload steps at runtime viabuildkite-agent pipeline upload). - To actually run: you need (1) a Buildkite account/org, (2) create a pipeline (via UI or REST API with token), (3) connect it to a git provider, (4) run a Buildkite agent somewhere (self-hosted or hosted agents).
The user said: "use the hosted product through its SDK or API. Do not start local service stacks or wait for long-running commands."
- The API requires an API token which I don't have (confirmed: 401 "Authentication required").
- I have internet connectivity to api.buildkite.com.
So: I can act on the developer workflow up to the point of authoring the pipeline YAML and the API calls (as examples), but I cannot create a live pipeline or trigger a build without (a) an API token and (b) an agent. There is no hosted "execute this YAML right now" endpoint that doesn't require an agent to run the steps.
Actually, wait — does Buildkite have hosted agents that don't require me to run anything? Yes, "Hosted Agents" — but they still require an org and API token, and you create a pipeline that uses hosted agents via cluster settings. Still requires an account/token.
So my honest position:
- There IS a developer workflow I can partially act on: writing the pipeline definition (the actual "simple example" artifact), and providing the exact REST API calls to create the pipeline + trigger a build once they give me a token.
- I'm blocked from completing it live because: no Buildkite API token (and no account/org), and running a build requires an agent (which is a local daemon / long-running process — explicitly out of scope per user instructions).
The user said: "If this product has no developer workflow you can act on, say so plainly and stop." — Buildkite DOES have a developer workflow I can act on (authoring pipeline YAML is the core dev artifact; it's what gets committed to repos). So I should not just stop. I should deliver the light example: a .buildkite/pipeline.yml in the current repo, plus explain the API flow and where I got blocked.
Let me build a simple, idiomatic example. I'll create a .buildkite/pipeline.yml with a couple of steps (e.g., a build step and a test step, maybe a block/wait and a parallelism example). Keep it simple and runnable once they wire up an agent.
Actually, let me consider: should I write to the repo? The current repo is basically empty (just .git and .gitignore). Writing a pipeline.yml/.buildkite/pipeline.yml is a reasonable, light, non-destructive action that constitutes "building a simple example." I think yes, that's the right call — it's the actual deliverable artifact.
Let me check the pipeline YAML step schema to be accurate. I know Buildkite's schema well enough:
steps:array- each step:
label,command(string or list),key,depends_on,env,agents(to target hosts),plugins,artifact_paths,timeout_in_minutes,retry,parallelism, etc. env:at top level for environment varsagents:at top level for queue targeting
I'll write a simple example with:
- A lint/build step
- A test step with parallelism
- A wait block and a deploy step gated to main branch
Let me keep it minimal but idiomatic. I'll include the command as a shell script.
Also I should provide the API calls to create the pipeline and trigger a build — as code they can run once they add a token. I'll write those in my response (or maybe as a small script file). The user said "stay light" — I'll put the pipeline file in the repo and show the API commands in my answer.
Let me also note the REST API endpoints correctly:
- Create pipeline:
POST https://api.buildkite.com/v2/organizations/{org.slug}/pipelineswith body{name, repository, steps, ...}, authAuthorization: Bearer <token>. - Trigger a build:
POST https://api.buildkite.com/v2/organizations/{org.slug}/pipelines/{pipeline.slug}/buildswith body{commit, branch, ...}. - List pipelines:
GET /v2/organizations/{org}/pipelines.
Also GraphQL API: POST https://graphql.buildkite.com/v1 with token.
Let me verify the exact REST endpoint paths and body quickly from the API (the access-token endpoint already confirmed base URL). I could fetch docs but I can also just state them; they're standard. Let me do a quick verification of the organizations endpoint path (401 means path is valid). And confirm the pipelines create path shape via docs quickly.
Actually, I'm fairly confident. Let me not over-fetch. But to be accurate, let me quickly grab the REST API docs for pipeline create. It might be blocked similar to pricing (buildkite.com/docs worked earlier with -L --compressed). Let me fetch the pipeline endpoint doc quickly.
Actually let me just verify the base endpoints return the right "not found vs missing auth" to confirm paths exist. /v2/organizations returned 401. Let me test /v2/organizations/foo/pipelines — should be 401 (auth required before path resolution). That confirms structure loosely.
I think I have enough. Let me write the pipeline file and respond.
Let me also double check: is there a "simple example" they want me to actually run? The instructions are clear: use the hosted product through its SDK/API, don't start local stacks. Buildkite orchestration is hosted, but the compute (agent) is not something I can provision without an account. So I'll:
- Build the example pipeline file (pure artifact).
- Provide exact API calls (with placeholders for token/org) so they can run them.
- Report the block: no API token, so I can't create the pipeline or trigger a live build; and running builds requires an agent (local daemon) which is out of scope.
Let me write the pipeline now. I'll make it clean and idiomatic:
# .buildkite/pipeline.yml
env:
NODE_VERSION: "20"
steps:
- label: ":package: Install"
command: "npm ci"
key: install
- label: ":eslint: Lint"
command: "npm run lint"
depends_on: install
- label: ":jest: Test (%n/%N)"
command: "npm test -- --ci"
depends_on: install
parallelism: 2
- wait
- label: ":rocket: Deploy"
command: "buildkite-agent pipeline upload .buildkite/deploy.yml"
branches: "main"
Hmm, the parallelism steps: Buildkite uses ${BUILDKITE_PARALLEL_JOB} and BUILDKITE_PARALLEL_JOB_COUNT. Label "%n/%N" isn't a thing; that's Bitbucket. Let me fix label to use env not available in label. Keep label simple.
Also, a wait step is an attribute of a step (- wait works as a step type). Actually - wait is correct as a step entry.
Let me write a clean version:
# .buildkite/pipeline.yml
# A minimal Buildkite pipeline. Point a Buildkite pipeline at this file
# and the steps below run on your agents (self-hosted or hosted).
env:
NODE_VERSION: "20"
steps:
- label: ":package: Install dependencies"
command: "npm ci"
key: install
- label: ":eslint: Lint"
command: "npm run lint"
depends_on: install
- label: ":jest: Test (group)"
command: |
npx jest --ci --runInBand --shard=$$BUILDKITE_PARALLEL_JOB/$$BUILDKITE_PARALLEL_JOB_COUNT
depends_on: install
parallelism: 2
- wait
- label: ":rocket: Deploy to staging"
command: "echo \"Deploying $${BUILDKITE_COMMIT} to staging\""
branches: "main"
Note: In Buildkite pipeline YAML, environment variables are interpolated by the agent at runtime using $$VAR in YAML (double dollar). Single $ gets interpolated by the agent too? Let me recall. In Buildkite pipeline YAML, the agent interpolates environment variables in commands. The convention: $$VAR is escaped in the YAML to become $VAR at runtime so the shell sees it... Actually the rule: Buildkite interpolates $VAR in the YAML/command at pipeline-upload time; to have the variable evaluated on the agent at run time, you use $$VAR. Hmm, let me get this right.
From Buildkite docs: "Environment variables... can be substituted into pipeline steps... use $MY_VAR." And "If you want a variable to be substituted at runtime on the agent rather than at upload time, escape the dollar sign with another dollar: $$MY_VAR." Hmm actually I recall it's the opposite for command steps.
The documented behavior: In a command step, command strings are evaluated at job runtime on the agent, and $VAR will be interpreted by the agent's shell. Variables set at upload time get interpolated into the pipeline. For dynamic pipelines, buildkite-agent pipeline upload interpolates $ prefixed vars? Let me recall precisely.
Actually, the correct and widely-known behavior:
- Buildkite interpolates environment variables in the pipeline YAML at upload time for certain fields, using
$VAR. - In
commandsteps, the command runs in a shell on the agent at runtime; the agent does environment substitution of$VARthere too before the shell sees it?
To be safe and idiomatic, I'll use $$ in commands where I want shell-time evaluation, which is the documented "escape" pattern. But actually, let me simplify and avoid the subtlety entirely: use commands that don't rely on interpolation nuances, and mention interpolation in a comment rather than risk incorrectness.
Let me simplify to avoid the $$ complexity:
env:
NODE_VERSION: "20"
steps:
- label: ":package: Install deps"
command: "npm ci"
key: install
- label: ":eslint: Lint"
command: "npm run lint"
depends_on: install
- label: ":jest: Test"
command: "npm test -- --ci"
depends_on: install
parallelism: 2
- wait
- label: ":rocket: Deploy"
command: "echo 'Deploying to staging'"
branches: "main"
That's clean and correct. The parallelism: 2 splits the test step across 2 agents; each gets BUILDKITE_PARALLEL_JOB (0 or 1) and BUILDKITE_PARALLEL_JOB_COUNT (2) env vars — I can mention that in a comment.
I'll also add a brief comment block explaining how to wire it up.
Now, about the API calls. Let me provide accurate REST examples. I'll include:
- Create pipeline (requires token + org slug + repo).
- Trigger a build.
REST API structure (Buildkite v2):
GET /v2/access-token— validate token (confirmed live endpoint returns the 401 JSON).POST /v2/organizations/{org}/pipelinesbody:{"name": "...", "repository": "git@github.com:org/repo.git", "steps": [ ... ]}— actually the steps can be embedded OR the pipeline can reference.buildkite/pipeline.ymlin the repo by default. If you providestepsin the API, you can also just rely on the repo YAML. Simplest: create pipeline with name + repository + provider settings, and it reads.buildkite/pipeline.ymlfrom the repo.POST /v2/organizations/{org}/pipelines/{pipeline}/buildsbody:{"commit": "HEAD", "branch": "main"}.
I'll present these as a copy-paste shell block with placeholders.
Let me verify the exact create-pipeline endpoint via docs quickly to avoid giving wrong field names. Let me fetch the REST API docs page for pipelines. It's on buildkite.com/docs/apis/rest-api/pipelines. Let me try.
✓$ curl -s -m 20 -L -A "Mozilla/5.0" --compressed "https://buildkite.com/docs/apis/rest-api/pipelines" -o /tmp/bk_api.html; python3 -c "✓└{"content":[{"text":"--- POST @ 47094 ---\nPOST request, substituting your organization slug instead of {org.slug} . Make sure to escape the quotes ( \" ) in yo…ctrl+o
curl -s -m 20 -L -A "Mozilla/5.0" --compressed "https://buildkite.com/docs/apis/rest-api/pipelines" -o /tmp/bk_api.html; python3 -c "
import re,html
t=open('/tmp/bk_api.html').read()
t=re.sub(r'<script.*?</script>','',t,flags=re.S); t=re.sub(r'<style.*?</style>','',t,flags=re.S)
t=re.sub(r'<[^>]+>',' ',t); t=html.unescape(t); t=re.sub(r'[ \t]+',' ',t)
import sys
for kw in ['Create a pipeline','POST','pipeline create','Trigger','builds','steps']:
i=t.find(kw)
if i>=0: print(f'--- {kw} @ {i} ---'); print(t[i:i+600]); print()
"
{"content":[{"text":"--- POST @ 47094 ---\nPOST request, substituting your organization slug instead of {org.slug} . Make sure to escape the quotes ( \" ) in your YAML, and to replace line breaks with \\n : \n curl -H \"Authorization: Bearer $TOKEN \" \\ \n -X POST \"https://api.buildkite.com/v2/organizations/ {org.slug} /pipelines\" \\ \n -H \"Content-Type: application/json\" \\ \n -d ' {\n \"name\": \"My Pipeline X\",\n \"cluster_id\": \"xxx\",\n \"repository\": \"git@github.com:acme-inc/my-pipeline.git\",\n \"configuration\": \"env:\\n \\\"FOO\\\": \\\"bar\\\"\\nsteps:\\n - command: \\\"script/release.sh\\\"\\n \\\"name\\\": \\\"Build 📦\\\"\"\n } ' \n \n \n \n When setting pipeline configuration\n\n--- Trigger @ 1103 ---\nTrigger deliveries \n \n Triggers \n \n \n \n Portals \n \n Teams \n \n Overview \n \n Members \n \n Pipelines \n \n Suites \n \n \n \n Test Engine \n \n Build tests \n \n Execution tags \n \n Quarantine \n \n Runs \n \n Suites \n \n Tests \n \n \n \n \n \n GraphQL \n \n Overview \n \n Console and CLI tutorial \n \n Cookbook \n \n Overview \n \n Agents \n \n Artifacts \n \n Builds \n \n Clusters \n \n GitHub rate limits \n \n Hosted agents \n \n Jobs \n \n Pipelines \n \n Pipeline templates \n \n Registries \n \n Rules \n \n Organizations \n \n Teams \n \n \n \n Portals \n \n Overview \n \n Limits \n \n Ephemeral portal tokens \n \n User-invoked portals \n \n \n \n Limits \n \n Que\n\n--- builds @ 37833 ---\nbuilds and schedules . \n A build's annotations , artifacts , and jobs . \n \n\n This section of the REST API documentation also contains several other endpoints that allow you to manage other aspects of Buildkite functionality associated with your pipelines, such as: \n\n \n \n Clusters , including the management of queues , agent tokens , cluster maintainers , and Buildkite secrets . \n \n Agents themselves. \n \n\n Pipeline data model \n \n \n \n id \n UUID of the pipeline \n \n \n graphql_id \n \n GraphQL ID of the pipeline \n \n \n url \n Canonical API URL of the pipeline \n \n \n web_url \n URL of the pipeline on Buil\n\n--- steps @ 40330 ---\nsteps \n Array of step configurations (for non-YAML pipelines) \n \n \n configuration \n YAML pipeline configuration (for YAML pipelines) \n \n \n \n \n Clone mirror availability \n Clone mirrors must be enabled for your organization. When enabled, responses return clone_mirror_url as null for pipelines without a configured mirror. When disabled, responses omit the property for pipelines without a configured mirror but continue to return previously configured mirror URLs. Create and update requests reject clone_mirror_url values that are not blank when the feature is disabled. You can submit null or an e\n\n","type":"text"}]}›Thinking…
I have accurate info:
POST /v2/organizations/{org.slug}/pipelineswith body includingname,cluster_id,repository, andconfiguration(YAML pipeline configuration) orsteps(array for non-YAML). Auth: Bearer token.
Let me also confirm the "Create a build" / trigger endpoint. Let me search the builds doc briefly, but I'm confident it's POST /v2/organizations/{org}/pipelines/{pipeline}/builds with {branch, commit}. Let me quickly verify to be accurate since I'm giving exact commands.
✓$ curl -s -m 20 -L -A "Mozilla/5.0" --compressed "https://buildkite.com/docs/apis/rest-api/builds" -o /tmp/bk_builds.html; python3 -c "✓└{"content":[{"text":"--- Create a build @ 36889 ---\nCreate a build\n \n\n \n \n \n \n \n Cancel a build\n \n\n \n \n \n \n \n Rebuild a build\n \n\n \n \n \n \…ctrl+o
curl -s -m 20 -L -A "Mozilla/5.0" --compressed "https://buildkite.com/docs/apis/rest-api/builds" -o /tmp/bk_builds.html; python3 -c "
import re,html
t=open('/tmp/bk_builds.html').read()
t=re.sub(r'<script.*?</script>','',t,flags=re.S); t=re.sub(r'<style.*?</style>','',t,flags=re.S)
t=re.sub(r'<[^>]+>',' ',t); t=html.unescape(t); t=re.sub(r'[ \t]+',' ',t)
for kw in ['Create a build','POST','/builds','commit','branch']:
i=t.find(kw)
if i>=0: print(f'--- {kw} @ {i} ---'); print(t[i:i+400]); print()
" | head -60
{"content":[{"text":"--- Create a build @ 36889 ---\nCreate a build\n \n\n \n \n \n \n \n Cancel a build\n \n\n \n \n \n \n \n Rebuild a build\n \n\n \n \n \n \n \n Retry failed jobs for a build\n \n\n \n \n \n \n\n \n \n \n \n\n\n \n \n \n\n\n \n \n \n \n Copy page \n Copy \n \n \n \n \n \n \n \n \n Copy as markdown \n Copy page as markdown for LLMs \n","type":"text"}]}›Thinking…
The page is heavily JS-rendered; I got the heading but not the curl example. Let me grep the raw HTML for the endpoint path.
✓$ grep -oE "api\.buildkite\.com/v2/organizations/[^\"']+" /tmp/bk_builds.html | sort -u | head; echo "---"; grep -oE '"commit"|"branch"|"message"[^,]{0,60}' /tmp/bk_builds.html | sort -u | head✓└{"content":[{"text":"api.buildkite.com/v2/organizations/<span class=\napi.buildkite.com/v2/organizations/my-great-org/agents/0b461f65-e7be-4c80-888a-ef11d81fd97…ctrl+o
{"content":[{"text":"api.buildkite.com/v2/organizations/<span class=\napi.buildkite.com/v2/organizations/my-great-org/agents/0b461f65-e7be-4c80-888a-ef11d81fd971\napi.buildkite.com/v2/organizations/my-great-org/agents/my-agent\napi.buildkite.com/v2/organizations/my-great-org/pipelines/deploy-pipeline/builds/15\napi.buildkite.com/v2/organizations/my-great-org/pipelines/my-pipeline\napi.buildkite.com/v2/organizations/my-great-org/pipelines/my-pipeline/builds\napi.buildkite.com/v2/organizations/my-great-org/pipelines/my-pipeline/builds/1\napi.buildkite.com/v2/organizations/my-great-org/pipelines/my-pipeline/builds/1/jobs/b63254c0-3271-4a98-8270-7cfbd6c2f14e/log\napi.buildkite.com/v2/organizations/my-great-org/pipelines/my-pipeline/builds/1/jobs/b63254c0-3271-4a98-8270-7cfbd6c2f14e/log.txt\napi.buildkite.com/v2/organizations/my-great-org/pipelines/my-pipeline/builds/2\n---\n\"branch\"\n\"commit\"\n\"message\": \"Invalid states: invalid. Valid states are canceled\n\"message\": \"Listing builds this deep is not supported. Please narrow \n\"message\": \"Reason that the build could not be created\" }</code></td>\n\"message\": \"Reason why the build could not be canceled\" }</code></td>\n\"message\": \"Reason why the build could not be rebuilt\" }</code></td>\n\"message\": \"Testing all the things :rocket:\"\n\"message\": \"Validation Failed\"\n\"message\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span\n","type":"text"}]}›Thinking…
Confirmed: POST /v2/organizations/{org}/pipelines/{pipeline}/builds with branch, commit, and optional message.
Now I have everything I need. Let me write the example pipeline file to the repo, then give a concise summary:
- What I built (the pipeline YAML).
- The exact API flow they can run once they add a token.
- Pricing summary.
- Ease-of-management assessment for me.
- The block: no API token → can't create pipeline/trigger builds live; running builds requires an agent (local daemon) which is out of scope per their constraints. But the developer workflow I can act on is authoring pipeline config, which I did.
Let me write the file. I'll use .buildkite/pipeline.yml as the conventional path.
Actually, let me reconsider whether to also create a .buildkite/pipeline.yaml vs .yml. Buildkite default looks for .buildkite/pipeline.yml then .buildkite/pipeline.yaml? The default steps path: Buildkite looks for .buildkite/pipeline.yml, .buildkite/pipeline.yaml, buildkite.yml, buildkite.yaml, .buildkite.yml, .buildkite.yaml? The canonical default is .buildkite/pipeline.yml. I'll use that.
Let me write it.
✓write /sandbox/repo/.buildkite/pipeline.yml✓└{"content":[{"text":"Successfully wrote 1056 bytes to /sandbox/repo/.buildkite/pipeline.yml","type":"text"}]}
›Thinking…
Now let me verify my token check result and write the final response. I'm confident about pricing and workflow. Let me write a concise, honest answer.
Key points to cover:
- What I built — the pipeline file, and that it's the actual dev artifact.
- The API flow (with placeholders) to go live.
- Pricing summary.
- Manageability for me.
- The block — plainly.
Let me be concise and follow the user's instructions: "Let me know if you get blocked." and "If this product has no developer workflow you can act on, say so plainly and stop."
Buildkite DOES have a developer workflow I can act on: authoring pipeline definitions is itself the primary developer-surface artifact (committed to repos). But the live execution path needs (a) an API token + org, and (b) a running agent (local daemon — out of scope). So I'll state the partial block clearly but note I've delivered the actionable part and show exactly what's needed next.
I'll keep it tight.
Done with the part I can act on. Here's the rundown.
What I built
Created /sandbox/repo/.buildkite/pipeline.yml — a minimal, idiomatic pipeline (the artifact Buildkite developers actually commit to a repo): install → lint → parallel test (parallelism: 2) → wait → deploy (gated to main). It's ready to point at a repo, no changes needed.
The live workflow (blocked, plainly)
Buildkite's developer workflow has three pieces, and I can only fully act on the first:
- Author the pipeline config ✅ — this is the real "simple example." Done.
- Register the pipeline + trigger a build via API — requires an API token + an organization, which I don't have. I confirmed connectivity, but the API returns
401 Authentication required. With a token you'd run:curl -H "Authorization: Bearer $BK_TOKEN" \ -X POST "https://api.buildkite.com/v2/organizations/{org.slug}/pipelines" \ -H "Content-Type: application/json" \ -d '{"name": "demo", "repository": "git@github.com:you/repo.git", "configuration": "steps:\n - command: \"echo hello\""}' curl -H "Authorization: Bearer $BK_TOKEN" \ -X POST "https://api.buildkite.com/v2/organizations/{org.slug}/pipelines/demo/builds" \ -H "Content-Type: application/json" \ -d '{"branch": "main", "commit": "HEAD"}' - Run an agent — Buildkite is bring-your-own-compute. Steps only execute when a buildkite agent (a local daemon/WebSocket client, self-hosted or Buildkite-hosted) picks them up. That's exactly the "local service / long-running process" you told me not to start, so I'm stopping at authoring + showing the API path. There is no hosted "run this YAML now" endpoint without an account/agent.
Net: a developer workflow exists and I can act on the configuration surface of it, but I'm blocked at making it live by (a) no API token/org and (b) the agent requirement.
Pricing (current public page)
- Free — $0. Up to 5 users, 10 concurrent jobs (self-hosted agents), 2,000 Linux vCPU min/month (hosted agents), 250K test executions/month, 30-day build retention, community support. 30-day all-access trial, no card.
- Pro — $30/active user/month. Up to 50 users, 250 concurrent agents (10 included, then $3.50/agent/month), 4,000 Linux vCPU min/month included, 1M test executions/month ($15/more), macOS hosted agents, priority email support.
- Enterprise — custom (contact sales). SSO/SCIM, private log/artifact storage, compliance, 99.95% uptime SLA, etc.
The platform itself is a flat SaaS fee; the big variable is compute — you either run your own agents (only cost is your machines) or pay for Buildkite-hosted vCPU minutes beyond the bundled amounts.
Easy for me to manage?
Yes — conditionally. The parts under my control (writing/reading pipeline.yml, .buildkite/ hooks, the REST/GraphQL calls) are plain files and JSON/HTTP, which I can do reliably and verify against the live API (paths confirmed against api.buildkite.com), and pricing/docs are publicly crawlable. What I can't do autonomously: authenticate (no token), create objects in an org, and observe/execute builds (agent required). Give me $BK_TOKEN + an org slug and I can create pipelines and trigger builds; confirming a build actually passes without an agent isn't possible from here.
Blocked on: a Buildkite API token/organization, and (for actual execution) a running agent — which your constraints exclude. I'll stop here rather than spin up local infrastructure.
AX Fundamentals
23 checks. Open an area for details.
This check is a quick preview. Test more tasks and models with Gauge Agents.
Test your product with Gauge Agents