qcheck
AI writes quantum code. qcheck reviews it.
qcheck is a lightweight review layer for AI-generated Qiskit, OpenQASM,
PennyLane and Cirq snippets. It catches common issues early - removed-in-1.0 APIs, unsafe patterns,
missing measurements, parse errors - so agents and developers can improve quantum
code before it reaches humans, CI, or simulators. Tiny, dependency-free, and it
reviews code without ever executing it.
Why it matters: LLMs write quantum code that fails to run 40-70% of the time one-shot (QuanBench+ 2026: Qiskit 59.5% / PennyLane 42.9% pass; QCoder 2026: ~70% one-shot failure). qcheck catches the avoidable share of that early.
qcheck verify circuit.qasm
qcheck verify snippet.py --json
Why this exists
An LLM agent (or a developer pasting from a chat assistant) produces a Qiskit/QASM snippet.
Will it run? Is it using an API that was removed in Qiskit 1.0? Does it measure?
Is it even safe to touch? Today you find out by running it - wasting time, and
in an agent loop, running untrusted model output. qcheck answers in
milliseconds, statically.
Install
pip install qcheck-quantum
The PyPI distribution name is qcheck-quantum (the bare qcheck name is
taken on PyPI); the installed command and the import package are both
qcheck. v0 has zero runtime dependencies (standard library only).
To work on qcheck itself, install from source:
git clone https://github.com/JCQuankey/qcheck && cd qcheck
pip install -e ".[dev]" # editable install + pytest
Release process: docs/RELEASING.md.
Quickstart
qcheck verify examples/broken_qiskit_execute.py # one file
qcheck verify examples/ # a whole directory (recursive)
qcheck verify a.py b.qasm circuits/ # several paths at once
cat snippet.py | qcheck verify - # stdin (for agents)
Example output:
qcheck 0.10.1 [FAIL] examples/broken_qiskit_execute.py (qiskit)
[error] QISKIT-REMOVED-IMPORT: 'from qiskit import execute' was removed in Qiskit 1.0
[warning] QISKIT-DEPRECATED-GATE: QuantumCircuit.cnot() is deprecated; use .cx().
fix -> Replace execute() with a primitive (Sampler/Estimator) or backend.run().
Reviewing multiple files prints a per-file summary and exits with the worst
result found (unsafe > failed > passed). Directory recursion skips virtualenvs,
VCS, caches, and build output (.venv, node_modules, .git, site-packages,
build, dist, ...) so it reviews your code, not your dependencies. To review a
file inside one of those, pass it explicitly.
JSON output (for agents & CI)
qcheck verify snippet.py --json
For a single file, returns {status, framework, syntax_valid, unsafe, static_checks, errors, warnings, suggested_fixes, confidence, runnable_in_simulator, qcheck_version}. For multiple files or a directory,
returns an envelope {qcheck_version, results: [<per-file object + "path">...], summary: {files, passed, failed, unsafe, read_errors}}. Designed to be parsed by
an LLM agent that just generated the code, or by a CI gate. Exit codes: 0 pass,
1 verification failed, 2 unsafe/unsupported, 3 internal error.
Use it in CI (GitHub Action)
qcheck ships a composite GitHub Action. In your repo's
.github/workflows/qcheck.yml:
- uses: actions/checkout@v4
- uses: JCQuankey/qcheck@v0.10.1
with:
paths: "." # or a folder, e.g. "circuits/"
For paths containing spaces, pass one path per line:
- uses: JCQuankey/qcheck@v0.10.1
with:
paths: |
my circuit.py
openqasm sample.qasm
The step fails the job when qcheck finds errors or unsafe code. See
examples/github-action.yml.
SARIF output (GitHub Code Scanning)
qcheck can emit SARIF 2.1.0 so findings show up as code scanning alerts on the Security tab and inline on pull requests, instead of only in the log:
qcheck verify . --format sarif --output qcheck.sarif
In a workflow, generate the SARIF and let the caller upload it (upload needs
security-events: write, best granted by the consuming repo):
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@v4
- uses: JCQuankey/qcheck@v0.10.1
with:
format: sarif
output: qcheck.sarif
- uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: qcheck.sarif
SARIF reports static qcheck findings (rule id, level, file, line). stdin input
uses a synthetic stdin URI and is not meant for code-scanning upload.
Rule catalog (explain your findings)
qcheck ships 50 rules, and every finding carries a stable rule id (for
example QISKIT-REMOVED-IMPORT). Each id is backed by catalog metadata - a
title, category, default severity, a plain-language summary, why it matters, and
a recommended next step - so a developer or an agent can act on a finding right
away and triage faster.
Browse the catalog from the CLI:
qcheck rules # table: id, level, category, summary
qcheck rules --json # full metadata, for agents and CI
The same metadata enriches SARIF driver.rules[], so code-scanning alerts show
each rule's description, severity and guidance inline. Rule ids are stable across
releases, which keeps CI gates and agent loops consistent as qcheck grows.
qcheck's JSON, qcheck rules --json, SARIF and exit codes are documented as
stable output contracts for agents and CI in docs/CONTRACTS.md. For agent/CI consumption examples, see docs/AGENTS.md.
What v0 checks
OpenQASM 2/3: missing header, undeclared, duplicate and zero-sized
registers, index-out-of-range, malformed measurements, missing measurement,
two-qubit gates on a single qubit, OpenQASM 2/3 syntax mismatches, unsupported
includes, suspicious non-QASM content.
Qiskit Python: Python syntax, missing QuantumCircuit import, zero-qubit
circuits, qubit/classical-bit indices out of range, measure() with no
classical bits, two-qubit gates on one qubit, missing measurement,
get_counts() on an unmeasured circuit, and Qiskit-1.0 breaking changes LLMs
still emit (execute(), assemble(), from qiskit import Aer/execute,
deprecated gate aliases like cnot->cx).
PennyLane: qml used without import, zero/negative device wires, and
QNodes with no return.
Cirq: cirq used without import, cirq.measure() with no qubits,
two-qubit gates given the same qubit twice, and empty LineQubit.range(...)
calls.
Run qcheck rules to see the full catalog with guidance for each rule.
Suppressing findings in CI
Waive a specific finding on the line it is reported, or disable a rule for a run - both are counted in every output, never silent:
qc.cnot(0, 1) # qcheck: ignore[QISKIT-DEPRECATED-GATE]
qcheck verify src/ --disable UNSUPPORTED # skip non-quantum .py files
qcheck verify snippet.py --no-inline-suppress # agent loops: ignore in-code directives
Safety findings (PY-UNSAFE-*, QASM-SUSPICIOUS) can never be suppressed -
inline comments live inside the code under review, so the safety screen cannot
be waived from in-band. Details in docs/CONTRACTS.md.
Safety policy
qcheck never executes the input. Qiskit snippets are analyzed with the
Python ast module (parse, don't run). Any filesystem/network/process/dynamic-
exec construct (os, subprocess, eval, open, ...) marks the snippet
unsafe and exits 2. QASM input is text-scanned. This is deliberate: an
agent-facing verifier that ran untrusted model output would be a remote-code-
execution vector (see Qiskit CVE-2025-2000 for the QPY/pickle precedent). See
SECURITY.md for the full threat model.
Scope
qcheck v0 focuses on static review signals for Qiskit and OpenQASM: API usage (including Qiskit 1.0 removals), unsafe patterns, missing measurements, parse issues, and common LLM-generated mistakes. It reviews code without executing it, so it's safe to run on untrusted model output inside an agent loop or CI.
It's a fast first-pass reviewer - pair it with your tests and simulators for the rest. For methodology and scope details, see the leaderboard methodology.
Roadmap
- v0 (shipped, on PyPI): CLI, Qiskit + OpenQASM static checks, JSON + SARIF output, safety screen, GitHub Action. Zero runtime deps.
- Shipped since: PennyLane + Cirq static review surfaces, a documented rule catalog (50 rules).
- Next: more rules per surface, LLM-powered fix suggestions, MCP server (
verify_quantum_code), sandboxed simulation (opt-in). - Public static-check leaderboard for LLM-generated quantum code (see
leaderboard/) + anonymized error dataset.
Leaderboard
qcheck includes a static review benchmark for AI-generated quantum code: it
tracks how often model outputs pass qcheck's current review checks
(static_pass_rate) on a small public Qiskit/OpenQASM task set - an early quality
signal for agents and LLM workflows. The rows shown today are labelled SAMPLE/demo.
leaderboard/README.md- how to add a submission and run itleaderboard/methodology.md- scope and methodologyleaderboard/site/leaderboard.md- the generated table
Contributing
Issues and PRs welcome - especially new failure fixtures (a real LLM-generated snippet that should fail but currently passes, or vice versa). Each fixture makes qcheck sharper and feeds the public error taxonomy.
Contact
- Technical questions / maintainer contact: dev@quankey.xyz
- Security issues: security@quankey.xyz (see
SECURITY.md)
Maintained by JCQuankey / qcheck contributors. qcheck runs locally, sends no telemetry, and reviews code without executing it.
License
Apache-2.0.
Metadata
Release files for qcheck-quantum 0.10.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| qcheck_quantum-0.10.1.tar.gz | 57.4 kB | With provenance | Details for qcheck_quantum-0.10.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| qcheck_quantum-0.10.1-py3-none-any.whl | Python 3 | none | any | Details for qcheck_quantum-0.10.1-py3-none-any.whl |
Total release size: 98.6 kB
Release files / qcheck_quantum-0.10.1.tar.gz
| Download URL | qcheck_quantum-0.10.1.tar.gz |
|---|---|
| Size | 57.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
586b45a460b9002cb31631fa282aaf5cfc7dbb3a9a5216cefb65b865cbec9067
|
|
BLAKE2b-256 checksum How to use checksums |
953f9179b8980e9ae696ba4c38aa7097cd1ad39470f83ceac21fa98ecd933cd5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.
Transparency logRelease files / qcheck_quantum-0.10.1-py3-none-any.whl
| Download URL | qcheck_quantum-0.10.1-py3-none-any.whl |
|---|---|
| Size | 41.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
83af4a93e9d734d007f4885e148b9c41b4a517be48a36da975bf8fc0a6ca2ca2
|
|
BLAKE2b-256 checksum How to use checksums |
7bd21bbcf915e59c7ce3f6dfa8994e5d101ccb116cbd48fa1dc3c067baa973c5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.
Transparency logSecurity for qcheck-quantum 0.10.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for qcheck_quantum-0.10.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.