# Bring your own quantum WAI gives you the engine, the free job service and the verifier at no cost. It does not sell time on anyone's hardware, and it never pays for yours. You bring your own quantum hardware: a device on your bench, an on-premises system, an account with a provider, or a simulator you trust. Every surface then treats a run on it as it treats a WAI run: - it is **planned**: the circuit is compiled exactly to the device's own gates and connectivity, and the compiled program is checked against the circuit by simulation before anything is sent; - its **cost is shown before it is submitted**, and a run that is not free (or whose cost is unknown) runs only when you confirm it; - its counts are **sealed in a receipt** with your key, which the existing verifier checks. Your credentials stay with you, in the operating system's keychain. They never go to a browser page, a log, a receipt, or the hosted service. ## What is free ```sh runnable wai-quantum providers free ``` lists what anyone can use at no cost: - the engine's own methods on your machine, each with the most qubits it holds in a job's memory; - the free job service, `https://wai.transaction.science/quantum-jobs`, with no account (its limits are per client; `GET …/v1` states them); - each of your providers whose own description states free use, with the limits it states. No provider is named in WAI's code: a provider says what it offers, about itself. ## Adding a provider A provider is one of six kinds: | kind | what it is | the credential | |---|---|---| | `http` | any provider of the [open provider protocol](../extensions/quantum-providers.md) at an HTTPS URL | `Authorization: Bearer` | | `process` | any program on your machine that speaks the protocol on its standard input and output | its environment (`WAI_PROVIDER_CREDENTIAL`) | | `sampler-v2` | a Sampler V2 job service (OpenQASM 3 on physical qubits, rz sx x cz) | an API key, exchanged for a bearer token | | `prx-circuits` | a circuit service of phased-X and CZ instructions, star devices (qubits round a computational resonator, reached by `move`) among them | the token you generate in the service's dashboard | | `native-turns` | a native-gate service with angles in turns (gpi gpi2 zz, or gpi gpi2 ms where the backend, or its noise model's device, runs only ms) | an API key | | `cloud-tasks` | a cloud service of quantum tasks, on your own account, its results in your own storage bucket | your account's keys, `id:secret` or `id:secret:token`, or its usual environment variables | ```sh runnable # A program of your own, or the reference provider, on this machine: wai-quantum providers add lab --kind process -- wai-quantum providers reference --stdio # A provider at a URL, its credential read from standard input into the keychain: wai-quantum providers add cloud --kind http --endpoint https://quantum.example/provider --credential-stdin < token.txt # A built-in protocol, its settings beside it, its credential in the keychain: wai-quantum providers add mine --kind sampler-v2 --set crn=… --set backend=… --credential-stdin < key.txt # A cloud service of tasks: a device by its name there, your own results bucket and your own keys: wai-quantum providers add tasks --kind cloud-tasks --set region=us-east-1 --set device=… --set bucket=your-results-bucket --credential-stdin < keys.txt # Or a credential read from an environment variable whenever it is used, kept nowhere: wai-quantum providers add turns --kind native-turns --set backend=simulator --credential-env MY_TURNS_KEY ``` A credential is never given on a command line (where other users of the machine could read it). `--credential-stdin` keeps it: - on macOS, in the keychain, through the system `security` tool; - on Linux, in the desktop secret service, through `secret-tool`, when it is installed and answers; - elsewhere (Linux with no secret service, Windows), in a file only you can read (`~/.config/wai/quantum-provider-credentials/NAME`, mode 0600), and every listing says so. `WAI_QUANTUM_CREDENTIALS=file` chooses the file; `WAI_QUANTUM_CREDENTIALS=keychain` accepts nothing but the keychain. The list itself (`~/.config/wai/quantum-providers.json`, or the file `$WAI_QUANTUM_PROVIDERS` names) holds no credential: only each provider's kind, endpoint or command, non-secret settings, and where its credential is. A setting whose name looks like a credential (`token`, `key`, `secret`, …) is refused. The built-in kinds still read their environment variables (`WAI_QPU_SAMPLER_API_KEY` and the rest, in the [README](README.md)) when no credential is kept for them. ```sh runnable wai-quantum providers list # each provider, and where its credential is wai-quantum providers describe lab # its qubits, gates, connectivity, calibration and prices wai-quantum providers test lab # the protocol's conformance vectors; jobs only when free, or with --yes wai-quantum providers remove turns # and the credential kept for it ``` ## Running on it ```sh runnable wai-quantum run bell.qasm --provider lab --dry-run # the plan, the check and the estimate; nothing sent wai-quantum run bell.qasm --provider lab # free: it runs ``` On a provider that charges (here `cloud`, reached with your own account): ```sh norun=account wai-quantum run bell.qasm --provider cloud # not free: refused, with the estimate (exit 3) wai-quantum run bell.qasm --provider cloud --yes # you confirmed it: it runs wai-quantum run bell.qasm --provider cloud --json > job.json && wai-quantum verify job.json ``` A run on a provider asks for counts (`--shots`, 1024 by default) of a program whose measurements all come at the end and whose every angle is a dyadic multiple of 2π (`pi/4`, `3*pi/8`, …), so it compiles exactly. A job that asks for expectation values, amplitudes, a noise model or one of the engine's methods is refused; those are the engine's. An agent has the same through `wai-quantum mcp`: - `providers_list` lists your providers (and, with `free: true`, what is free); - `provider_estimate` is the dry run; - `run_on_provider` runs, and says in its description that it can spend your money. It refuses a run that is not free unless `confirm_cost: true`, which an agent sets only after you have seen the estimate and agreed. The desktop app lists your providers under **Your hardware**, asks for the estimate first, and shows a dialog before a run that is not free. The browser Studio cannot: a browser tab must not hold a credential, so there the switch says that such runs go through the desktop app or the command line. The hosted job service never routes a job to a provider and never takes a credential; a request that names a provider is refused there. ## When the queue is long A device's queue can take days, and nothing has to stay running for it. A job is written down before it is sent, in `provider-jobs` beside your registry (readable only by you, with no credential in it), and the provider's id beside that as soon as the provider gives one. ```sh norun=account wai-quantum run bell.qasm --provider lab --no-wait # sends it, and answers with its handle wai-quantum providers jobs # every job recorded here, and where it last stood wai-quantum providers collect pj-0123456789abcdef # asks, and seals its result when it has one wai-quantum providers cancel pj-0123456789abcdef ``` A plain `run` waits two hours and then stops waiting, with the job left at the provider and its handle on the screen. Only your asking cancels a job. If the command, the terminal or the machine stops, the job goes on, and `collect` picks it up: exit 0 done, 1 ended otherwise, 2 still at the provider, 75 could not ask, which says nothing of the job. An agent has the same in `get_provider_job`, `cancel_provider_job` and `list_provider_jobs`, and the job from `run_on_provider` is the same job. The counts are read against the program that was sent, and the receipt states that program and what the provider said when it was sent, whatever its calibration has become since. A request that did not complete may have reached the provider, so it is never sent again, since that could be a second bill: the record says so, and you look in the provider's own list. A provider you run as a local process has to keep its jobs itself, or they end with it. ## The protocol, and the reference as your template The [open provider protocol](../extensions/quantum-providers.md) is six operations as JSON messages, over HTTP or a local process: `describe` (native gates, connectivity, qubits, durations, a calibration snapshot id with optional per-qubit and per-pair errors, and the billing: `free`, a unit and its price, or not free with no price set, so that a job's cost is unknown and it runs only when you confirm it), `estimate`, `submit`, `status`, `result` (counts keyed by classical bits) and `cancel`. A program travels in your device's own gates, every angle an exact fraction of a turn, with the same program as OpenQASM 3 beside it. The reference provider is the protocol around WAI's exact simulator: ```sh runnable wai-quantum providers reference --stdio # on standard input and output wai-quantum providers reference --help-args # its device: qubits, basis, connectivity, a price, a readout error ``` ```sh norun=server wai-quantum providers reference --http 127.0.0.1:8090 # over HTTP, until stopped ``` To bring a device, copy [`src/reference.rs`](src/reference.rs): keep the message handling, the checks of a program against the device, and the two servers, and replace `Reference::simulate` with your device's run (and `describe` with your device's description). Then hold it to the vectors: ```sh norun=account wai-quantum providers add mine --kind process -- ./my-provider --stdio # your own provider's program wai-quantum providers test mine ``` A device whose gates are a phased `X` rotation, a `Z` rotation and `XX(θ)`, reached through a service with an interface of its own (its angles in units of π, say), is brought the same way. Its provider describes `"native_gates": ["prx", "rz", "xx"]` and is sent programs in `prxrzxx`, which it writes in the service's terms: `prx(t, p)` as the rotation by 2t and the phase 2p in units of π (0 to 1, and 0 to 2), `rz(t)` as 2t (less 2 past 1, where the service takes −1 to 1), and `xx(t)`, which is exp(−iπt·X⊗X), as 2t (0 to ½: every `cz` arrives as `xx(¼)`, so ½). Each angle is a dyadic fraction and stays exact as a number of that form. The provider turns off whatever the service would compile, remap or mitigate, and says what it sent in the answer's `execution`; and where the service deletes a result a day after it is read, it keeps each result as it reads it. A sign or a unit wrong in its `xx` leaves the probe's counts as they are: run a circuit whose outcome turns on the entangling gate's phase, as the certification's do, before trusting other results. A star device describes its `resonators` and the `moves` into them, and is sent `move` in `prxcz` or `rzsxxcz`. The first job on a new provider is the probe, an `X` on qubit 0 whose counts must all land on `…01`. It settles the bit order before any other result is trusted. ## Programs that call WebAssembly between gates A wasmQ envelope ([quantum-wasmq](../extensions/quantum-wasmq.md)) calls its WebAssembly modules between gates: a decoder between a syndrome and its correction, a planner between loading atoms and moving them. A provider's program is a fixed sequence of native gates measured at the end, so it cannot carry that, and `run ENVELOPE.wai --provider NAME` is refused; the envelope runs on this machine, its quantum part simulated. Nothing about bringing your own quantum changes for it. What a hardware run of such a program would need, and what replays from its record, is §7 of that extension. ## What the receipt proves, and what it does not A processor's result is labelled `measured`. A result from a provider's simulator or emulator is labelled `simulated`, since no device measured it, and `approximate` too when the provider says its simulator is. Its receipt binds the request, the provider's name, kind and protocol, the device and its provenance, the hash of the provider's own description, the calibration snapshot, the compiled program's text and its hash, the counts, the cost (the estimate, the charge, and whether you confirmed it), and the counts set beside the circuit's exact distribution with the distance between them. It also says two things a later receipt could not add: - **Where the counts come from** (`counts_source`): tallied from the device's records, one a shot (`shots`); the provider's own counts (`vendor_counts`); or rebuilt from probabilities (`probabilities`). Rebuilt counts are derived, not shot records. `native-turns` reads its job's shot records where the service lists them (as a noisy simulation does), else the service's own counts, and rebuilds them only from probabilities, as on an ideal simulator; it holds every form the job lists to the others, and the shots the service flags as leaked are counted as read, and their number sealed beside them (`leakage`). A result the service narrows to the qubits up to the last its gates touch is read with the qubits above it 0. A job the service finished whose result does not read (keys of no form it writes, forms that disagree, or a width it does not write) ends `failed`, with the reason, and is not asked again. `cloud-tasks` reads a task's rows and rebuilds only when its result has none. - **What was set at the provider** (`execution`), built from the very request the client sends: each of mitigation, twirling, dynamical decoupling, remapping and optimisation as `off`, `on`, or `default` when the request sets nothing for it, and whether the gates were to run as written. `sampler-v2` turns decoupling and twirling off; `native-turns` turns debiasing off, and sends its simulator, under a device's noise model, the job's seed, so a noisy simulation is the same at each run of that seed, and its note ends with what the service says it compiled (precision, gate basis, version) and whether the circuit it lists as compiled is the one sent; `cloud-tasks` puts a processor's gates in the service's verbatim box; `prx-circuits` pins the job to the calibration set it was compiled against and sends dynamical decoupling disabled, with the service's other modes as it wants them. A provider of the open protocol states its own (§5.5 of the protocol), and a wrapper around another service must. `wai-quantum verify` checks the seal and every rule a receipt keeps, and names each one it breaks (the protocol's §8.4); `--json` gives the verdict as data. It proves that your key signed this result for this request: what it says your host received from the provider and device it names, sent and checked is your host's word, and the counts are the provider's. It does not prove that the device ran that program, or ran anything. The counts are not reproducible by recomputation; the same job run again gives other counts. The distance from the exact distribution tells you how far they are from what the circuit gives: a distance well above what the shots alone leave is the device's or the simulator's error, or a program not run as sent. A receipt seals the provider's id for the job. For `cloud-tasks` that is the task's identifier, which names your account's number: sharing the receipt shares it. ## A first run on a phased-X circuit service's mock quantum computer A `prx-circuits` service may list, beside each quantum computer, a mock of it: the same name with `:mock` after it, a server with no quantum hardware that answers random bits. It checks the whole wire (your token, the device's description, the job, the cancel, the counts) before any processor runs anything. Its results are sealed as `simulated`, never as `measured`. 1. In the service's dashboard, generate your token. Generating it again makes the old one stop working. 2. Keep it where `wai-quantum` keeps every credential, read from standard input (paste it, then press Ctrl-D), never from the command line: ```sh norun=account wai-quantum providers add mock --kind prx-circuits --set qc=NAME:mock --credential-stdin ``` On macOS that is the keychain: an item whose service is `wai-quantum-provider` and whose account is the provider's name, here `mock`. On Linux it is the desktop secret service, and elsewhere a file only you can read; `wai-quantum providers list` says which. A token you keep already, under another item of the keychain, goes over without being shown: ```sh norun=account security find-generic-password -s YOUR-ITEM -w | wai-quantum providers add mock --kind prx-circuits --set qc=NAME:mock --credential-stdin ``` `WAI_QPU_PRX_TOKEN` is read instead when a provider names no credential. 3. Read the device, its calibration and its errors, with nothing sent: ```sh norun=account wai-quantum providers describe mock # qubits, gates, pairs, and the calibration set it is under wai-quantum providers test mock # the device and its calibration's errors; the programs only with --yes wai-quantum targets import --provider mock --name mock # the calibration's quality metrics, kept as a target wai-quantum run probe.qasm --provider mock --dry-run # the compile, the placement, the calibration it is pinned to ``` 4. Run the probe, then the conformance programs. The service sets no price through its interface, so each is confirmed with `--yes`; look at your account's usage before and after to see what the mock cost: ```sh norun=account wai-quantum run probe.qasm --provider mock --yes --json > probe.json && wai-quantum verify probe.json wai-quantum providers test mock --yes ``` Each job is sent pinned to the calibration set the device was read under, so the receipt's `calibration` is the set the service says it compiled the job against, and a run is refused rather than sealed when the service says it compiled against another. If the service recalibrated and no longer runs the pinned set, it fails the job (calibration set not found), its record stating no billed time, and the next run reads the current one. A service that publishes no quality metrics for its calibration leaves the compiler's own layout, and the plan's `placement` says so. A `sampler-v2` backend's calibration is its published properties, read after the device and named by their `last_update_date`: the job is placed by them, and once it has run the client reads the properties in force when it began running, so a job that ran under another calibration than the one it was placed by is refused rather than sealed. On a free plan the estimate says how many seconds of the plan's limit are left, and the receipt seals what the job was charged, in `qpu-seconds`. ## Connecting a real device: what is yours to do WAI ships no account and no key. To run on a real device: 1. Open an account with the provider, or set up your own device, and accept its terms. Any price, quota or free tier is between you and the provider. 2. Mint a credential (an API key or a token) in the provider's own console. 3. Add it: `wai-quantum providers add NAME --kind … --credential-stdin`, with the settings its kind takes (`crn` and `backend` for `sampler-v2`, and `basis=rzsxxczrxrzz` to compile to its `rx` and `rzz` too where the backend lists them; `qc` for `prx-circuits`, `backend` for `native-turns`, `region`, `device` and `bucket` for `cloud-tasks`), or `--kind http` for a provider of the open protocol. For `cloud-tasks`, first turn the service on in your account. The bucket must be in the device's region, its name must begin `amazon-braket-`, and its policy must let the service write to it. A name with a dot works: it is read by path. A region or a bucket that is not a name is refused when the provider is added, and this kind takes no `--endpoint`. On one of its simulators, `--set basis=gpizz` (or `prxcz`, or `prxrzxx` for a processor of `prx`, `xx` and `rz`) compiles to that processor basis, so you can check the gates before paying for the processor. 4. Run `wai-quantum providers describe NAME`, then `wai-quantum run probe.qasm --provider NAME --dry-run` to see the compile and the estimate, then the probe itself, confirmed with `--yes` if it is not free. Nothing in WAI's tests spends money: they run against the reference provider, whose price, when it has one, is a number in its configuration.