Skip to main content
shotgate logomark

shotgate

Container-native CI/CD quality gates for quantum circuits.

Statistically validate the probabilistic output of quantum programs across simulators and real quantum processing units (QPUs), defined as code.

CI License: Apache-2.0 Python Status


shotgate run on the bell-state example: five statistical assertions (chi-square, TVD, Hellinger fidelity, allowed-states leakage, marginal probability) pass against the local-aer simulator, exit 0

Representative output of shotgate run examples/bell-state/workflow.yaml.


Why shotgate exists

Classical CI/CD relies on determinism: the same input gives the same output, so assert x == y holds. Quantum programs break that assumption. Run the same circuit twice and the shot counts differ, so a pipeline cannot gate on exact equality. The community has noted the same gap:

"Unlike deterministic classical programs, quantum algorithms often produce probabilistic results, requiring specialized validation and error mitigation strategies in CI/CD pipelines." (DevOps community guidance)

"Terraform modules and Helm charts may need support for quantum backends, simulators..."

The statistical oracles that handle probabilistic output are established in the literature (QUTest, QuCheck, chi-square as oracle): chi-square goodness-of-fit (GoF), total variation distance (TVD), and Hellinger fidelity. They live mostly in research prototypes rather than in production DevOps tooling. shotgate packages them so a quantum circuit can be gated in an ordinary pipeline. It:

  1. Defines quantum test workflows as declarative YAML ("quantum workflow as code").
  2. Executes circuits on simulators or real QPUs through a pluggable backend layer.
  3. Validates the output distribution statistically and emits JUnit, JSON, and Markdown reports.
  4. Returns exit code 0 on pass and 1 on failure, so it drops into a CI quality gate directly.
  5. Ships an Infrastructure-as-Code layer (Terraform) and isolation tiers (Podman, KVM/QEMU).

See docs/architecture.md for the design and docs/motivation.md for the market and community analysis with sources.

What it looks like

# Trimmed from examples/bell-state/workflow.yaml
apiVersion: shotgate.dev/v1alpha1
kind: QuantumWorkflow
metadata:
  name: bell-state
defaults:
  backend: { provider: local-aer, shots: 8192, seed: 1234 }
jobs: [
  { name: bell-pair,
    circuit: { format: qasm2, path: bell.qasm },
    assertions: [
      { type: chi_square,       expected: { "00": 0.5, "11": 0.5 }, significance: 0.01 },
      { type: distribution_tvd, expected: { "00": 0.5, "11": 0.5 }, max_distance: 0.03 },
      { type: allowed_states,   states: ["00", "11"], max_leakage: 0.0 }
    ]
  }
]
$ shotgate run examples/bell-state/workflow.yaml
─────────────────────────── shotgate :: bell-state ───────────────────────────
 job: bell-pair · aer_simulator · 8192 shots
 ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
 ┃ Assertion                 ┃ Result ┃ Detail                                    ┃
 ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
 │ chi-square p >= 0.01      │  PASS  │ chi-square=0.410 dof=1 p-value=0.5220     │
 │ TVD <= 0.03               │  PASS  │ total variation distance 0.0043 (<= 0.03) │
 │ fidelity >= 0.99          │  PASS  │ Hellinger fidelity 1.0000 (>= 0.99)       │
 │ leakage <= 0.0            │  PASS  │ support leakage 0.0000 (<= 0.0)           │
 │ P(00) >= 0.45 and <= 0.55 │  PASS  │ P(00) = 0.4957                            │
 └───────────────────────────┴────────┴───────────────────────────────────────────┘
 PASSED · 5/5 assertions · 0.214s

The same run drops into a pipeline through the Markdown reporter (--markdown), rendered as a step summary or a PR comment:

shotgate: bell-state (✅ passed)

  • Jobs: 1, failed: 0
  • Assertions: 5, failed: 0
  • Duration: 0.214s
Job Backend Shots Assertion Result Detail
bell-pair aer_simulator 8192 chi-square p >= 0.01 ✅ chi-square=0.410 dof=1 p-value=0.5220 (>= alpha=0.01)
bell-pair aer_simulator 8192 TVD <= 0.03 ✅ total variation distance 0.0043 (<= 0.03)
bell-pair aer_simulator 8192 fidelity >= 0.99 ✅ Hellinger fidelity 1.0000 (>= 0.99)
bell-pair aer_simulator 8192 leakage <= 0.0 ✅ support leakage 0.0000 (<= 0.0)
bell-pair aer_simulator 8192 P(00) >= 0.45 and <= 0.55 ✅ P(00) = 0.4957

Install and run

Two install paths are supported and produce identical validation results. Use the container when you want a pinned, reproducible runtime with the simulator baked in; use the pip package when you want the shotgate CLI or the pytest plugin inside an existing Python environment.

Path A: Podman (pull and run)

Pull the published image and gate a workflow without installing anything into your host Python:

# --userns=keep-id --user maps you through the container's user namespace so the
# JUnit report is written back owned by you (the image runs as a non-root user).
podman run --rm --userns=keep-id --user "$(id -u):$(id -g)" \
  -v "$PWD:/work:Z" -w /work \
  ghcr.io/coldqubit/shotgate:latest \
  run examples/bell-state/workflow.yaml --junit report.xml

For the cloud/QPU path, use the IBM-enabled image variant and pass a token:

podman run --rm -e SHOTGATE_IBM_TOKEN \
  -v "$PWD:/work:Z" -w /work \
  ghcr.io/coldqubit/shotgate:latest-ibm \
  run examples/bell-state-hardware/workflow.yaml --backend ibm

The same images are mirrored to Docker Hub if you prefer it: swap the registry prefix for docker.io/coldqubit/shotgate (tags latest, latest-ibm, and each version). GHCR is the canonical registry; the Docker Hub copy is a convenience mirror.

Path B: pip (CLI and pytest plugin)

Install the package with the backend extra you need (aer for the local simulator, ibm for IBM Quantum). This installs the shotgate CLI and registers a pytest plugin:

pip install 'shotgate[aer]'
shotgate run examples/bell-state/workflow.yaml --junit report.xml

The pytest plugin turns each declared assertion into one pytest item. Point it at a workflow with --shotgate, or rely on auto-collection of files named exactly workflow.yaml:

pytest --shotgate examples/bell-state/workflow.yaml

A workflow whose backend dependencies are absent skips with a reason naming the extra to install, rather than erroring at import. The shotgate_paths ini key collects the same way without a command-line flag.

Exit code 0 means all assertions passed, 1 means a gate failed, and 2 means a bad workflow or usage error, so either path drops into a pipeline. The container is the default for this repo's own development (see Build from source) because the tests run against the source tree.

Build from source

make build         # podman build -t shotgate:dev .
make run WORKFLOW=examples/bell-state/workflow.yaml
make test          # full test suite in a container

For hardware-isolated runs (each pipeline in a throwaway KVM micro-VM), see infra/qemu/. For declarative provisioning, see the Terraform module in infra/terraform/.

The assertion catalog

Type Oracle Use it for
chi_square Pearson χ² GoF test (p-value vs α) Formal hypothesis test; simulator-only (see catalog)
distribution_tvd Total variation distance (TVD) ≤ bound Default distribution check; interpretable, shot-count-agnostic
hellinger_fidelity Classical fidelity ≥ threshold Fidelity tracking against an ideal distribution
state_probability Marginal P(state) in a window / ≈ target Single-outcome amplitude checks (e.g. Grover)
allowed_states Probability mass outside support ≤ budget Structural/leakage guarantees (e.g. GHZ corners)
kl_divergence KL D(obs‖exp) ≤ bound (bits) Information-theoretic distance; simulator-only (zero-support)
shannon_entropy Entropy in a min/max window (bits) Assert the intended randomness/concentration
expectation_value <Z..Z> in [-1, 1] via window / target Correlation/parity observable tracking
most_frequent_outcome Modal state (optional min probability) Single intended answer (e.g. Grover)

Full reference: docs/assertions.md. The statistical core is pure Python (no SciPy), including a from-scratch χ² survival function via the regularised incomplete gamma function. See src/shotgate/validation/metrics.py.

Architecture at a glance

flowchart LR
    subgraph dev["Author"]
        wf["workflow.yaml<br/>(quantum workflow as code)"]
        qasm["circuit.qasm"]
    end
    subgraph shotgate["shotgate (in a Podman container)"]
        cfg["Schema / validation<br/>(pydantic)"]
        ld["Circuit loader"]
        be["Backend registry"]
        val["Statistical oracles<br/>χ² · TVD · fidelity"]
        rep["Reporters<br/>JUnit · JSON · MD"]
    end
    subgraph targets["Execution targets"]
        aer["Local Aer<br/>simulator"]
        ibm["IBM Quantum<br/>(QPU/cloud)"]
    end
    wf --> cfg --> ld --> be
    qasm --> ld
    be --> aer & ibm
    aer & ibm --> val --> rep
    rep -->|exit 0/1| ci["CI/CD gate"]

The layers are decoupled: the validation core has no quantum-SDK dependency, so the metrics and schema run anywhere, and heavy SDKs are imported lazily only when a backend is actually used. The same artifact therefore runs in a small CI container and against a real QPU.

Repository layout

shotgate/
├── src/shotgate/          # the package (validation core, backends, runner, CLI, pytest plugin)
├── examples/              # runnable workflows: bell/ghz/grover + backend & oracle variants
├── tests/                 # unit tests (core) + integration tests (gated on aer)
├── infra/
│   ├── terraform/         # IaC module: "quantum workflow as code"
│   └── qemu/              # ephemeral KVM/QEMU runner (cloud-init)
├── docs/                  # architecture, pipeline schema, ADRs, specs, diagrams
├── .github/workflows/     # Podman-based CI + release
├── Containerfile          # the shotgate runtime image
└── Makefile               # Podman/QEMU task runner

Backends

Provider Status
local-aer (Qiskit Aer simulator) Working, default, baked into the image
ibm (IBM Quantum via Qiskit Runtime) Validated on real hardware (ibm_fez, 2026-06-11: Bell/GHZ/Grover gates passed at 4096 shots; measured baseline)
braket (AWS Braket via qiskit-braket-provider) Working: local simulation (no AWS account). Cloud devices need AWS credentials; not yet validated on real Braket hardware.
Error mitigation (Mitiq) Planned

Roadmap

  • v0.1: YAML workflows, local Aer backend, χ²/TVD/fidelity/structural oracles, JUnit/JSON/MD reporters, Podman and KVM/QEMU isolation, Terraform module, pytest plugin, PyPI package, published GHCR image with an IBM-enabled variant.
  • v0.2: statistical gates validated against real quantum hardware (ibm_fez, 2026-06-11, Bell/GHZ/Grover at 4096 shots; measured baseline and runbook in docs/hardware-validation.md), hardware example gates for GHZ and Grover, and a dispatchable QPU validation workflow.
  • v0.3.0 (latest release): the OpenQASM 3 fix and fail-closed validation, four more oracles (kl_divergence, shannon_entropy, expectation_value, most_frequent_outcome), declarative noise-model simulation and noise-aware expected distributions (so chi_square/kl_divergence can gate on hardware), and the AWS Braket backend (local simulation; the cloud path awaits validation on real hardware).
  • Planned: error mitigation via Mitiq, multi-backend differential testing, circuit fixtures and property-based generation, a Helm chart, an optional OpenTelemetry exporter for the telemetry layer (kept out of the core dependencies), and validation of the Braket cloud path on real hardware.

See CHANGELOG.md and the ADRs for decisions and rationale.

Contributing and security

Contributions are welcome. Start with CONTRIBUTING.md and the CODE_OF_CONDUCT.md. Report vulnerabilities per SECURITY.md.

Maintainers

shotgate is an independent open-source project, developed in the open under the coldqubit project home. It is maintained today by one maintainer; co-maintainers and new contributors are welcome. See MAINTAINERS.md for the current roster and how to join it, GOVERNANCE.md for how decisions are made, and CONTRIBUTING.md to get started.

License

Apache-2.0 © 2026 coldqubit.

shotgate is free and open source under the Apache License 2.0. You may use, modify, and redistribute it for any purpose, including commercial and closed-source software, provided you retain the license text and the copyright and attribution notices (Apache-2.0 sections 4(a) through 4(d)).

Note on prior art: the existing coveooss/terraform-provider-quantum is unrelated to quantum circuits; it manipulates JSON.

Metadata

Release files for shotgate 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for shotgate 0.3.0
File Size Uploaded
shotgate-0.3.0.tar.gz 109.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for shotgate 0.3.0
File Interpreter ABI Platform
shotgate-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 154.8 kB

Release files / shotgate-0.3.0.tar.gz

Download URL shotgate-0.3.0.tar.gz
Size 109.4 kB
Tags Source
SHA-256 checksum
How to use checksums
411b27f93afcf7a0f80d54b3c04da2e3de455cc9a2641be66e0f88a9b38a429f
BLAKE2b-256 checksum
How to use checksums
078739903fca37159f1b0f91a12eee13cfbb3eb47520250eaceea091d863ba0f
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 Jun 26, 2026.

Transparency log

Release files / shotgate-0.3.0-py3-none-any.whl

Download URL shotgate-0.3.0-py3-none-any.whl
Size 45.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c66c5f1efe99b6453b47b1ba6f1108eee619676c94c2c1e1ce42c704a6561ff0
BLAKE2b-256 checksum
How to use checksums
5843b26292958cf86fb84afc5263f69df7a42f47cae5d255c1ea0357491d2d5f
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 Jun 26, 2026.

Transparency log

Release history Release notifications | RSS feed

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

This release

0.3.0 This release

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page