kicad-yamlApril 2026

A declarative schema for KiCad, designed for AI


The gap

In SolidWorks, a design table lets you define a parametric model in a spreadsheet. Dimensions, configurations, and variants are pure data. The CAD engine generates the geometry. You never touch the underlying file format.

KiCad doesn't have anything like this. If you want to programmatically generate a board, you write a Python script against kiutils or pcbnew. Your design intent — which components, how they're arranged, what connects to what — gets tangled up with S-expression file-format plumbing. The script works, but it's not reusable and it's not readable by anything that isn't intimately familiar with KiCad internals.

This matters more now than it used to, because the thing that wants to generate PCB designs next isn't another Python script. It's an LLM.

Why YAML

The real problem isn't "how do I script KiCad." It's "what contract do I give an AI tool so it can generate a valid board without understanding KiCad's file format?"

KiCad's native format is S-expressions — nested, verbose, full of internal IDs and coordinates that only make sense in context. Asking an AI to write that directly is like asking it to write a compiled binary. It might get close, but the failure modes are subtle and hard to debug.

YAML gives you a declarative layer on top. You describe what the board is: components, nets, grid layouts, sheet hierarchy. The compiler handles the rest — symbol resolution, footprint placement, net assignment, file generation. The schema is the contract, and it's small enough that an AI can learn it from the reference docs.

yaml
board:
  width: 100
  height: 100

templates:
  led:
    symbol: Device:LED
    footprint: LED_SMD:LED_WS2812B_PLCC4_5.0x5.0mm_P3.2mm

parts:
  matrix:
    template: led
    grid:
      rows: 8
      cols: 8
      pitch: 10

That's an 8x8 LED matrix. No UUIDs, no coordinate arithmetic, no S-expressions. The YAML describes the design intent and the tool compiles it to valid .kicad_sch and .kicad_pcb files.

What this is actually for

I built kicad-yaml for three use cases, in order of priority:

MCP servers. An MCP server that wraps kicad-yaml can accept natural-language instructions — "add a decoupling cap next to each LED" — and translate them into schema changes. The server doesn't need to understand KiCad internals. It reads and writes YAML.

AI coding assistants. Claude, Copilot, or any coding assistant can generate or modify a YAML design file directly. The schema is documented, the validation is strict, and errors are structured with source locations. An AI can iterate on a design the same way it iterates on code.

Automated pipelines. Higher-level specs — a bill of materials, a netlist, a parametric configuration — can be compiled down to YAML and then to KiCad files. The YAML layer is the stable interface between whatever generates the design and the KiCad output.

Hand-authoring YAML is possible and the schema is designed to be readable, but it's not the primary use case. The primary use case is giving AI tools a target they can hit reliably.

Parametric grids and expressions

Most PCB designs have repetition. LED matrices, connector arrays, sensor grids. Describing each component individually defeats the purpose of a declarative format.

kicad-yaml handles this with parametric grids. You define the grid dimensions and pitch, and optionally use expressions in references and net names:

yaml
parts:
  leds:
    template: led
    grid:
      rows: 8
      cols: 8
      pitch: 10
    reference: 'LED{index + 1}'
    nets:
      din: 'LED_DATA_{index}'
      dout: 'LED_DATA_{index + 1}'

Expressions have access to index, row, col, rows, and cols. They support arithmetic, comparisons, and ternaries — enough to handle the wiring patterns that show up in real grid designs without being a general-purpose scripting language.

Each grid cell can also carry offsets for associated components. A decoupling cap 3mm from each LED, for instance, is a per-cell offset — not a second grid that you have to keep in sync.

Hierarchical sheets

Flat designs are fine for simple boards, but anything with repeated subcircuits — a multi-channel audio interface, a modular power supply — benefits from hierarchy. kicad-yaml supports hierarchical sheets with automatic cross-boundary wiring.

You define a child sheet with its own parts and nets, then instantiate it from the parent with a pin map. Global nets (power, ground) propagate automatically. Sheet-local nets get exposed through hierarchical pins that the tool generates and connects.

The YAML for a hierarchical design reads like a module system: define the subcircuit once, instantiate it with the connections you need, let the tool handle the KiCad-specific wiring.

Structured errors, not exceptions

When a build fails — missing library symbol, invalid footprint, broken net reference — you get a structured result, not a stack trace. Each error has a code, a message, and a source location pointing back to the YAML.

python
from kicad_yaml import build

result = build("design.yaml", output_dir="./out")

for error in result.errors:
    print(f"{error.code}: {error.message}")
    # SYMBOL_NOT_FOUND: Symbol 'Device:LED_FAKE' not found in libraries

This matters for the AI use case. An MCP server or coding assistant needs to understand what went wrong and where, not parse a Python traceback. Structured errors give the AI enough information to fix the problem and retry.

Where this is going

kicad-yaml is at v0.1.0. It handles flat and hierarchical sheets, grid parametrics, back-side components, and expression syntax. It targets KiCad 10 only — no backwards compatibility with older file formats.

The next step is an MCP server that wraps the library, so you can go from "I need an 8x8 NeoPixel grid with per-LED decoupling caps" to a KiCad project in a conversation. The schema and the compiler are the foundation. The interface layer is what makes it useful.

The project is MIT licensed and on GitHub.