# aiopsctl (command line)

> The supported command-line client over the REST API: install and authenticate, the command reference, and how to use it as a CI gate.

_Reference · Updated 2026-10-26 · Describes release 0.1.164_

`aiopsctl` authenticates with a [personal access token](/help/personal-access-tokens.md) and calls the [REST API](/help/rest-api.md), so the same scope and role rules apply.

## aiopsctl (command line) {#aiopsctl-command-line}

`aiopsctl` is a thin, supported CLI over the REST API, built for CI steps rather than daily operations. There is no screenshot on this page because there is no screen: it prints aligned tables for list commands and JSON for detail and mutation commands.

### Install and authenticate

Requires a personal access token and a role carrying the permission each command needs.

1. Install the platform package with the CLI extra. `httpx` is already a base dependency, so the extra only documents intent.

```bash
pip install .[cli]
aiopsctl --help
```

2. Export the base URL and your token.

```bash
export AIOPS_URL=https://aiops.example.com   # default: http://localhost:8787
export AIOPS_TOKEN=ntp_your_token_here
```

3. Confirm the credential works.

```bash
aiopsctl tenants
```

You should see a table of the tenants your account can see, with `ID`, `SLUG`, `NAME` and `DISABLED` columns. Every command below accepts either the id or the slug wherever a tenant is expected — it resolves the slug through `GET /api/aiops` on each invocation.

The CLI uses REST, where token scope and workspace role both apply. Use `read` with a viewer or executive role for reporting. Operational changes and back-tests require `write` plus the relevant workspace permission; credential management, and changes to members, the identity provider or an organization's workspace staffing, require `admin` scope as well.

### Command reference

| Command | What it does | Permission behind the token |
|---|---|---|
| `tenants` | table of the tenants you can see | any membership |
| `incidents <tenant>` | incident table: id, status, pillar, title, alert count, opened at | `incidents.view` |
| `incident <tenant> <incident_id>` | full JSON detail: alerts, investigations, approvals, rechecks | `incidents.view` |
| `approvals <tenant>` | pending approvals across the tenant | `incidents.view` |
| `approve <tenant> <investigation> <approval_id>` | approve one gated call | `approvals.decide` |
| `deny <tenant> <investigation> <approval_id> --reason` | deny with feedback the agent reads | `approvals.decide` |
| `datasources <tenant>` | connected instances and their last test result | `datasources.view` |
| `add-datasource <tenant> --type --name [--config K=V …] [--secret K=V …]` | connect a catalog type | `datasources.manage` |
| `benchmark <tenant> [--pillar]` | run the built-in scenario pack | `benchmark.manage` |
| `benchmark-runs <tenant>` | run history with pass rate and fingerprint | `benchmark.view` |
| `benchmark-upload <tenant> <file>` | upload a golden set (CSV or JSON) and start the back-test | `benchmark.manage` |
| `benchmark-rerun <tenant> <run_id>` | replay a prior run's exact scenario set | `benchmark.manage` |
| `benchmark-wait <tenant> <run_id> [--timeout] [--interval]` | poll until terminal; exit 2 on timeout | `benchmark.view` |
| `benchmark-compare <tenant> <run_id> [--baseline] [--min-pass] [--max-regressions]` | gate verdict against a baseline; exit 1 on `fail` | `benchmark.view` |
| `fire-alert <tenant-slug> <webhook-token> [--service] [--alertname] [--severity]` | post a test alert to the generic webhook | none — webhook token only |

`approvals` reads `GET /api/aiops/{tenant_id}/pending-approvals` in one call: every pending tool-call approval of a paused analysis, whether an alert, a schedule or a person started it. Chat, x-ray and benchmark runs are left out, and so are change approvals and risk requests — `GET /api/aiops/{tenant_id}/needs-you` lists those. Note the odd one out: `fire-alert` takes the tenant **slug** and a **webhook** token, not a personal access token, because it posts to the ingest endpoint like any alert source would.

### Use it as a CI gate

Requires `benchmark.manage` for the run and `benchmark.view` for the verdict.

1. Start the back-test from your pipeline.

```bash
RUN=$(aiopsctl benchmark-upload acme golden-set.csv | python -c 'import json,sys; print(json.load(sys.stdin)["id"])')
```

2. Wait for it. The default timeout is four hours, polled every 60 seconds, because a real model grading a few hundred cases takes that long.

```bash
aiopsctl benchmark-wait acme "$RUN" --timeout 14400 --interval 60
```

3. Compare against the baseline and let the exit code be the gate. `--baseline auto` picks the latest run over the same dataset; the defaults are an 80% floor and zero tolerated regressions.

```bash
aiopsctl benchmark-compare acme "$RUN" --min-pass 80 --max-regressions 0
```

You should see the compare verdict printed as JSON and the step exit `0` on `pass`, `1` on `fail`, or `2` if step 2 timed out. Those three exit codes are the entire contract — do not parse the table output.

## Next steps {#next-steps}

- [Personal access tokens](/help/personal-access-tokens.md) — the credential `AIOPS_TOKEN` holds.
- [REST API](/help/rest-api.md) — what each command calls.
- [Benchmarks and scores](/help/benchmarks-and-scores.md) — what the gate's verdict means.
