████████╗██████╗ █████╗ ███████╗███████╗██╗ ██████╗
╚══██╔══╝██╔══██╗██╔══██╗██╔════╝██╔════╝██║██╔════╝
██║ ██████╔╝███████║█████╗ █████╗ ██║██║
██║ ██╔══██╗██╔══██║██╔══╝ ██╔══╝ ██║██║
██║ ██║ ██║██║ ██║██║ ██║ ██║╚██████╗
╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═════╝
tm is a single static-binary CLI for the TrafficMorph /api/v1
API. Designed for CI integration: trigger a run, wait for the
regression verdict, and gate the build on the result.
tm <command> [flags]
curl -sSL https://raw.githubusercontent.com/trafficmorph-gif/tm-cli/main/install.sh | shDetects your OS + architecture, downloads the matching binary from
GitHub Releases, verifies its SHA-256, and installs to
~/.local/bin/tm. Linux amd64/arm64 + macOS amd64/arm64 supported.
Pin a version (recommended for CI):
curl -sSL https://raw.githubusercontent.com/trafficmorph-gif/tm-cli/main/install.sh \
| TM_VERSION=v0.2.0 shOverride the install dir (e.g. inside Docker):
curl -sSL https://raw.githubusercontent.com/trafficmorph-gif/tm-cli/main/install.sh \
| TM_INSTALL_DIR=/usr/local/bin sh- uses: trafficmorph-gif/tm-cli/cli/action@v0.2.0
with:
api-key: ${{ secrets.TRAFFICMORPH_API_KEY }}
base-url: https://app.your-trafficmorph-host.com
- run: tm runs start 42 --wait --fail-on-verdict FAIL,WARNSee action/README.md for inputs and the
composite-action design.
Grab the right tarball from
the releases page,
extract, and move tm somewhere on your PATH. Use this when you
can't run the install script (corporate proxies, etc.).
git clone https://github.com/trafficmorph-gif/tm-cli.git
cd tm-cli
make build # → bin/tm
sudo cp bin/tm /usr/local/bin/$ tm version
tm v0.2.0 (spec v1)- A TrafficMorph API key in the form
tm_…. Provision one from the in-app Settings → API keys page. - A reachable TrafficMorph install. Examples below assume
http://localhost:8080for local development; swap for your hosted URL. There is no built-in default — the CLI requires the base URL to be set explicitly.
Commands that talk to the server — tm profiles list|get,
tm runs start|stop|pause|resume, tm history get — require both
an API key and a base URL. Offline / local commands (tm version,
tm help …, tm completion …, any --help flow, plus the bare
parent groups like tm profiles) work without configuration, so
first-run setup like tm completion bash >> ~/.bashrc succeeds
before you've provisioned a key.
Set both values:
export TM_API_KEY=tm_xxxxxxxxxxxxxxxx
export TM_BASE_URL=https://app.your-trafficmorph-host.com…or pass them per invocation with --api-key / --base-url.
Malformed inputs (missing scheme, wrong scheme, query strings, fragments in the base URL; control bytes in the API key) are rejected at startup rather than failing late on the first call.
tm runs start 42 --wait --fail-on-verdict FAIL,WARNStarts a run for profile 42, polls until it finishes, fetches the auto-comparison verdict, and exits with a verdict-specific code so your CI script can branch:
| Exit code | Meaning |
|---|---|
| 0 | Verdict was PASS, or not in --fail-on-verdict set |
| 1 | HTTP / network / configuration error |
| 2 | FAIL — one or more checks crossed the failure threshold |
| 3 | WARN — one or more checks crossed the warn threshold |
| 4 | NO_BASELINE — no baseline run designated for the profile |
$ tm profiles list
ID NAME CREATED
42 smoke-test-api 2026-04-12T09:14:01Z
43 load-test-checkout 2026-04-14T17:22:55Z
JSON for scripting:
tm profiles list --json | jq -r '.[] | "\(.id) \(.name)"'tm history get 1234 > run-1234.jsonReturns the full metric set: response-code distribution, latency quantiles, RPS / latency time series, secondary stats from response scripts, the auto-comparison snapshot, and verdict reasoning.
tm runs start 42 # one-shot start, don't wait
tm runs stop 42 # idempotent — succeeds even if no run is in flight
tm runs pause 42 # idempotent
tm runs resume 42 # 400 if no paused run to resume| Source | Precedence |
|---|---|
| Command-line flags | Highest |
Environment variables (TM_*) |
Middle |
| Flag | Env var | Default | Notes |
|---|---|---|---|
--api-key |
TM_API_KEY |
(required) | Full tm_… value. Rejected at startup if it contains control bytes (CR/LF/NUL/DEL). |
--base-url |
TM_BASE_URL |
(required) | URL of your TrafficMorph install. Rejected at startup if it's missing the scheme, wrong scheme, has a query string, or has a fragment. Path-prefixed deployments behind reverse proxies keep their prefix during URL resolution. |
--timeout |
— | 30s |
Per-HTTP-call timeout. |
--json |
— | false |
Emit machine-readable JSON. |
Apache 2.0 — see LICENSE.