From kicad-skills
Use when the user asks to clean up, tidy, beautify, or improve the layout/readability/`sch inspect` score of a KiCad schematic sheet. Stage-2 visual pass; not for connectivity changes.
How this skill is triggered — by the user, by Claude, or both
Slash command
/kicad-skills:kicad-sch-cleanup-loopThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Main loop plans + scores; subagents edit one cluster at a time. Edit conventions: `kicad-hardware-editing`. CLI: `kicad-tool`. Connectivity-parity: `kicad-validate`.
Main loop plans + scores; subagents edit one cluster at a time. Edit conventions: kicad-hardware-editing. CLI: kicad-tool. Connectivity-parity: kicad-validate.
Inputs: <sheet> (child) and <top> (the project's top-level .kicad_sch).
Never Read/cat/grep the .kicad_sch (thousands of S-expr lines blow context). Use sch query (region/symbol/pin/wire/label/net/list) and mutate via sch edit. Missing query/edit → extend kicad-tool.
kicad-tool sch validate <top> --sheet <sheet> \
--save-baseline tmp/cleanup-baseline > tmp/cleanup-baseline.json
Repo-root-relative paths. No 2>&1 (stderr breaks JSON). Record score.total, collisions, symbol_wire_conflicts.
Greedy "fix highest-priority first" produces myopic rewires that later moves invalidate. Plan the target area with surrounding context first.
tmp/cleanup-overview.png via sch render-region. Read alongside JSON.symbol_wire_conflicts/collisions before wire_corner_count/diagonal/wire_length.sch query region over the wire's bbox (+~0.01 mm). Endpoint stubs orphan mid-span taps. Pass tap list to subagent.tmp/cleanup-plan.md — clusters in order, one block each. Update as work progresses.Score is a long-horizon target: an anchor rotation may temporarily lengthen neighbor wires, paying off only after 1–2 more clusters. Use checkpoints, not per-edit gating, for score.
git checkout -- <sheet>, record (cluster, approach). Never tolerate.Last-good checkpoint = most recent state with score.total ≤ baseline checkpoint. Materialized by tmp/cleanup-baseline/ (only refreshed on accept) + working tree. Rollback = git checkout -- <sheet> (no stash/branch). Accepting mid-streak resets the streak counter to 0 — there is no "streak with accepted edits in the middle".
For each cluster in planned order:
tmp/cleanup-area.png, re-query bbox issues. Skip if already resolved upstream.tmp/cleanup-area.png, issue records, symbols/labels/wires inside, pre-edit score.total, planned approach + rationale, fix preference, and a note that short-term score regression is allowed if it sets up the next cluster (prefer non-regressing fixes when equivalent).sch validate <top> --sheet <sheet> --baseline tmp/cleanup-baseline > tmp/cleanup-latest.json
--save-baseline tmp/cleanup-baseline). Clear streak.tmp/cleanup-overview.png, read it, compare against the plan's predicted intermediate topology. Diverges → planning miss: roll streak back, record divergence, update tmp/cleanup-plan.md.Stop Phase 1 when:
tmp/cleanup-plan.md alongside the cluster log.After Phase 1 stabilizes positions. Cosmetic only — long-horizon argument does not apply. Per-cluster strict gate: accept only if ERC parity, score.total not worse, no new collisions; else revert immediately. Group components into local clusters; subagent places Value/Reference adjacent to symbol body and tightens labels onto wire endpoints — no symbol moves unless trivial. Stop after one full pass with zero accepts.
wire_hits is data, not a stop sign. Order of operations:
sch render-region over the area, look at it. Identify visually: which side of the body is open, where rails / stubs / siblings sit. The PNG answers "where could the label go" before any math.sch inspect, read its actual bbox.{x1,y1,x2,y2}. Do not estimate from n_chars × 1.1 mm; the probe is cheap and the estimate misses justify/baseline offsets. The probe edit is also the first edit of the cluster — keep it.bbox and the input at = (ax, ay): dx_left = ax - bbox.x1, dx_right = bbox.x2 - ax, dy_top = ay - bbox.y1, dy_bot = bbox.y2 - ay. KiCad anchor is not bbox-center — it's text justify + font baseline, so these four offsets are asymmetric. Reuse them for the final position.body_center_x. Anchor Value/Reference at body_left_x or body_right_x — never center — so the narrow vertical-text bbox is disjoint from the stub and y can pass through the rail-to-pin band even when shorter than text height. Note: the property's own angle field combines with the parent symbol's rotation; vertical-rendered text often appears with property angle=0 when the symbol itself is rotated 90°/270°. Trust the probed bbox, not the angle field.anchor_y = body_top_y - dy_bot - 0.25. Below: anchor_y = body_bottom_y + dy_top + 0.25. Left: anchor_x = obstacle_x - dx_right - 0.25. Right: anchor_x = obstacle_x + dx_left + 0.25. ε = 0.25 mm clearance. Source for body_top_y etc.: use sch query region <bbox covering the symbol>, then read symbols[<i>].bbox — that is the graphic body only. Do not use sch inspect's component_hits[].bbox (can include attached property text), and sch query symbol does not return a bbox.(x, y) formula; anchor consistency beats visual symmetry.Forbidden: "try A, try B, try C". The probe edit is your one allowed exploratory placement; after that, re-read the PNG, apply the offset arithmetic, commit.
Sheet: <sheet>
Baseline: total=<n0> ERC=<e0>
Plan: <k> clusters
Phase 1: total=<n1> Δ=<n1-n0> checkpoints=<a1> hard-reverts=<r1> exploratory-rollbacks=<x1> skipped=<s1>
Phase 2: accepted=<a2> passes=<p2>
Final ERC: <parity | listed intentional>
Show git diff --stat <sheet>. Do not commit unless asked.
tmp/cleanup-plan.md exists.removed_nodes catches it.tmp/ filenames: cleanup-baseline.json, cleanup-latest.json, cleanup-overview.png, cleanup-area.png, cleanup-plan.md.Guides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub mash/kicad-skills --plugin kicad-skills