
Description
Author new experiment scripts that are compatible with the lab system's auto-discovery. Use when the user asks to create a new experiment type, add a custom measurement, or write a Python script that should be discoverable via the `lab` and `run_experiment` tools. Covers required function signatures, type hints, docstrings, and return formats.
SKILL.md
Writing Experiment Scripts
How to create experiment scripts compatible with the lab system.
Quick Reference
| Requirement | Details |
|---|---|
| Location | Scripts directory (see system prompt) |
| Function | ONE public function per file (no _ prefix) |
| Type hints | Required with Annotated bounds |
| Docstring | Google-style with Args/Returns |
| Return | Dict with status, results, arrays, plots |
Function Signature
from typing import Annotated
def experiment_name(
param1: Annotated[float, (min, max)] = default,
param2: Annotated[int, (min, max)] = default,
target: str = "qubit_0",
) -> dict:
"""Short description of the experiment.
Args:
param1: Description with units
param2: Description with units
target: Target qubit identifier
Returns:
Measurement results with data and plots
"""
# Implementation
return {...}
Return Format
Success
{
"status": "success",
"results": {
"peak_frequency": 5042.3, # Scalar results
"linewidth_mhz": 1.2,
},
"arrays": {
"frequencies": [4900.0, 4902.0, ...], # Array data
"amplitudes": [0.01, 0.02, ...],
},
"plots": [
{"name": "spectrum", "format": "png", "data": "base64..."},
],
"metadata": {
"target": "qubit_0",
"experiment_type": "qubit_spectroscopy",
},
}
Failure
{
"status": "failed",
"error": "No peak found in frequency range"
}
Parameter Types
Supported Types
float- Floating point numbersint- Integersstr- Strings (no range validation)bool- Boolean flagslist- Lists (no range validation)
Range Constraints
from typing import Annotated
# Float with range [0.0, 100.0]
amplitude: Annotated[float, (0.0, 100.0)] = 50.0
# Int with range [1, 10000]
num_averages: Annotated[int, (1, 10000)] = 1000
Important: Parameters without defaults are required. Parameters with defaults are optional.
Complete Example
"""Simulated qubit spectroscopy experiment."""
from typing import Annotated
import numpy as np
import base64
import io
def qubit_spectroscopy(
start: Annotated[float, (3000.0, 8000.0)] = 4900.0,
stop: Annotated[float, (3000.0, 8000.0)] = 5100.0,
step: Annotated[float, (0.1, 100.0)] = 2.0,
num_avs: Annotated[int, (1, 10000)] = 1000,
target: str = "qubit_0",
) -> dict:
"""Qubit spectroscopy frequency sweep.
Performs a frequency sweep to find the qubit resonance frequency.
Args:
start: Start frequency in MHz
stop: Stop frequency in MHz
step: Frequency step in MHz
num_avs: Number of averages
target: Target qubit identifier
Returns:
Measurement results with frequency estimate and data
"""
# Generate frequency array
frequencies = np.arange(start, stop + step, step)
# Simulate measurement (replace with real hardware calls)
center_freq = (start + stop) / 2
linewidth = 3.0
signal = 1.0 / (1.0 + ((frequencies - center_freq) / linewidth) ** 2)
noise = np.random.normal(0, 0.05, len(frequencies))
magnitude = signal + noise
# Find peak
peak_idx = np.argmax(magnitude)
frequency_guess = float(frequencies[peak_idx])
# Generate plot (optional)
plots = []
try:
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(frequencies, magnitude, 'b-')
ax.axvline(frequency_guess, color='r', linestyle='--')
ax.set_xlabel('Frequency (MHz)')
ax.set_ylabel('Magnitude')
ax.set_title(f'Spectroscopy - {target}')
buf = io.BytesIO()
fig.savefig(buf, format='png', dpi=100)
buf.seek(0)
plots.append({
"name": "spectroscopy",
"format": "png",
"data": base64.b64encode(buf.read()).decode('ascii')
})
plt.close(fig)
except ImportError:
pass
return {
"status": "success",
"results": {
"frequency_guess": frequency_guess,
"linewidth_mhz": linewidth,
},
"arrays": {
"frequencies": frequencies.tolist(),
"magnitude": magnitude.tolist(),
},
"plots": plots,
"metadata": {
"target": target,
"experiment_type": "qubit_spectroscopy",
},
}
Common Patterns
Sweep Experiment
def frequency_sweep(
start: Annotated[float, (1000.0, 10000.0)] = 4000.0,
stop: Annotated[float, (1000.0, 10000.0)] = 6000.0,
step: Annotated[float, (0.1, 100.0)] = 1.0,
) -> dict:
Time-Domain Measurement
def t1_measurement(
delay_start: Annotated[float, (0.0, 1000.0)] = 0.0,
delay_stop: Annotated[float, (0.0, 1000.0)] = 100.0,
num_points: Annotated[int, (10, 500)] = 50,
num_averages: Annotated[int, (100, 50000)] = 1000,
) -> dict:
Amplitude Calibration
def rabi_amplitude(
amp_start: Annotated[float, (0.0, 1.0)] = 0.0,
amp_stop: Annotated[float, (0.0, 1.0)] = 1.0,
num_points: Annotated[int, (10, 200)] = 50,
drive_frequency: Annotated[float, (3000.0, 8000.0)] = 5000.0,
) -> dict:
Validation
After creating or modifying an experiment script, always validate it using the CLI tool:
qca experiments validate <path-to-script> --human
This command checks:
- File exists and is a valid Python file
- Contains a public function (no underscore prefix)
- Function has
-> dictreturn type annotation - Parameters have type hints (ideally with
Annotatedranges) - Syntax is valid
Example output (valid script):
Validation Result: VALID
File: scripts/my_experiment.py
┏━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Check ┃ Status ┃ Details ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ file_exists │ ✓ PASS │ File exists │
│ python_file │ ✓ PASS │ File has .py extension │
│ not_private │ ✓ PASS │ File is public (no underscore prefix) │
│ syntax_valid │ ✓ PASS │ Python syntax is valid │
│ has_public_function │ ✓ PASS │ Found public function: my_experiment │
│ return_type_dict │ ✓ PASS │ Return type is dict │
│ has_docstring │ ✓ PASS │ Function has docstring │
│ has_typed_parameters │ ✓ PASS │ Found 3 typed parameter(s) │
│ has_annotated_ranges │ ✓ PASS │ 3 parameter(s) have range constraints │
│ optional_parameters │ ✓ PASS │ 3 optional parameter(s) with defaults │
└────────────────────────┴──────────┴─────────────────────────────────────────┘
Experiment Schema:
Name: my_experiment
Description: My experiment description.
Module Path: /path/to/scripts/my_experiment.py
Parameters:
┏━━━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━┓
┃ Name ┃ Type ┃ Required ┃ Default ┃ Range ┃
┡━━━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━┩
│ amplitude │ float │ No │ 0.5 │ 0.0 to 1.0 │
│ num_points │ int │ No │ 51 │ 10 to 200 │
│ target │ str │ No │ qubit_0 │ - │
└───────────────┴───────┴──────────┴─────────┴──────────────┘
Example output (invalid script):
Validation Result: INVALID
File: scripts/bad_experiment.py
┏━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Check ┃ Status ┃ Details ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ file_exists │ ✓ PASS │ File exists │
│ python_file │ ✓ PASS │ File has .py extension │
│ not_private │ ✓ PASS │ File is public │
│ syntax_valid │ ✓ PASS │ Python syntax is valid │
│ has_public_function │ ✓ PASS │ Found public function: my_func │
│ return_type_dict │ ✗ FAIL │ No return type annotation │
└────────────────────────┴──────────┴─────────────────────────────────┘
Errors:
• Function must have return type annotation '-> dict'
After validation passes, verify the experiment appears in the list:
qca experiments list --human
Checklist
Before running your script:
- File is in the scripts directory
- Only ONE public function (no
_prefix) - All parameters have type hints with
Annotated - All parameters have default values (or are intentionally required)
- Function has Google-style docstring
- Returns dict with
statuskey - Arrays are converted to lists (
.tolist()) - Plots are base64-encoded PNG or Plotly JSON
- Run
qca experiments validate <path> --humanto verify - Run
qca experiments list --humanto confirm discovery
More skills from the Quantum-Calibration-Agent-Blueprint repository
View all 6 skillsanalysis-scripts
analyze quantum experiment data
Jul 14Data AnalysisNVIDIAPythonQuantum Computingexperiment-execution
run quantum calibration experiments
Jul 14BenchmarkingNVIDIAQuantum ComputingSimulationvlm-configuration
configure Vision Language Models
Jul 14AI InfrastructureLLMNVIDIAworkflow-execution
execute quantum calibration workflows
Jul 14AutomationNVIDIAQuantum ComputingWorkflow Automationworkflow-planning
plan quantum calibration workflows
Jul 14NVIDIAPlanningQuantum ComputingWorkflow Automation
More from NVIDIA
View publishernemoclaw-user-guide
retrieve NemoClaw documentation and configuration
NemoClaw
Jul 20DocumentationMCPSearchmcore-build-and-dependency
manage Megatron-LM development environments
Megatron-LM
Jul 14ContainersDeploymentPythonmcore-bump-base-image
update NVIDIA PyTorch base images
Megatron-LM
Jul 14CI/CDDeploymentmcore-cicd
manage CI/CD pipelines for Megatron-LM
Megatron-LM
Jul 14CI/CDDeploymentGitHubmcore-create-issue
investigate CI failures and create issues
Megatron-LM
Jul 14DebuggingGitHubTriagemcore-linting-and-formatting
lint and format Megatron-LM code
Megatron-LM
Jul 14Best PracticesCode Analysis