# What a Qsolve workflow is

> A Qsolve workflow is a plain Qiskit program in a public Git repository plus a qsolve.yaml manifest; the SDK bridges to Qsolve, which runs and measures it.

Source: https://qsolve.omlabs.co/docs/build/overview
Updated: 2026-11-12

A Qsolve workflow is a Qiskit program in a GitHub repository (public, or private through the Qsolve GitHub app), plus a manifest called `qsolve.yaml` that says what the program takes in, what it returns and which methods it compares. You write the quantum algorithm, the error mitigation and the classical baseline in ordinary Qiskit. Qsolve runs the program, measures every number it publishes, and lists the workflow with its track record against the best classical method you declared.

## The three pieces

| Piece | What it is | Who writes it |
|---|---|---|
| Workflow | A Git repository: Python code, `qsolve.yaml`, two JSON Schemas, benchmark cases | You |
| `qsolve-sdk` | A Python package: the contract your class implements, a Qiskit backend and primitives, a local test harness and the `qsolve` command line | Qsolve |
| Qsolve platform | Runs your workflow on simulators and quantum computers and publishes the result | Qsolve |

The SDK contains no quantum algorithm and no solver. Everything algorithmic is your code, built on Qiskit, NumPy, SciPy, scikit-learn and PySCF. [Project layout](/docs/build/project-layout) lists every importable module.

## What a workflow looks like

The workflow is one class that subclasses `qsolve.Workflow`. This is the scaffold `qsolve init` generates, trimmed to its signatures:

```python
from qsolve import Context, Outcome, Workflow

class Qubo(Workflow):
    def __init__(self, input, params): ...        # parse the input; raise WorkflowError for mistakes
    def size(self) -> int: ...                    # qubits or variables
    def quantum(self, ctx: Context) -> Outcome:   # plain Qiskit: build circuits, run them through ctx
        counts = ctx.sampler.run([(circuit, params, shots)]).result()[0].data.meas.get_counts()
        ...
    def reference(self, ctx) -> Outcome: ...      # the classical answer you are judged against
    def classical_annealing(self, ctx) -> Outcome: ...   # any other classical method you declare
    def evaluate(self, solution) -> float: ...    # the objective of a solution, lower is better
    def answer(self, outcome) -> dict: ...        # the domain answer people read
```

`qsolve.yaml` declares the methods and describes each in plain words; Qsolve shows that text next to the numbers it measures. See [Writing the workflow](/docs/build/writing-the-workflow) for the contract and [The manifest](/docs/build/manifest) for the file.

## What Qsolve checks, and what it cannot

Workflow code is untrusted, so Qsolve measures instead of trusting. Circuits, shots, depth and fidelity come from what crosses the backend; accuracy comes from the baseline you declare with `role: reference`. In addition:

- Each method's objective is recomputed with your `evaluate`. A method that claims a different number fails validation.
- A quantum method that sends no circuit fails validation. A classical method that tries to send one is refused.
- Your `estimate()` is compared with the circuits and shots the run actually sent.

Qsolve cannot prove that your classical baseline is the best one, or that your error mitigation is legitimate. Mitigated figures are labelled reported and appear beside the measured raw figures, so a reader sees both. See [Error mitigation and fidelity](/docs/build/error-mitigation-and-fidelity).

See [Your first workflow](/docs/build/your-first-workflow) to build one, [The examples](/docs/build/examples) for seven published ones, and [Validation and publishing](/docs/build/validation-and-publishing) for every check. Importable modules are listed in [Project layout](/docs/build/project-layout).
