Delta Quantum

Overview

Delta Quantum is an agent-operated workspace for quantum and classical computation. It has three parts that deploy separately: a Next.js frontend, a FastAPI service with a dedicated worker (Python, Qiskit, Qiskit Aer, PostgreSQL), and two Solidity contracts for Robinhood Chain.

Quantum computation runs offchain on the local statevector simulator or, when configured, on IBM Quantum hardware through the user's own credentials. The assistant, Delta Agent, is a language model that plans and explains; it is not a quantum computer and it never executes anything on its own. Robinhood Chain is used only for optional execution-record commitments and, when explicitly enabled and deployed, prepaid platform jobs.

Setup

Local run without Docker (Windows, macOS, Linux). SQLite is the default database for a single machine; PostgreSQL via DATABASE_URL for anything shared.

# API + worker
cd api
uv venv .venv --python 3.12 && uv pip install -r requirements.txt
cp .env.example .env            # leave keys empty for a local, credential-free run
.venv/Scripts/python -m uvicorn delta_api.main:app --port 24301
.venv/Scripts/python -m delta_api.worker          # second terminal

# Web
cd web
pnpm install
cp .env.local.example .env.local
pnpm dev                                           # http://localhost:24300

With Docker Compose (PostgreSQL + API + worker; the web app runs with pnpm dev or its own Dockerfile):

docker compose up --build        # api on :24301, postgres on :5432
docker compose exec api alembic upgrade head

Migrations live in api/alembic. For SQLite the API creates missing tables at startup; for PostgreSQL run alembic upgrade head before the first start.

Backend types

  • local_simulator: Qiskit Aer statevector. Produces exact Born probabilities of the measured register and finite-shot sampled counts with an explicit seed (generated and recorded when omitted). Free, isolated in a child process with a wall-clock timeout, limited to the configured qubit, gate, shot and memory budgets.
  • ibm_hardware: qiskit-ibm-runtime SamplerV2 on an IBM Quantum backend. Enabled only when QISKIT_IBM_TOKEN and QISKIT_IBM_INSTANCE (an instance CRN) are configured on the API and worker, the instance answers, the selected backend is listed, and the user ticks the per-job approval. Results are sampled counts with device noise; exact probabilities are not available; no seed applies. Queue and cost estimates are reported as unavailable because the adapter does not receive them; the provider bills the credential owner and no hard monetary cap can be enforced. Max-Cut (an optimizer loop) is simulator-only.

A simulator job is never labelled hardware, and simulator results are never substituted for hardware results. Cancelling a hardware job forwards a cancel request; the provider decides, and the page keeps showing the provider's own status.

Circuit schema

Every job carries a validated structured circuit; the service never parses or executes uploaded code.

{
  "version": 1,
  "num_qubits": 2,                       // 1..MAX_QUBITS (default 8)
  "gates": [
    {"gate": "h",  "qubits": [0]},
    {"gate": "rz", "qubits": [0], "theta": 1.5707963},   // rx/ry/rz need a finite theta, |theta| <= 8*pi
    {"gate": "cx", "qubits": [0, 1]},                    // [control, target], must differ
    {"gate": "measure", "qubits": [0, 1]}                // terminal: a measured qubit cannot be touched again
  ]
}

Without a measure operation every qubit is measured at the end. Bitstrings follow the Qiskit convention: the rightmost character is classical bit 0, i.e. the first measured qubit. OpenQASM 2.0 export is available for every job (GET /jobs/{id}/circuit.qasm); template circuits that use multi-controlled gates are transpiled into the h x y z rx ry rz cx basis first.

Experiments

  • Bell state: H, CX. Ideal 00/11 at 1/2 each. The result shows the exact distribution, the sampled counts, the mass on ideal outcomes and the total variation distance.
  • GHZ state: 2..MAX_QUBITS qubits, CX chain. Ideal all-zeros / all-ones.
  • Small Grover search: 2..4 qubits (4..16 states), 1..4 marked states, optional iteration count (defaults to the theoretical optimum). Reports the analytic success probability next to the measured one. Educational only.
  • Max-Cut: weighted graph of up to 8 nodes / 16 edges, QAOA with p ≤ 2 optimized by COBYLA on the exact statevector expectation, final state sampled with the configured shots, compared with an exhaustive classical solver that is exact for every accepted graph. The result lists best cut, objective, runtime, circuit evaluations, backend, parameters and the baseline, and states plainly which method was faster or better.

Delta Agent

Delta Agent calls the Claude API with server-side credentials (ANTHROPIC_API_KEY). It has one tool, propose_plan, with a strict JSON schema. A proposal is validated against the same Pydantic schemas and limits as a manual submission and shown to the user with backend, parameters and expected resources; the user loads it into the workspace and presses Run. When a job id is attached, the job's stored spec and result are given to the model so explanations use actual data.

The agent cannot execute generated code, sign transactions, transfer funds, change limits, or submit hardware jobs. If no key is configured the chat panel says planning is unavailable; nothing is faked.

Jobs and states

Compute status: draft → queued → running → completed | failed | cancelled, with cancel_requested as the in-flight cancel state. Three more states are tracked independently: provider_state (the provider's own status string), payment_state (not_required unless escrow is enabled) and receipt_state (none, pending, confirmed, failed). A completed job can exist without a receipt.

The worker claims one queued job at a time with an atomic update, runs it in an isolated child process (restarted after timeouts or crashes), and records resource usage, software versions, result, error and a manifest. Status updates reach the UI over server-sent events (GET /jobs/{id}/events) with polling as a fallback. No progress percentages are invented. Submissions accept an Idempotency-Key header: the same key with the same body returns the original job; a different body is a 409.

Jobs are owned by the session (a guest token in this browser or a wallet-linked session via Sign-In with Ethereum: domain-bound message, one-time nonce, five-minute expiry). Every job endpoint checks ownership and answers 404 for jobs of other users.

Receipts and manifests

Canonicalization dq-canonical-json-v1: keys sorted, no whitespace, UTF-8, NaN rejected, Python json number rendering. Two commitments:

job_commitment    = 0x + sha256(canonical_json({commitment_version, kind, spec, backend_type, backend_name, shots, seed}))
result_commitment = 0x + sha256(manifest_bytes)  // the exact bytes served by GET /jobs/{id}/manifest.json

The manifest (manifest_version 1) holds job id, kind, job commitment, backend identity and provider job id, timestamps, the full result and software versions. It never contains prompts, credentials or personal information. Verification is byte-exact: hash the downloaded file and compare, in the browser (Web Crypto) or with any sha256 tool.

ExecutionRecordRegistry.record(jobCommitment, resultCommitment) stores both hashes with the submitter and the block timestamp and emits ExecutionRecorded. The job page submits the transaction from the connected wallet, stores the hash immediately, shows pending/confirmed/failed, links the explorer and, when CHAIN_RPC_URL and REGISTRY_ADDRESS are configured on the API, verifies the event server-side; otherwise the browser read is labelled as such.

A receipt records a commitment to this result. It does not independently prove correct quantum execution.

Prepaid escrow (feature-gated)

JobEscrow holds a fixed-price deposit per job commitment. A quote signed by the operator (EIP-712: jobCommitment, asset, amount, expiry, settlementDeadline, payer) is funded once in an allowlisted asset (native ETH or an ERC-20 with received-amount checks). Only the configured operator can settle, once, before the deadline, by posting a result commitment; anyone can refund the payer after the deadline if the job was not settled; the operator may refund early. A refund never stops provider computation.

Trust model: the operator decides settlement and the recorded commitment does not prove correctness. Paid execution stays off until ESCROW_ENABLED=true, ESCROW_ADDRESS and NEXT_PUBLIC_ESCROW_ADDRESS point at a reviewed deployment; until then payments show as unavailable and free local simulation keeps working. There is no project token, staking or yield.

Limits and honesty rules

Defaults (environment-configurable): 8 qubits, 256 gates per custom circuit, 8,192 simulator shots (4,096 on hardware), 30 s wall clock, 512 MB memory (enforced through OS limits where available, bounded by the qubit cap elsewhere), graphs up to 8 nodes / 16 edges, QAOA p ≤ 2 with ≤ 200 optimizer iterations, Grover ≤ 4 qubits / 4 iterations, 60 jobs per hour, 5 hardware jobs per day, 60 agent requests per hour.

  • Only live data is called live; unavailable things say Not configured, Unavailable or No jobs yet.
  • No quantum advantage claims; toy experiments are reported as measured, including classical wins.
  • Exact probabilities and finite-shot counts are shown as distinct quantities.
  • Seeded reproducibility is claimed for the simulator only.
  • No invented partnerships, benchmarks, customer numbers, capacity, queue times or prices.

Token

$DELTAQ is the community token of Delta Quantum on Robinhood Chain. Its contract address is shown on the landing page only after it has been published; until then the block says Soon. The address is written by pnpm token:ca 0x…, which verifies the ERC-20 on-chain (chain id, code, name, symbol, decimals, total supply) before writing config/token.json and redeploying; pnpm token:ca SOON reverts it. Announcements come from @DeltaQuantumRH only. The token has no role in the compute pipeline: simulations, hardware jobs, receipts and the escrow never depend on it, and nothing here promises yield or returns.

Architecture

web/        Next.js 15 + TypeScript + Tailwind + React Three Fiber + wagmi/viem   (port 24300)
api/        FastAPI + SQLAlchemy + Alembic + Pydantic                              (port 24301)
            delta_api/quantum   schema -> Qiskit circuit, Aer simulation, templates, QAOA
            delta_api/providers local simulator status, IBM Quantum adapter
            delta_api/worker    queue consumer, isolated executor, provider polling
            delta_api/agent     Claude planner with a strict tool schema
contracts/  Foundry: ExecutionRecordRegistry.sol, JobEscrow.sol, tests, deploy script

Long-running work never runs inside frontend request handlers. The API only validates and enqueues; the worker executes. Frontend, API and worker deploy separately; docker-compose.yml wires PostgreSQL, API and worker for local use.

Deployment

# Contracts (testnet 46630 first; values verified at docs.robinhood.com/chain/connecting)
cd contracts && cp .env.example .env     # PRIVATE_KEY of a funded testnet account
forge test
forge script script/Deploy.s.sol --rpc-url robinhood_testnet --broadcast
# verify (Sourcify, works for Robinhood Chain explorers)
forge verify-contract <address> src/ExecutionRecordRegistry.sol:ExecutionRecordRegistry --chain-id 46630 --verifier sourcify

# then configure
api/.env:        CHAIN_ID=46630  CHAIN_RPC_URL=https://rpc.testnet.chain.robinhood.com  REGISTRY_ADDRESS=0x...
web/.env.local:  NEXT_PUBLIC_CHAIN_ID=46630  NEXT_PUBLIC_REGISTRY_ADDRESS=0x...

Web: pnpm build and host on any Node platform with NEXT_PUBLIC_API_URL set to the API origin. API and worker: the api/Dockerfile runs either process (command uvicorn … or python -m delta_api.worker) against the same DATABASE_URL. Set CORS_ORIGINS to the web origin and SIWE_DOMAIN / SIWE_URI to the web host so wallet sign-in messages are domain-bound.

Open the workspace →