Documentation Index
Fetch the complete documentation index at: https://docs.pcb.new/llms.txt
Use this file to discover all available pages before exploring further.
Specification
Overview
Zener is a domain-specific language built on top of Starlark for describing PCB schematics. It provides primitives for defining components, symbols, nets, interfaces, and modules in a type-safe, composable manner. This specification describes the language extensions and primitives added on top of Starlark. For the base Starlark language features, please refer to the Starlark specification and the starlark-rust types extension.Table of Contents
- Modules and Imports
- Nets and Interfaces
- Components and Symbols
- Modules
- Utilities
- Schematic Position Comments
Modules and Imports
Each.zen file is a Starlark module that can be used in two ways:
-
Symbol imports with
load()bring functions and types into scope: -
Schematic modules with
Module()create instantiable subcircuits:
Import Paths
Import paths support local files, stdlib, and remote packages:@stdlib alias is special and virtual—its content is controlled by the toolchain. You don’t need to declare it in [dependencies].
Remote package URLs don’t include version information. Versions are declared separately in pcb.toml, so import statements remain stable across upgrades:
Dependency Resolution
Dependencies are automatically resolved when you import remote packages. The toolchain discovers dependencies from import paths, resolves versions, downloads packages, and updatespcb.toml.
@stdlib is toolchain-managed and implicit.
KiCad symbol/footprint/model linkage is configured by workspace-level [[workspace.kicad_library]] entries.
Dependencies are still declared in [dependencies], and auto-deps can add them from imports.
If [[workspace.kicad_library]] is omitted, the toolchain defaults the workspace to two entries:
- KiCad 9:
version = "9.0.3"andmodels.KICAD9_3DMODEL_DIR = "gitlab.com/kicad/libraries/kicad-packages3D" - KiCad 10:
version = "10.0.0"andmodels.KICAD10_3DMODEL_DIR = "gitlab.com/kicad/libraries/kicad-packages3D"
symbols = "gitlab.com/kicad/libraries/kicad-symbols"footprints = "gitlab.com/kicad/libraries/kicad-footprints"parts = "https://kicad-mirror.api.diode.computer/kicad-parts-{version}.toml"http_mirror = "https://kicad-mirror.api.diode.computer/{repo_name}-{version}.tar.zst"
parts and http_mirror are optional and support template placeholders:
{repo}{repo_name}{version}{major}
pcb.sum) records exact versions and cryptographic hashes. Commit it to version control for reproducible builds across machines.
See Packages for complete details on version resolution and dependency commands.
Project Structure
A Zener project is a git repository containing a workspace with boards, modules, and components. Create a new project withpcb new workspace:
pcb new board <name> to add boards and pcb new package <path> to add modules or components.
Workspace manifest (root pcb.toml):
repository: Git remote URL (used to derive package URLs for publishing)pcb-version: Minimum compatiblepcbtoolchain release series (e.g.,"0.3"). Required for workspaces.endpoint: Optional Diode host suffix used for workspace-scoped app/API URLs."diode.computer"resolves toapp.diode.computerandapi.diode.computer.members: Glob patterns matching subdirectories that contain packages
pcb migrate to upgrade manifests and import paths.
Only the workspace root pcb.toml should contain a [workspace] section.
Board manifest (e.g., boards/MainBoard/pcb.toml):
[board]: Defines a buildable board withnameand entrypath[dependencies]: Version constraints for this board’s dependencies
modules/PowerSupply/pcb.toml):
[board] section—they’re libraries meant to be instantiated by boards or other modules.
[dependencies]: Version constraints for packages imported by this packageparts: Optional default sourcing metadata keyed by symbol file. Each entry providesmpn,manufacturer, optionalqualifications, optionaldatasheet, a package-relative.kicad_symsymbolpath, and optionalsymbol_nameto target a specific symbol within a multi-symbol library file. Ifsymbol_nameis omitted, the referenced.kicad_symfile must contain exactly one symbol; otherwise resolution fails andsymbol_nameis required.Component()sourcing precedence is described below.
Prelude
These stdlib symbols are available in every user.zen file without load():
io,input,output— from@stdlib/io.zenNet,Power,Ground,NotConnected— from@stdlib/interfaces.zenBoard— from@stdlib/board_config.zenLayout,Part— from@stdlib/properties.zen
Nets and Interfaces
Nets
ANet represents an electrical connection between component pins. Net is the base net type; specialized types like Power, Ground, and NotConnected add metadata (schematic symbols, voltage) while remaining fundamentally nets.
Net(name, voltage=None, impedance=None) — all parameters optional. Power and Ground additionally accept a voltage parameter. Additional net types (Analog, Pwm, Gpio) are available from @stdlib/interfaces.zen.
If a net constructor omits name, the assigned variable name is used when available:
Power("VCC", voltage="3.3V") is equivalent to Power("VCC", voltage=Voltage("3.3V")).
Net types follow automatic conversion rules across io() boundaries: NotConnected promotes to any type (universal donor), any specialized type demotes to Net, but Net cannot automatically promote to specialized types. For explicit casting, call the target constructor with an existing net: Power(net, voltage=Voltage("3.3V")) or Net(power_net).
Interfaces
Interfaces define reusable connection patterns — groups of related nets. Define custom interfaces withinterface():
field() specs. When instantiated, the first positional argument is an optional name; named arguments override defaults.
If an interface instance omits its explicit name, the assigned variable name becomes the root used for generated child nets:
Spi, I2c, Uart, Usb2, DiffPair, Pcie, Jtag, Swd, etc.) in @stdlib/interfaces.zen. Helper functions UartPair(a, b) and UsartPair(a, b) create cross-connected pairs for point-to-point links.
Components and Symbols
Component
Components represent physical electronic parts with pins, a schematic symbol, and a PCB footprint.Component(**kwargs)
| Parameter | Required | Description |
|---|---|---|
name | yes | Instance name |
symbol | yes | Symbol object defining the schematic representation |
pins | yes | Dict mapping pin names to nets; omit KiCad no_connect pins |
part | no | Part object specifying manufacturer sourcing (preferred) |
prefix | no | Reference designator prefix (default: "U") |
manufacturer | no | Manufacturer name (legacy — prefer part) |
mpn | no | Manufacturer part number (legacy — prefer part) |
footprint | no | PCB footprint path (default: inferred from symbol Footprint property) |
type | no | Component type string |
properties | no | Additional properties dict |
spice_model | no | Explicit SpiceModel; default: inferred from symbol Sim.* properties when present |
dnp | no | Do Not Populate flag |
skip_bom | no | Exclude from BOM (default: inverse of symbol in_bom flag) |
datasheet | no | Datasheet URL or path (default: part.datasheet, then this component value, then symbol Datasheet property; local component paths resolved relative to the .zen file, symbol-local paths resolved relative to the .kicad_sym file) |
- omitted
no_connectpins are auto-wired toNotConnected() - explicit
no_connectentries warn power_inandpower_outpins warn if connected to plainNetinstead ofPowerorGround- if
spice_modelis omitted and the symbol providesSim.Library,Sim.Name,Sim.Device=SUBCKT,Sim.Pins, and optionalSim.Params,Component()derives the SPICE model from those symbol properties
Part
Part specifies manufacturer sourcing for a component. It is a prelude symbol — available in all .zen files without load().
Constructor: Part(mpn, manufacturer, qualifications=[], datasheet=None)
| Parameter | Required | Description |
|---|---|---|
mpn | yes | Manufacturer part number (non-empty string) |
manufacturer | yes | Manufacturer name (non-empty string) |
qualifications | no | List of qualification strings (e.g. ["AEC-Q200"]) |
datasheet | no | Datasheet URL or path for this manufacturer part |
.mpn, .manufacturer, .qualifications, .datasheet
Use Part with the part parameter on Component() for primary sourcing, and in properties["alternatives"] for alternate parts:
pcb build, reference designators are automatically allocated per-prefix (e.g. R1, R2, C1).
Symbol
ASymbol represents a schematic symbol loaded from a KiCad symbol library.
Symbol(library, name=None)
library: Path to a.kicad_symfile. Supports local paths,@kicad-symbols/alias, and package paths.name: Symbol name within the library. Required for multi-symbol libraries; omit for single-symbol files.
Physical Quantities
Physical quantities represent electrical values with a nominal value, optional min/max bounds, and a unit. Unit-specific constructors are provided by@stdlib/units.zen (e.g. Voltage, Current, Resistance, Capacitance, Inductance, Impedance, Frequency, Temperature):
@stdlib/units.zen for the complete list of unit constructors.
Properties: .value (alias for .nominal), .nominal, .min, .max, .tolerance, .unit
Methods: .with_tolerance(t), .with_value(v), .with_unit(u), .abs(), .diff(other), .within(other), .matches(other)
Operators: +, -, *, / (with unit tracking), <, >, <=, >=, == (strict equality against another PhysicalValue), unary -
Use .matches(other) when you want coercive comparisons against strings or scalars such as Voltage("5V").matches("5V").
String formatting: Point values → "3.3V". Symmetric tolerances → "10k 5%". Ranges → "11–26V (16V nom.)".
Generic Components
Prefer generic components over rawComponent() where possible. Generics come with standard symbols, footprints, and automatic BOM matching to house parts.
@stdlib/generics/ for the full list of available generics and their accepted parameters.
Modules
Modules are reusable subcircuits —.zen files that declare their electrical interface and configuration, then build a circuit from them. They are the primary mechanism for hierarchical design.
Module()
Module() loads a .zen file and returns a callable that instantiates it as a subcircuit:
name and passes remaining arguments as inputs to the module’s io() and config() declarations:
properties: Dict of property overrides for the module instance.dnp: Bool — mark as Do Not Populate.schematic:"collapse"or"embed"— controls schematic rendering of the subcircuit.
io()
Declare a net or interface input for a module. This defines the module’s electrical interface — the nets that a parent must (or may) connect when instantiating it.io, input, and output are prelude symbols re-exported from @stdlib/io.zen. The low-level builtin is builtin.io(...).
Signature: io(name, typ_or_template, checks=None, optional=False, help=None, direction=None) or io(typ_or_template, checks=None, optional=False, help=None, direction=None)
name: Optional explicit input name (conventionally UPPERCASE). If omitted,io()must be assigned to a top-level variable and that variable name is used.typ_or_template: A net type (Net,Power,Ground, etc.), an interface factory (Spi,Uart, etc.), a net template value, or an interface template value.checks: Optional check function or list of checks applied to the resolved value.optional: IfTrue, a generated net/interface is used when the parent doesn’t provide one. DefaultFalse.help: Help text for documentation and signatures.direction: Optional signature metadata. Must be"input"or"output"when provided.
typ_or_template is a template value, io() derives all three of these from it:
- the placeholder type
- the default/template metadata
- implicit checks that constrain any provided input
io(Power(voltage="1.8V - 3.6V")) requires any supplied Power net to stay within that voltage range.
Use direction for genuinely one-way ports like signal or power flow. Shared rails such as GND should usually remain plain io() declarations.
When the explicit name matches the assigned variable name, omitting it is the preferred style and emits no redundancy advice.
input(name, typ_or_template, ...) and output(name, typ_or_template, ...) are equivalent to io(...) with direction="input" or direction="output" respectively, and they also support omitted explicit names when assigned to top-level variables.
config()
Declare a typed configuration input for a module. This defines parameters that control the module’s behavior — values (not nets) provided by the parent. Signature:config(name, typ, checks=None, default=None, allowed=None, optional=None, help=None) or config(typ, checks=None, default=None, allowed=None, optional=None, help=None)
name: Optional explicit input name (conventionally lowercase). If omitted,config()must be assigned to a top-level variable and that variable name is used.typ: Expected type — primitives (str,int,float,bool),enum,record, or physical quantity constructors.checks: Optional check function or list of checks.default: Default value. When provided,optionaldefaults toTrue.allowed: Optional finite set of allowed values. Accepts alist,tuple, ordict(using only the keys). Supported forstr,int,float,bool,enum, and physical quantity types.optional: Explicit override. WhenTruewith no default, returnsNone.help: Help text.
"true" → True, "42" → 42, "3.3" → 3.3), physical quantities ("10k" → Resistance("10k")), and enum variants ("0603" → Package("0603")). This is why Resistor(name="R1", value="10k", package="0603", ...) works even though value expects Resistance and package expects Package. When allowed is present, both the allowed set and the provided value are normalized through that same coercion path before membership is checked, and physical values are surfaced using their canonical formatting.
As with io(), repeating the assigned variable name as an explicit config() name is redundant and triggers a style advice.
Writing a Module
A module is a.zen file that declares its interface with io() and config(), then uses those values to build its circuit:
Utilities
Board and Layout
Board() configures PCB manufacturing parameters — stackup, design rules, and layout path. It is a prelude symbol.
name, layout_path, layers (2/4/6/8/10), config (explicit BoardConfig), outer_copper_weight ("1oz" or "2oz"), copper_finish (default "ENIG").
When layers is provided, Board() selects an appropriate default stackup, netclasses, and design rules. An explicit config is merged on top. See @stdlib/board_config.zen for BoardConfig, Stackup, DesignRules, NetClass, and preset stackups.
Layout() defines reusable layout blocks for modules. When writing a module, use Layout(name, path) to associate a PCB layout with the subcircuit. See @stdlib/properties.zen.
Simulation(name, setup=None, modifiers=None, bom_profile=...) — Attach inline simulation setup and component modifiers to the current module.
Simulation() uses the same BOM-profile hook as Layout(): by default it registers the standard house-part matcher, modifiers run before bom_profile, and bom_profile=None disables automatic house matching for simulation-only evals.
File and Path
File(path) — Resolve a path relative to the current .zen file. Raises an error if it doesn’t exist.
Path(path, allow_not_exist=False) — Like File() but supports package paths and optional non-existence.
Assertions
Three global functions for validation and diagnostics:check(condition, message)— Assert a condition. Raises an error withmessageifconditionis false.error(message)— Raise an error unconditionally.warn(message)— Emit a warning diagnostic.
Electrical Checks
@stdlib/checks.zen provides reusable check functions for typed inputs. For example, voltage_within(range) validates that a net with voltage metadata, or a direct Voltage value, falls within a specified range:
io() can also contribute implicit checks. A typed net template with a meaningful voltage property enforces the same containment rule automatically:
checks= still run as well, after type validation and any template-derived implicit checks.
E-Series
@stdlib/utils.zen provides functions to snap values to standard resistor/capacitor E-series: e3(), e6(), e12(), e24(), e48(), e96(), e192().
Schematic Position Comments
Zener supports persisted schematic placement metadata in trailing comment blocks. These comments are consumed by tooling and surfaced in netlist output. Do not edit these comments directly. Canonical line format:id: Position key (component or net symbol key in comment form, e.g.R1,VCC.1)x,y: Schematic coordinatesrot: Rotation in degreesmirror(optional): Mirror axis (xory)