Claude
Skills
Sign in
Back

kicad-schematic

Included with Lifetime
$97 forever

Generate, validate, and fix KiCad 8/9 schematic files (.kicad_sch) programmatically. Use this skill whenever the user wants to create, modify, or fix KiCad schematics, generate netlists from circuit descriptions, fix ERC errors, or migrate schematics between KiCad versions. Triggers on: KiCad, schematic, .kicad_sch, ERC, electrical rules check, circuit design, PCB schematic, netlist generation, S-expression schematic, KiCad migration.

Designscripts

What this skill does


# KiCad Schematic Agent

Generate ERC-clean KiCad 8/9 schematics by writing Python scripts that use computed pin positions — never guess coordinates. Also fix ERC errors on existing schematics and handle KiCad 8→9 migration.

## Critical Principle

**The #1 cause of broken schematics is guessed pin positions.** When connecting labels to IC pins, you MUST compute exact coordinates using the symbol definition's pin positions and the coordinate transform formula. The helper library in `scripts/kicad_sch_helpers.py` does this automatically.

### The Y-axis Trap (Most Common Bug)

Symbol libraries (.kicad_sym) use **Y-up** (math convention). Schematics (.kicad_sch) use **Y-down** (screen convention). This means you MUST negate the Y coordinate when transforming from library to schematic space. Forgetting this will place labels 10-50mm away from their pins, causing massive pin_not_connected and label_dangling errors.

**Transform formula** — pin at library (px, py), symbol placed at schematic (sx, sy) with rotation R:
- **Rotation 0**:   schematic position = (sx + px, sy **-** py)
- **Rotation 90**:  schematic position = (sx + py, sy + px)
- **Rotation 180**: schematic position = (sx - px, sy **+** py)
- **Rotation 270**: schematic position = (sx - py, sy - px)

Always use `pin_abs()` from the helper library — never compute these by hand.

## Architecture

```
User describes circuit
        |
Read symbol libraries (.kicad_sym) to get pin positions
        |
Build pin position dictionaries for every multi-pin IC
        |
Write Python script using SchematicBuilder (from helper library)
  - Use connect_pin() for IC pins (computes positions automatically)
  - Use place_2pin_vertical() for passives (knows pin 1/2 positions)
        |
Generate .kicad_sch file
        |
Post-process with fix_subsymbol_names()
        |
Run ERC validation: kicad-cli sch erc --format json
        |
Parse errors -> fix script -> regenerate -> repeat (max 5 iterations)
```

## Step-by-step Workflow

### 0. Ensure kicad-cli is Available

Before running any ERC validation, verify that `kicad-cli` is on the system PATH. Run:

```bash
which kicad-cli 2>/dev/null || where kicad-cli 2>/dev/null
```

If **not found**, check for a local KiCad installation and offer to create a symlink:

**macOS:**
```bash
# Check if KiCad is installed as an app
KICAD_CLI="/Applications/KiCad/KiCad.app/Contents/MacOS/kicad-cli"
if [ -f "$KICAD_CLI" ]; then
    echo "Found kicad-cli inside KiCad.app. Creating symlink..."
    sudo ln -sf "$KICAD_CLI" /usr/local/bin/kicad-cli
    echo "Done! kicad-cli is now available on PATH."
else
    echo "KiCad not found. Install from https://www.kicad.org/download/macos/"
fi
```

**Linux:**
```bash
# kicad-cli is typically installed alongside KiCad via package manager
# Check common locations
for p in /usr/bin/kicad-cli /usr/local/bin/kicad-cli /snap/kicad/current/bin/kicad-cli; do
    if [ -f "$p" ]; then
        echo "Found kicad-cli at $p"
        # If not on PATH, symlink it
        if ! command -v kicad-cli &>/dev/null; then
            sudo ln -sf "$p" /usr/local/bin/kicad-cli
        fi
        break
    fi
done
# If still not found:
# Ubuntu/Debian: sudo apt install kicad
# Fedora: sudo dnf install kicad
# Arch: sudo pacman -S kicad
# Or install from https://www.kicad.org/download/linux/
```

**Windows:**
```powershell
# Check standard install path
$kicadCli = "C:\Program Files\KiCad\8.0\bin\kicad-cli.exe"
if (Test-Path $kicadCli) {
    Write-Host "Found kicad-cli. Add to PATH:"
    Write-Host '  [Environment]::SetEnvironmentVariable("PATH", $env:PATH + ";C:\Program Files\KiCad\8.0\bin", "User")'
} else {
    Write-Host "KiCad not found. Install from https://www.kicad.org/download/windows/"
}
```

Tell the user what you found and ask for confirmation before creating any symlinks. If kicad-cli is truly not installed, provide the download link for their OS and stop — ERC validation requires it.

### 1. Understand the Circuit

Before writing any code, gather:
- Component list with specific part numbers
- Power architecture (voltage rails, regulators)
- Signal connections (which pins connect to which)
- Symbol libraries needed (standard KiCad libs + any custom .kicad_sym files)

### 2. Read Symbol Libraries (NON-NEGOTIABLE)

For **every IC and multi-pin component**, read its .kicad_sym definition to get exact pin names, numbers, positions, and types. You cannot connect pins correctly without this data.

```python
from kicad_sch_helpers import SymbolLibrary

lib = SymbolLibrary()
lib.load_from_kicad_sym("path/to/library.kicad_sym")

# Now you know exact pin positions
ad9363 = lib.get("AD9363ABCZ")
for pin in ad9363.pins:
    print(f"{pin.name} ({pin.number}): at ({pin.x}, {pin.y}), type={pin.pin_type}")
```

**For manual/inline approaches**, build a pin dictionary from the library:
```python
# Extract from .kicad_sym file — these are LIBRARY coordinates (Y-up)
AD_PINS = {
    'TX1A_P': (-17.78, 25.40),
    'TX1A_N': (-17.78, 22.86),
    'SPI_CLK': (-17.78, -10.16),
    # ... all pins
}

# SOT-23-5 packages (common for LDOs like AP2112K, ME6211):
SOT5_PINS = {
    'VIN':  (-7.62,  2.54),   # Pin 1 - top left
    'GND':  ( 0.00, -7.62),   # Pin 2 - bottom center
    'EN':   (-7.62, -2.54),   # Pin 3 - bottom left
    'NC':   ( 7.62, -2.54),   # Pin 4 - bottom right  <- NOT VOUT!
    'VOUT': ( 7.62,  2.54),   # Pin 5 - top right     <- THIS is VOUT!
}
```

**WARNING — SOT-23-5 pin trap:** VOUT is at (7.62, **+2.54**) and NC is at (7.62, **-2.54**). These are only 5.08mm apart. Confusing them means your LDO output goes nowhere. Always verify from the actual library file.

### 3. Write the Generator Script

Use `SchematicBuilder` for all schematic construction. The key method is `connect_pin()` which computes exact pin positions automatically:

```python
from kicad_sch_helpers import SchematicBuilder, SymbolLibrary, snap

lib = SymbolLibrary()
lib.load_from_kicad_sym("custom_symbols.kicad_sym")

sch = SchematicBuilder(symbol_lib=lib, project_name="my_project")
sch.set_lib_symbols(lib_symbols_content)  # Raw S-expression for embedded symbols

# Place an IC
sch.place("CubeSat_SDR:AD9363ABCZ", "U1", "AD9363ABCZ",
          x=320, y=200, footprint="CubeSat_SDR:AD9363_BGA144")

# Connect pins by NAME — coordinates computed automatically
sch.connect_pin("U1", "TX1A_P", "TX1A_P", wire_dx=-5.08)
sch.connect_pin("U1", "SPI_CLK", "SPI_CLK", wire_dy=-5.08)
sch.connect_pin("U1", "GND", "GND", wire_dy=5.08)

# For unused pins, add no-connect flags
sch.connect_pin_noconnect("U1", "AUXDAC1")

# For 2-pin passives, use convenience helpers
from kicad_sch_helpers import place_2pin_vertical
place_2pin_vertical(sch, "Device:C", "C1", "100nF",
                    x=snap(230), y=snap(155),
                    top_net="VCC_3V3", bottom_net="GND",
                    footprint="Capacitor_SMD:C_0402_1005Metric")
```

**If using inline pin dictionaries** (without SymbolLibrary), use `pin_abs()`:
```python
from kicad_sch_helpers import pin_abs, snap

GRID = 1.27

def wl(sch, sx, sy, pin_name, pins_dict, net, dx=0, dy=0, rot=0, label_angle=0):
    """Wire + Label: connect an IC pin to a net label."""
    px, py = pin_abs(sx, sy, pins_dict[pin_name][0], pins_dict[pin_name][1], rot)
    ex, ey = snap(px + dx), snap(py + dy)
    if dx != 0 or dy != 0:
        sch.w(px, py, ex, ey)
    sch.label(net, ex, ey, label_angle)

# Usage:
wl(sch, 320, 200, 'TX1A_P', AD_PINS, "TX1A_P", dx=-7.62)
```

### 4. Handle the lib_symbols Section

Every symbol referenced must be embedded in the schematic's lib_symbols. Three critical rules:

1. **Parent symbols** use the full lib_id: `(symbol "Device:R" ...)`
2. **Sub-symbols** must NOT have the library prefix: `(symbol "R_0_1" ...)` not `(symbol "Device:R_0_1" ...)`
3. **Always post-process** with `fix_subsymbol_names()` to catch any mistakes

Use `fix_subsymbol_names()` as a post-processing step:
```python
from kicad_sch_helpers import fix_subsymbol_names

content = sc
Files: 6
Size: 93.7 KB
Complexity: 66/100
Category: Design

Related in Design