Installation | Authorization | Usage | Changelog
The Steadybit CLI enables you to use the Steadybit platform features easier in an automated way and implement e.g. GitOps practices easily. You can retrieve, create or adjust experiment designs as well as running them straight away.
You need a Steadybit account. You can create a free account via our website.
The CLI is a single binary for macOS, Linux and Windows, on amd64 (x86-64) and arm64. The
downloads below are those of the latest release; releases
has the earlier versions, and each release's checksums.txt lists the SHA-256 of its files.
Up to version 5, the CLI was installed with npm install -g steadybit. That package is no
longer updated; uninstall it with npm uninstall -g steadybit and install the binary instead.
Profiles in ~/.steadybit keep working.
Shell completion is available for bash, zsh, fish and PowerShell, see steadybit completion --help.
With Homebrew, which also installs the shell completions:
brew install steadybit/tap/steadybitOr download steadybit_darwin_arm64.tar.gz (Apple
silicon) or steadybit_darwin_amd64.tar.gz (Intel)
and put steadybit on your PATH.
With Homebrew, as on macOS.
On Debian, Ubuntu, Fedora or RHEL, install the package attached to every release from v6.1.0 on, which also installs the shell completions:
# Debian, Ubuntu
curl -fsSLO https://github.com/steadybit/cli/releases/latest/download/steadybit-cli_amd64.deb
sudo apt-get install ./steadybit-cli_amd64.deb
# Fedora, RHEL, Amazon Linux
curl -fsSLO https://github.com/steadybit/cli/releases/latest/download/steadybit-cli_amd64.rpm
sudo dnf install ./steadybit-cli_amd64.rpmFor arm64, use steadybit-cli_arm64.deb and steadybit-cli_arm64.rpm.
Or download steadybit_linux_amd64.tar.gz or
steadybit_linux_arm64.tar.gz and put steadybit on
your PATH:
curl -sL https://github.com/steadybit/cli/releases/latest/download/steadybit_linux_amd64.tar.gz | tar -xz steadybit
sudo mv steadybit /usr/local/bin/Download steadybit_windows_amd64.zip (x64) or
steadybit_windows_arm64.zip (Arm) and put
steadybit.exe in a folder on your PATH.
With Go installed:
go install github.com/steadybit/cli/v6/cmd/steadybit@latestThe CLI is also available as the container image steadybit/cli, and
in GitHub Actions through steadybit/cli.
At a terminal, the CLI tells you once a day when a newer release is out. Set
STEADYBIT_NO_UPDATE_CHECK=1 to turn that off; it is always off in CI.
You need an API access token. You can grab one via our platform through the Settings -> API Access Tokens page.
➜ steadybit config profile add
? Profile name: steadybit
? API access token: [hidden]
? Base URL of the Steadybit server: https://platform.steadybit.comThe platform meters API requests with a token bucket: a burst of 100 requests, refilling
by 25 every 15 seconds. The CLI paces itself to that allowance, so a command that walks a
large tenant — experiment dump above all — takes a while rather than being
rejected part way through. It warns up front when a dump covers more than 100 experiments.
Override the allowance if your deployment is configured differently:
| Variable | Default | Meaning |
|---|---|---|
STEADYBIT_RATE_LIMIT_BURST |
100 |
Requests allowed before pacing |
STEADYBIT_RATE_LIMIT_REFILL |
25 |
Requests restored each interval |
STEADYBIT_RATE_LIMIT_INTERVAL |
15 |
Length of that interval, seconds |
Get an existing experiment yaml from Steadybit and write it to file:
steadybit experiment get -k ADM-1 -f experiment.ymlOnly apply the experiment:
steadybit experiment apply -f experiment.ymlApply and run the experiment in one step:
steadybit experiment run -f experiment.ymlRun existing experiment:
steadybit experiment run -k ADM-1Dump all experiments and executions from all teams:
steadybit experiment dump -d ./dumpDump only certain teams, by team key:
steadybit experiment dump -d ./dump --team ADM WEBHOOKValidate advice status
steadybit advice validate-status -e "Global" -q "k8s.cluster-name=dev-demo and k8s.namespace=steadybit-demo"Every command shows examples with --help, e.g. steadybit schedule create --help.
Find a template and the placeholders it asks for:
steadybit template list --search kubernetes
steadybit template get -i <template-id> --placeholders -f values.ymlCreate an experiment from it, or update the one created before with the same external id:
steadybit experiment apply --template <template-id> --team ADM --environment Global \
--external-id shop-latency --placeholders values.yml -p CLUSTER=prodCreate and run it in one step:
steadybit experiment run --template <template-id> --team ADM --placeholders values.ymlsteadybit execution list --team ADM --state FAILED --from 2026-09-28
steadybit execution list --team ADM --state FAILED ERRORED --from 2026-09-28 --fail-on-match # fail a pipeline
steadybit execution get -i 1234 -t json
steadybit execution cancel -i 1234
steadybit execution property set -i 1234 -k approvedBy --value "Jane Doe"
steadybit execution artifact list -i 1234
steadybit execution artifact download -i 1234 -d ./artifactsShow the state of an experiment's latest run in a README with a status badge. The badge URL carries the tenant key, never the access token:
steadybit experiment badge -k ADM-1 # Markdown; --format html or urlsteadybit schedule create -k ADM-1 --cron "0 0 9 ? * MON-FRI" --timezone Europe/Berlin
steadybit schedule list --team ADM
steadybit schedule disable -i <schedule-id>Schedules can be kept in Git like experiments. apply writes the id of a new schedule back
into its file, so that applying it again updates it:
steadybit schedule get -i <schedule-id> -f schedule.yml
steadybit schedule apply -f ./schedules -RKeep services in Git like experiments. apply writes the id of a new service back into
its file, so that applying it again updates it:
steadybit service list --team ADM
steadybit service get -i <service-id> -f service.yml
steadybit service apply -f ./services -RGate a pipeline on the risk of a service:
steadybit service risk -i <service-id> --fail-above 50Manage the experiments and variables of a service:
steadybit service experiment list -i <service-id>
steadybit service experiment provide -i <service-id> --template <template-id> -p REPLICAS=3
steadybit service experiment link -i <service-id> -k ADM-1 --category Redundancy
steadybit service variable set -i <service-id> endpoint=http://shop.internal region=euService profiles work the same way:
steadybit service-profile list --origin custom
steadybit service-profile apply -f profile.ymlExperiment templates, environments, teams, hubs, integrations and property definitions and
associations are managed the same way, with list, get, apply and delete:
steadybit environment get -i <environment-id> -f environment.yml
steadybit team apply -f ./teams -R
steadybit integration webhook apply -f webhook.yml
steadybit template apply -f ./templates -RTheir parts have commands of their own:
steadybit environment variable set -i <environment-id> region=eu
steadybit team member add -k ADM --email jane@example.com --role OWNER
steadybit team environment add -k ADM --environment Globalsteadybit access-token create --name ci --type TEAM --team ADM --expires-at 2026-12-31
steadybit user invite --email jane@example.com --team ADM
steadybit user list --query jane
steadybit user delete --username <username>
steadybit killswitch status
steadybit audit-log --from 2026-09-01 -t json
steadybit license show
steadybit report experiments-executed --group-by STATE --rollup MONTHLYCommands that cannot be undone, such as killswitch activate, access-token delete,
user delete or team member set, ask for confirmation on a terminal; --yes skips the question.
steadybit target query -e Global --target-type com.steadybit.extension_container.container --attribute k8s.namespace
steadybit target attribute values -e Global --target-type com.steadybit.extension_container.container -k k8s.namespace
steadybit target stats -q 'k8s.namespace="shop"'
steadybit action list --kind ATTACKsteadybit experiment init # create an experiment from a template, answering its placeholders
steadybit execution watch -k ADM-1 # follow the latest run of an experiment live
steadybit experiment get -k ADM-1 --profile prod # use another configured profile for one commandShell completion (steadybit completion --help) completes experiment keys, team keys,
environment names, and the ids of templates, schedules, services and service profiles
from the platform.
Keep a team's experiments, schedules, services and custom service profiles in Git:
steadybit export --team ADM -d ./chaos # write them as files
steadybit diff -d ./chaos # what differs from the platform; exits with 2 if anything does
steadybit apply -d ./chaos --dry-run # what an apply would create or update
steadybit apply -d ./chaos # profiles, services, experiments, then schedulesKeep the tenant's configuration in Git the same way: experiment templates, environments,
teams, property definitions, hubs, integrations and custom service profiles, one directory
each (templates/, environments/, teams/, property-definitions/, hubs/,
integrations/<kind>/, service-profiles/):
steadybit export --tenant -d ./platform # needs an admin access token
steadybit diff -d ./platform
steadybit apply -d ./platform --dry-run
steadybit apply -d ./platform # definitions, environments, teams, hubs, templates, integrations, profilesWhat the platform provides is left out: the hubs it connects, the templates imported from
a hub (template import brings them back) and Steadybit's service profiles. Hubs are
synchronized as they are applied, so that the service profiles find their templates.
Credentials of integrations (secrets, header values, Slack webhook URLs) are written as
'********'. A mask stands for what the platform holds: diff does not report it, and
apply leaves out the integrations that match the platform and sends the stored header
values and URLs in place of their masks. The platform never reads a secret back, so to
change an integration that has one, put the secret in, e.g. from a CI secret, before
applying. As the platform cannot say whether that is the secret it holds, such a file is
always a difference. diff never prints credentials.
Each kind also has its own diff, and its apply a --dry-run, e.g.
steadybit experiment diff -f ./experiments -R or
steadybit integration webhook diff -f ./platform/integrations/webhook -R. Fields the
platform fills in with defaults are not reported as differences.
experiment run waits for the run and fails the job when the run fails; with --no-wait it
still watches the run until it started, for up to 15 seconds, and fails when the platform
canceled or errored it before it ran. A few options make it fit pipelines:
| Option | Does |
|---|---|
--report steadybit.xml |
A JUnit report, one test case per step; .json for JSON |
--timeout 30m |
Cancels the run and fails when it has not ended in time |
--show-steps |
Prints each step's state as it changes |
--keep-running-on-interrupt |
Leaves the run going when the job is cancelled; by default it is stopped |
--parallel 3 |
Runs up to 3 of the experiments at once; all are reported |
--expect-state FAILED |
Passes once the run reaches this state, and fails when it ends in another |
--expect-reason "…" |
Also requires the run's reason to be exactly this |
--expectation-retries 2 |
Runs the experiment again when a run did not end as expected |
--busy-retries 3 |
Waits and tries again while another experiment runs, instead of failing |
--run-again |
Starts another run when the experiment is already running |
--external-id shop-latency |
Runs the experiment with this external id, instead of -k |
In GitHub Actions a summary of every run is added to the job summary.
- uses: steadybit/cli@v6
- run: steadybit experiment run -f ./experiments -R --yes --report steadybit.xml
env:
STEADYBIT_TOKEN: ${{ secrets.STEADYBIT_TOKEN }}
- uses: mikepenz/action-junit-report@v5
if: always()
with:
report_paths: steadybit.xmlThe steadybit/run-experiment action is being deprecated in favor of this CLI, which
does what it does and more: it cancels the attack when the job is canceled, runs several
experiments at once, writes a JUnit report, and works the same in any CI. A step using
the action becomes:
# Before
- uses: steadybit/run-experiment@v1
with:
apiAccessToken: ${{ secrets.STEADYBIT_TOKEN }}
experimentKey: ADM-1
expectedState: FAILED
# After
- uses: steadybit/cli@v6
- run: steadybit experiment run -k ADM-1 --yes --busy-retries 3 --expect-state FAILED
env:
STEADYBIT_TOKEN: ${{ secrets.STEADYBIT_TOKEN }}| Action input | experiment run |
|---|---|
apiAccessToken |
the STEADYBIT_TOKEN variable |
baseURL |
the STEADYBIT_URL variable, for an on-premise platform |
experimentKey |
-k ADM-1 |
externalId |
--external-id shop-latency |
expectedState |
--expect-state FAILED |
expectedReason, expectedFailureReason |
--expect-reason "..." |
parallel: true |
--allowParallel |
maxRetries (3 by default) |
--busy-retries 3; the CLI does not retry unless asked |
maxRetriesOnExpectationFailure |
--expectation-retries 2 |
delayBetweenRetriesOnExpectationFailure |
--expectation-retry-interval 1m (a duration, not ms) |
maxRetriesOnValidationFailure |
--retries 2 |
delayBetweenRetriesOnValidationFailure |
--retryInterval 15 (seconds) |
The action's outputs are in the JSON report: --report run.json writes each run's id,
state, reason and apiLocation (the action's executionUrl).
- id: chaos
run: |
steadybit experiment run -k ADM-1 --yes --report run.json
echo "state=$(jq -r '.[0].state' run.json)" >> "$GITHUB_OUTPUT"chaos:
image:
name: steadybit/cli:6
entrypoint: ['']
script:
- steadybit experiment run -f ./experiments -R --yes --report steadybit.xml
artifacts:
when: always
reports:
junit: steadybit.xmlEvery listing prints the platform's items with -t json or -t yaml, and --jq filters
whatever JSON a command prints, without jq installed:
steadybit service list --team ADM --jq '.[] | "\(.id) \(.name)"'You can also use the cli via our container image. -e STEADYBIT_TOKEN passes the token
from your environment, so it stays out of the command and your shell history:
docker run --rm -e STEADYBIT_TOKEN steadybit/cli:6 experiment get -k ADM-1