agentleFS
diodeincdiodeinc/pcb/skills/zener-language/SKILL.md

zener-language

Skill477 starsChanged 11 days agoMITView on GitHub

Read or edit Zener HDL, package APIs, and tool-managed dependencies.

The file

Show its rules and text

We split this skill into the rules it gives an agent

19 rules. About 0 are common, 6 are distinctive, and 13 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈6

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 13

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Use pcb list -m -json @stdlib or pcb list -m -json <package>[@<version>] to find a package's local source directory, then read its .zen …

    line 12
  2. Very specific:

    Use refdes-like names only when the user explicitly asks.

    line 35
  3. Very specific:

    Use Symbol(library, name=...) for multi-symbol libraries.

    line 39
  4. Very specific:

    Do not introduce legacy Pins = struct(...) wrappers in new or touched APIs.

    line 53
  5. Very specific:

    Use stdlib interfaces such as DiffPair, I2c, I3c, Spi, Qspi, Uart, Usart, Swd, Jtag, Usb2, and Usb3 when the grouped protocol semantics are …

    line 59
  6. Very specific:

    Use UartPair() and UsartPair() when a point-to-point link should cross-connect the two endpoints.

    line 61
  7. Distinctive:

    Do not use conditional instantiation to change topology.

    line 88
  8. Very specific:

    Use an IC's internal pull-up or pull-down for its default mode when appropriate.

    line 89
  9. Distinctive:

    Put non-trivial electrical calculations in named functions.

    line 91
  10. Very specific:

    Use check, warn, error, and stdlib checks for enforceable electrical constraints rather than documenting them only in comments.

    line 95
  11. Distinctive:

    If consumers must change to adopt an update, treat it as breaking.

    line 103
  12. Very specific:

    Use pcb list -m -u to inspect compatible and breaking updates.

    line 118
  13. Distinctive:

    Prefer stdlib generics for common passives, discretes, connectors, test points, and mechanical features.

    line 133
  14. Distinctive:

    Use each supported primitive for its own purpose:

    line 139
  15. Very specific:

    after changing imports or dependencies, run pcb sync from the relevant workspace or package.

    line 141
  16. Very specific:

    run pcb fmt on changed Zener.

    line 142
  17. Very specific:

    run pcb build <path> for affected entrypoints to evaluate the design and collect diagnostics.

    line 143
  18. Very specific:

    use pcb bom <entrypoint>.zen -f json only when sourceability or part selection is relevant.

    line 144
  19. Distinctive:

    Use the applicable checks and engineering evidence for the changed API, circuit, or dependencies.

    line 146

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Zener Language

Zener is Starlark plus PCB-specific modules, typed electrical connections, physical parts, sourcing, layout, and diagnostics.

Discover Before Authoring

Use pcb list -m -json @stdlib or pcb list -m -json <package>[@<version>] to find a package's local source directory, then read its .zen files for the public API and exact behavior.

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 dnp and properties arguments.

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.

Project() takes layout = False or schematic = False to disable either. Use one declaration per entrypoint with a config-independent path relative to its .zen file; use separate entrypoints for distinct projects.

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. Inspect the installed API for other operations.

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

Inspect the root declaration and its flags:

  • Board(..., schematic = True) uses layout_path; Project(...) uses path with schematics enabled by default. These KiCad files are persistent state.
  • Without a linked schematic, preserve legacy # pcb:sch <ID> ... placement comments, add new code above the block, and do not use the agent-schema CLI. On rename or deletion, update only the corresponding records; do not hand-edit coordinates outside requested schematic layout work.

For a requested legacy migration, first run pcb-sch export-kicad <root.zen> --output <fresh-directory>. Preserve the exported placement and existing layout when linking the KiCad files: enable schematic = True on the existing Board(), or replace a module's Layout() with Project(). Run pcb apply schematic --no-open <root.zen> twice; the second must report schematic unchanged.

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: _P and _N suffixes (KiCad pairs nets by these suffixes alone).

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 sync from the relevant workspace or package;
  • run pcb fmt on changed Zener;
  • run pcb build <path> for affected entrypoints to evaluate the design and collect diagnostics; for registry package curation, use pcb build -Wstyle <path> to promote style advice to warnings; and
  • use pcb bom <entrypoint>.zen -f json only when sourceability or part selection is relevant.

Use the applicable checks and engineering evidence for the changed API, circuit, or dependencies. Preserve schematic position state and report unverified work.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.