Skip to content

WonderTwin in CircleCI

Run a twin against your test suite in a CircleCI workflow. Capture replay artifacts on every run, including failures.

Drop this into .circleci/config.yml (or merge into your existing config):

version: 2.1
jobs:
test-with-twin:
docker:
- image: cimg/base:current
environment:
WT_TWIN_URL: http://127.0.0.1:<TWIN_PORT>
steps:
- checkout
- run:
name: Install wt
command: |
curl -sSL "https://github.com/wondertwin-ai/wondertwin/releases/latest/download/wt-linux-amd64" -o /usr/local/bin/wt
chmod +x /usr/local/bin/wt
- run:
name: Install WonderTwin license
command: |
if [ -n "$WONDERTWIN_LICENSE" ]; then
printf '%s' "$WONDERTWIN_LICENSE" > /tmp/license.json
wt license install /tmp/license.json
rm /tmp/license.json
fi
- run:
name: Start twin-<TWIN>
background: true
command: |
wt install <TWIN>@<TWIN_VERSION>
wt up
- run:
name: Wait for twin
command: |
for i in $(seq 1 30); do
curl -sf "$WT_TWIN_URL/admin/state" > /dev/null && exit 0
sleep 0.2
done
echo "twin did not become healthy in 6s"
exit 1
- run:
name: Start run
environment:
CI: "true"
command: |
wt runs start \
--twin "$WT_TWIN_URL" \
--seed 42 \
--run-id "${CIRCLE_WORKFLOW_ID}-${CIRCLE_BUILD_NUM}"
- run:
name: Test
command: <TEST_COMMAND>
- run:
name: Finish run + export replay
when: always
command: |
mkdir -p /tmp/wondertwin-artifacts
wt runs finish \
--twin "$WT_TWIN_URL" \
--run-id "${CIRCLE_WORKFLOW_ID}-${CIRCLE_BUILD_NUM}" \
--export /tmp/wondertwin-artifacts/replay.jsonl.gz
- store_artifacts:
path: /tmp/wondertwin-artifacts
destination: wondertwin-replay
workflows:
build-test:
jobs:
- test-with-twin
  1. Pick your twin and version. Replace <TWIN> (e.g. stripe, twilio), <TWIN_VERSION> (e.g. 0.1.0), and <TWIN_PORT> (twin-stripe: 4111).
  2. Replace <TEST_COMMAND> with your actual test invocation.
  3. Set the license environment variable. In CircleCI: Project Settings → Environment Variables → Add Variable. Name: WONDERTWIN_LICENSE. Value: the full contents of the license JSON file (paste it as-is; do not base64-encode). Or use a Context if you want to share the secret across multiple projects.
  4. Tell your test code where the twin is. The job exports WT_TWIN_URL. Most SDKs let you override the base URL via env var or config — see your SDK’s docs.
  5. Choose a Docker image. cimg/base:current works for most cases. If your tests need a specific runtime (Node, Go, Python), use cimg/node:20, cimg/go:1.22, etc.
- run:
name: Start run with fixtures
command: |
wt runs start \
--twin "$WT_TWIN_URL" \
--seed 42 \
--fixtures fixtures/stripe-snapshot.json \
--run-id "${CIRCLE_WORKFLOW_ID}-${CIRCLE_BUILD_NUM}"

Without an explicit run lifecycle (using wt runs wrap)

Section titled “Without an explicit run lifecycle (using wt runs wrap)”
- run:
name: Test with wrap
environment:
CI: "true"
command: |
wt runs wrap \
--twin "$WT_TWIN_URL" \
--seed 42 \
--run-id "${CIRCLE_WORKFLOW_ID}-${CIRCLE_BUILD_NUM}" \
--export /tmp/wondertwin-artifacts/replay.jsonl.gz \
-- <TEST_COMMAND>
- store_artifacts:
path: /tmp/wondertwin-artifacts
destination: wondertwin-replay

Use separate background: true steps with different ports:

- run:
name: Start twin-stripe
background: true
command: |
wt install stripe@0.1.0
PORT=4111 wt up
- run:
name: Start twin-twilio
background: true
command: |
wt install twilio@0.1.0
PORT=4112 wt up

For most use cases, one twin per job is simpler.

- run: |
curl -sSL "https://github.com/wondertwin-ai/wondertwin/releases/download/v0.4.2/wt-linux-amd64" -o /usr/local/bin/wt
chmod +x /usr/local/bin/wt
- run: wt install stripe@0.1.0

CircleCI background steps don’t fail the job if the command exits non-zero. The Wait for twin step is the gate — if the twin never becomes healthy, that step exits non-zero and the job fails clearly.

My replay step doesn’t run when tests fail

Section titled “My replay step doesn’t run when tests fail”

CircleCI’s when: always is the equivalent of GitHub’s if: always(). Make sure the Finish run + export replay and store_artifacts steps both have when: always set.

cimg/base:current includes curl. If you’re using a custom image, install curl first or use the wget form:

- run: |
wget -O /usr/local/bin/wt "https://github.com/wondertwin-ai/wondertwin/releases/latest/download/wt-linux-amd64"
chmod +x /usr/local/bin/wt

See the GitHub Actions guide’s troubleshooting — the causes are platform-agnostic.