The manifest
Complete reference for qsolve.yaml: every field, its type, default, valid values and limits, the error each mistake raises, how the platform uses it, and annotated examples from published workflows.
Updated 13 November 2026 View as markdown
On this page
qsolve.yaml sits at the root of a workflow repository. It names the workflow, points to its schemas and class, declares its parameters and methods, and sets its size and resource limits. It is the only place these are declared, and the platform stores a copy of it with every published version.
How the manifest is checked
Three checks read it, in this order:
- Load (
qsolve validate, and the first thing every other command does). The file must be valid YAML and match the model below. Failure printsInvalid workflow:followed by the reason and exits 1. On submission and inqsolve lintthe same failure is reported as lint errorE002(invalid workflow definition: ...); a missing file isE001. - Schema files. The two schema paths are read. See Input and output schemas.
- Lint and gates. Further manifest rules (examples, license, hardware cases) are lint codes; see Lint codes.
Rules that apply at every level:
- Unknown keys are rejected, in the top level and in every nested object. A typo such as
enveloppe:fails the load with the validator'sExtra inputs are not permittedmessage naming the key. - Required keys that are missing fail with
Field required. Wrong types fail with a message naming the field; for example,version: 1.0is read by YAML as a number and rejected, so write1.0.0. - Values are not coerced. A string where a number is expected, or a number where a string is expected, is an error.
The platform also re-validates the stored manifest every time it accepts a run, with the same code.
A complete manifest
This is the manifest of the max-cut example (version 1.0.2), which uses every section. Long prose strings are shortened here; the full file is in examples/max-cut/qsolve.yaml.
schema_version: 1
name: max-cut
version: 1.0.2
family: qubo_optimization
summary: Split a weighted graph into two groups to maximize the total weight of edges between them (network partitioning, clustering, circuit layout)
license: Apache-2.0
tags: [graph, partitioning, qubo, qaoa, logistics]
inputs:
schema: schemas/input.json
examples: [examples/ring_6.json]
parameters:
- {name: layers, label: Circuit depth, type: int, default: 3, min: 1, max: 8, description: "More layers can find better answers but take longer to train"}
- {name: shots, label: Final shots, type: int, default: 4000, min: 100, max: 20000, description: Final sampling shots}
- {name: train_shots, label: Shots per training step, type: int, default: 1000, min: 100, max: 8000, description: Shots per optimizer step when training is sampled}
- {name: optimizer_iters, label: Optimiser iterations, type: int, default: 100, min: 5, max: 400, description: COBYLA iterations}
- {name: train_on, label: Train angles on, type: enum, default: sim, choices: [sim, backend], description: "sim trains noise-free and uses the device only to measure"}
outputs:
schema: schemas/output.json
entrypoint: src.workflow:MaxCut
category: Networks and logistics
objective: {label: Negative cut weight, unit: "", decimals: 3}
metric: {kind: relative_gap, note: "100% means the quantum objective equals the best classical objective. It falls by the relative amount the quantum objective is worse."}
methods:
- id: qaoa
role: quantum
title: QAOA (quantum approximate optimisation)
what: A short quantum circuit that alternates between favouring low-cost answers and mixing possibilities.
strength: Samples good answers directly from a quantum state.
limit: On today's noisy chips only small circuits stay faithful.
- id: exhaustive-or-annealing
role: reference
title: Exhaustive search (annealing beyond 22 variables)
what: Tries every possible answer and keeps the best one.
strength: Provably the best answer whenever it can run exhaustively.
limit: Beyond 22 variables it is a heuristic with no guarantee.
- id: annealing
role: classical
title: Simulated annealing
what: Starts from a random answer and keeps trying small changes.
strength: Fast, scales to large problems, and usually lands close to the best answer.
limit: No guarantee that it finds the best answer.
envelope:
max_qubits: 24
max_variables: 24
notes: "Up to 24 nodes per run"
targets:
simulators: [cpu, gpu]
qpu: [ibm]
min_qubits_qpu: 4
resources:
timeout_s: 1800
memory_mb: 1536
network: none
runtime:
python: "3.12"
dependencies: requirements.lock
Top-level fields
| Field | Type | Required | Default | Valid values and errors |
|---|---|---|---|---|
schema_version |
integer | Yes | Exactly 1. Any other value fails the load. |
|
name |
string | Yes | ^[a-z0-9][a-z0-9-]{1,62}$: lowercase letters, digits and dashes, 2 to 63 characters, starting with a letter or digit. Error: name must be lowercase letters, digits and dashes (2-63 chars). It becomes the workflow's address (its slug) and is its identity: a different name is a different workflow. A name already owned by another developer, or by a workflow you deleted, is refused at publish. See Versioning. |
|
version |
string | Yes | ^\d+\.\d+\.\d+$: three whole numbers, no pre-release suffix, no leading v. Error: version must be semver, e.g. 0.1.0. |
|
family |
string | Yes | Any string; the platform does not check it against a list and accepts an empty one. Use a stable snake_case name such as qubo_optimization, electronic_structure or quantum_ml. It is shown in the listing and used for filtering, and it is refreshed from the newest version at every publish. |
|
summary |
string | Yes | Any string, no length limit in the model. One sentence on what the workflow solves; shown in the listing and refreshed at every publish. | |
license |
string | Yes | Any string, but blank or whitespace-only is lint error E051. Also add a LICENSE file, or lint warns W051. |
|
tags |
list of strings | No | [] |
Free-form search tags. No limit on count or length is enforced. Refreshed at every publish. |
inputs |
object | Yes | See Inputs and outputs. | |
parameters |
list | No | [] |
See Parameters. |
outputs |
object | Yes | See Inputs and outputs. | |
entrypoint |
string | Yes | ^[A-Za-z_][\w.]*:[A-Za-z_]\w*$, that is package.module:ClassName. Error: entrypoint must look like 'package.module:ClassName'. Lint E030 if the module or class is not found, E031 on a syntax error. |
|
category |
string | No | "" |
At most 60 characters. The field the workflow belongs to as a person would say it, for example Finance. Shown in the marketplace. |
objective |
object | No | {label: Objective, unit: "", decimals: 4} |
See objective. |
metric |
object | No | {kind: relative_gap, ...} |
See metric. |
methods |
list | Yes | At least 2 entries; see Methods. | |
envelope |
object | Yes | The largest problem the workflow accepts; see envelope. |
|
targets |
object | No | {simulators: [cpu], qpu: []} |
See targets. |
resources |
object | No | see below | See resources. |
runtime |
object | No | see below | See runtime. |
Things that are not manifest keys
Because unknown keys are rejected, these will fail the load if you add them:
- Visibility, first-party status, ownership. The platform sets them: a new developer workflow starts
unlistedand becomes public when an admin approves it (or when auto-publish is on). There is nothing to declare. - Pricing and cost hints. There is no price field. The quote for a run comes from what your
estimate()returns and the platform's rate card; see Credits and pricing and Writing the workflow. - Error mitigation. Mitigation is code you write, and you report its result at run time with
ctx.report_mitigation(...). There is no manifest switch; see Error mitigation and fidelity. - Benchmark cases and hardware cases. They live in
benchmarks/cases.yaml; see Benchmarks.
Inputs and outputs
Both have the same shape:
| Field | Type | Required | Default | Meaning |
|---|---|---|---|---|
schema |
string | Yes | Path to a JSON file inside the repository, relative to the repository root. A path that resolves outside the repository fails with schema path escapes workflow directory: <path>. A missing file fails with schema file not found: <path>. A file that is not a JSON object fails with <path> must contain a JSON object. |
|
examples |
list of strings | No | [] |
Paths to JSON example files. |
For inputs, at least one example is required (lint E024), and each must read and validate against the input schema (lint E023). The example files are copied into the version's record and shown to researchers as starting points. For outputs, examples is accepted but not used. The schema files themselves are checked by lint E020 to E022 (see Input and output schemas).
Parameters
Each entry declares one setting a user can change. Every field, the type rules and how values reach your code are in Parameters. In short:
| Field | Type | Required | Default | Constraints |
|---|---|---|---|---|
name |
string | Yes | Unique across the list: parameter names must be unique. |
|
type |
string | Yes | int, float, bool, str or enum. |
|
default |
any | Yes | Must pass the parameter's own type, range and choices checks, or the manifest does not load. | |
label |
string | No | "" |
At most 60 characters. |
description |
string | No | "" |
No length limit. |
min, max |
number | No | none | Applied to int and float; ignored for other types. |
choices |
list | For enum |
none | The allowed values; ignored for other types. |
objective
Describes the number each method reaches, so every value is shown with the right label and unit. The platform never writes this text itself.
| Field | Type | Default | Constraints |
|---|---|---|---|
label |
string | Objective |
No length limit. |
unit |
string | "" |
For example Ha. |
decimals |
integer | 4 |
0 to 10 inclusive. |
metric
Picks one of three accuracy formulas. You choose a kind and explain it in words; you do not supply a formula. Benchmarks gives the formulas and the rule for when a result matches the baseline.
| Field | Type | Default | Constraints |
|---|---|---|---|
kind |
string | relative_gap |
relative_gap (lower-is-better objective, only a worse result loses accuracy), relative_error (distance to the reference, with the quantum value's error bar), error_rate (the value is a share of mistakes, with a 95% interval). Any other value fails the load. |
note |
string | "" |
At most 600 characters. Says what accuracy means for this workflow. |
tolerance |
number | 0.0 |
0 to 1 inclusive. Accuracy within this of 100% counts as matching the reference. |
tolerance_abs |
number or null | null |
At least 0. A difference to the reference up to this, in the objective's own units, counts as matching, for example 0.0016 Ha (chemical accuracy). |
Methods
methods lists every method Qsolve runs and compares on each input. You need exactly one quantum and exactly one reference, any number of classical, and at least two methods in total. The platform runs the classical methods first and the quantum method last.
| Field | Type | Required | Default | Constraints |
|---|---|---|---|---|
id |
string | Yes | Same pattern as name (method id must be lowercase letters, digits and dashes). Unique within the list. |
|
role |
string | Yes | quantum, reference or classical. |
|
title |
string | Yes | At most 80 characters. | |
what |
string | No | "" |
At most 500 characters. What the method does, for a reader who does not know it. |
strength |
string | No | "" |
At most 300 characters. |
limit |
string | No | "" |
At most 300 characters. |
List-level errors: method ids must be unique, and declare exactly one method with role 'quantum' (or 'reference'). A list with fewer than two methods also fails the load.
Each method is implemented by a method of your Workflow class. The role decides the name, and the id only matters for classical:
| Role | Python method it calls |
|---|---|
quantum |
quantum(self, ctx) |
reference |
reference(self, ctx) |
classical |
classical_<id>(self, ctx), with dashes in the id turned into underscores: id annealing calls classical_annealing, id greedy-swap calls classical_greedy_swap |
A declared method with no matching Python method stops the run with method 'x' is declared in the manifest but the workflow has no name method. A reference method that touches the quantum backend fails the run with QuantumNotAllowed; a classical one that does is shown as unavailable. Qsolve shows title, what, strength and limit as written and never writes its own text about your workflow, so write for someone who does not know the method.
envelope
The largest problem the workflow accepts.
| Field | Type | Required | Default | Constraints |
|---|---|---|---|---|
max_qubits |
integer | Yes | 1 to 1000. | |
max_variables |
integer | Yes | 1 to 100000. | |
notes |
string | No | "" |
Shown in the rejection message, for example "Up to 24 nodes per run". |
How it is enforced:
- After your
__init__runs, Qsolve callssize()and refuses the input if the result is greater than eithermax_variablesormax_qubits, before any circuit runs and before anything is charged. The message isProblem has <n> variables; this workflow supports at most <smaller of the two> (<notes>). In practice the smaller of the two is the limit. max_qubitsis also a hard cap in the sandbox: a circuit with more qubits than this is refused by the executor withcircuit exceeds the allowed qubit count.- The input form shows
notesnext to "Your problem". - It is separate from your input schema bounds. The schema (
maxItems,maximum, ...) rejects a malformed input withInvalid input at <path>: <reason>; the envelope rejects a well-formed input whose size, as yoursize()reports it, is too big. Set both: schema bounds so the form can show limits early, and the envelope as the size limit that holds whatever shape the input takes.
targets
| Field | Type | Default | Valid values | Meaning |
|---|---|---|---|---|
simulators |
list | [cpu] |
cpu, gpu |
A run on sim-cpu is accepted only if cpu is listed, and on sim-gpu only if gpu is listed. Any other entry fails the load. |
qpu |
list | [] |
ibm |
A run on ibm:<device> needs ibm listed. No other provider is accepted: Amazon Braket is not available yet, and braket in this list fails the manifest load. |
min_qubits_qpu |
integer or null | null |
any integer | Accepted and stored, but nothing reads it: it has no effect on which runs are accepted, quoted or run. Lint reports it as warning W052 so nobody relies on it. |
A run requesting an unlisted target is refused with HTTP 422 target_not_supported and the message This workflow does not support target 'x'., with the workflow's lists attached. For ibm:<device>, the device name after the colon must match ^[A-Za-z0-9_.-]{1,64}$. Noise-model targets (fake:...) are not accepted by the run API, so they are not listed here; they exist for benchmark cases and local runs. If hardware_cases are declared in benchmarks/cases.yaml, qpu: [ibm] is required (lint E054). See Backends and targets and Machines and targets.
resources
| Field | Type | Default | Valid values | Meaning |
|---|---|---|---|---|
timeout_s |
integer | 1800 |
1 to 86400 | Wall-clock limit for a run, in seconds. |
memory_mb |
integer | 4096 |
256 to 65536 | Memory limit for the sandbox, in MB. A run that exceeds it stops with exceeded the <n> MB memory limit. |
network |
string | none |
none only |
Workflows have no network. Any other value fails the load. |
How the limits are applied:
- Timeout. The sandbox stops a run at
timeout_swithexceeded its <n>s compute limit. The platform also caps every run at its own maximum, 4 hours by default, whatever the manifest asks. Time spent waiting for a quantum computer does not count against it: the limit is extended by the queue wait, up to a platform cap (6 hours by default). - Up-front check. If the run time predicted from your
estimate()(itsruntime_s, to which the SDK adds 20 s of run overhead) is above the effective limit (the smaller oftimeout_sand the platform cap), the run is refused before it starts withrun_too_long. - Validation. The benchmark run during validation uses a time limit of
timeout_sraised to at least 300 seconds and capped at 7200, and memory capped at 8192 MB. A heavy workflow therefore gets its wholetimeout_sup to 2 hours while validating.
runtime
| Field | Type | Default | Meaning |
|---|---|---|---|
python |
string | 3.12 |
Informational: the value is stored but not read when a run starts. Runs use the Python of the platform image. |
dependencies |
string | requirements.lock |
Informational: stored but not read. The package set is fixed by the platform image; see Project layout. |
Examples of choices
A chemistry workflow measures energies, so it uses an absolute tolerance in the objective's units. From molecular-ground-state:
objective: {label: Ground-state energy, unit: "Ha", decimals: 6}
metric: {kind: relative_error, tolerance_abs: 0.0016, note: "1 minus the energy difference to the exact active-space answer, as a fraction of that answer. Total energies are large numbers, so read the error in mHa too: chemical accuracy is 1.6 mHa."}
A classifier's objective is an error rate. From quantum-kernel-classifier:
objective: {label: Test error rate, unit: "", decimals: 3}
metric: {kind: error_rate, note: "Share of held-out test points classified correctly, with its 95% interval. Fewer test points mean a wider interval."}
An error-rate workflow must put the number of test cases in its quantum method's Outcome.details as n_test, so the interval can be computed. See Writing the workflow.
Resources scale with the work. max-cut (a 24-variable QAOA) asks for the defaults of 1800 s and 1536 MB; molecular-ground-state runs a chemistry solver, so it asks for timeout_s: 3600 and memory_mb: 2048; electrolyte-solvent-screen runs up to eight chemistry systems and asks for timeout_s: 7200. The envelope scales the same way: 24 qubits for the graph problems, 12 for the chemistry ones (6 active orbitals), 8 for the kernel classifier (one qubit per feature).
Validate it
qsolve validate .
A manifest error prints Invalid workflow: with the field and reason, and exits 1. After the manifest loads, validate also checks that every example validates against the input schema. Common errors are in Troubleshooting and every lint code is in Lint codes.