zener-language
Use before reading or changing `.zen` files for Zener semantics, package APIs, dependency workflow, stable topology, and completion evidence.
How do I install this agent skill?
npx skills add https://github.com/diodeinc/pcb --skill zener-languageIs this agent skill safe to install?
- Gen Agent Trust Hubpass
The skill provides comprehensive guidance for authoring Zener HDL code, a hardware description language based on Starlark. It establishes coding conventions, explains standard library usage, and integrates with the 'pcb' command-line tool for documentation and package management. No security risks or malicious patterns were identified.
- Socketpass
No alerts
- Snykwarn
Risk: MEDIUM · 2 issues
- ZeroLeakspass
Score: 93/100 · 2 sections analyzed
What does this agent skill do?
Zener Language
Zener is Starlark plus PCB-specific modules, typed electrical connections, physical parts, sourcing, layout, and diagnostics.
Discover Before Authoring
Use pcb doc --package @stdlib or pcb doc --package <package> to inspect public APIs and their source roots. Read the installed implementation when exact behavior matters.
For CLI behavior, use the installed command's --help; do not invent or infer subcommands or flags. When version history matters, inspect the installed version and nearby entries in the pcb changelog instead of relying on old examples.
Modules and Components
A .zen file can be:
- a normal Starlark module imported with
load(); or - an instantiable schematic module imported with
Module().
Relative paths stay within the current package. Cross-package imports use full package URLs:
load("./helpers.zen", "helper")
LocalBlock = Module("./LocalBlock.zen")
RemoteBlock = Module("github.com/org/repo/modules/RemoteBlock.zen")
An instantiation passes name=..., its public io() and config() inputs, and optional properties such as dnp, properties, or schematic.
name establishes instance-path identity, not a fixed reference designator. Refdes-like names are only annotation hints; exact source-reference preservation is not supported.
Use refdes-like names only when the user explicitly asks. In that case, set prefix= on the underlying Component() to match the refdes prefix.
Component() creates a physical part from name, symbol, and pins. The selected symbol is the authority for its footprint, part identity, datasheet, and pins. Keep those properties correct in .kicad_sym rather than repeating them in Zener. Omit true no_connect pins; they are wired to NotConnected() automatically.
Use Symbol(library, name=...) for multi-symbol libraries. Use Part(mpn=..., manufacturer=...) only when the symbol does not already provide part identity.
Layout(name, path) associates reusable layout metadata with a module. A root-level Project(name, path) links persistent KiCad project files; its path is relative to the root .zen file.
IO and Config
Define public electrical connections as flat top-level assignments:
VDD = io(Power(voltage="3.0V to 5.5V"))
GND = io(Ground)
EN = io(Net, optional=True)
Do not introduce legacy Pins = struct(...) wrappers in new or touched APIs.
With optional=True, an omitted IO receives an automatically generated net or interface.
Net is the base connection type. Power, Ground, NotConnected, and stdlib interfaces add constraints and semantics. Across an io() boundary, NotConnected can promote to any net type, a specialized net can demote to Net, and a plain Net does not automatically gain specialized semantics. Adapt intentionally with casts such as Power(net, voltage=...) or Net(power_net).
Use stdlib interfaces such as DiffPair, I2c, I3c, Spi, Qspi, Uart, Usart, Swd, Jtag, Usb2, and Usb3 when the grouped protocol semantics are meaningful.
Use UartPair() and UsartPair() when a point-to-point link should cross-connect the two endpoints.
Declare a voltage range on every public Power IO unless the API is intentionally generic.
Define non-electrical choices with typed config():
output_voltage = config(Voltage, default="3.3V", allowed=["3.3V", "5V"])
Load physical value types from @stdlib/units.zen: Voltage, Current, Resistance, Capacitance, Inductance, Impedance, Frequency, Temperature, Time, and Power. String defaults and allowed values auto-convert to the declared physical type. Use enums for non-physical modes and strategies. Expose application-level choices rather than internal passive values or implementation details.
Physical constructors accept point values, engineering notation, ranges, and tolerances. Arithmetic tracks units. Equality between two physical values is strict; use .matches(...) for coercive comparison with a string or scalar.
Useful physical-value operations include .with_tolerance(...), .with_value(...), .abs(), .diff(...), .within(...), and .matches(...).
Enum defaults use the selected string value:
Mode = enum("PULLUP", "PULLDOWN")
mode = config(Mode, default="PULLUP")
Stable Topology
Configs may change values and dnp= state, but should not add, remove, or reconnect schematic instances. Stable instance and net identity preserves layout and reviewability.
- Compute a selected value on one component when the nets do not change.
- Instantiate every mutually exclusive strap or option and DNP the inactive alternatives.
- Do not use conditional instantiation to change topology.
- Use an IC's internal pull-up or pull-down for its default mode when appropriate; add external bias components with
dnp=only for populated alternatives.
Put non-trivial electrical calculations in named functions. Cite the relevant datasheet equation or table and snap calculated values with the appropriate stdlib E-series helper.
The available E-series helpers in @stdlib/utils.zen are e3, e6, e12, e24, e48, e96, and e192.
Use check, warn, error, and stdlib checks for enforceable electrical constraints rather than documenting them only in comments.
For reusable power-rail boundary checks, inspect and prefer voltage_within(...) from @stdlib/checks.zen instead of duplicating the constraint.
Public Compatibility
Reusable-package compatibility includes the public io() and config() API, entrypoints, behavior, layout, and physical integration assumptions. A build of the current package does not prove existing consumers remain compatible.
If consumers must change to adopt an update, treat it as breaking. Document the migration and use a breaking commit.
Schematic Position State
First inspect the root entrypoint for Project(...):
- With
Project(...), the KiCad files under itspathare persistent schematic state. Usepcb apply schematicto reconcile Zener changes and useschematic-compositionwithagent-schemafor visual composition. - Without
Project(...), the project uses the legacy generated schematic.# pcb:sch <ID> ...comments persist placement; preserve them during textual edits, add new code above the block, and do not useagent-schema.
To upgrade a legacy project, export before adding Project(...):
pcb-sch export-kicad board.zen --output schematic
Then add Project(name = "Board", path = "schematic") to the root and run pcb apply schematic --no-open board.zen twice. The first pass may normalize the exported KiCad files; the second must report schematic unchanged.
When renaming or deleting an item, update or remove only its corresponding records. Do not add records or edit coordinates by hand unless the user requested schematic layout work.
Packages and Dependencies
The stdlib is toolchain-managed and does not belong in [dependencies]. Other packages are declared by their load() or Module() imports, and the dependency state in pcb.toml, including indirect entries, is tool-managed.
Use pcb list -m -u to inspect compatible and breaking updates. Use pcb add -u for compatible updates and pcb list -m -versions <url> plus pcb add <url>@<version> for a specific or breaking version. Do not hand-edit resolved versions or use the legacy pcb update workflow.
Board roots contain workspace and board metadata. Registry roots contain reusable component and module members without a root board. Reusable packages contain their own direct dependencies and optional default parts.
Style
Match the surrounding Zener code. Keep declarations concise, use comments for evidence or non-obvious judgment, and avoid decorative section banners or prose that restates the code. These cleanup rules never apply to # pcb:sch records.
Use established naming:
- public
io()names: uppercase; config()names: lowercase;- component instances: uppercase functional names; and
- differential signals:
_Pand_N.
Prefer stdlib generics for common passives, discretes, connectors, test points, and mechanical features. Inspect the current stdlib package rather than relying on a memorized inventory. Use Rectifier, Zener, or Tvs instead of the deprecated generic Diode.
For ordinary boards, prefer Board(..., layers=<count>); standard defaults exist for 2, 4, 6, 8, and 10 layers. Customize them with outer_copper_weight, copper_finish, solder_mask_color, track_widths, and via_dimensions. Use explicit stackup and design-rule records only when those defaults are insufficient; an explicit config merges over the layers-derived defaults.
Completion Evidence
Use each supported primitive for its own purpose:
- after changing imports or dependencies, run
pcb syncfrom the relevant workspace or package; - run
pcb fmton changed Zener; - run
pcb build <path>for affected entrypoints to evaluate the design and collect diagnostics; for registry package curation, usepcb build -Wstyle <path>to promote style advice to warnings; and - use
pcb bom <entrypoint>.zen -f jsononly when sourceability or part selection is relevant.
Command success is evidence, not a complete correctness verdict. Separately review the public API, electrical constraints, stable topology, dependencies, applicable sourceability, and preservation of schematic position state. Report commands actually run and their results separately from engineering conclusions; call unavailable or unperformed work unverified.
How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/diodeinc/pcb/zener-language">View zener-language on skillZs</a>