Building Your Own Integration
The same surfaces the bundled skills use are there for your own scripts, bots and agents. No SDK, no separate API client: the CLI is the integration point, and everything it does is scriptable.
JSON everywhere
atlas projects --json
atlas capacity --json
atlas results SHOP-20260917-101500 --jsonEvery command takes --json. On failure it prints the error as JSON on standard error, so standard out stays parseable:
{"error":{"message":"Project 'SHOPP' not found","code":"not_found"}}Exit codes are the contract, and they do not change with --json:
| Code | Meaning |
|---|---|
0 | Success, and any thresholds passed |
1 | A --gate threshold was breached — the test ran, the numbers failed |
2 | A usage or authentication problem: bad flags, unknown project, not signed in |
3 | The run failed or timed out, or Atlas could not be reached |
1 and 3 are deliberately distinct: a breached threshold is a result, an unreachable server is not.
Discovering the surface
Rather than hard-coding flags, read them:
atlas schema --jsonThis returns every command, argument and option, with its description. Two fields worth knowing: takesValue says whether the flag expects a value, and valueOptional whether that value may be omitted. Neither means the flag itself is mandatory.
Documentation, offline
atlas docs # list the topics
atlas docs troubleshooting # print oneThe documentation is bundled inside the package, so it works with no network — in CI, in a container, in a sandboxed agent.
Checking a plan without running it
atlas plan check ./checkout.jmx -p SHOP --jsonRead-only and advisory: it never rewrites your plan. Useful as a pre-commit hook or a pipeline step, because it exits non-zero when the plan would produce no usable results.
Driving the recorder from code
The recorder can be controlled step by step, which is what lets an agent click through a flow. It is also a perfectly good scripting interface:
atlas-rec start https://shop.example.com -o flow.jmx -n "Checkout"
atlas-rec snapshot # the page, as an accessibility tree
atlas-rec tx new "Search" # name the step that follows
atlas-rec click --role button --name "Search"
atlas-rec fill "laptop" --selector "#q"
atlas-rec wait --selector ".results"
atlas-rec state --full # everything captured so far
atlas-rec stop # writes the plan and the captureThe window stays visible and a person can click in the same session — the two mix freely, so a script can pause for a human to sign in and then carry on.
The control channel is local to your machine: it listens on the loopback interface, on an ephemeral port, and requires a per-session token that is kept out of the process list. It only accepts commands while a recording you started is open.
Afterwards, a capture can be re-read and rebuilt without recording again:
atlas-rec inspect flow.capture.json # transactions, hosts, response codes
atlas-rec suggest flow.capture.json # per-session values, with evidence
atlas-rec generate flow.capture.json -o flow.jmx --correlations rules.jsonThe same capture always produces the same plan, so regenerating is safe to repeat and easy to review.
Authentication for automation
Use an API token, never a password:
export ATLAS_TOKEN=atlas_pat_...
export ATLAS_URL=https://atlas.cloudbeat.io
export ATLAS_PROJECT=SHOP
atlas run --servers 4 --gate "error_rate<1,p95<800" --junit results.xmlA token acts as its creating user, in one account. Revoking it takes effect immediately, and a token cannot mint further tokens or change a password — so a leaked CI credential cannot entrench itself. See Signing In.
A worked example
Everything together — gate a deployment on a load test:
#!/usr/bin/env bash
set -euo pipefail
# Refuse to run a plan that could not report
atlas plan check -p SHOP --jmx checkout.jmx --json >/dev/null
# `|| rc=$?` keeps `set -e` from aborting on a breached threshold, which is a
# result we want to act on rather than a crash
rc=0
atlas run -p SHOP --jmx checkout.jmx --servers 4 \
--args "-Jthreads=125 -Jrampup=300" \
--gate "error_rate<1,p95<800" \
--junit results.xml --json > run.json || rc=$?
case $rc in
0) echo "passed: $(jq -r .testId run.json)" ;;
1) echo "thresholds breached"; jq '.gates[] | select(.passed | not)' run.json; exit 1 ;;
*) echo "the test did not run (exit $rc)"; exit "$rc" ;;
esacWith --wait — which --gate and --junit imply — the JSON on standard out carries testId, state, durationSec, the overall figures and every gate result. It is written before a breached threshold sets the exit code, so run.json is complete either way.
Running in CI has the pipeline-ready version, including GitHub Actions.