> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.conductorquantum.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.conductorquantum.com/_mcp/server.

# Overview

[Stanza](https://github.com/conductorquantum/stanza) is an open-source Python framework for tuning up quantum devices. We built it while automating the tune-up of 128 [double quantum dots](/control/stanza/core-concepts/routines/dqd-search), designing it to be easy to use while solving the real challenges we hit along the way. We open-sourced it so the community can use and build upon it too.

## What is Stanza?

Stanza helps you characterize and calibrate quantum devices by providing:

* **YAML-based device configuration** - Define your device topology once, reuse it everywhere
* **Decorator-based routines** - Write tune-up sequences as simple Python functions
* **Automatic logging** - Sessions and data are logged automatically in HDF5 or JSONL formats
* **Resource management** - Access devices, loggers, and instruments through a unified context
* **Result chaining** - Build complex workflows by passing results between routines
* **Type safety** - Built on Pydantic for configuration validation and type checking

## Architecture

Stanza separates concerns into three layers:

### 1. Configuration Layer (YAML)

Define your device topology, routine parameters, and instrument connections:

```yaml
name: "My Quantum Device"

gates:
  G1: {type: BARRIER, control_channel: 1, v_lower_bound: -3.0, v_upper_bound: 3.0}
  G2: {type: PLUNGER, control_channel: 2, v_lower_bound: -3.0, v_upper_bound: 3.0}

contacts:
  DRAIN: {type: DRAIN, control_channel: 4, measure_channel: 2, v_lower_bound: -3.0, v_upper_bound: 3.0}

routines:
  - name: sweep_barrier
    parameters:
      gate: G1
      v_start: -2.0
      v_stop: 0.0
      n_points: 100

instruments:
  - name: qdac2-control
    type: CONTROL
    driver: qdac2
    ip_addr: 127.0.0.1
    slew_rate: 1.0
```

### 2. Routine Layer (Python)

Implement your tune-up logic as decorated functions:

```python
import numpy as np
from stanza.routines import routine

@routine
def sweep_barrier(ctx, gate, v_start, v_stop, n_points, contact="DRAIN"):
    """Sweep a barrier gate and measure current."""
    device = ctx.resources.device
    voltages = np.linspace(v_start, v_stop, n_points)
    v_data, i_data = device.sweep_1d(gate, voltages.tolist(), contact)
    return {"voltages": v_data, "currents": i_data}
```

### 3. Execution Layer (Runner)

Orchestrate resources, merge parameters, and execute routines:

```python
from stanza.routines import RoutineRunner
from stanza.models import DeviceConfig

# Load configuration
config = DeviceConfig.from_yaml("device.yaml")

# Create runner - automatically loads routine parameters from config
runner = RoutineRunner(configs=[config])

# Execute with config parameters
result = runner.run("sweep_barrier")

# Or override specific parameters at runtime
result = runner.run("sweep_barrier", gate="G2", n_points=50)
```

## Key Features

### Device Abstraction

Access quantum devices through a unified interface:

```python
# Jump to voltages
device.jump({"G1": -1.5, "G2": -0.8})

# Measure current
current = device.measure("DRAIN")

# Check current voltage
voltage = device.check("G1")

# Sweep operations
v_data, i_data = device.sweep_1d("G1", voltages, "DRAIN")
v_data, i_data = device.sweep_2d("G1", v1, "G2", v2, "DRAIN")
```

### Automatic Logging

Data is logged automatically when you use a `RoutineRunner`:

```python
@routine
def my_routine(ctx, session=None):
    device = ctx.resources.device

    # Sweeps are automatically logged if session is provided
    v, i = device.sweep_1d("G1", voltages, "DRAIN", session=session)

    # Manual logging also available
    if session:
        session.log_measurement("gate_voltages", {"G1": v, "currents": i})

    return {"voltages": v, "currents": i}
```

### Result Chaining

Build multi-step workflows by accessing results from previous routines:

```python
@routine
def sweep_gate(ctx, gate):
    device = ctx.resources.device
    voltages = np.linspace(-2, 0, 100)
    v_data, i_data = device.sweep_1d(gate, voltages.tolist(), "DRAIN")
    return {"voltages": v_data, "currents": i_data}

@routine
def analyze_sweep(ctx):
    # Get results from previous routine
    data = ctx.results.get("sweep_gate")
    currents = np.array(data["currents"])

    return {
        "max_current": float(np.max(np.abs(currents))),
        "mean_current": float(np.mean(np.abs(currents)))
    }
```

### Nested Routines

Organize complex tune-up sequences hierarchically:

```yaml
routines:
  - name: full_characterization
    parameters:
      threshold: 50e6
    routines:
      - name: leakage_test
        parameters:
          gate: G1
      - name: accumulation_test
        parameters:
          gate: G2
```

Execute all nested routines with a single call:

```python
runner.run_all(parent_routine="full_characterization")
```

## Supported Instruments

Stanza includes drivers for:

* **QDAC-II** (QDevil) - Control and measurement via TCPIP
* **OPX** (Quantum Machines) - RF measurement with QUA integration

Custom drivers can be implemented using the protocol-based interface.

## Installation

Install the base package:

```bash
pip install cq-stanza
```

Or with Quantum Machines support:

```bash
pip install "cq-stanza[qm]"
```

## Next Steps

* [Quickstart Guide](/control/stanza/quickstart) - Get up and running in 5 minutes
* [Device Configuration](/control/stanza/core-concepts/device-configuration) - Learn how to configure devices
* [Routines](/control/stanza/core-concepts/routines/overview) - Write your first tune-up sequence
* [Data Logging](/control/stanza/core-concepts/data-logging) - Understand logging and data formats
* [Drivers](/control/stanza/core-concepts/drivers) - Implement custom instrument drivers