# Query project data from the CLI

Source: https://docs.qualflare.com/docs/cli/read-commands · Last updated: 2026-10-27

List and get suites, cases, steps, test plans, launches, defects, failure clusters and milestones with the Qualflare CLI, as JSON you can filter with jq.

This page lists every read command of the Qualflare CLI with its flags and defaults: `qf <identifier> <resource> list` prints one page of 10 to 20 suites, test plans, launches, defects, failure clusters or milestones as JSON, and `get` prints one record by its number. `cases list` returns all of one suite's cases at once. The examples use the identifier `myapp`; replace it with the one you saved with `qf login`.

| Resource                                                                               | List command               | Get commands                         | Page size   | MCP tools                                                  |
| -------------------------------------------------------------------------------------- | -------------------------- | ------------------------------------ | ----------- | ---------------------------------------------------------- |
| [Suites](https://docs.qualflare.com/docs/cli/read-commands#suites)             | `suites list`              | `suite get <seq>`                    | 20          | `list_test_suites`, `get_test_suite`                       |
| [Cases and steps](https://docs.qualflare.com/docs/cli/read-commands#cases)     | `cases list --suite <seq>` | `case get <seq>`, `case steps <seq>` | whole suite | `list_suite_cases`, `get_test_case`, `list_case_steps`     |
| [Test plans](https://docs.qualflare.com/docs/cli/read-commands#plans)          | `plans list`               | `plan get <seq>`, `plan cases <seq>` | 10          | `list_test_plans`, `get_test_plan`, `list_test_plan_cases` |
| [Launches](https://docs.qualflare.com/docs/cli/read-commands#launches)         | `launches list`            | `launch get <seq>`                   | 10          | `list_launches`, `get_launch`                              |
| [Defects](https://docs.qualflare.com/docs/cli/read-commands#defects)           | `defects list`             | `defect get <seq>`                   | 14          | `list_defects`, `get_defect`                               |
| [Failure clusters](https://docs.qualflare.com/docs/cli/read-commands#clusters) | `clusters list`            | `cluster get <id>`                   | 10          | `list_failure_clusters`, `get_failure_cluster`             |
| [Milestones](https://docs.qualflare.com/docs/cli/read-commands#milestones)     | `milestones list`          | `milestone get <seq>`                | 10          | `list_milestones`, `get_milestone`                         |

## How the read commands work

The Qualflare CLI read commands use the access token saved with [qf login](https://docs.qualflare.com/docs/cli/authentication). A token can read without **Allow writes**, which is needed only to change data ([Access Tokens](https://docs.qualflare.com/docs/api/access-tokens)). Each command prints pretty-printed JSON on stdout and its messages on stderr, so you can pipe stdout into `jq`. Coding agents read the same data through the [MCP read tools](https://docs.qualflare.com/docs/api/mcp-reference).

### Pages and sorting

Each paginated `list` returns `{items, paging}`. `--page` takes 1 to 1,000 and defaults to 1. `--sort-by` takes the fields each resource lists below, `--sort-desc` sorts in descending order and `--sort-desc=false` in ascending order. `qf` sends the direction only when you pass the flag, so each list keeps its own default order: launches and defects come back newest first, and in ascending order with `--sort-by` alone; clusters come back most failures first.

```bash
qf myapp suites list --page 2 --sort-by name
qf myapp suites list | jq '.paging'
```

The second command prints:

```text
{
  "page": 1,
  "pages": 3,
  "perPage": 20,
  "totalItems": 45
}
```

### Find a record's number

`get` takes the number Qualflare shows on the record, which is the `seq` of each list item. A failure cluster takes its `id` instead, which is also the end of the cluster's page URL.

*Figure: The number Qualflare shows on a suite, case, test plan, launch, defect or milestone is the seq you pass to get. A failure cluster uses the ID in its URL.*

## Test suites

Test suites group test cases by feature or area. You see them under **Browse**, and `qf <identifier> suites list` lists 20 per page. See [Test suites and Browse](https://docs.qualflare.com/docs/test-management/test-suites).

### `suites list`

| Flag          | Type   | Default | Description                                                                                                       |
| ------------- | ------ | ------- | ----------------------------------------------------------------------------------------------------------------- |
| `--query`     | string | `""`    | Filter suites by name or description                                                                              |
| `--page`      | int    | `1`     | Page to return, starting at `1`                                                                                   |
| `--sort-by`   | string | `""`    | Field to sort by: `seq`, `name`, `priority`, `caseCount`, `teamName`, `coverageScore`, `createdAt` or `updatedAt` |
| `--sort-desc` | bool   | `false` | Sort in descending order                                                                                          |

```bash
qf myapp suites list --query "authentication"
qf myapp suites list --sort-by createdAt --sort-desc
qf myapp suites list | jq '.items[0] | {seq, name, priority, caseCount, coverageScore}'
```

The last command prints:

```text
{
  "seq": 42,
  "name": "Authentication Tests",
  "priority": "high",
  "caseCount": 18,
  "coverageScore": 82
}
```

Each suite has `seq`, `name`, `description`, `priority`, `automation`, `testType`, `coverageScore`, `caseCount`, `teamSeq`, `teamName`, `isArchived`, `createdAt` and `updatedAt`.

### `suite get`

`qf myapp suite get 42` prints one suite, with the same fields as a list item.

## Test cases and steps

Test cases belong to a suite, which you open under **Browse**, and hold ordered steps. `cases list --suite <seq>` returns the whole suite with a `total` count, so it has no `--page` flag. See [Test cases: fields, states and steps](https://docs.qualflare.com/docs/test-management/test-cases).

### `cases list`

| Flag          | Type   | Default | Description                                                                                                                                                                                                                                |
| ------------- | ------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `--suite`     | int    | —       | **Required.** Suite sequence number to list cases from                                                                                                                                                                                     |
| `--query`     | string | `""`    | Filter cases by name (case-insensitive, partial match)                                                                                                                                                                                     |
| `--state`     | string | `""`    | Filter by one or more lifecycle states, comma-separated: `active`, `review`, `outdated`, `draft`. Pass and fail results belong to launches, not cases; see [launches](https://docs.qualflare.com/docs/cli/read-commands#launches). |
| `--priority`  | string | `""`    | Filter by one or more priorities, comma-separated: `low`, `medium`, `high`, `critical`                                                                                                                                                     |
| `--sort-by`   | string | `""`    | Field to sort by: `seq`, `name`, `createdAt`, `updatedAt`, `flakyScore` or `position` (the order in the suite)                                                                                                                             |
| `--sort-desc` | bool   | `false` | Sort in descending order                                                                                                                                                                                                                   |

```bash
qf myapp cases list --suite 5 --state draft,review
qf myapp cases list --suite 5 --priority high,critical --sort-by flakyScore --sort-desc
qf myapp cases list --suite 5 | jq '{total, first: .items[0] | {seq, name, state, priority}}'
```

The last command prints:

```text
{
  "total": 18,
  "first": {
    "seq": 101,
    "name": "User can log in with valid credentials",
    "state": "active",
    "priority": "critical"
  }
}
```

Each case has `seq`, `position`, `uid`, `name`, `description`, `state`, `priority`, `testType`, `automation`, `isFavorite`, `isFlaky`, `flakyScore`, `mark`, `isArchived`, `suiteSeq`, `suiteName`, `createdAt` and `updatedAt`. In `cases list`, `suiteName` is always empty; `case get` and `plan cases` fill it in.

### `case get`

`qf myapp case get 101` prints one case with the same fields, with `suiteName` filled in.

### `case steps`

`qf myapp case steps 101` prints the case's steps as an array, in order. Each step has `id`, `instruction`, `stepType`, `position`, `origin`, `createdAt` and `updatedAt`. Expected results are steps of their own, with `stepType` `expected_result`, and a step that comes from a shared step also carries a `sharedStep` object.

```bash
qf myapp case steps 101 | jq -r '.[] | "\(.position) \(.stepType) \(.instruction)"'
```

```text
1 action Open the login page
2 expected_result The login form is displayed
```

## Test plans

A test plan lists the cases to run for a release or testing cycle. You see test plans under **Test Plans**, and `plans list` shows 10 per page. See [Test Plans](https://docs.qualflare.com/docs/test-management/test-plans).

### `plans list`

| Flag          | Type   | Default | Description                                            |
| ------------- | ------ | ------- | ------------------------------------------------------ |
| `--query`     | string | `""`    | Filter plans by name (case-insensitive, partial match) |
| `--page`      | int    | `1`     | Page to return, starting at `1`                        |
| `--sort-by`   | string | `""`    | Field to sort by: `seq`, `name` or `description`       |
| `--sort-desc` | bool   | `false` | Sort in descending order                               |

```bash
qf myapp plans list --query "regression"
qf myapp plans list --sort-by seq --sort-desc
```

Each plan has `seq`, `name`, `description`, `createdAt` and `updatedAt`.

### `plan get`

`plan get` adds `caseSeq` and `querySeq`. `caseSeq` lists the cases added to the plan, and `querySeq` the saved queries attached on its **Dynamic Queries** tab. `plan cases` returns the cases in `caseSeq`. Saved queries add no cases today; see [Test Plans](https://docs.qualflare.com/docs/test-management/test-plans).

```bash
qf myapp plan get 5 | jq -c '{seq, name, caseSeq, querySeq}'
```

```text
{"seq":5,"name":"v2.4 Regression Suite","caseSeq":[101,102,115],"querySeq":[2]}
```

### `plan cases`

`qf myapp plan cases 5` prints an array of the plan's cases, with the fields of [`cases list`](https://docs.qualflare.com/docs/cli/read-commands#cases-list), except that `isFlaky` is always `false` and `flakyScore` always `0` here; read them with `case get`. `state` is the case's lifecycle state (`active`, `review`, `outdated` or `draft`), not a run result. To see how a plan's runs went, look at its [launches](https://docs.qualflare.com/docs/cli/read-commands#launches): a launch run from a plan carries its `testPlanSeq`.

## Launches

A launch is one test run. Each `qf <identifier> collect` creates one, sharded files merge into one, and manual runs and test plan runs are launches too. You see them under **Launches**, and `launches list` shows the newest first, 10 per page. See [Launches](https://docs.qualflare.com/docs/runs/launches).

### `launches list`

| Flag            | Type   | Default | Description                                                                                                                             |
| --------------- | ------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `--milestone`   | int    | `0`     | Filter by milestone sequence number                                                                                                     |
| `--environment` | string | `""`    | Filter by environment Identifier (e.g., `production`, `staging`); see [Environments](https://docs.qualflare.com/docs/runs/environments) |
| `--page`        | int    | `1`     | Page to return, starting at `1`                                                                                                         |
| `--sort-by`     | string | `""`    | Field to sort by: `seq`, `branch`, `platform`, `os`, `milestone`, `environment`, `language`, `browser`, `createdAt` or `updatedAt`      |
| `--sort-desc`   | bool   | `false` | Sort in descending order                                                                                                                |

With no sort flags, launches come back newest first. With `--sort-by` and no `--sort-desc`, they come back in ascending order.

```bash
qf myapp launches list --milestone 3 --environment staging
qf myapp launches list --sort-by createdAt
qf myapp launches list | jq '.items[0] | {seq, status, branch, totalCount, passedCount, failedCount}'
```

The last command prints:

```text
{
  "seq": 88,
  "status": "failed",
  "branch": "main",
  "totalCount": 111,
  "passedCount": 104,
  "failedCount": 2
}
```

Each launch has `seq`, `framework`, `platform`, `os`, `branch`, `commit`, `status`, `automation`, `totalCount`, `passedCount`, `failedCount`, `errorCount`, `skippedCount`, `timeoutCount`, `abortedCount`, `flakyCount`, `retryCount`, `properties`, `environmentId`, `environmentName` (the environment's display name), `languageName`, `languageUid`, `milestoneSeq`, `milestoneName`, `browser`, `metadata`, `aiSummary`, `aiSummaryStatus`, `createdAt` and `updatedAt`. A launch run from a test plan also has `testPlanSeq`.

### `launch get`

`qf myapp launch get 88` prints one launch, with the same fields as a list item.

## Defects

Defects track the bugs found in testing. You see them under **Defects**, and `defects list` shows the newest first, 14 per page. See [Defects](https://docs.qualflare.com/docs/defects).

### `defects list`

| Flag          | Type         | Default | Description                                                                                                           |
| ------------- | ------------ | ------- | --------------------------------------------------------------------------------------------------------------------- |
| `--severity`  | string slice | —       | Filter by severity. Accepts comma-separated values: `critical`, `high`, `medium`, `low`                               |
| `--status`    | string slice | —       | Filter by status. Accepts comma-separated values: `active`, `action_required`, `false_positive`, `closed`, `reopened` |
| `--page`      | int          | `1`     | Page to return, starting at `1`                                                                                       |
| `--sort-by`   | string       | —       | Field to sort by: `seq`, `name`, `severity`, `status`, `category`, `environment`, `createdAt` or `updatedAt`          |
| `--sort-desc` | bool         | `false` | Sort results in descending order                                                                                      |

```bash
qf myapp defects list --severity critical,high --status active
qf myapp defects list | jq '.items[0] | {seq, name, severity, status, category}'
```

The last command prints:

```text
{
  "seq": 7,
  "name": "Login form fails with special characters",
  "severity": "high",
  "status": "active",
  "category": "assertion_failure"
}
```

Each defect has `seq`, `name`, `severity`, `status`, `category`, `rootCauses`, `automation`, `isClosed`, `description`, `expected`, `actual`, `teamSeq`, `teamName`, `environmentId`, `environmentName`, `clusterId`, `clusterLabel`, `clusterStatus`, `clusterSeverity`, `closedAt`, `reopenedAt`, `reopenedReason`, `createdAt` and `updatedAt`.

### `defect get`

`qf myapp defect get 7` prints one defect, with the same fields as a list item.

## Failure clusters

A failure cluster groups failed results that share a root cause. You see them under **Failure Clusters**, and `clusters list` shows 10 per page, most failures first. See [Failure Clusters](https://docs.qualflare.com/docs/ai/failure-clusters).

### `clusters list`

| Flag          | Type         | Default | Description                                                                                        |
| ------------- | ------------ | ------- | -------------------------------------------------------------------------------------------------- |
| `--severity`  | string slice | —       | Filter by severity. Accepts comma-separated values: `critical`, `high`, `medium`, `low`            |
| `--page`      | int          | `1`     | Page to return, starting at `1`                                                                    |
| `--sort-by`   | string       | —       | Field to sort by: `failureCount` (the default), `firstSeenAt`, `lastSeenAt`, `severity` or `label` |
| `--sort-desc` | bool         | —       | Results are descending unless you pass `--sort-desc=false` for ascending order                     |

Clusters come back in descending order, by `failureCount` unless you pass `--sort-by`, and `--sort-by` alone keeps the descending order.

```bash
qf myapp clusters list --severity critical
qf myapp clusters list --sort-by lastSeenAt
qf myapp clusters list | jq '.items[0] | {id, label, failureCount, severity, status}'
```

The last command prints:

```text
{
  "id": 15,
  "label": "NullPointerException in PaymentService.processRefund",
  "failureCount": 38,
  "severity": "critical",
  "status": "analysed"
}
```

Each cluster has `id`, `label`, `summary`, `failureCount`, `severity`, `status`, `firstSeenAt`, `lastSeenAt`, `rootCause`, `fixSuggestion`, `createdAt` and `updatedAt`.

### `cluster get`

`cluster get` takes the cluster's `id`, not a `seq`, for example `qf myapp cluster get 15`. It adds `sampleFailures`, example failures with `caseRunId`, `caseName`, `suiteName`, `errorText`, `similarity`, `launchSeq`, `caseRunSeq` and `suiteRunSeq`. `sampleFailures` can be missing from `clusters list` items, so read it with `cluster get`.

## Milestones

A milestone is a release or sprint target that launches link to. You see milestones under **Milestones**, and `milestones list` shows 10 per page. See [Milestones](https://docs.qualflare.com/docs/test-management/milestones).

### `milestones list`

| Flag          | Type   | Default | Description                                                           |
| ------------- | ------ | ------- | --------------------------------------------------------------------- |
| `--query`     | string | —       | Filter milestones by name (case-insensitive, partial match)           |
| `--page`      | int    | `1`     | Page to return, starting at `1`                                       |
| `--sort-by`   | string | —       | Field to sort by: `seq`, `name`, `duesAt`, `createdAt` or `updatedAt` |
| `--sort-desc` | bool   | `false` | Sort results in descending order                                      |

```bash
qf myapp milestones list --query "release" --sort-by duesAt
qf myapp milestones list | jq '.items[0] | {seq, name, kind, isCompleted, duesAt}'
```

The last command prints:

```text
{
  "seq": 3,
  "name": "v2.0 Release",
  "kind": "release",
  "isCompleted": false,
  "duesAt": "2026-04-30T00:00:00Z"
}
```

Each milestone has `seq`, `name`, `description`, `kind`, `isCompleted`, `totalCount`, `passedCount`, `failedCount`, `errorCount`, `skippedCount`, `timeoutCount`, `abortedCount`, `assignees`, `duesAt`, `completedAt`, `createdAt` and `updatedAt`. `kind` is one of `cycle`, `feature`, `iteration`, `plan`, `release`, `sprint` or `version`. `completedAt` always holds a timestamp, even for an open milestone (it starts as the creation time), so check `isCompleted` to see whether a milestone is done.

### `milestone get`

`milestone get` adds `launchCount` and `runCount`. List a milestone's launches with `qf myapp launches list --milestone 3` ([launches list](https://docs.qualflare.com/docs/cli/read-commands#launches-list)).

## Filter the output with jq

Every read command prints JSON, so `jq` can filter it, fail a CI job on it or loop over its pages:

```bash
# Fail a CI job while critical defects are open (jq -e exits 1 on false)
qf myapp defects list --severity critical --status active,action_required | jq -e '.paging.totalItems == 0'
# The status of the newest launch
qf myapp launches list | jq -r '.items[0].status'
# The pass rate of each launch on the page (null for a launch with no tests)
qf myapp launches list | jq '.items[] | {seq, passRate: (if .totalCount > 0 then (.passedCount / .totalCount * 100 | round) else null end)}'
# The flaky cases in a suite
qf myapp cases list --suite 5 | jq '[.items[] | select(.isFlaky) | {seq, name, flakyScore}]'
# A plan's cases by lifecycle state
qf myapp plan cases 5 | jq 'group_by(.state) | map({state: .[0].state, count: length})'
# The launches on the page that ran plan 5
qf myapp launches list | jq '[.items[] | select(.testPlanSeq == 5)]'
# The clusters with the most failures
qf myapp clusters list | jq '.items[] | {id, label, failureCount}'
# The milestones due after a date
qf myapp milestones list | jq '.items[] | select(.duesAt > "2026-04-01T00:00:00Z") | {seq, name, duesAt}'
# Every suite across all pages
pages=$(qf myapp suites list | jq '.paging.pages')
for p in $(seq 1 "$pages"); do qf myapp suites list --page "$p" | jq -c '.items[] | {seq, name}'; done
```

## Errors

A read command that fails prints one `Error:` line on stderr and exits with a code your script can check:

| What you see                                                                                                                                             | Why                                                                                                            | Exit code |
| -------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | --------- |
| `Error: no identifier "myapp" configured. Run 'qf login myapp <token>' to add it. (See 'qf projects' for the list.)`                                     | No identifier of that name is saved on this machine                                                            | `1`       |
| `Error: --suite flag is required`                                                                                                                        | `cases list` ran without `--suite`                                                                             | `1`       |
| ``Error: get: <message> (status: 401) — run `qf login <identifier> <token>` to re-authenticate``                                                         | The token is expired, revoked or wrong; see [Access Tokens](https://docs.qualflare.com/docs/api/access-tokens) | `3`       |
| `Error: get: … (status: 403) — the token lacks access to this project`, or `(status: 402) — a plan limit was reached; check your Qualflare subscription` | The token can't read this project (403), or a plan limit was reached (402)                                     | `4`       |
| `Error: get: … (status: 404)`                                                                                                                            | No record with that number (or cluster ID) in the project                                                      | `5`       |
| `Error: get: … (status: 400)`                                                                                                                            | A filter value the API rejects, or a `--page` above 1,000                                                      | `1`       |
| `Error: get: … (status: 429)`, or a 5xx status                                                                                                           | The API is busy or failed; safe to retry                                                                       | `7`       |

Quote the `[request_id: …]` at the end of an API error when you [contact support](https://docs.qualflare.com/docs/faq/getting-help). `--verbose` prints the request line on stderr, and `--debug` logs the whole HTTP exchange with the token redacted.

## Limits

These are flag value limits, not rate limits:

* `--page` takes 1 to 1,000, and `--query` up to 255 characters.
* `--state`, `--priority`, `--severity` and `--status` take only the values in the flags tables.
* Each command waits up to 120 seconds for the API, set by [`QF_TIMEOUT`](https://docs.qualflare.com/docs/cli/configuration#retry--timeout).

## Related

* **Guides:** [Test suites and Browse](https://docs.qualflare.com/docs/test-management/test-suites) · [Test Plans](https://docs.qualflare.com/docs/test-management/test-plans) · [Launches](https://docs.qualflare.com/docs/runs/launches) · [Defects](https://docs.qualflare.com/docs/defects) · [Failure Clusters](https://docs.qualflare.com/docs/ai/failure-clusters) · [Milestones](https://docs.qualflare.com/docs/test-management/milestones)
* **Reference:** [Test cases: fields, states and steps](https://docs.qualflare.com/docs/test-management/test-cases) · [Glossary](https://docs.qualflare.com/docs/reference/glossary)
* **CLI/API:** [qf command reference](https://docs.qualflare.com/docs/cli/commands) · [Upload results with qf collect](https://docs.qualflare.com/docs/cli/collect) · [Configuration](https://docs.qualflare.com/docs/cli/configuration) · [MCP server reference](https://docs.qualflare.com/docs/api/mcp-reference)
