I keep needing the same thing - a really basic dev board for whatever Espressif module I’m playing with. USB-C, a 3.3V regulator, BOOT and EN buttons, three LEDs (5V present, 3.3V present, and one on a GPIO so you can run the blink sketch), and every GPIO broken out on headers. Nothing clever, just the minimum board that gets a bare module doing something.
While building the ESP32 module database I noticed there are twelve modules that fit one sensible recipe - a PCB antenna and native USB - spread across the S2, S3, C3, C5, C6 and H2 families. Native USB is the bit that keeps the component count down. There’s no USB to UART bridge to buy and route, just a USB-C socket and a couple of 5.1K resistors on the CC pins so the host actually hands over power.
Twelve near-identical boards is exactly the kind of job that makes you question your life choices in KiCad.
So I did what everyone on the internet is currently telling you to do and asked Claude to spin up a team of AI agents to design the boards for me.
And it said no.
Not a flat no, more of a “this is beneath me” no. Its argument, roughly - this is a mechanical, repetitive job, and you don’t want a swarm of agents improvising twelve layouts. What you want is deterministic scripts that produce the same board every time, with AI involved only where there’s a real judgement call to make.
Which is a surprisingly sensible thing for it to say. So I let it write the scripts instead, and the AI’s contribution to each board shrank down to a single file. More on that below.
That montage is to scale - the render pipeline normalises the zoom so a 29×33 mm C3-MINI board looks properly tiny next to a 28×55 mm S2-MINI.
The whole thing is on GitHub at atomic14/kicad-esp32-dev-boards, with fab-ready Gerbers and openable KiCad projects for all twelve boards on the releases page.
Almost all of the pipeline is just deterministic scripting. The only real
judgement call is a small board.yaml
per module, and it holds the things a script can’t work out for itself from the symbol and footprint:
SPIIO6
, SPIIO7
and SPIDQS
are reserved for the octal flash on an S3-WROOM-1, but the same names are perfectly usable GPIO on the quad S3-MINI-1.That’s the whole hand written input for a board. Everything else gets derived from the module’s symbol and footprint - power, GND, EN, the USB D+/D- pair, the GPIO net labels.
And this file is where the AI actually lives. All those judgement calls are already written up in plain English on each module’s page of the module database - for humans. So the job I hand to the AI is a simple one: read the page, fill in the file. Messy prose in, clean data out, which is the one thing a script can’t do.
It works under a safety net too. If it picks an unsafe pin for the LED then the build hard-errors and refuses to generate the board at all.
Each board starts from a pre-built skeleton project - the USB-C connector, LDO, buttons and LEDs, already placed, routed and sanity checked.
There are actually two skeletons, mirror images of each other, one with EN on the left and BOOT on the right and one the other way round. That one came out of playing about with the AI. Depending on which edge a module’s reset pin comes out on, putting the matching button on that side makes the routing much easier, so the generator has a look at the footprint and picks whichever skeleton fits.
From there the script does four things:
The back of each board gets the pin names in silk next to the headers, and one
little touch I’m quite pleased with - a vertical identifier down the middle
with the module name and the git revision that generated it. That’s just
git describe
baked into the silkscreen. Tag the repo v1.0
and every board fabbed from that tag says so.
Every push builds all twelve boards on GitHub Actions, and pushing a version
tag publishes a release with the Gerber zips, KiCad projects and montage
renders attached. It all runs inside KiCad’s official Docker image, which is
the supported way to run kicad-cli
headless.
Even then, three things bit me. They might save you an afternoon.
kicad-cli
segfaulted on startup - even for kicad-cli version
. It turned
out to be crashing while it scanned the Plugin & Content Manager addon
directory, where the Espressif libraries live, when the global library
tables don’t exist yet. Which is true on any machine where the KiCad GUI has
never been run. The fix is to seed empty sym-lib-table
and fp-lib-table
files first.uv
environment resolves to the venv
interpreter, which has no pcbnew
module. Every board came out “routed” but
with an empty ground plane and a pile of DRC errors. The fix is to use the
python that lives next to kicad-cli
.git describe
refused to run at all, throwing git’s “dubious ownership” error, because the Actions workspace is bind mounted into the container under a different uid. The boards built fine, but the version stamp quietly fell back to just the module name. One ``` git config --global --add safe.directory
sorts it out, and there’s now a canary step so it can never
fail quietly again.The Gerber zips and full KiCad projects for all twelve boards are on the
[releases page](https://github.com/atomic14/kicad-esp32-dev-boards/releases),
ready to upload to your board house of choice.
One honest caveat before you spend any money - these boards are machine generated. They pass DRC with zero errors, they add no new ERC errors against the skeleton, and I do eyeball every render, but I haven’t yet had physical copies of all twelve back from a fab and tested them.
So treat them like any open source hardware design - trust, but verify. Open
the KiCad project, sanity check the schematic against the
[module’s page](https://www.atomic14.com/esp32/), and have a proper look at the
board before you order. Which is good practice for *any* design you download
off the internet, very much including mine…
I am going to get a batch of these made up, so let me know in the comments
which ones you’d like to see. And if you do build one, I’d genuinely love to
hear how it goes. If you find a problem, file an issue on the
[repo](https://github.com/atomic14/kicad-esp32-dev-boards) so the fix lands in
the generator rather than just on one board.
**Picking a module for your own project?** I've built an interactive ESP32 reference with specs and pinouts for every Espressif module: browse the [module database](https://www.atomic14.com/esp32/), or [compare them all in one big table](https://www.atomic14.com/esp32/table/).