pdk-ci-workflow

September 3, 2026 · View on GitHub

Centralized CI/CD workflows, pre-commit hooks, and GitHub Actions standards for GDSFactory PDK projects.

Overview

This repository provides reusable automation tooling for Process Design Kit (PDK) repositories in the GDSFactory ecosystem. It centralizes CI/CD standards, code quality checks, and release management across multiple PDK projects, ensuring consistency and reducing maintenance overhead.

Who should use this: Maintainers of GDSFactory PDK repositories who want to standardize their development workflows without duplicating configuration across repos.

Key benefits:

  • Standardized testing, linting, and type checking across all PDKs
  • Automated documentation builds and deployments
  • AI-powered code reviews via Claude
  • 15 pre-commit hooks enforcing PDK structural compliance
  • Semantic versioning and automated release notes
  • Template files for onboarding new PDK repos

Features

This repository provides four complementary automation patterns:

  • Reusable GitHub Actions Workflows - Complete CI/CD jobs for testing, docs, releases, and code review
  • Pre-commit Hooks - 18 PDK compliance checks plus 11 third-party tool wrappers (ruff, pydocstyle, codespell, etc.) with centrally controlled versions
  • Templates - Reference configuration files for onboarding new PDK repos
  • Composite Actions - Shared step sequences for flexible workflow composition (in development)

Additional capabilities:

  • Automated release management with semantic versioning
  • AI code review powered by Claude Sonnet 4
  • GitHub Pages deployment for Sphinx documentation
  • Dependency update automation via Dependabot

Architecture

This repository uses three distinct GitHub Actions patterns, each suited for different use cases:

Reusable Workflows

Location: .github/workflows/*.yml Pattern: workflow_call Use when: You want to delegate an entire job with standardized behavior

Reusable workflows are complete, self-contained workflow definitions triggered via workflow_call. When a PDK repo calls a reusable workflow, it delegates the entire job — the workflow controls the runner, permissions, steps, and secret handling. The calling repo just says "run this job for me" and passes inputs. This is ideal for enforcing standardized processes where teams shouldn't customize internals.

Composite Actions

Location: actions/*/action.yml Pattern: uses: org/repo/path/to/action@ref Use when: You want to share step sequences but retain job-level control

Composite actions are bundles of steps packaged with an action.yml file. They execute within a job at the step level, using the calling job's runner. The calling repo retains full control over job definition (runner, permissions, surrounding steps) and drops the composite action in as a convenience. This is ideal for sharing common step sequences (like toolchain setup) while leaving teams free to structure their own jobs.

Pre-commit Hooks

Location: hooks/*.py Pattern: Referenced via .pre-commit-config.yaml Use when: You want local validation before code is committed

Pre-commit hooks run locally on developer machines before commits are created. They validate repository compliance against organizational standards — for example, verifying required files exist, checking field formats, or enforcing naming conventions. Hooks can auto-fix issues and fail the commit for manual review.

Quick Start

1. Copy workflow templates

Copy all files from templates/.github/workflows/ into your repo. Each is a thin wrapper that delegates to this repo and forwards the required secrets explicitly:

# .github/workflows/test_code.yml
name: Test code
on:
  pull_request:
  push:
    branches: [main]

jobs:
  test:
    uses: doplaydo/pdk-ci-workflow-public/.github/workflows/test_code.yml@main
    secrets:
      GFP_API_KEY: ${{ secrets.GFP_API_KEY }}

2. Set up pre-commit

Add to your Makefile:

dev: install
	curl -sf https://raw.githubusercontent.com/doplaydo/pdk-ci-workflow-public/main/templates/.pre-commit-config.yaml -o .pre-commit-config.yaml
	uv run pre-commit clean
	uv run pre-commit install

Add to your .gitignore:

.pre-commit-config.yaml

Then run make dev.

How pre-commit works

  • The config is never committed to PDK repos. It lives in this repo at templates/.pre-commit-config.yaml and is always fetched from upstream.
  • In CI: The test_code.yml reusable workflow fetches the canonical config automatically before running pre-commit run --all-files. No setup needed in the PDK repo.
  • Locally: make dev downloads the config and installs the git hooks. Pre-commit then runs automatically on every git commit.
  • Versions of all tools (ruff, codespell, nbstripout, pretty-format-toml, etc.) are controlled centrally in this repo via additional_dependencies. Bumping a version here propagates to all PDK repos — no downstream PRs needed.
  • PDK-specific overrides (e.g. custom check-yaml excludes): keep a committed .pre-commit-config.yaml instead, still referencing pdk-ci-workflow as the only repo.
  • If git commit fails with `<hook-id>` is not present in repository https://github.com/doplaydo/pdk-ci-workflow-public: your local pre-commit cache predates a hook that was added upstream. Run pre-commit clean && make dev — do not run pre-commit autoupdate, it does not work for the mutable rev: main pin and will not fix this.

Reusable Workflows

PDK repos reference these workflows via workflow_call. Create thin wrapper workflows in your repo's .github/workflows/ directory.

Available Workflows

WorkflowJobsDescription
test_code.ymlpre-commit, test_code, test_gfpPre-commit (canonical config), pytest, GFP validation
test-sample-projects.ymldiscover, test, notebooks, drcUnit tests, notebook execution, and DRC for all *--sample-projects/ directories
pages.ymlbuild-docsSphinx docs build and Pages artifact upload. The caller's wrapper supplies the deploy-docs job that publishes to GitHub Pages
claude-pr-review.ymlreviewAI code review via Claude Sonnet 4. Runs once on PR open/reopen; re-run on demand by commenting /claude-api review
drc.ymldrcDesign Rule Check with GFP and badge generation
gds-xor.ymlgds-xorPer-layer XOR of every *.gds changed by a PR: a downloadable XOR GDS plus a PDF report with one page per differing layer, and a PR comment showing the difference area in um^2
issue.ymladd-labelAuto-labels issues with "pdk" tag
test_coverage.ymlcoveragePytest with line coverage reporting
model_coverage.ymlmodel-coveragePDK model-to-cell coverage check
model_regression.ymlmodel-regressionModel-specific regression tests
generate_nyanlib.ymldiscover, generateInstalls each *--sample-projects/ directory from configured package indexes while ignoring local source overrides for the root PDK package, runs gfp serve inside the gfp-server container, and produces <dir>/build/models.nyanlib + SVG symbols per directory; opens an update PR per directory only on a manual workflow_dispatch from main
update_badges.ymlbadgesGenerate coverage, model, issue, and PR badges

PDK repos call these workflows from thin wrapper files in .github/workflows/, passing secrets explicitly. See templates/.github/workflows/ for ready-to-copy wrappers.

Required Secrets

PDK repos must have these secrets configured and forwarded explicitly in their wrapper workflows:

SecretUsed by
GFP_API_KEYtest_code, test-sample-projects, pages, drc, test_coverage, model_coverage, model_regression, update_badges, generate_nyanlib
GFP_GHCR_APP_IDgenerate_nyanlib — GitHub App ID for cross-org GHCR pull of the gfp-server container image
GFP_GHCR_APP_PRIVATE_KEYgenerate_nyanlib — GitHub App private key for cross-org GHCR pull
ANTHROPIC_API_KEYclaude-pr-review
SIMCLOUD_APIKEYpages
GITHUB_TOKENissue, update_badges, generate_nyanlib (automatic)

Pre-commit Hooks

Two types of hooks are defined in .pre-commit-hooks.yaml:

  • 18 PDK compliance hooks (hooks/*.py) — validate repo structure, cells, tech, tests, etc.
  • 11 third-party wrapper hooks — ruff, pydocstyle, codespell, nbstripout, trailing-whitespace, etc. with versions pinned via additional_dependencies so they're controlled centrally

All hooks use always_run: true and pass_filenames: false (repo-level checks). Errors = failure, warnings = pass but alert.

See hooks/README.md for detailed documentation.

Available Hooks

Project Structure

Hook IDWhat it checks
check-required-filesREADME.md, CHANGELOG.md, LICENSE, Makefile, pyproject.toml, .gitignore, .pre-commit-config.yaml, tests/, test workflow
check-pyproject-sectionsDeep validation of pyproject.toml: build-system, project fields, ruff, codespell, pytest, tbump, mypy, towncrier, package-data (11 sub-checks)
check-package-init__version__ defined as string literal, __all__ defined in package __init__.py
check-version-syncVersion consistency across pyproject.toml, tbump config, __init__.py, and README.md

Cells & Technology

Hook IDWhat it checks
check-cells-structure@gf.cell decorators on component functions, Google-style docstrings with Args, cells/__init__.py re-exports
check-tech-structuretech.py defines LAYER, LAYER_STACK, LAYER_VIEWS, cross_sections; optional layers.yaml cross-check
check-pdk-objectPdk() constructor has required kwargs (name, cells, layers, cross_sections), uses get_cells()
check-no-raw-layersFlags (int, int) tuples in cell files that should use LAYER.XXX constants
check-no-main-in-cellsFlags if __name__ == "__main__" blocks in cell files

Infrastructure

Hook IDWhat it checks
check-test-structuretests/ directory with test files, GDS reference dirs, difftest() calls, data_regression usage
check-makefile-targetsRequired targets (install, test) and recommended targets (docs, build, test-force, update-pre, dev). Auto-fix: rewrites dev target's stale pre-commit-config fetch to curl against the public repo (exit 1; re-run exits 0)
check-workflows.github/workflows/ has test_code.yml with pre-commit and test jobs
check-precommit-config.pre-commit-config.yaml includes required hooks (trailing-whitespace, end-of-file-fixer, ruff or ruff-lint, ruff-format, pydocstyle)
check-template-drift.github/dependabot.yml and .github/workflows/*.yml thin callers match upstream templates. Auto-fixes by rewriting or creating files. Conditionally deploys sample-projects.yml and generate_nyanlib.yml in repos containing *--sample-projects/ directories. Deletes deprecated templates (listed in DEPRECATED_TEMPLATES) if still present.

Multi-band

Hook IDWhat it checks
check-multi-bandFor multi-band PDKs: consistent module sets per band, corresponding tests, shared layers

Templates

Reference configuration files are provided in templates/ for onboarding new PDK repos. Copy these files into your repo as-is — they use @main and secrets: inherit, no modification needed.

Template Files

TemplatePurpose
.pre-commit-config.yamlCanonical pre-commit config (PDK hooks + third-party tools with centralized versions)
.github/workflows/test_code.ymlPre-commit, pytest, and GFP validation
.github/workflows/sample-projects.ymlUnit tests, notebooks, and DRC for *--sample-projects/ directories (auto-deployed by check-template-drift when sample dirs are present)
.github/workflows/pages.ymlSphinx docs build and GitHub Pages deployment
.github/workflows/claude-pr-review.ymlAI code review via Claude — runs once on PR open/reopen; re-run on demand with /claude-api review comment
.github/workflows/drc.ymlDesign Rule Check via GFP
.github/workflows/gds-xor.ymlPer-layer XOR report for GDS files changed by a PR
.github/workflows/issue.ymlAuto-label PDK issues
.github/workflows/test_coverage.ymlPytest with line coverage reporting
.github/workflows/model_coverage.ymlPDK model-to-cell coverage check
.github/workflows/model_regression.ymlModel-specific regression tests
.github/workflows/generate_nyanlib.ymlGenerate <sample-project-dir>/build/models.nyanlib + SVG symbols from the published root PDK package for each *--sample-projects/ directory (auto-deployed by check-template-drift when sample dirs are present)
.github/workflows/update_badges.ymlGenerate coverage, model, issue, and PR badges
.github/workflows/code-security.ymlSAST (Semgrep) and SCA (Trivy) security scans
.github/dependabot.ymlMonthly pip and github-actions dependency updates

Composite Actions

Status: In development

Composite actions provide reusable step sequences that can be embedded within jobs. Unlike reusable workflows, they execute on the calling job's runner and give the caller full control over the job context.

Planned actions:

  • setup_environment - Set up Python, uv, and install dependencies

Location: actions/*/action.yml

Check back for updates as composite actions are added to this repository.

Configuration Files

Some configuration files cannot be referenced remotely and must live directly in each PDK repository:

  • .github/dependabot.yml - Dependency update configuration (template provided)
  • .github/CODEOWNERS - Code ownership rules (no template — repo-specific)
  • Makefile - Build targets: install, test, docs, dev (no template — repo-specific)

Requirements

PDK repositories consuming these workflows need:

Software

  • Python: 3.12 (minimum 3.9 supported)
  • uv: Astral package manager
  • Makefile: Must define install, test, and docs targets

GitHub Secrets

For PDK repositories (passed explicitly in each wrapper workflow):

  • GFP_API_KEY - GDSFactory Platform validation and package-index configuration (test_code, pages, drc, test_coverage, model_coverage, model_regression, update_badges, generate_nyanlib)
  • GFP_GHCR_APP_ID - GitHub App ID for cross-org GHCR pull of the gfp-server container (generate_nyanlib)
  • GFP_GHCR_APP_PRIVATE_KEY - GitHub App private key for cross-org GHCR pull (generate_nyanlib)
  • ANTHROPIC_API_KEY - Claude code reviews (claude-pr-review)
  • SIMCLOUD_APIKEY - Simulation cloud access (pages)

GitHub Pages (for documentation)

Enable GitHub Pages in your repository settings:

  • Source: GitHub Actions
  • Branch: Leave as default (workflow controls deployment)

Contributing

Adding a New Workflow

  1. Create workflow file in .github/workflows/
  2. Use workflow_call trigger with defined inputs/secrets
  3. Add a corresponding thin wrapper template in templates/.github/workflows/
  4. Document in this README under "Reusable Workflows"
  5. Test in a PDK repository before tagging a release

Adding a New Pre-commit Hook

  1. Create Python script in hooks/ directory
  2. Add entry point to pyproject.toml under [project.scripts]
  3. Register hook in .pre-commit-hooks.yaml with unique ID
  4. Add the hook to templates/.pre-commit-config.yaml
  5. Document in hooks/README.md
  6. Test locally: pre-commit try-repo . <hook-id> --verbose --all-files

Adding a New Template

  1. Create the template file in templates/ mirroring the target path
  2. Use @main to reference pdk-ci-workflow and secrets: inherit to pass secrets

Versioning

This repository uses semantic versioning:

  • Major (v2.0.0): Breaking changes to workflow inputs/outputs
  • Minor (v1.1.0): New workflows, hooks, or backward-compatible features
  • Patch (v1.0.1): Bug fixes, documentation updates

PDK repositories currently reference @main for all workflows and pre-commit hooks.

Repository Structure

pdk-ci-workflow/
├── .github/
│   ├── workflows/          # Reusable workflows
│   └── README.md
├── hooks/                  # Pre-commit hook implementations
│   ├── _utils.py           # Shared utilities (TOML/YAML, AST, CheckResult)
│   ├── check_*.py          # Individual hook scripts (15 total)
│   └── README.md
├── templates/              # Config templates synced to PDK repos
│   ├── .pre-commit-config.yaml
│   ├── .github/
│   └── README.md
├── scripts/                # Local CLI utilities
│   └── README.md
├── actions/                # Composite actions (in development)
│   └── README.md
├── .pre-commit-hooks.yaml  # Hook registration for pre-commit framework
└── pyproject.toml          # Package config and hook entry points

License

This project is open source. Check the repository for license details.