Query project data from the CLI
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.
Last updated
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 | suites list | suite get <seq> | 20 | list_test_suites, get_test_suite |
| Cases and steps | cases list --suite <seq> | case get <seq>, case steps <seq> | whole suite | list_suite_cases, get_test_case, list_case_steps |
| Test plans | plans list | plan get <seq>, plan cases <seq> | 10 | list_test_plans, get_test_plan, list_test_plan_cases |
| Launches | launches list | launch get <seq> | 10 | list_launches, get_launch |
| Defects | defects list | defect get <seq> | 14 | list_defects, get_defect |
| Failure clusters | clusters list | cluster get <id> | 10 | list_failure_clusters, get_failure_cluster |
| 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. A token can read without Allow writes, which is needed only to change data (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.
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.
qf myapp suites list --page 2 --sort-by name
qf myapp suites list | jq '.paging'The second command prints:
{
"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.
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.
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 |
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:
{
"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.
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. |
--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 |
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:
{
"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.
qf myapp case steps 101 | jq -r '.[] | "\(.position) \(.stepType) \(.instruction)"'1 action Open the login page
2 expected_result The login form is displayedTest 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.
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 |
qf myapp plans list --query "regression"
qf myapp plans list --sort-by seq --sort-descEach 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.
qf myapp plan get 5 | jq -c '{seq, name, caseSeq, querySeq}'{"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, 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: 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.
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 |
--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.
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:
{
"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.
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 |
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:
{
"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.
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.
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:
{
"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.
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 |
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:
{
"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).
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:
# 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}'; doneErrors
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 | 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. --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:
--pagetakes 1 to 1,000, and--queryup to 255 characters.--state,--priority,--severityand--statustake only the values in the flags tables.- Each command waits up to 120 seconds for the API, set by
QF_TIMEOUT.
Related
- Guides: Test suites and Browse · Test Plans · Launches · Defects · Failure Clusters · Milestones
- Reference: Test cases: fields, states and steps · Glossary
- CLI/API: qf command reference · Upload results with qf collect · Configuration · MCP server reference
qf command reference
Every qf command in the Qualflare CLI, with flags, output and exit codes: validate result files without a token, list the formats and print the version.
Troubleshoot qf and CI uploads
Fix Qualflare CLI and CI upload errors: what each qf exit code means, the exact messages for tokens, environments, formats and timeouts, and how to fix them.