This is a Python-based superconducting microwave Process Design Kit (PDK) built on gdsfactory for designing quantum devices and circuits. It provides components like transmons, resonators, couplers, and quantum layouts. Please follow these guidelines when contributing:
Behavioral guidelines to reduce common LLM coding mistakes. Adapted from Andrej Karpathy's observations on LLM coding pitfalls (source). These guidelines bias toward caution over speed — for trivial tasks, use judgment.
Don't assume. Don't hide confusion. Surface tradeoffs.
- State your assumptions explicitly. If uncertain, ask.
- If multiple interpretations exist, present them — don't pick silently.
- If a simpler approach exists, say so. Push back when warranted.
- If something is unclear, stop. Name what's confusing. Ask.
Minimum code that solves the problem. Nothing speculative.
- No features beyond what was asked.
- No abstractions for single-use code.
- No "flexibility" or "configurability" that wasn't requested.
- No error handling for impossible scenarios.
- If you write 200 lines and it could be 50, rewrite it.
Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.
Touch only what you must. Clean up only your own mess.
When editing existing code:
- Don't "improve" adjacent code, comments, or formatting.
- Don't refactor things that aren't broken.
- Match existing style, even if you'd do it differently.
- If you notice unrelated dead code, mention it — don't delete it.
When your changes create orphans:
- Remove imports/variables/functions that YOUR changes made unused.
- Don't remove pre-existing dead code unless asked.
The test: every changed line should trace directly to the user's request.
Define success criteria. Loop until verified.
Transform tasks into verifiable goals:
- "Add validation" → "Write tests for invalid inputs, then make them pass"
- "Fix the bug" → "Write a test that reproduces it, then make it pass"
- "Refactor X" → "Ensure tests pass before and after"
For multi-step tasks, state a brief plan:
1. [Step] → verify: [check]
2. [Step] → verify: [check]
3. [Step] → verify: [check]
Example for this PDK:
1. Add new cell in qpdk/cells/ → verify: pre-commit hooks pass
2. Register in qpdk/cells/__init__.py → verify: component importable
3. Generate regression tests → verify: just test-gds passes
Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification.
- ALWAYS run pre-commit hooks before committing any changes by using
uvx prek run --all-files - Pre-commit hooks will automatically run code formatting (ruff), linting, YAML formatting, and other quality checks
- All pre-commit hooks must pass before any changes can be committed
- Install dependencies:
just install(usesuv sync --all-extras) - Test:
just test(runsuv run pytest -n autowith parallel execution) - Test GDS components:
just test-gds(runs only GDS regression tests intests/test_pdk.py) - Regenerate GDS regression tests:
just test-gds-force(regenerates reference GDS files) - Test with fail-fast:
just test-gds-fail-fast(stops at first test failure for debugging) - Run pre-commit hooks:
just run-pre(runs all pre-commit hooks on all files) - Update pre-commit hooks:
just update-pre(updates pre-commit hooks to latest versions) - Build package:
just build(creates distribution packages) - Build documentation:
just docs(builds Sphinx documentation, this needs to succeed in order to be mergeable to main)
qpdk/: Core Python package containing quantum device components and PDK configurationqpdk/cells/: Device cell, or gdsfactory component, definitions (transmons, resonators, couplers, etc.)qpdk/models/: S-parameter and circuit models for quantum RF componentsqpdk/klayout/: KLayout technology files and layer definitionsqpdk/tech.py: Layer stack and main technology cross sections etc.tests/: Test suite using pytestdocs/: Documentation built with Sphinxinstall_tech.py: Script to symlink technology files to KLayout, rarely needed for AI agents
- Python versions: Specified in
pyproject.toml(currently >=3.11,<3.15) - Package manager:
uv(preferred over pip/conda) - Main dependencies: gdsfactory (>=9.15.0,<9.21.0), doroutes (>=0.2.0)
- Testing: pytest with regression testing using
pytest_regressions, hypothesis for property-based testing - Linting: ruff for Python code formatting and linting, pyrefly for type checking
- Layout tool: KLayout for viewing and editing GDS layouts
- Documentation: Sphinx for building documentation, jupytext for notebook management
- Simulation tools (optional): sax, scqubits, jaxellip (install with
uv sync --extra models)
- Git LFS Required: This repository uses Git LFS (Large File Storage) for test data files. Install Git LFS before cloning or testing: https://git-lfs.github.com/
- Binary files: GDS and OAS files are tracked as binary in
.gitattributesto prevent merge conflicts - Test data with LFS: CSV files in
tests/models/data/are stored with Git LFS (filter=lfs diff=lfs merge=lfs) - Branching: Work on feature branches, not directly on
main. Pull requests are required for merging tomain - Commit messages: Write clear, concise commit messages. Use imperative mood (e.g., "Add component" not "Added component")
The repository uses several automated workflows:
- test.yml: Runs on every PR and push to main. Executes pre-commit hooks and pytest test suite
- pages.yml: Builds HTML and PDF documentation, deploys to GitHub Pages on push to main
- build.yml: Builds Python package distribution files
- release.yml: Publishes to PyPI when a version tag (e.g.,
v0.0.3) is pushed
All PRs must pass:
- Pre-commit hooks (linting, formatting, type checking, etc.)
- Full test suite (203+ tests including regression tests)
- Documentation build (both HTML and PDF must build successfully)
- Bump the version with
uv version --bump patchThe version should be updated inpyproject.toml,qpdk/__init__.py, andREADME.md - Create and push a version tag. For example:
git tag v0.0.X && git push origin v0.0.X - GitHub Actions automatically builds and publishes to PyPI
- Draft release is automatically published on GitHub
- Follow quantum device design patterns: This PDK is specifically for superconducting quantum circuits
- Maintain layer stack consistency: All layer definitions must match between
qpdk/layers.yamlandqpdk/tech.py - Use regression testing: New components should have regression tests for both settings and netlists, the files are
generated automatically with
just test-gds-force - Prefer Justfile commands: Use
justcommands instead of direct tool invocation if possible - Write comprehensive tests: Add tests for new functionality following existing patterns in
tests/ - Document quantum-specific behavior: Include docstrings explaining the quantum physics and device characteristics,
ideally with citations. Use
:math:notation for inline LaTeX math (avoid$or$$). - Expose new components to PDK: Import new all components from new files with the form
from ... import *inqpdk/cells/__init__.py - Use predefined layers: Prefer predefined layers from the
LAYERenumerable inqpdk/tech.py. An agent rarely needs to create a new layer. - Use centralized physical constants: Prefer using physical constants (like
e,h,Φ_0,ε_0) fromqpdk/models/constants.pyinstead of defining them locally. - Use the centralized logger: ALWAYS prefer using the fancy
qpdk.loggerinstead of rawprintstatements for reporting information, warnings, or errors. Import it asfrom qpdk import logger. - Use JAX for analytical models: When implementing analytical models for S-parameters, prefer using JAX-compatible
functions (e.g.,
jnpinstead ofnp,jaxellipfor elliptic integrals) and enable JIT compilation with@partial(jax.jit, inline=True)for helper functions. - Manage bibliography entries cleanly: When editing the
bibliography.bibfile, ensure that if a reference contains a validdoifield, it should not include aurlorurldatefield to avoid redundant citation information. - Python imports: Place imports at the top of the file, not inside functions, unless the dependency is missing from
pyproject.tomlor is exceptionally heavy without lazy loading.
- Component tests: Each new component should be added to the cell registry with
@gf.celland categorized withtags. - Netlist validation: Components must generate valid netlists that can be round-tripped (component -> netlist ->
component). This is tested by
test_netlistsintests/test_pdk.py. - Model tests: New models should have unit tests in
tests/models/verifying their behavior, passivity, and reciprocity. - Prefer using the
hypothesislibrary: Use thehypothesislibrary to generate tests with generic arguments with appropriate types. Note the following gotchas when usinghypothesis:- Do NOT use
@staticmethod: When using the@givendecorator from Hypothesis, do not add@staticmethodto the test function. Hypothesis inspects the__code__attribute of the decorated function during test collection, which causesAttributeErroron staticmethod descriptors. - Handle JAX JIT compilation overhead: When testing JAX JIT-compiled functions with Hypothesis, the first run
incurs a compilation overhead which often causes
DeadlineExceedederrors. Add@settings(deadline=None)to Hypothesis@giventests that call JIT-compiled code to prevent flaky tests.
- Do NOT use
When adding new quantum device components:
- Define the component in
qpdk/cells/ - Categorize the component using the
tagsparameter in the@gf.celldecorator (e.g.,@gf.cell(tags=("qubits", "transmons"))). - Add it to the
cellsregistry inqpdk/cells/__init__.py, withfrom ... import * - Create appropriate layer assignments using the defined
LAYERenum fromqpdk/tech.py - Add regression tests following the existing parametrized test pattern, generated by running
just test-gds-forcemultiple times - Ensure the component works with the netlist extraction system
- Document the quantum device physics and design parameters
The qpdk/models/ directory contains S-parameter and circuit models for quantum RF components:
- Models available: Resonators, couplers, waveguides, generic components
- Simulation frameworks: Uses
saxfor S-parameter simulations,scqubitsfor quantum circuit analysis - Media definitions:
qpdk/models/cpw.pydefines coplanar waveguide (CPW) parameters - Installing simulation tools: Run
uv sync --extra modelsto install optional simulation dependencies - Model structure: Each model typically provides functions that return S-parameters or network parameters as functions of frequency
- Integration with components: Models can be linked to layout components through the netlist system
Models are typically used in notebooks and sample scripts (see notebooks/ and qpdk/samples/simulate_resonator.py)
for examples of:
- Calculating resonator frequencies
- Simulating S-parameters for coupled systems
- Optimizing component parameters
- Comparing simulated results with measurements
- Notebook source: Notebook source files live in
notebooks/src/. Python notebooks use.py; the MATLAB-kernel notebook uses.m(seenotebooks/src/matlab_integration.m) - Conversion: Run
just convert-notebooksor./.github/convert-notebooks.shto convert source files to.ipynb - Pre-commit hook: Notebooks are automatically converted when
.pyor.mfiles innotebooks/src/are modified - Format: Python notebooks use the "percent" format with
# %%cell markers; MATLAB notebooks use% %%markers - Documentation: Converted notebooks are copied to
docs/notebooks/during documentation build. Notebooks that require external tooling (HFSS, MATLAB) are listed innb_execution_excludepatternsindocs/conf.pyso the docs build does not try to execute them
- Location:
qpdk/samples/contains example layout and simulation scripts - Purpose: Demonstrates how to use PDK components to create complete designs
- Examples include:
- Simple component demonstrations (
sample0.pythroughsample6.py) - Resonator test chips (
resonator_test_chip.py) - Filled test chips with multiple components (
filled_test_chip.py) - Routing examples with airbridges (
route_with_airbridges.py) - Simulation workflows (
simulate_resonator.py)
- Simple component demonstrations (
- YAML files: Some samples use
.pic.ymland.scm.ymlfor pictorial and schematic component definitions - Testing: Samples are tested to ensure they generate valid GDS files (see
tests/test_pdk.py)
- For notebooks: Create
.pyfile innotebooks/src/using jupytext percent format with proper YAML header. Ensure the first code cell contains the Google Colab installation snippet withtags=["hide-input", "hide-output"]so it can be run online without cluttering the docs. - For samples: Create
.pyfile inqpdk/samples/following existing examples - Include docstrings and comments explaining the design and physics
- Add citations where appropriate using Sphinx citation syntax
- Test that the script runs without errors
- For samples, ensure the generated component is added to the test suite
- Update
docs/notebooks.rstwhen adding or removing notebooks — this page describes each notebook and categorizes it by simulation approach
The repository uses extensive pre-commit hooks Including, but not limited to:
ruff: Python code formatting and lintingyamlfmt: YAML file formattingcodespell: Spell checkingnbstripout: Jupyter notebook cleaningactionlint: GitHub Actions validationuv-lock: Lock file validation
Problem: Tests fail with "File not found" errors for CSV data files, or GDS files appear as text pointers
Solution: Install Git LFS and run git lfs pull to download large files
# Install Git LFS (varies by OS)
# Ubuntu/Debian:
sudo apt-get install git-lfs
# RHEL/Rocky
sudo dnf install git-lfs
# macOS:
brew install git-lfs
# Initialize and pull
git lfs install
git lfs pullProblem: CI fails with formatting or linting errors
Solution: Always run pre-commit hooks before committing
just run-pre
# or
uvx prek run --all-filesProblem: Components render incorrectly in KLayout or documentation
Solution: Ensure layers are defined in both qpdk/layers.yaml AND qpdk/tech.py. Layer numbers and datatypes must
match exactly.
Problem: just docs fails with import errors or missing cells
Solution:
- Ensure all dependencies are installed:
just install - Run
just setup-ipython-configto set up IPython configuration - Check that all components are properly registered in
qpdk/cells/__init__.py - Verify that notebooks in
notebooks/src/are valid Python files with correct jupytext format
Problem: GDS regression tests fail after making changes
Solution:
- If changes are intentional, regenerate reference files:
just test-gds-force - Review the diff to ensure changes are expected
- Commit both code and updated reference files in
tests/gds_ref/ - Note: GDS reference files may change between gdsfactory versions
Problem: ModuleNotFoundError when importing simulation modules
Solution: Install optional model dependencies: uv sync --extra models
Problem: Pyrefly or mypy report type errors in pre-commit
Solution:
- Review the specific error message
- Add type hints where missing
- Use
cast()for type conversions only when absolutely necessary - Check
pyproject.tomlfor any type checking configuration that may be ignoring specific errors