{"id":51148853,"url":"https://github.com/sopherapps/qpi","last_synced_at":"2026-06-26T04:30:40.113Z","repository":{"id":365435939,"uuid":"1262608990","full_name":"sopherapps/qpi","owner":"sopherapps","description":"A universal interface for a quantum computer","archived":false,"fork":false,"pushed_at":"2026-06-25T04:03:44.000Z","size":20622,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-25T05:05:30.900Z","etag":null,"topics":["quantum","quantum-computing"],"latest_commit_sha":null,"homepage":"https://sopherapps.github.io/qpi/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sopherapps.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-08T06:37:04.000Z","updated_at":"2026-06-25T04:02:55.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/sopherapps/qpi","commit_stats":null,"previous_names":["sopherapps/qpi"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/sopherapps/qpi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sopherapps%2Fqpi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sopherapps%2Fqpi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sopherapps%2Fqpi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sopherapps%2Fqpi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sopherapps","download_url":"https://codeload.github.com/sopherapps/qpi/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sopherapps%2Fqpi/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34803678,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-26T02:00:06.560Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["quantum","quantum-computing"],"created_at":"2026-06-26T04:30:39.321Z","updated_at":"2026-06-26T04:30:40.100Z","avatar_url":"https://github.com/sopherapps.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cpre align=\"center\"\u003e\n ██████╗ ██████╗ ██╗\n██╔═══██╗██╔══██╗██║\n██║   ██║██████╔╝██║\n██║▄▄ ██║██╔═══╝ ██║\n╚██████╔╝██║     ██║\n ╚══▀▀═╝ ╚═╝     ╚═╝\n\u003c/pre\u003e\n\n\u003ch1 align=\"center\"\u003eQPI: Quantum Processing Interface\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/sopherapps/qpi/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://github.com/sopherapps/qpi/actions/workflows/ci.yml/badge.svg\" alt=\"CI/CD Workflow\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://badge.fury.io/py/qpi-driver\"\u003e\u003cimg src=\"https://badge.fury.io/py/qpi-driver.svg\" alt=\"PyPI qpi-driver\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://badge.fury.io/py/qpi-client\"\u003e\u003cimg src=\"https://badge.fury.io/py/qpi-client.svg\" alt=\"PyPI qpi-client\"\u003e\u003c/a\u003e\n  \u003cimg src=\"https://img.shields.io/github/v/tag/sopherapps/qpi\" alt=\"GitHub Tag\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003e\u003ca href=\"https://sopherapps.github.io/qpi/\"\u003e📚 Read the Documentation\u003c/a\u003e\u003c/strong\u003e | \u003cstrong\u003e\u003ca href=\"https://qpi.sopherapps.se\"\u003e🚀 Live Demo\u003c/a\u003e\u003c/strong\u003e\n\u003c/p\u003e\n\n## What is QPI?\n\nQPI is a distributed quantum control stack architecture designed to manage, schedule, and execute quantum circuits across multiple Quantum Processing Units (QPUs). \n\nIt consists of three main components:\n1. **Server (`qpi-ui`)**: A Go-based server that manages the job queue, user time-slot bookings, and dispatches jobs to available QPUs. It includes a built-in React web dashboard.\n2. **QPU Driver (`qpi-driver`)**: A Python daemon that runs alongside the actual quantum hardware (or simulator), executing incoming jobs from the Server and returning results.\n3. **Clients**: SDKs (Python, Go, JS) for end-users to submit OpenQASM (or Qiskit) quantum jobs over the network.\n\n```mermaid\nflowchart LR\n    User[Clients] --\u003e|Submit Quantum Jobs| Server\n    Server --\u003e|Dispatch Jobs| Driver1[QPI Driver]\n    Server --\u003e|Dispatch Jobs| Driver2[QPI Driver]\n    Driver1 --\u003e|Control| Hardware1[Physical QPU]\n    Driver2 --\u003e|Control| Hardware2[Simulated QPU]\n```\n\n## Quick Start\n\n### Prerequisites\n* **Go**: `\u003e= 1.25` (tested up to `1.26`)\n* **Python**: `~= 3.12`\n* **Nodejs**: `\u003e= 20.x` (tested up to `22.x`)\n\n### 1. Start the Server\n\nCompile and run the PocketBase Go server (this automatically builds the React dashboard if you use `make`):\n\n```bash\nmake build\n./bin/qpi serve\n```\n*The dashboard is now available at `http://127.0.0.1:8090/dashboard/`. You can log in using the PocketBase Admin UI at `http://127.0.0.1:8090/_/` to create your initial superuser account.*\n\n### 2. Connect a QPU Driver\nOpen a new terminal. In the dashboard, navigate to **QPU Registry** and register a new QPU. You will receive an access token and a `ca-fingerprint`. Use them to start the Python driver (using the `mock` executor for local testing):\n\n```bash\n# Install the python driver CLI (using uv for speed)\nuv tool install ./qpi-driver[cli]\n\n# Start the driver daemon\nqpi-driver start --qpi-addr http://127.0.0.1:8090                  --token \"\u003cYOUR_ACCESS_TOKEN\u003e\"                  --ca-fingerprint \"\u003cYOUR_CA_FINGERPRINT\u003e\"                  --name \"local_mock_qpu\"                  --executor \"mock\"\n```\n*(Note: For production deployments, the dashboard will provide a convenient systemd script to install this driver as a background service.)*\n\n### 3. Submit a Job\nUsers can now submit quantum jobs via the Python client!\n```bash\npip install qpi-client\n```\n```python\nfrom qpi_client import QPIClient\n\nclient = QPIClient(\"http://127.0.0.1:8090\", api_token=\"\u003cYOUR_USER_API_TOKEN\u003e\")\njob = client.submit_job(circuits=[{\"circuit\": \"OPENQASM 2.0; ...\"}], shots=100)\nprint(job)\n```\n\n---\n\n## Architecture Deep Dive\n\nThe architecture consists of four primary components under the hood:\n1. **PocketBase Go Server (`qpi-ui/main.go`):** Extends PocketBase with Go, handling job queues, session-based bookings, and real-time job dispatching. Actively listens for LAN connections on dynamically allocated network ports.\n2. **React SPA Dashboard (`qpi-ui/internal/dashboard`):** Single-page application built with Vite, React 19, TypeScript, and Tailwind CSS. It is served directly from the server (via `//go:embed`) at `/dashboard/` for viewing jobs, allocating QPU time, scheduling announcements, managing bookings, and observing calibration telemetry.\n3. **Python QPU Driver (`qpi-driver`):** Runs on isolated hardware nodes controlling the QPU. Uses Python's `multiprocessing` library to isolate network handling, quantum circuit compilation/simulation, and translation into separate processes.\n4. **QPI Clients (Python, JavaScript, Go):** SDKs for submitting jobs to the quantum computer using OpenQASM specification (and Qiskit circuits if one uses the Python client)\n\nTo optimize performance and simplify communication over multiprocessing queues, the worker process executes the quantum job, processes the resulting `xarray` dataset into a Qiskit-compatible result dictionary using the executor's `process_result()` method, and directly sends the results via the queue to the result sender process. This removes file-system serialization overhead.\n\n```mermaid\ngraph TD\n    subgraph pocketbase [PocketBase Go Server]\n        PB[PocketBase API / DB]\n        Dispatcher[NNG PUSH Dispatcher]\n        Listener[NNG PULL Listener]\n        Recovery[Recovery Engine]\n    end\n\n    subgraph python_driver [Python QPU Driver Package]\n        MainProc[Main Process: NNG PULL]\n        Worker[Worker Process: Executor]\n        ResultSender[Result Sender Process: NNG PUSH]\n    end\n\n    %% Client Interactions\n    User[Client] --\u003e|Submit Job| PB\n    \n    %% Handshake \u0026 Connection\n    MainProc --\u003e|HTTP POST /api/op/qpus/connect| PB\n    PB --\u003e|Assigned Ports \u0026 JWT| MainProc\n    \n    %% Multiprocessing Communication\n    Dispatcher --\u003e|NNG PUSH Command Port| MainProc\n    MainProc --\u003e|multiprocessing.Queue Job Payload| Worker\n    Worker --\u003e|1. Executes \u0026 Processes Results| Worker\n    Worker --\u003e|2. Queue Qiskit-format Dict| ResultSender\n    ResultSender --\u003e|3. NNG PUSH Result Port| Listener\n```\n\n### Key Server Features\n* **Session-Based Booking with Opportunistic FIFO:** Dispatches jobs prioritizing users who have booked the current time slot. Fallback mechanism allows other users' pending jobs to execute if the slot booker is idle.\n* **Auto-Schema Migration \u0026 Port Allocation:** Automatically creates required database collections (`qpus`, `time_slots`, `quantum_jobs`, `qpu_time_requests`, `notifications`) and dynamically allocates race-free TCP ports for registered QPUs.\n* **Stale Job Recovery:** A background ticking routine monitors running jobs and resets them to `pending` if their driver hangs or disconnects (timeout default: 20 seconds).\n* **Admin Notifications:** Broadcast or targeted notifications with time-window visibility and per-user dismiss support. Only superusers can create, update, or delete notifications. Authenticated users see only notifications relevant to them (broadcast or targeted) that are within their active time window and not dismissed.\n\n### Server Configuration Options\n\nThe Go server can be configured via CLI flags, environment variables, or a configuration file (JSON or YAML, specified via `--config-file` or `QPI_CONFIG_FILE`). The precedence hierarchy is: CLI Flag \u003e Env Var \u003e Config File \u003e Default.\n\n| CLI Option | Environment Variable | Default | Description |\n|---|---|---|---|\n| `--config-file` | `QPI_CONFIG_FILE` | `qpi.config.yml` | Path to JSON or YAML configuration file. |\n| `--domain` | `QPI_DOMAIN` | | The domain name this server is running on. |\n| `--server-port` | `QPI_SERVER_PORT` | `8090` | The port this server should run on. |\n| `--tls-ca-cert-file` | `QPI_TLS_CA_CERT_FILE` | `.qpi.ca.pem` | Path to TLS root CA certificate file. |\n| `--tls-ca-key-file` | `QPI_TLS_CA_KEY_FILE` | `.qpi.ca.key` | Path to TLS root CA key file. |\n| `--tls-cert-file` | `QPI_TLS_CERT_FILE` | `.qpi.cert.pem` | Path to TLS certificate file. |\n| `--tls-key-file` | `QPI_TLS_KEY_FILE` | `.qpi.key` | Path to TLS key file. |\n| `--qpus-collection` | `QPI_QPUS_COLLECTION` | `qpus` | Collection name for QPUs. |\n| `--timeslots-collection` | `QPI_TIMESLOTS_COLLECTION` | `time_slots` | Collection name for Reservation Time Slots. |\n| `--jobs-collection` | `QPI_JOBS_COLLECTION` | `quantum_jobs` | Collection name for Quantum Jobs. |\n| `--api-tokens-collection` | `QPI_API_TOKENS_COLLECTION` | `api_tokens` | Collection name for API Tokens. |\n| `--notifications-collection` | `QPI_NOTIFICATIONS_COLLECTION` | `notifications` | Collection name for Notifications. |\n| `--qpu-time-requests-collection` | `QPI_QPU_TIME_REQUESTS_COLLECTION` | `qpu_time_requests` | Collection name for QPU Time Requests. |\n| `--idle-threshold` | `QPI_IDLE_THRESHOLD` | `5s` | Time to wait before running fallback FIFO jobs. |\n| `--recovery-interval` | `QPI_RECOVERY_INTERVAL` | `10s` | Interval for resetting hung/stale jobs. |\n| `--job-timeout` | `QPI_JOB_TIMEOUT` | `20s` | Max execution time before a job is reset. |\n| `--dispatch-poll-interval` | `QPI_DISPATCH_POLL_INTERVAL` | `1s` | Frequency of checking queue for pending jobs. |\n| `--port-range-start` | `QPI_PORT_RANGE_START` | `6000` | NNG port range start. |\n| `--port-range-end` | `QPI_PORT_RANGE_END` | `7000` | NNG port range end. |\n| `--disable-email-password-auth` | `QPI_DISABLE_EMAIL_PASSWORD_AUTH` | `false` | Disable email/password login on the users collection. |\n| `--oauth2-providers` | `QPI_OAUTH2_PROVIDERS` | | JSON string representing OAuth2 providers config. |\n\n---\n\n## Server API \u0026 Collections\n\nThe server exposes both **custom HTTP routes** and **PocketBase collection endpoints** for client interaction.\n\n### Custom Routes\n\n| Method | Route | Auth | Description |\n|---|---|---|---|\n| `POST` | `/api/op/qpus/create` | Superuser | Creates a new QPU record and returns the generated access token. |\n| `POST` | `/api/op/qpus/connect` | Access token | Connects a QPU driver and returns assigned NNG ports + JWT. |\n| `POST` | `/api/op/qpu/toggle` | Superuser | Enables or disables a QPU by name. |\n| `GET`  | `/api/op/version` | Superuser | Retrieves the application's current version. |\n| `POST` | `/api/jobs` | Authenticated | Submits a new quantum job. |\n| `GET`  | `/api/jobs` | Authenticated | Lists jobs for the authenticated user. |\n| `GET`  | `/api/jobs/{id}` | Authenticated | Retrieves a specific job. |\n| `POST` | `/api/jobs/{id}/cancel` | Authenticated | Cancels a pending job. |\n| `GET`  | `/api/qpus` | Public | Lists all registered QPUs. |\n| `GET`  | `/api/qpus/{name}` | Public | Retrieves a specific QPU. |\n| `POST` | `/api/tokens` | Authenticated | Creates a new API token. |\n| `GET`  | `/api/tokens` | Authenticated | Lists API tokens for the authenticated user. |\n| `GET`  | `/api/tokens/{id}` | Authenticated | Retrieves a specific API token. |\n| `PATCH`| `/api/tokens/{id}` | Authenticated | Updates an API token (name/expiry). |\n| `DELETE`| `/api/tokens/{id}` | Authenticated | Deletes an API token. |\n| `PATCH`| `/api/admin/users/{id}` | Superuser | Updates `qpu_seconds` or `api_tokens` on any user. |\n| `POST` | `/api/notifications/{id}/dismiss` | Authenticated | Dismisses a notification for the current user. |\n\n### PocketBase Collections\n\nAll collection endpoints follow the standard PocketBase REST pattern: `/api/collections/{name}/records`.\n\n| Collection | Auth Rules | Description |\n|---|---|---|\n| `users` | Owner-only | Authenticated users with `qpu_seconds` balance. |\n| `qpus` | Public read; superuser CUD | QPU hardware records with status, ports, and config. |\n| `time_slots` | Owner-only CRUD; superuser bypass | Calendar reservations linked to `users`. |\n| `quantum_jobs` | Public read; authenticated create | Job queue with payload, status, and results. |\n| `qpu_time_requests` | Owner-only CRUD; superuser update | Requests for additional QPU time (pending/approved/rejected). |\n| `notifications` | Authenticated read (visibility-filtered); superuser CUD | Admin announcements with broadcast/targeted reach, time windows, and dismiss tracking. |\n\n---\n\n## Python Driver Package (`qpi-driver`)\n\nThe Python driver has been modularized as a standard package structure inside the `qpi-driver/` directory.\n\n### Extensible Executors\nThe package introduces an abstract base `Executor` class (`base.py`) which library users can extend to implement custom hardware/simulator backends:\n\n```python\nfrom qpi_driver import Executor, JobPayload\nimport xarray as xr\n\nclass MyCustomExecutor(Executor):\n    def execute(self, payload: JobPayload) -\u003e xr.Dataset:\n        # Implement custom control/simulation logic here\n        ...\n        return xr.Dataset(...)\n\n    def process_result(self, dataset: xr.Dataset, job_id: str) -\u003e dict:\n        # Convert dataset to Qiskit-compatible results dict\n        ...\n        return {\"counts\": {...}, \"shots\": ...}\n```\n\nBuilt-in executors include:\n* `MockExecutor` (`mock`): Simulates quantum circuits using Qiskit's `BasicSimulator`.\n* `QiskitAerExecutor` (`qiskit_aer`): Runs quantum circuit simulations using `qiskit-aer`.\n* `QuantifyExecutor` (`quantify`): Executes quantum circuits using `quantify-scheduler` and a Qblox cluster compiler.\n* `QbloxExecutor` (`qblox`): Executes quantum circuits using `qblox-scheduler` and a Qblox cluster compiler.\n* Placeholder executors: `PrestoExecutor` (`presto`).\n\n### Running the Driver for Each Executor\n\nDepending on the backend you wish to run, start the driver using the `--executor` / `-e` option.\n\n#### 1. Mock Executor\nRuns simulated measurements without external physics dependencies.\n```bash\n# Install the package with cli extra\npip install ./qpi-driver[cli]\n\n# Start the driver using mock executor\nqpi-driver start --token \"my-super-secret-token-12345\" --ca-fingerprint \"\u003cfingerprint\u003e\" --executor \"mock\"\n```\n\n#### 2. Qiskit Aer Simulator\nRuns realistic circuit simulations using Qiskit Aer.\n```bash\n# Install the package with simulator extras\npip install ./qpi-driver[cli,aer]\n\n# Start the driver using qiskit_aer executor\nqpi-driver start --token \"my-super-secret-token-12345\" --ca-fingerprint \"\u003cfingerprint\u003e\" --executor \"qiskit_aer\"\n```\n\n#### 3. Quantify Executor (Qblox Cluster)\nCompiles and runs circuits using `quantify-scheduler`.\n* **Dummy/Simulation Mode**: Compiles the schedule and executes it against a dummy local Qblox instrument cluster.\n  ```bash\n  # Install the package with quantify extra\n  pip install ./qpi-driver[cli,quantify]\n\n  # Start driver in dummy mode\n  qpi-driver start --token \"my-super-secret-token-12345\" --ca-fingerprint \"\u003cfingerprint\u003e\" --executor \"quantify\" --is-dummy --quantify-hardware-config quantify.hardware.example.json --quantify-device-config quantify.device.example.json\n  ```\n* **Real Hardware Mode**: Compiles and deploys to actual physical Qblox hardware.\n  ```bash\n  # Start driver with a hardware config file\n  qpi-driver start --token \"my-super-secret-token-12345\" --ca-fingerprint \"\u003cfingerprint\u003e\" --executor \"quantify\" --quantify-hardware-config quantify.hardware.example.json --quantify-device-config quantify.device.example.json\n  ```\n\n#### 4. Qblox Executor (Qblox Cluster)\nCompiles and runs circuits using `qblox-scheduler`.\n* **Dummy/Simulation Mode**: Compiles the schedule and executes it against a dummy local Qblox instrument cluster.\n  ```bash\n  # Install the package with qblox extra\n  pip install ./qpi-driver[cli,qblox]\n\n  # Start driver in dummy mode\n  qpi-driver start --token \"my-super-secret-token-12345\" --ca-fingerprint \"\u003cfingerprint\u003e\" --executor \"qblox\" --is-dummy --quantify-hardware-config quantify.hardware.example.json --quantify-device-config quantify.device.example.json\n  ```\n* **Real Hardware Mode**: Compiles and deploys to actual physical Qblox hardware.\n  ```bash\n  # Start driver with a hardware config file\n  qpi-driver start --token \"my-super-secret-token-12345\" --ca-fingerprint \"\u003cfingerprint\u003e\" --executor \"qblox\" --quantify-hardware-config quantify.hardware.example.json --quantify-device-config quantify.device.example.json\n  ```\n\n### CLI Usage\nThe package exposes a command-line interface via `typer`. Options can be passed as CLI arguments/flags or will automatically fall back to their corresponding environment variables.\n\nCommon options:\n* `-a`, `--qpi-addr`: Full URL of the QPI server (env: `QPI_ADDR`, default: `http://127.0.0.1:8090`).\n* `-t`, `--token`: Access token for the QPU (env: `QPI_ACCESS_TOKEN`, required).\n* `-n`, `--name`: Human-readable name for this QPU (env: `QPU_NAME`, default: `qpu_sim_01`).\n* `-e`, `--executor`: Which executor backend to use (env: `DRIVER_BACKEND`, default: `mock`).\n* `-d`, `--data-dir`: Directory for intermediate NetCDF datasets (env: `QPI_DATA_DIR`, default: `bin/data`).\n* `--is-dummy`: Enable/disable dummy/simulation mode (default: `false`).\n* `--quantify-hardware-config`: Path to the quantify's hardware-layer config file (JSON/YAML) for the RF control instruments (env: `QPI_QUANTIFY_HARDWARE_CONFIG`, default: `quantify.hardware.json`).\n* `--quantify-device-config`: Path to the quantify's device-layer config file (JSON/YAML) for the quantum chip (env: `QPI_QUANTIFY_DEVICE_CONFIG`, default: `quantify.device.yml`).\n* `--job-timeout`: the number of seconds to wait for results of the job before timing out (env: `QPI_JOB_TIMEOUT`, default: 10)\n* `-d`, `--data-dir`: the path to the folder where experiment data is to be saved (env: `QPI_DATA_DIR`, default: `./bin/data`)\n* `--ca-file`: the path to the downloaded Certificate Authority (CA) root certificate of the server (env: `QPI_CA_FILE`, default: `./bin/qpi.ca.pem`)\n* `--ca-fingerprint`: the fingerprint to verify the authenticity the automatically downloaded root CA certificate of the QPI server. You get it from the server after creating the QPU in the dashboard (env: `QPI_CA_FINGERPRINT`, required: true)\n\n---\n\n## Developer Lifecycle (Makefile)\n\nA `Makefile` is provided in the root directory to simplify development, linting, formatting, and testing.\n\n```bash\n# Build Go binary (automatically compiles the React dashboard) and sync Python driver package\nmake build\n\n# Run all unit tests and end-to-end integration tests (clients and driver)\nmake test\n\n# Run only Python driver unit tests\nmake test-py\n\n# Run dashboard Cypress E2E tests (PocketBase + Driver + Cypress)\nmake test-e2e-dashboard\n\n# Run linters across Go, Python driver, JS client, and dashboard codebases\nmake lint\n\n# Automatically format all source files in the repository\nmake format\n\n# Clean database, build artifacts, cache files\nmake clean\n```\n\n## TODOs\n\n- [ ] Add a way of translating the configuration files (calib seed etc.) of tergite to the quantify.device.yml of this one\n- [ ] Dismissed notices got from the header and the notice banner disappear only on client but reappear on refresh. (Is this a regression? Didn't the tests catch it?)\n- [ ] Jobs remain running but never complete/fail (maybe could it be disconnected drivers when the QPI server restarts?)\n\n## License\n\nCopyright (c) 2026 [Martin Ahindura](https://github.com/Tinitto)\n\nLicensed under the [MIT License](https://github.com/sopherapps/qpi/blob/main/LICENSE)\n\n\n## Gratitude\n\n\u003e \"What is more, I consider everything a loss because of the surpassing worth of knowing Christ Jesus\n\u003e my Lord, for whose sake I have lost all things\"\n\u003e\n\u003e -- Philippians 3: 8\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsopherapps%2Fqpi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsopherapps%2Fqpi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsopherapps%2Fqpi/lists"}