For the complete documentation index, see llms.txt. This page is also available as Markdown.

Triggering explorations from any CI

Triggering explorations from any CI

Duku's GitHub Actions are thin wrappers around our Platform API. If your pipelines run somewhere else - CircleCI, Jenkins, GitLab CI, Buildkite - you can make the same API calls directly with curl. This page walks through the complete flow, with CircleCI as the worked example.

Using GitHub Actions? Use the Duku preview or environment actions instead - they implement everything on this page for you.

What you will set up:

  • Exchange your Duku API key for a short-lived access token.

  • Preview flow - register a per-PR build and start an exploration against its preview deployment.

  • Environment flow - start an exploration and test-case run against a long-lived environment target.

  • Get results posted back to your GitHub pull requests via the Duku AI GitHub App.

  • Optionally, block your pipeline until the exploration finishes.

Status. This API surface is the same one our published actions are built on. Like the actions, it is pre-release - operation and field names are stable in practice but may evolve before 1.0.

Endpoints

What
URL

Token endpoint

https://auth.duku.ai/realms/duku/protocol/openid-connect/token

Platform API (GraphQL)

https://platform.duku.ai/graphql

All Platform API operations are GraphQL: POST a JSON body of the form {"query": "...", "variables": {...}} with an Authorization: Bearer <token> header.

Prerequisites

  • A Duku API key. Generate one in Viewport → Settings → API Keys. The key is shown once - store it as a secret in your CI. In CircleCI, put it in a context as DUKU_API_KEY.

  • Preview flow: your product ID (Viewport → Products).

  • Environment flow: a pre-created environment target ID (created in Viewport).

  • Your exploration must be set up in Viewport first. If a target has no exploration configured, startExploration returns an error describing what is missing - complete the setup in Viewport and retry.

  • curl and jq in your job image. CircleCI's cimg/base image includes both.

  • For PR comments: the Duku AI GitHub App installed on your repository (next section).

Tip. You can list your products over the API with query { subjects { id name } } - products are called "subjects" in the API schema.

Install the Duku AI GitHub App

When you pass a repository and pull-request number with an exploration, Duku posts a sticky comment on that PR - first "exploration in progress", then updated in place with the results once the exploration finishes. Those comments are posted by the Duku AI GitHub App, so you never need to handle a GitHub token in your CI job.

  1. Click Install (or Configure if your organisation already has it) and choose the GitHub organisation that owns your repositories. If you are not an organisation owner, GitHub forwards the request to one for approval.

  2. Choose Only select repositories and pick the repositories whose pull requests should receive Duku comments (or All repositories).

  3. Accept the requested permissions - the app only needs to read and write pull-request comments.

That's it. There is nothing to configure on the Duku side: the platform discovers the installation automatically from the repository you name in the API call.

If the app is not installed, explorations still run normally - you just won't get PR comments. Results remain available in Viewport.

Step 1 - Exchange your API key for an access token

See API Keys for how keys work and how to exchange one for an access token. In short: the key is a base64-encoded clientId:clientSecret pair; decode it, split on the first :, and use the standard OAuth2 client-credentials grant to get a short-lived access token.

Save the following helpers to scripts/duku-lib.sh in your repository - the rest of this page builds on them:

Important. Access tokens are short-lived (about 5 minutes). Don't fetch one token at the top of a long job and reuse it - duku_gql above fetches a fresh token per call, which is the simplest safe pattern.

Important. GraphQL errors come back with HTTP status 200, so a bare curl -f will not catch them. Always check the response for an errors array, as duku_gql does.

A word on hygiene: treat the API key and access tokens as secrets. Avoid set -x in steps that call these helpers, and never echo the token.

Avoid sending passwords in the request body. Instead of passing raw login credentials inline, create a credential set once in Viewport and pass its ID or name as credentialSetId on startExploration or runAllTestCases. Duku decrypts it server-side, so the secret never travels through your CI logs or the GraphQL request.

Adapting the scripts to your CI

The helper scripts on this page use CircleCI environment variable names (CIRCLE_*) as examples. If you run a different CI, substitute your provider's equivalents - the GraphQL calls and the rest of each script stay exactly the same.

What it is
CircleCI (used in the scripts)
GitHub Actions
GitLab CI
Jenkins

Repository (owner/repo)

$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME

$GITHUB_REPOSITORY

$CI_PROJECT_PATH

derive from $GIT_URL, or set manually

Pull / merge request number

parsed from $CIRCLE_PULL_REQUEST (or $CIRCLE_PR_NUMBER)

github.event.pull_request.number

$CI_MERGE_REQUEST_IID

$CHANGE_ID

Commit SHA

$CIRCLE_SHA1

$GITHUB_SHA

$CI_COMMIT_SHA

$GIT_COMMIT

Branch name

$CIRCLE_BRANCH

$GITHUB_HEAD_REF (PRs) / $GITHUB_REF_NAME

$CI_COMMIT_REF_NAME

$BRANCH_NAME

Build number

$CIRCLE_BUILD_NUM

$GITHUB_RUN_NUMBER

$CI_PIPELINE_IID

$BUILD_NUMBER

Build / job URL

$CIRCLE_BUILD_URL

$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID

$CI_JOB_URL

$BUILD_URL

Flow A - preview deployments

Two API calls per pipeline, run after your preview deploy step:

  1. upsertSimulationTarget registers the build as a target under your product. The buildKey deduplicates reruns - every pipeline on the same PR updates the same target instead of creating a new one.

  2. startExploration starts the exploration against the preview URL. Passing githubRepository, githubPrNumber, and serverManagedComment: true makes Duku post and maintain the PR comment for you.

Unlike the GitHub Action - which discovers the preview URL from the GitHub Deployments, Checks, and Statuses APIs - your CI job supplies the preview URL directly. Your deploy step already knows it: vercel deploy prints it, netlify deploy --json returns it as deploy_url, or you may construct it from the PR number.

The exploration runs asynchronously - the script exits in seconds and results appear in Viewport and on the PR comment when the run finishes (typically 5 to 40 minutes).

If one pull request triggers explorations for several products, each product gets its own PR comment.

Vercel Deployment Protection. If your previews are protected, pass the bypass secret when registering the build. Add --arg bypass "$VERCEL_AUTOMATION_BYPASS_SECRET" to the first jq call and metadata: {vercelAutomationBypassSecret: $bypass} to its input object.

Not on a PR? For pushes without a pull request, use buildKey: "github:repo=${REPO}:sha=${CIRCLE_SHA1}" and omit githubRepository, githubPrNumber, and serverManagedComment - there is no PR to comment on.

Keep the github:repo=... buildKey convention shown above even though you're not on GitHub Actions: it matches what the Duku GitHub Actions generate, so if you ever run both, they deduplicate onto the same targets.

For the full list of input fields on upsertSimulationTarget and startExploration, see the GraphQL API reference.

Flow B - environment deployments

For a staging environment, prod canary, or any pre-created environment target: skip target registration and start the run directly, then trigger the target's test cases.

  • PR-gate mode: to run this against a fixed environment as a pull-request check and get the PR comment, add githubRepository, githubPrNumber, and serverManagedComment: true to the startExploration input, exactly as in the preview flow.

  • runAllTestCases plans the test runs synchronously and can take up to ~90 seconds to respond; the runs themselves then execute asynchronously.

Gate your pipeline on the result

Both flows are async by design: they kick off the run and exit, and results arrive in Viewport and the PR comment. If you want the CircleCI job to pass or fail with the exploration instead, poll the batch status. Add to scripts/duku-lib.sh:

Usage after either flow script:

  • pending and running are in-flight; completed and failed are terminal.

  • Explorations typically take 5 to 40 minutes - set the step timeout accordingly (the loop prints a line every 30 seconds, so CircleCI's no-output timeout won't trip).

  • Polling keeps a CircleCI executor occupied for the whole run. If you only need the results, skip the gate and let the PR comment deliver them.

Putting it together in CircleCI

Store DUKU_API_KEY (and DUKU_PRODUCT_ID or DUKU_TARGET_ID) in a context named duku under Organization Settings → Contexts, then:

Note. CircleCI only populates CIRCLE_PULL_REQUEST / CIRCLE_PR_NUMBER when the pipeline is associated with a pull request. If those are empty on your PR pipelines, check Project Settings → Advanced → Only build pull requests, or pass the PR number into the script yourself.

Troubleshooting

Token request fails with HTTP 401 (invalid_client). The API key is malformed, revoked, or expired. Check that the secret contains the full base64 string from Viewport with no line breaks, or generate a new key in Viewport → Settings → API Keys.

Authentication required in a GraphQL error. The access token expired mid-job - tokens last about 5 minutes. Fetch a fresh token per call (the duku_gql helper does this) rather than reusing one.

Exploration setup error. The product or target has not been set up for exploration yet. Complete its setup in Viewport, then retry.

Not found when referencing a target or product. The ID is wrong, or it belongs to a different organisation - API keys only see resources in the organisation they were created in.

The PR comment never appears. Verify the Duku AI GitHub App is installed on the repository, that githubRepository is exactly owner/repo, and that githubPrNumber is an integer. The results comment posts only when the run finishes - check its status in Viewport if you're unsure whether it's still running.

Duku's agents can't reach your preview. If your site sits behind a firewall, WAF, or bot protection, see Firewall & WAF Allowlisting. For protected Vercel previews, use the Deployment Protection bypass described above.

Need help? If anything on this page doesn't work for your setup, or you're integrating a CI provider with quirks we haven't covered, contact your Duku account team.

Last updated