Files
rebbarb/.claude/skills/kicad-bom-edit/SKILL.md
T
2026-07-08 22:00:53 +02:00

5.4 KiB

name, description
name description
kicad-bom-edit Use when adding or editing BOM/part fields (MPN, LCSC, Manufacturer, tolerance, voltage/current ratings, DNP) on KiCad .kicad_sch symbols by hand or script, or when a kicad-cli BOM export is missing parts. Covers safe property insertion, the "malformed property silently drops a whole sheet" pitfall, and the netlist-vs-BOM count verification that catches it. KiCad 7/8/9/10 S-expression schematics.

Editing KiCad schematics for BOM

Adding manufacturer part numbers (MPN), LCSC codes, ratings, etc. to a KiCad .kicad_sch so the BOM can be ordered/assembled (e.g. JLCPCB). Prefer the KiCad GUI (Symbol Fields Table / per-symbol properties) — it can't corrupt the file. Only hand/script-edit when the GUI isn't available, and then follow this exactly.

How symbols store fields

Each placed symbol is (symbol (lib_id ...) (at ...) ... <properties> <pins> (instances ...)). A field is a property, a direct child of the symbol:

(property "MPN" "FNR4018S3R3MT"
    (at 139.7 87.63 0)
    (hide yes)
    (show_name no)
    (do_not_autoplace no)
    (effects (font (size 1.27 1.27)))
)

Properties Reference, Value, Footprint, Datasheet, Description are mandatory; MPN/LCSC/Manufacturer/V/Type/Current/etc. are custom BOM fields. Field names must be unique within a symbol. kicad-cli sch export bom --fields '...' selects which show up as columns.

⚠️ THE PITFALL: a malformed property silently drops the WHOLE sheet

New BOM fields must be siblings of Value (direct children of the symbol) — NOT nested inside another property. If you accidentally place them inside the Value property, kicad-cli sch export bom will silently omit every component on that sheet — no warning, exit code 0 — while kicad-cli sch export netlist still parses fine and shows nothing wrong. A whole page of parts (regulators, connectors…) can vanish from the BOM you send to the fab.

Root cause seen in practice: naive regex insertion. Property indentation varies by file (some use 2 tabs for (property, some 1). A regex like .*?\n\t\t\t\) grabs the first 3-tab close — which is the inner effects/font close, not the property's own close — so the insert lands inside Value.

Safe insertion (script)

  1. Match the entire target property block by balanced parens, keyed on its unique content (e.g. Value = "2.2uH" at a known (at ...)), from the (property "Value" line to its own closing paren at the property's indent level. Don't rely on a fixed tab count guessed from another file — detect the file's actual property indentation first.
  2. Insert new (property ...) blocks after that close, at the same indent level as Value (siblings), with children one level deeper.
  3. Keep every block paren-balanced (each (property / (effects / (font has its close).

Robust pattern (Python) — replace the whole Value block and append siblings:

import re
src=open(f).read()
# whole L1 Value property: 2-tab property line, 3+tab children, 2-tab close
pat=re.compile(r'\t\t\(property "Value" "2\.2uH"\n(?:\t\t\t.*\n)*?\t\t\)\n')
m=pat.search(src)
def prop(n,v):
    return (f'\t\t(property "{n}" "{v}"\n\t\t\t(at 139.7 87.63 0)\n\t\t\t(hide yes)\n'
            f'\t\t\t(show_name no)\n\t\t\t(do_not_autoplace no)\n\t\t\t(effects\n\t\t\t\t(font\n'
            f'\t\t\t\t\t(size 1.27 1.27)\n\t\t\t\t)\n\t\t\t)\n\t\t)\n')
block=m.group(0).replace('"2.2uH"','"3.3uH"')          # keep Value block intact
add=prop("MPN","FNR4018S3R3MT")+prop("LCSC","C167805")+prop("Manufacturer","cjiang")
src=src[:m.start()]+block+add+src[m.end():]
open(f,'w').write(src)

(Whitespace inside S-expressions is not significant to KiCad — matching indent is only for legibility and to hit the right closing paren. KiCad rewrites formatting on its next save.)

ALWAYS verify: netlist component count must equal BOM row count

This is the check that catches the silent-drop bug. After any schematic edit:

kicad-cli sch export netlist --format kicadsexpr -o /tmp/n.net project.kicad_sch
kicad-cli sch export bom --fields 'Reference,Value,MPN,LCSC' -o /tmp/b.csv project.kicad_sch
# count components in each; they MUST match

Parse the netlist (components (comp (ref ...))) for the ref set, and the BOM CSV first column for its ref set, and print the difference. If the BOM set is smaller, some sheet was dropped — you have a malformed property. Confirm the specific row (grep '"L1"' /tmp/b.csv) shows its new fields populated.

Dual-project-instance sheets

A sub-sheet that was once its own standalone project (e.g. Power.kicad_sch reused in re-bba-rb) has (instances (project "power" ...) (project "re-bba-rb" ...)) on each symbol. This is normal, but it makes such sheets extra-sensitive to malformed properties in BOM export — always run the count check after editing these.

Part selection for JLCPCB / LCSC

  • Fill MPN, Manufacturer, and the LCSC C-number (e.g. C167805) — the LCSC code is what JLC assembly needs. Don't invent C-numbers; verify each on lcsc.com / jlcpcb.com/parts (existence, stock, Basic vs Extended — Extended = small one-time fee).
  • For power inductors, record and check Isat (saturation ≥ peak current) and Irms; a value/footprint alone isn't enough.
  • Match the field-naming already used in the project (this repo uses V, Type, Current, MPN, LCSC, Manufacturer).