> ## Documentation Index
> Fetch the complete documentation index at: https://qodex.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Run tests in Buildkite

> Trigger Qodex from a Buildkite step, wait for completion, and gate downstream deploy steps.

# Run tests in Buildkite

Use a Buildkite step to trigger Qodex, poll the run result, and fail the build if Qodex reports a failed run.

## Before you start

You need:

* A Qodex project with runnable scenarios.
* A project API key from **Settings > Platform > API keys**.
* A Buildkite pipeline connected to your repository.

## Store the secrets

Expose these values to the Buildkite job through Buildkite secrets, an agent environment hook, Vault, AWS Secrets Manager, or another secret manager:

* `QODEX_API_KEY`: your `qk_...` key.
* `QODEX_PROJECT`: your Qodex project slug.

Treat the API key like any other deploy credential.

## Add the step

Save this file at `.buildkite/pipeline.yml`.

```yaml theme={null}
steps:
  - label: ":qodex: smoke"
    key: qodex-smoke
    timeout_in_minutes: 30
    plugins:
      - docker#v5.11.0:
          image: alpine:3.20
          environment:
            - QODEX_API_KEY
            - QODEX_PROJECT
          command:
            - sh
            - -lc
            - |
              apk add --no-cache curl jq

              ENV_NAME=staging
              if [ "$$BUILDKITE_BRANCH" = "main" ]; then ENV_NAME=prod; fi

              RESPONSE=$$(curl -fsS -X POST \
                "https://agents.qodex.ai/api/projects/$$QODEX_PROJECT/webhooks/trigger" \
                -H "Authorization: Bearer $$QODEX_API_KEY" \
                -H "Content-Type: application/json" \
                -d "{\"environment\":\"$$ENV_NAME\",\"tags\":[\"smoke\"]}")

              RUN_ID=$$(echo "$$RESPONSE" | jq -r .testRunId)
              if [ -z "$$RUN_ID" ] || [ "$$RUN_ID" = "null" ]; then
                echo "Failed to start run. Response: $$RESPONSE"
                exit 1
              fi

              DEADLINE=$$(( $$(date +%s) + 1500 ))
              while [ "$$(date +%s)" -lt "$$DEADLINE" ]; do
                STATUS=$$(curl -fsS \
                  "https://agents.qodex.ai/api/projects/$$QODEX_PROJECT/test-runs/$$RUN_ID" \
                  -H "Authorization: Bearer $$QODEX_API_KEY" | jq -r .status)
                echo "status=$$STATUS"
                case "$$STATUS" in
                  completed) exit 0 ;;
                  failed) exit 1 ;;
                  *) sleep 10 ;;
                esac
              done
              echo "Timed out waiting for Qodex run $$RUN_ID"
              exit 1
```

Buildkite uses `$$` so variables are expanded inside the job rather than at pipeline upload time.

## Gate deploys

Add `depends_on: qodex-smoke` to any deploy step that should wait for Qodex.

```yaml theme={null}
  - label: ":rocket: deploy"
    depends_on: qodex-smoke
    command: ./scripts/deploy.sh
```

For post-deploy validation, add a second Qodex step after deploy and point it at the production environment.

## Related

<CardGroup cols={2}>
  <Card title="Jenkins recipe" icon="server" href="/run-tests-ci-jenkins" />

  <Card title="Generic shell recipe" icon="terminal" href="/run-tests-ci-generic-shell" />
</CardGroup>
