revsch is a Python tool for turning a small reverse-engineering DSL into a KiCad schematic.
The DSL supports two closely related workflows:
- schematic-style capture: declare parts, pins, and named nets explicitly
- probe-first mapping: capture continuity quickly with
X -> Y, Ztraces, batch-generated parts, and sparse pin metadata
The output is a valid .kicad_sch file that opens in KiCad and can be refined there by swapping symbols, improving layout, and adding drawing detail.
For standard generic parts, the emitter now prefers official KiCad library symbols. For custom and unknown parts, it falls back to embedded generated symbols so the schematic remains self-contained.
Install and Run
This project uses uv.
uv run revsch lint examples/basic_minimal.revsch
uv run revsch compile examples/basic_minimal.revsch -o ~/tmp/basic_minimal.kicad_schUseful commands:
uv run revsch lint input.revsch uv run revsch lint --mapping-mode input.revsch uv run revsch compile input.revsch -o output.kicad_sch uv run revsch compile --mapping-mode input.revsch -o output.kicad_sch uv run revsch compile input.revsch -o output.json --output-format json uv run revsch dump-ir input.revsch uv run revsch dump-json input.revsch uv run revsch format input.revsch
DSL Overview
Supported statement types:
part REFDES ...pin REFDES.PIN ...net NAME = REFDES.PIN, REFDES.PINalias ALT = NETproperty TARGET KEY = VALUEnote TARGET = VALUEPREFIX key=value ...Used for batch generation, for exampleIC name=PLA pincount=16 count=6A -> B, C, DUsed for fast probe mapping
Comments start with #. Quoted strings are supported.
<X> Batch Part Syntax
part REFDES<X> ... count=N [start=S] generates multiple identical parts.
<X> is replaced with an index for each generated part.
start sets the first index (default 0).
For example, part ENC<X> count=2 start=1 creates ENC1 and ENC2.
Subsequent pin, net, property, note, and trace statements
using <X> in the reference designator expand across all generated parts.
Schematic-Style Example
part U1 kind=IC value="STM32F103C8" package=LQFP48
pin U1.24 name=VDD type=power_in
pin U1.32 name=PA11 type=bidirectional
pin U1.33 name=PA12 type=bidirectional
part J1 kind=CONN value="USB-C" package=USB_C_16
pin J1.A6 name=D+
pin J1.A7 name=D-
net VCC_3V3 = U1.24
net USB_D+ = U1.33, J1.A6
net USB_D- = U1.32, J1.A7
alias +3V3 = VCC_3V3
Probe-First Mapping Example
This is the fast capture workflow for tracing a board with a continuity probe.
IC name=PLA pincount=16 count=6
C count=10
R count=5
J name=EDGE pincount=44 count=1
J1.1 -> +5V
J1.2 -> C1, R3, IC1.3
C1 -> GND
R3 -> GND
Behavior:
IC name=PLA pincount=16 count=6createsIC1throughIC6, each with 16 pinsC count=10createsC1throughC10with two pins eachJ1.2 -> C1, R3, IC1.3creates one net containingJ1.2, one implicit pin fromC1, one implicit pin fromR3, and explicit pinIC1.3- bare net names such as
+5VorGNDbecome canonical net names - if no net name appears in a trace statement, an automatic net name is created
Sparse Capture
For reverse engineering, most pin metadata can be omitted:
part U1
pin U1.6
pin U1.7
net ROW0 = U1.6
net COL0 = U1.7
If a pin has no explicit name, the emitter falls back to the pin ID so the generated symbol is still usable.
Mapping Mode
--mapping-mode is intended for probe capture, where many pins are still untraced.
It suppresses warnings that are usually noise during early reverse engineering:
- missing
value - missing
package - unused pins
- single-member nets
It does not suppress structural errors such as undeclared pins, duplicate parts, or conflicting net assignments.
No-Connect Handling
Pins explicitly marked as no-connect emit real KiCad no_connect markers:
Pins marked this way do not produce unused-pin warnings.
Symbol Strategy
The emitter uses two symbol strategies.
Official KiCad library symbols are used for common standard parts:
- resistor ->
Device:R_Small - capacitor ->
Device:C_Small - inductor / coil ->
Device:L_Small - diode ->
Device:D - LED ->
Device:LED - crystal ->
Device:Crystal - 2-pin switch ->
Switch:SW_SPST - 3-pin switch ->
Switch:SW_SPDT
Embedded generated symbols are used for:
- ICs
- connectors that do not map cleanly to a stock symbol
- unknown parts
- anything else without a supported stock mapping
This keeps standard parts recognizable in KiCad while preserving a self-contained fallback for reverse-engineered or custom devices.
JSON Output
There are two JSON export paths:
dump-jsonExports the parsed DSL statement structuredump-irExports the normalized internal representation used for validation and emissioncompile --output-format jsonWrites the parsed DSL statement structure to a file
Example:
uv run revsch dump-json examples/mapping_probe.revsch
uv run revsch dump-ir examples/mapping_probe.revsch
uv run revsch compile examples/mapping_probe.revsch -o ~/tmp/mapping_probe.json --output-format jsondump-json and compile --output-format json are useful if another tool wants to consume the DSL without reimplementing the parser.
Examples
See examples/README.md for the full example index.
Included examples:
examples/basic_minimal.revschexamples/metadata_and_aliases.revschexamples/sparse_reverse_capture.revschexamples/mapping_probe.revschexamples/mapping_probe_named_nets.revschexamples/esp_keyboard.revschexamples/ch579m_key12_v02.revsch
Status
Current implementation includes:
- parser and semantic validation
- KiCad
.kicad_schemission - deterministic UUID and symbol generation
- mapping-mode warning profile
- source-level and IR-level JSON exports
- pytest coverage for parser, semantics, emitter, and CLI