KiCad Monkey
▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓░░░░░░▓▓░░░░░░▓▓▓▓
░░░░▓▓░░░░░░░░░░░░░░░░░░▓▓░░░░
░░░░▓▓░░ ░░░░░░ ░░▓▓░░░░
░░▓▓░░ ██░░░░░░ ██░░▓▓░░
▓▓░░░░░░░░░░░░░░░░░░▓▓
▓▓░░░░░░░░░░░░░░▓▓
▓▓▓▓░░░░░░▓▓▓▓
░░ ▓▓▓▓▓▓
▓▓ ▓▓▓▓▓▓▓▓▓▓
▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓░░▓▓░░▓▓▓▓
kicad_monkey is a focused Python package for KiCad source-file parsing,
round-trip modeling, close-to-format utilities, and IR-backed 2D rendering.
Use it when you need Python code to inspect or modify KiCad files directly:
- read
.kicad_pro,.kicad_sch,.kicad_pcb,.kicad_sym, and.kicad_modfiles; - query schematic and PCB objects through typed model facades;
- compile KiCad-native design netlists and design JSON;
- render schematic, PCB, symbol, and footprint views through plotter IR and SVG;
- make focused model edits, then write KiCad files back out.
This package is the low-level parser/model/rendering library. The same
repository also contains the separately published kicad-cruncher workflow
CLI under packages/kicad_cruncher/. The CLI depends on Monkey; Monkey never
depends on the CLI.
The Rust port has closed its Plotter-IR boundary and its bounded Windows x64 native Cruncher delivery milestone. See the native Cruncher delivery audit. The accepted native base SVG slice is followed by the accepted Windows no-fallback PCB physical provider, which retains Cruncher-owned enrichment and composition while replacing its physical-base serialization seam. The accepted source-bound native design-facts slice next switches the Windows compiled graph and version-E netlist while retaining Python Design JSON, netlist JSON, presentation, and orchestration. The accepted native-backed CLI compatibility slice governs the installed entry points, primary design aliases, artifact tree, logs, exits, and no-fallback failures without claiming a separate all-Rust Cruncher executable. The accepted Windows x64 release exit binds one tested candidate set to CI and release publication. That milestone remains the historical native-provider boundary: Linux and macOS retained the established Python provider path, and Python still owned Cruncher orchestration and presentation.
The accepted
pure-Rust design CLI follow-on
now supersedes that boundary for the Windows x64 design, design-review, and
dr vertical slice. Release archives contain Python-free kicad-cruncher and
kcr executables that own the complete review-bundle orchestration and
transactional publication path, plus version reporting. This is deliberately
not an all-command or all-platform Rust claim: other Cruncher commands remain
available through the universal Python wheel and python -m kicad_cruncher,
and Monkey remains the reusable lower-level library rather than depending on
Cruncher.
Install
For library use inside an existing Python environment:
pip install kicad-monkey
For development:
git clone https://github.com/wavenumber-eng/kicad_monkey.git
cd kicad_monkey
uv sync --extra test
To develop and validate both public distributions from one checkout:
uv sync --all-packages --all-extras
uv run --package kicad-cruncher kicad-cruncher --help
uv run --all-packages --all-extras python -m pytest tests/cross_package -q
Quick Examples
Load A Design And Inspect Nets
from kicad_monkey import KiCadDesign
design = KiCadDesign.from_project_file("hardware/demo.kicad_pro")
netlist = design.to_netlist()
for net in netlist.nets:
terminals = ", ".join(
f"{terminal.designator}.{terminal.pin}"
for terminal in net.terminals
)
print(f"{net.name}: {terminals}")
Save the KiCad-native design JSON used by higher-level review tools:
from pathlib import Path
Path("build").mkdir(parents=True, exist_ok=True)
design.save_json("build/design.json")
Render PCB SVG
from pathlib import Path
from kicad_monkey import KiCadDesign
design = KiCadDesign.from_project_file("hardware/demo.kicad_pro")
out_dir = Path("build/svg")
out_dir.mkdir(parents=True, exist_ok=True)
svg = design.to_pcb_svg(
layers=["Edge.Cuts", "F.Cu", "F.SilkS"],
profile="enriched",
)
(out_dir / "front-copper.svg").write_text(svg, encoding="utf-8")
Use profile="oracle" when comparing against KiCad CLI output. Use
profile="enriched" when an app needs metadata on SVG elements. PCB SVG
rendering builds the board render IR before applying layers=, so layer
filters reduce output size but do not avoid full PCB parse or IR-build cost.
Render Every Schematic Sheet Instance
Hierarchical designs can instantiate one .kicad_sch file more than once.
KiCadSchematicInstance represents each concrete sheet view.
from pathlib import Path
from kicad_monkey import KiCadDesign, render_ir_to_svg
design = KiCadDesign.from_project_file("hardware/demo.kicad_pro")
out_dir = Path("build/schematic-svg")
out_dir.mkdir(parents=True, exist_ok=True)
for sheet in design.schematic_instances():
doc = design.to_schematic_instance_ir(sheet)
svg = render_ir_to_svg(doc)
safe_name = sheet.sheet_name.replace("/", "_").replace("\\", "_")
(out_dir / f"{sheet.instance_index:02d}_{safe_name}.svg").write_text(
svg,
encoding="utf-8",
)
To find where a reused child schematic appears:
for instance in design.schematic_instances_for("hardware/LED_Controller.kicad_sch"):
print(instance.sheet_name, instance.sheet_path, instance.sheet_instance_path)
Query And Mutate Schematic Objects
The .objects property is a live read-only query view over model-owned
objects. Mutate the returned objects, then call save().
from kicad_monkey import KiCadSchematic
schematic = KiCadSchematic.from_file("hardware/demo.kicad_sch")
for symbol in schematic.objects.where("SchSymbol"):
if symbol.reference.startswith("R"):
symbol.set_property_value("Value", "10 kOhm")
for label in schematic.objects.where("SchLabel"):
if label.effects is not None and label.effects.font is not None:
label.effects.font.size_x = 1.5
label.effects.font.size_y = 1.5
schematic.save("hardware/demo.edited.kicad_sch")
Query And Mutate PCB Objects
from kicad_monkey import KiCadPcb
board = KiCadPcb.from_file("hardware/demo.kicad_pcb")
for footprint in board.objects.where("Footprint"):
reference = footprint.get_property_value("Reference")
if reference.startswith("U"):
footprint.set_property_value("Reviewed", "yes", create=True)
for text in board.objects.where("GrText", layer="F.SilkS"):
text.effects.font.size_x = 1.0
text.effects.font.size_y = 1.0
text.text = text.text.strip()
board.save("hardware/demo.edited.kicad_pcb")
Object queries also work with class objects when you prefer typed imports:
from kicad_monkey import Footprint, KiCadPcb
board = KiCadPcb.from_file("hardware/demo.kicad_pcb")
connectors = [
footprint
for footprint in board.objects.where(Footprint)
if footprint.get_property_value("Reference").startswith("J")
]
Scan Large Files Without Full Model Materialization
Use projection or targeted readers when you only need narrow inventories, diagnostics, source spans, or selected object families from a large file.
from kicad_monkey import KiCadPcbProjection
projection = KiCadPcbProjection.from_file("hardware/demo.kicad_pcb")
for model_ref in projection.model_references():
print(model_ref.reference, model_ref.path)
route_count = len(projection.segments()) + len(projection.vias())
print(f"{route_count} route objects")
For schematic or custom narrow reads, use the generic targeted reader:
from kicad_monkey import SchSymbol, iter_kicad_objects_from_file
for symbol in iter_kicad_objects_from_file("hardware/demo.kicad_sch", SchSymbol):
print(symbol.reference, symbol.value)
Projection still scans the source file, but it hydrates only the requested
object families. Use KiCadPcb, KiCadSchematic, or KiCadDesign when you
need mutation, rendering, netlisting, full geometry, or cross-document context.
For measured tradeoffs, net-table caveats, and render cost details, see
Project Workflows And Read-Path Selection.
Testing
Rack is the primary public gate:
uv run --extra test python tests/rack.py run L0_foundation
uv run --extra test python tests/rack.py run L99_signoff
The parser-first Rust port uses the same Rack orchestrator. Its L0 gate is split into locked Cargo tests, shared Python/Rust vectors, generated-contract and executable WASM signoff, and comparative performance evidence:
uv run python tests/rack.py run L0_044
uv run python tests/rack.py run L0_045
uv run python tests/rack.py run L0_046
Performance cases L0_047, L1_023, and L1_024 are advisory and skip in
ordinary fast/full development runs. Run them explicitly in the strict lane:
uv run python tests/rack.py run L0_047 --lane strict
uv run python tests/rack.py run L1_023 --lane strict
uv run python tests/rack.py run L1_024 --lane strict
Run npm ci once to install the pinned TypeSpec toolchain. The executable WASM
test also requires the lock-compatible runner documented in
docs/design/rust-standard.html.
L99_signoff checks release metadata, changelog coverage, public API contract
resolution, API design-doc ownership, Rack test ownership, corpus archive
hygiene, and the current ruff/pyright ratchet state.
KiCad Newstroke Webfonts
The authoritative assets/fonts/ bundle contains the KiCad Stroke family as
Light, Regular, and Bold faces, each upright and italic, in TTF, OTF, WOFF,
and WOFF2 formats. The companion CSS and offline demo exercise electronics
notation, Greek, mathematical symbols, BOM text, and fabrication notes.
Regenerate and verify the complete bundle from the vendored CC0 Newstroke table with:
uv run python tools/package_kicad_stroke_webfont_assets.py
uv run python tools/package_kicad_stroke_webfont_assets.py --check
The checked manifest pins the generator, source table, mark, theme, every font file, CSS, and demo. See KiCad Newstroke Webfont Bundle for the format and ownership decisions.
The redistributable KiCad corpus is restored locally as
tests/corpus/kicad.zip; the archive itself is ignored and is not tracked with
Git LFS. CI restores that archive from the public object URL recorded in
tests/corpus/kicad.archive.toml and verifies size and SHA-256 before tests run.
KICAD_MONKEY_CORPUS_URL may override the manifest URL for local testing or an
emergency reroute. The loose mirror is ignored locally; test helpers extract the
archive on demand when no external corpus is configured.
Restore and verify the archive before running mandatory corpus-backed Rust parity gates:
uv run --extra test python scripts/kicad_corpus_archive.py restore --check-zip
uv run --extra test python tests/rack.py run L1_029
API Shape
Stable package-root exports are recorded in
kicad_monkey.kicad_api_contract. Those names are the public API that
downstream code should rely on. The broader package __all__ remains a
discovery surface while downstream integrations prove which additional symbols
should become stable public exports.
The public OOP facade groups and supporting public classes are documented under docs/design/api. Use Project Workflows And Read-Path Selection for practical guidance on which API to choose for project, render, inventory, and large-file workflows. L99 fails when a stable public class or major interface is missing design documentation or Rack test ownership.
Typical entrypoints:
from kicad_monkey import KiCadDesign, KiCadFootprint, KiCadPcb, KiCadSchematic
from kicad_monkey import KiCadSymbolLib
schematic = KiCadSchematic.from_file("design.kicad_sch")
board = KiCadPcb.from_file("board.kicad_pcb")
design = KiCadDesign.from_project_file("project.kicad_pro")
symbols = KiCadSymbolLib.from_file("library.kicad_sym")
footprint = KiCadFootprint.from_file("package.kicad_mod")
For workflow-level API choice, use Project Workflows And Read-Path Selection as the canonical guide.
Fixture Model
Public fixtures should be redistributable and package-local when possible. Broader fixture families should use this shape:
input/reference_output/output/
output/ is transient and should stay local or temporary.
Documentation
License
MIT.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file kicad_monkey-2026.8.30.tar.gz.
File metadata
- Download URL: kicad_monkey-2026.8.30.tar.gz
- Upload date:
- Size: 9.3 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
332d6542d5116a0e538d380ba8a96312ad65acd67a9cf941cc60af42c663db80
|
|
| MD5 |
f941023f2e826c711f54973d0d739a20
|
|
| BLAKE2b-256 |
ae186a8edf06236839d8bff017e298211631c949a91631f2af8060fe0b67bcd3
|
Provenance
The following attestation bundles were made for kicad_monkey-2026.8.30.tar.gz:
Publisher:
release.yml on wavenumber-eng/kicad_monkey
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kicad_monkey-2026.8.30.tar.gz -
Subject digest:
332d6542d5116a0e538d380ba8a96312ad65acd67a9cf941cc60af42c663db80 - Sigstore transparency entry: 2666427852
- Sigstore integration time:
-
Permalink:
wavenumber-eng/kicad_monkey@67b84206b0cb34e1036bb8e54cae015e67fe1e7a -
Branch / Tag:
refs/heads/main - Owner: https://github.com/wavenumber-eng
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@67b84206b0cb34e1036bb8e54cae015e67fe1e7a -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file kicad_monkey-2026.8.30-py3-none-win_amd64.whl.
File metadata
- Download URL: kicad_monkey-2026.8.30-py3-none-win_amd64.whl
- Upload date:
- Size: 2.4 MB
- Tags: Python 3, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d1e0ca9b094d96fec4d993e1b4751f55fe141bfada5651f5c23ccc14a53a8ed7
|
|
| MD5 |
fa90d24e6caf388e042a3fa92e734aa2
|
|
| BLAKE2b-256 |
5a351acdcacdc747397bd0da294784aa51938a2171091c5795b01896d06ae1fc
|
Provenance
The following attestation bundles were made for kicad_monkey-2026.8.30-py3-none-win_amd64.whl:
Publisher:
release.yml on wavenumber-eng/kicad_monkey
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kicad_monkey-2026.8.30-py3-none-win_amd64.whl -
Subject digest:
d1e0ca9b094d96fec4d993e1b4751f55fe141bfada5651f5c23ccc14a53a8ed7 - Sigstore transparency entry: 2666427969
- Sigstore integration time:
-
Permalink:
wavenumber-eng/kicad_monkey@67b84206b0cb34e1036bb8e54cae015e67fe1e7a -
Branch / Tag:
refs/heads/main - Owner: https://github.com/wavenumber-eng
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@67b84206b0cb34e1036bb8e54cae015e67fe1e7a -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file kicad_monkey-2026.8.30-py3-none-any.whl.
File metadata
- Download URL: kicad_monkey-2026.8.30-py3-none-any.whl
- Upload date:
- Size: 778.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fa951994ce540bbc5017df33a347be862c8b41f85f49f4616e5eddd4f3eeefa0
|
|
| MD5 |
8f7cf589694b9b8b5dbb2c604b925fbe
|
|
| BLAKE2b-256 |
f1205c830e4521afd81b12dee2bae4ffc05381d5c8abd4ab3fa5508f2f3d081e
|
Provenance
The following attestation bundles were made for kicad_monkey-2026.8.30-py3-none-any.whl:
Publisher:
release.yml on wavenumber-eng/kicad_monkey
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kicad_monkey-2026.8.30-py3-none-any.whl -
Subject digest:
fa951994ce540bbc5017df33a347be862c8b41f85f49f4616e5eddd4f3eeefa0 - Sigstore transparency entry: 2666427900
- Sigstore integration time:
-
Permalink:
wavenumber-eng/kicad_monkey@67b84206b0cb34e1036bb8e54cae015e67fe1e7a -
Branch / Tag:
refs/heads/main - Owner: https://github.com/wavenumber-eng
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@67b84206b0cb34e1036bb8e54cae015e67fe1e7a -
Trigger Event:
workflow_dispatch
-
Statement type: