How the catalog works:
GET /api/v1/runtime/backends iterates every
supplier’s providers; each provider target string becomes a backend id.
A backend shows available: true only when all of its required environment
variables are set. Dispatch resolves a backend_id to execution through
dispatch_provider_job (built-in cloud branches first, then the HAL for
plugins / on-premise / vendor drivers).
A. Built-in cloud provider — set the credential env var
The provider already exists in the registry. Set its credential(s), restart the server, and its backends flip toavailable: true.
Azure Quantum caveat (important, differs from older docs): the Azure providers (IonQ/Rigetti/Quantinuum/PASQAL) declare no required env var, so they always showConfig changes are read at process start — restart the server after setting any variable. Full list in Configuration.available: truein the catalog. Their execution credentials are read at dispatch time: setAZURE_QUANTUM_RESOURCE_ID(or the trioAZURE_QUANTUM_SUBSCRIPTION_ID+AZURE_QUANTUM_RESOURCE_GROUP
AZURE_QUANTUM_WORKSPACE_NAME) plusAZURE_QUANTUM_LOCATION. The variablesIONQ_API_KEY/QUANTINUUM_API_KEY/RIGETTI_API_KEYare not used for the Azure path — do not rely on them.
B. Bring-your-own (BYO) credentials — per tenant/user
A tenant attaches their own cloud account at runtime, without the operator setting a server-wide env var. Onlyazure_quantum, ibm_quantum and
braket backends support BYO (they carry supports_byo: true).
provider_type: ibm_quantum | azure_quantum | aws_braket | google_quantum | ionq_direct | other. scope: tenant | workspace | user. Manage with
GET /provider-connections and POST /provider-connections/{id}/test.
After connecting, the matching backends report supports_byo: true and jobs
dispatch to the concrete provider adapter with your credentials.
C. On-premise supplier — you host the QPU
Register aSupplierType.ON_PREMISE supplier. Its provider targets become
backend ids; dispatch instantiates your backend_class. On-premise devices
are always classified real_qpu, so the real-QPU gates
(QCOS_REAL_QPU_ENABLED, payment reservation, plan tier) apply.
examples/oem_console/server.py.
The catalog entry provides identity + billing + gating; execution happens
through a driver (usually method D). In practice you pair C (catalog) + D
(driver wheel) for a real customer QPU.
Behaviour (proven by tests/unit/test_onprem_byo_dispatch.py): the target
appears in /backends with provider_source = your supplier id; without a
qpu_reservation_id the job parks in approval_required; with payment but
QCOS_REAL_QPU_ENABLED=false the door returns 403 real_qpu_disabled.
D. Vendor HAL driver — the manufacturer’s own driver
A QPU manufacturer ships a pip-installable wheel that implements the canonicalQPUDriver contract and declares a qcos.drivers entry
point. pip install on the QCOS host is the whole deployment — no core
source, no code changes.
The contract (src/hal/driver.py) — two
mandatory methods:
execute must return at least: job_id, backend_id, shots, counts, execution_time_ms, timestamp, status (ACOS-ISA-009). Optional overrides
(with defaults): transpile_to_native, execute_batch, get_job_status,
cancel_job, connect/disconnect.
Ship it — one line in the wheel’s pyproject.toml:
ReferenceSimulatorDriver (src/hal/reference.py)
as a full-contract template; full worked example in
examples/vendor-driver-demo/.
Licensing (commercial builds): driver registration is gated by license
features (hal:*, hal:<glob>, hal_<vendor>, hal_max_devices:N).
Skipped when QCOS_SKIP_LICENSE_CHECK=true or in internal build mode. See
docs/oem/VENDOR_ONBOARDING.md.
How dispatch resolves a backend id
dispatch_provider_job(backend_id, qasm, shots)
(src/adapters/providers/router.py)
— first match wins:
- Built-in simulator ids → local engines (
auto_sim,statevector_sim, …) - Built-in cloud ids →
ionq./rigetti./quantinuum./pasqal.(Azure),ibm*(IBM),braket/sv1/tn1/dm1(Braket) - Anything else → the HAL: registered drivers (exact) → plugin backends → on-premise suppliers → HAL wildcard drivers
No runtime provider adapter for backend '<id>') — a QPU id is never silently run on a simulator.
Hardware drivers are serialized one-job-at-a-time per device by the
scheduler; simulators run concurrently.