Quality CI
Instructions
Generate a GitHub Actions workflow that enforces code quality and test coverage on every pull request: $ARGUMENTS. $ARGUMENTS may specify the branch, workflow name, or special requirements.
Nexa Rules Gate
Read and follow ${CLAUDE_PLUGIN_ROOT}/shared/readiness/NEXA_RULES_GATE.md.
Prerequisites
- The project must have
oxlintandoxfmtindevDependencies(use/code-qualityfirst if needed) - The project must have
vitestwith coverage configured invitest.config.ts(use/vitest-testfirst if needed) - The project must have an
oxlintrc.jsonat the root with theeslint/complexityrule
Workflow
Read the project context:
- Verify
oxlintrc.jsonexists in the project root - Verify
vitest.config.tsexists and hascoverageconfigured with thresholds - Read
package.jsonto determine the Node.js version and check thatoxlint,oxfmt, and@vitest/coverage-v8are indevDependencies - Check for any existing GitHub Actions workflows in
.github/workflows/ - Ask the user for: workflow trigger branch (default:
main), whether to also trigger on pull requests (default: yes)
- Verify
Create the GitHub Actions workflow at
.github/workflows/quality.ymlusing the template.Fill in the template placeholders:
Placeholder Description Default {{NODE_VERSION}}Node.js version from package.jsonenginesfield or.nvmrc22{{BRANCH}}Branch that triggers the workflow mainEnsure the following are present in the generated workflow:
- Concurrency: The
concurrencykey must cancel in-progress runs for the same branch/PR to prevent redundant CI billing - Package manager detection: Detect the package manager from the lockfile (
package-lock.json→ npm,pnpm-lock.yaml→ pnpm,yarn.lock→ yarn) and pass it toactions/setup-node'scacheparameter - Coverage report upload: The coverage job must use
actions/upload-artifactto save the Vitest HTML report fromcoverage/
- Concurrency: The
Verify the workflow file:
- Validate YAML syntax by reading the file back
- Ensure no placeholder
{{...}}markers remain - Ensure the workflow file is under 80 lines
Output a summary with:
- What was created and where
- How the workflow triggers (push, PR, or both)
- What each job checks (lint job: oxlint + oxfmt, coverage job: vitest --coverage)
- Reminder: the coverage job will fail if any metric drops below the thresholds in
vitest.config.ts
Reference Templates
- GitHub Actions workflow: templates/github-actions/quality.yml
Workflow Template Placeholders
| Placeholder | Description | Example |
|---|---|---|
{{NODE_VERSION}} |
Node.js major version | 22 |
{{BRANCH}} |
Branch that triggers the workflow on push | main |
Design Decisions
Two separate jobs: lint and coverage
The lint job runs oxlint and oxfmt — these are fast (seconds) and have no external dependencies.
The coverage job runs Vitest with coverage — this needs Docker for Testcontainers and takes longer.
Splitting them gives faster feedback: a formatting issue fails in ~30 seconds instead of waiting for
the full test suite.
Why v8 coverage, not istanbul
The v8 provider uses V8's built-in code coverage, which is faster and requires no code instrumentation. It is Vitest's recommended provider for Node.js environments.
Coverage thresholds fail the CI job
The vitest.config.ts defines thresholds (statements, branches, functions, lines at 80%).
When npx vitest run --coverage detects coverage below these thresholds, it exits with a
non-zero code, which fails the GitHub Actions job. No additional threshold checking is needed
in the workflow — Vitest handles it natively.
Update CLAUDE.md
After creating the workflow, append a ## Quality CI section to the target project's
CLAUDE.md so that future sessions know CI is configured.
- If
CLAUDE.mddoes not exist, create it - If a
## Quality CIsection already exists (check for<!-- NEXA_QUALITY_CI_CONFIGURED -->), ask the user whether to overwrite or skip - Append the following section (fill in the actual values from the setup):
## Quality CI
<!-- NEXA_QUALITY_CI_CONFIGURED -->
- Workflow: `.github/workflows/quality.yml`
- Triggers: push to `[branch]`, pull requests to `[branch]`
- Lint job: `oxlint` (with complexity rule) + `oxfmt --check`
- Coverage job: `vitest run --coverage` (v8 provider, 80% thresholds)
- Artifacts: coverage report uploaded on every run
Do not remove or modify any other content in CLAUDE.md.
DO NOT
- Combine lint and coverage into a single job — they have different performance profiles and dependencies
- Hard-code the Node.js version — read it from the project's
package.jsonor.nvmrc - Hard-code the package manager (npm/pnpm/yarn) — detect it from the lockfile present in the project root
- Omit the
concurrencykey — we must prevent redundant CI billing on rapid pushes - Skip
actions/setup-nodecaching — speed is a priority for the Nexa ecosystem - Add matrix strategies for multiple Node versions or OS — keep the workflow single-purpose
- Add deployment steps or notifications — this workflow is only for quality gates
- Overwrite an existing
.github/workflows/quality.ymlwithout reading it first and asking the user - Add ESLint or Prettier steps — the project uses Oxc (oxlint + oxfmt) exclusively