# Claude Code plugin reference

Source: https://docs.qualflare.com/docs/ai/claude-code-reference · Last updated: 2026-10-27

Reference for the Qualflare plugin for Claude Code: every /qf- command, the coverage nudge rules, state files, authentication and the formats it knows.

This page lists the 8 slash commands of the Qualflare plugin for Claude Code, the rules of its coverage nudge, its state files and the format slugs it knows, with arguments, defaults and limits.

## Installation

| Command                                                   | Description                                            |
| --------------------------------------------------------- | ------------------------------------------------------ |
| `/plugin marketplace add Qualflare/qualflare-claude-code` | Add the Qualflare marketplace                          |
| `/plugin install qualflare@qualflare`                     | Install the plugin. It stays installed across sessions |
| `/plugin update qualflare`                                | Upgrade to the latest version                          |

The plugin is `qualflare`, from the marketplace `qualflare`. It needs `qf` on your PATH, and Node.js for the coverage nudge.

## Slash commands

| Command      | Argument                                                        | What it does                          |
| ------------ | --------------------------------------------------------------- | ------------------------------------- |
| `/qf-init`   | —                                                               | Sets up the project                   |
| `/qf-cover`  | `[--all] [path or glob]`                                        | Writes tests for changed code         |
| `/qf-run`    | `[framework-slug \| package/path [slug] \| report-path [slug]]` | Runs tests and uploads the results    |
| `/qf-fix`    | `[framework-slug or package/path]`                              | Fixes failing tests from the last run |
| `/qf-doctor` | —                                                               | Checks the setup                      |
| `/qf-update` | `[framework-slug or package/path]`                              | Refreshes file counts                 |
| `/qf-state`  | —                                                               | Shows what the plugin knows           |
| `/qf-hook`   | `on\|off`                                                       | Turns the coverage nudge on or off    |

### `/qf-init`

`/qf-init` sets up a project once, from its root (a folder with `.git/`, `package.json`, `go.mod` or another manifest). In order, it:

1. finds a monorepo's packages (npm or pnpm workspaces, or several `go.mod` or `pyproject.toml` files);
2. detects each package's languages, frameworks and test-file counts, and asks you to confirm them;
3. writes `.qualflare/test-state.md`;
4. prints a `qf login <identifier>` line per identifier not logged in, and waits for `done` or `skip`;
5. asks about the coverage nudge and writes `.qualflare/config.json`;
6. writes a Qualflare block between `<!-- BEGIN qualflare-ai -->` and `<!-- END qualflare-ai -->` in `CLAUDE.md`, changing nothing outside it.

An identifier is the package name lowercased, with characters outside `[a-z0-9_-]` turned into `-`, runs of `-` collapsed and the ends trimmed. `pkg-` is prefixed when the result is empty, starts with anything but a letter or digit, or is a `qf` command name such as `login` or `help`, and the identifier is cut to 63 characters: `@acme/web` becomes `acme-web`.

### `/qf-cover`

`/qf-cover` writes tests for source files changed in the session that lack tests; a path or glob narrows them, and `--all` takes every source file in the path. It proposes 2 to 5 cases per function (a happy path, an edge case and, for error handling, an error case) and writes them once you approve. With `--all`, or in a project with no tests, it asks you to narrow to 8 files or fewer per round. It writes jest (Vitest imports when Vitest is a dependency), playwright, pytest, Go, RSpec, PHPUnit, JUnit or TestNG tests, and appends to an existing test file without removing a test.

### `/qf-run`

`/qf-run` runs the frameworks in `test-state.md` and uploads each result with `qf <identifier> collect`. The first matching rule reads its argument:

1. an exact slug from `test-state.md` runs that framework (`/qf-run cypress` runs Cypress even with a `cypress/` folder);
2. a package path, or its start, runs that package, narrowed by a slug after it;
3. an existing file, a glob, or a directory plus a slug is a report: it is uploaded, and nothing runs;
4. anything else is read as a slug.

| Slug          | What `/qf-run` runs                                       | Uploads                        |
| ------------- | --------------------------------------------------------- | ------------------------------ |
| `jest`        | `npx vitest run` with Vitest, else `npx jest`             | Jest JSON                      |
| `mocha`       | `npx mocha`                                               | Mocha JSON                     |
| `python`      | `pytest`                                                  | JUnit XML                      |
| `golang`      | `go test ./... -json`                                     | Go test JSON                   |
| `playwright`  | `npx playwright test`                                     | Playwright JSON                |
| `cypress`     | `npx cypress run`; needs `mochawesome` as a dependency    | Mochawesome JSON, one per spec |
| `rspec`       | `bundle exec rspec`                                       | RSpec JSON                     |
| `phpunit`     | `./vendor/bin/phpunit`                                    | JUnit XML                      |
| `junit`       | `mvn clean test` or `gradle cleanTest test`               | JUnit XML from every module    |
| `cucumber`    | `cucumber-js`, `bundle exec cucumber` or `mvn clean test` | Cucumber JSON                  |
| `webdriverio` | `npx wdio run` with the `@qualflare/webdriverio` reporter | One JSON per worker            |
| `appium`      | `npx wdio run` with the `@qualflare/appium` reporter      | One JSON per worker            |
| `flutter`     | `flutter test` (requires qf 0.2.0 or later)               | Flutter JSON                   |

The CLI reads `qualflare_flutter` data (labels, steps, screenshots) (requires qf 0.3.0 or later). Other slugs need a report you produce, uploaded with `/qf-run <report-path> <slug>`:

| Slugs                                      | Report the CLI parses                              |
| ------------------------------------------ | -------------------------------------------------- |
| `selenium`, `testcafe`, `karate`, `newman` | The tool's JSON report                             |
| `k6`                                       | k6 JSON end-of-test summary                        |
| `testng`, `maestro`, `espresso`, `xctest`  | JUnit XML; for `xctest`, not an `.xcresult` bundle |
| `zap`, `trivy`, `snyk`                     | The tool's JSON output                             |
| `sonarqube`                                | SonarQube issues export (JSON)                     |

Without a slug, `/qf-run` detects a report's format with `qf validate` (local, no login) and asks you to confirm. A report goes to the only identifier, or the one whose package path matches; otherwise `/qf-run` asks.

Before uploading, `/qf-run` deletes each framework's previous result, and checks `qf version` and, with `qf projects`, every login. It continues past failing tests, passes `--branch` and `--commit` from git, and never passes `--environment`, so results go to `QF_ENVIRONMENT`, or `development` when it is unset ([Environments](https://docs.qualflare.com/docs/runs/environments)). It prints `Uploaded to Qualflare ✅` only when every upload succeeded.

### `/qf-fix`

`/qf-fix` reads the last `/qf-run` results in `.qualflare/results/` and makes the smallest source change for each failing test. It edits source files, not tests, and skips a test whose assertion looks wrong. It then re-runs the affected frameworks once and reports what still fails. It makes no second pass and doesn't upload.

### `/qf-doctor`

`/qf-doctor` checks the setup and prints a report with a fix for each problem:

| Check                | Runs or reads                                                                                                         | Result                                                                                                                               |
| -------------------- | --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| CLI                  | `qf version --short`                                                                                                  | ❌ when `qf` isn't found                                                                                                              |
| Auth, per identifier | `qf projects`                                                                                                         | ⚠️ when not logged in: `qf login <identifier>`, with a token from **Project Settings** > **Access Tokens**                           |
| Slug sync            | `qf list-formats` against the plugin's slugs                                                                          | ⚠️ for a slug only one side knows                                                                                                    |
| Config               | `.qualflare/config.json`                                                                                              | ❌ when missing or invalid                                                                                                            |
| Hook registration    | the plugin's `hooks.json`                                                                                             | ⚠️ when no Stop hook is registered                                                                                                   |
| State file age       | `Generated at` in `test-state.md`                                                                                     | ✅ up to 30 days; ⚠️ 31 to 60 days (`/qf-update` or `/qf-init`); ❌ over 60 days (`/qf-init`)                                          |
| Plugin version       | `test-state.md` against the plugin                                                                                    | ⚠️ when they differ (`/qf-init`)                                                                                                     |
| File counts          | each framework's test files, counted again                                                                            | ⚠️ when they drift by more than 10 % and more than 5 files (`/qf-update`); ❌ when none remain of a stored count above 0 (`/qf-init`) |
| Framework tooling    | the version command of jest or Vitest, mocha, playwright, cypress, golang, python, rspec, phpunit, junit and cucumber | ⚠️ when the tool isn't found; other slugs are skipped                                                                                |

Example report:

```
Setup
  CLI                    ✅  qf <version>
  Auth (<identifier>)    ⚠️  not configured
  State file age         ✅  12 day(s) old
File counts
  jest                   ✅  47 live  (stored: 42)
Framework tooling
  jest tooling           ✅  <version>

Overall: 1 warning(s), 0 error(s)
Suggested fixes:
  qf login <identifier>
```

### `/qf-update`

`/qf-update` counts each framework's test files again and updates **File count** and **Generated at** in `test-state.md`. It doesn't detect frameworks again; `/qf-init` does.

### `/qf-state`

`/qf-state` shows the detected frameworks with live test-file counts, the coverage nudge setting, and whether each identifier is logged in (`configured`).

### `/qf-hook`

`/qf-hook on` (or `yes`) turns the coverage nudge on, and `/qf-hook off` (or `no`) turns it off; either creates `.qualflare/config.json` when it is missing. With no argument, `/qf-hook` prints the current setting, or says the hook is not configured when there is no `config.json`.

## The coverage nudge (Stop hook)

The plugin registers a Claude Code Stop hook, which runs each time Claude finishes a response, not only at the end of a session. When `stopHookEnabled` is `true` in `.qualflare/config.json`, it reads the session transcript and prints one line when all three conditions below hold:

```
🔍 Qualflare: 3 source file(s) changed without test updates. Run /qf-cover to add coverage.
```

### When the nudge appears

* At least one source file was edited (`.js`, `.ts`, `.go`, `.py`, `.rb`, `.php`, `.rs`, `.java`, `.kt`, and their JSX and module variants (`.jsx`, `.tsx`, `.mjs`, `.cjs`, `.mts`, `.cts`)).
* No test files were edited in the same session.
* At least one of those edits is substantive. An edit made with the Edit tool is trivial, and ignored, when its old and new text are each a single line and their lengths differ by 40 characters or fewer. Whole-file writes (Write) and multi-edits (MultiEdit) always count.

### What the hook ignores

| Excluded category            | Files                                                                                                                                                                                                                                                                                                               |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Test files                   | `.test.` and `.spec.` files with a js, ts, jsx, tsx, mjs, cjs, mts or cts extension; `*_test.go`; `test_*.py`; `*_test.py`; `*_spec.rb` under `spec/`; `*Test.php` under `tests/`; and any file under `__tests__/`, `e2e/`, `cypress/` or `playwright/`                                                             |
| Config files                 | `*.config.` js, ts, jsx, tsx, mjs, cjs, mts, cts or json (for example `vite.config.ts`); `.<name>rc.` js, ts, mjs, cjs, mts, cts, json, yaml or yml (for example `.eslintrc.json`); the bare `.eslintrc`, `.prettierrc`, `.babelrc`, `.stylelintrc` and `.commitlintrc`; `tsconfig.json` and `tsconfig.<name>.json` |
| Type-only files              | `*.d.ts`, `*.d.mts`, `*.d.cts`, `types.ts`, `types.tsx`, `*.types.ts`, `*.types.tsx`                                                                                                                                                                                                                                |
| Build and dependency folders | `node_modules/`, `vendor/`, `.git/`, `dist/`, `build/`, `.next/`, `__pycache__/`, `.cache/`                                                                                                                                                                                                                         |

### Toggling

```
/qf-hook on     — enable the nudge
/qf-hook off    — disable the nudge
/qf-hook        — print current status
```

## State files

`/qf-init` creates a `.qualflare/` directory in the project root:

```
.qualflare/
├── test-state.md    — framework + file-count context (commit this)
├── config.json      — hook preference (commit this)
└── results/         — raw test-runner output uploaded by qf <identifier> collect (gitignore this)
```

Add `.qualflare/results/` to your `.gitignore`. The other two files should be committed — they give every session the context it needs without re-running setup.

### `test-state.md` structure

Generated by `/qf-init`, updated by `/qf-update`. Contains:

* **Project** — name, languages, generation timestamp, plugin version
* **Packages** — path and CLI identifier for each package (one row per package; `(root)` for single-package projects)
* **Frameworks in use** — slug, language, file count, and top-level paths per (package, framework) pair
* **Frameworks suggested** — frameworks detected as possible but not yet installed
* **Conventions** — test naming pattern and coverage threshold
* **Notes** — free-text notes from setup

### `config.json` fields

| Field             | Type    | Description                          |
| ----------------- | ------- | ------------------------------------ |
| `version`         | number  | Schema version (currently `1`)       |
| `stopHookEnabled` | boolean | Whether the coverage nudge is active |

## Authentication

The plugin uses the same identifier-based auth as the Qualflare CLI. After `/qf-init` prints your identifiers, register each one in your own terminal, not in Claude Code:

```bash
qf login <identifier>
```

`qf login` asks for the token at a hidden prompt. Don't paste a token into the chat or pass it as an argument. In CI, set `QF_TOKEN` and run `qf login <identifier> --force`.

In a monorepo, each package gets its own identifier — run `qf login` once per package. The CLI saves tokens in `qualflare/config.toml` under your user config directory: `$XDG_CONFIG_HOME`, or `~/.config` when it is unset, on Linux, `~/Library/Application Support` on macOS, `%AppData%` on Windows. The file is readable only by you (mode `0600`). Create tokens in **Project Settings** > **Access Tokens** (`https://app.qualflare.com/project/<project-identifier>/settings/access-tokens`). Creating one: (requires the Editor role or higher in the project).

Run `qf projects` to list currently registered identifiers. For the full CLI authentication reference, see [Configuration](https://docs.qualflare.com/docs/cli/configuration).

## Supported frameworks

The plugin uploads through the Qualflare CLI and knows the format slugs below. It doesn't know `allure`: upload an Allure results directory yourself with `qf <identifier> collect allure-results/` (requires qf 0.4.0 or later) (see [Allure results](https://docs.qualflare.com/docs/cli/formats#allure)).

| Category                       | Frameworks                                                                                                                    |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- |
| **Generic (JUnit-compatible)** | `junit`, `ctrf`, `qualflare-json`                                                                                             |
| **Unit Testing**               | `python` (pytest), `golang`, `jest`, `vitest`, `mocha`, `rspec`, `phpunit`, `testng`                                          |
| **BDD**                        | `cucumber`, `karate`                                                                                                          |
| **UI / E2E / Mobile**          | `playwright`, `cypress`, `selenium`, `testcafe`, `maestro`, `xctest`, `espresso`, `detox`, `webdriverio`, `appium`, `flutter` |
| **API Testing**                | `newman`, `k6`                                                                                                                |
| **Security Testing**           | `zap`, `trivy`, `snyk`, `sonarqube`                                                                                           |

[`/qf-run`](https://docs.qualflare.com/docs/ai/claude-code-reference#qf-run) lists the slugs it runs itself. For any other slug, produce the report with your own tooling, then upload it with `/qf-run <report-path> <slug>`.

`/qf-init` records Vitest projects under the `jest` slug, so `/qf-run` uploads them as `jest`. Use `--format vitest` only when you run `qf <identifier> collect` yourself. Multi-framework monorepos are supported — `/qf-init` detects each workspace and tracks them separately.

## Upload errors

`/qf-run` handles each upload by the CLI's exit code:

| Exit code | Meaning                                                          | What `/qf-run` does                                                                  |
| --------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| 0         | Uploaded                                                         | Records it                                                                           |
| 3         | Token rejected (401)                                             | Asks you to run `qf login <identifier>` again; skips that identifier's other uploads |
| 4         | Access denied or plan limit (402, 403)                           | Records the error                                                                    |
| 5         | Not found (404)                                                  | Records the error                                                                    |
| 7         | Rate limit or server error (429, 5xx)                            | Retries once, then records the error                                                 |
| 1         | Anything else, including an environment the project doesn't have | Records the error; stops as a missing login on `Error: no identifier`                |

## Limits

* Identifier: `^[a-z0-9][a-z0-9_-]{0,62}$` ([`/qf-init`](https://docs.qualflare.com/docs/ai/claude-code-reference#qf-init)).
* `/qf-cover`: 2 to 5 cases per function; 8 files per round with `--all` or no tests yet.
* `/qf-fix`: one pass and one re-run.
* Coverage nudge: needs Node.js; the hook times out after 30 seconds.

## Related

* **Guides:** [Claude Code plugin](https://docs.qualflare.com/docs/ai/claude-code) · [Quo agent](https://docs.qualflare.com/docs/ai/quo)
* **Reference:** [Collect command](https://docs.qualflare.com/docs/cli/collect) · [Configuration](https://docs.qualflare.com/docs/cli/configuration) · [Environments](https://docs.qualflare.com/docs/runs/environments)
* **CLI and API:** [CLI](https://docs.qualflare.com/docs/cli) · [Installation](https://docs.qualflare.com/docs/cli/installation) · [Access tokens](https://docs.qualflare.com/docs/api/access-tokens) · [CLI troubleshooting](https://docs.qualflare.com/docs/faq/troubleshooting)
