Notes

AI agents hallucinate pinouts

An AI-authored RP2040 devboard passed ERC completely clean — while its crystal caps were silently disconnected. The board would never boot. Here's why rule-checkers miss this, and the workflow that catches it.

The board looked perfect. Clean schematic, tidy layout, ERC passing with zero violations — the kind of output that would have taken a human engineer a full day to produce, finished by an AI coding agent in about twenty minutes.

It would never have booted.

The crystal load capacitors were silently disconnected. One net label had a typo — /XIN versus XIN — which in KiCad means two entirely different nets. The crystal had no capacitance to ground, so the oscillator never started, so the RP2040 never clocked, so the board was a paperweight with excellent trace aesthetics.

Electrical Rules Check had nothing to say about any of this. ERC doesn’t check whether your board works. It checks whether your schematic follows rules.

Rules are not intent

This is the distinction that matters, and it’s the same one that keeps showing up as LLMs move into physical engineering domains:

ERC/DRC verify that a design is self-consistent. They say nothing about whether it matches what you meant to build.

A human engineer doesn’t actually run a mental rules engine. They carry intent — “pin 20 of the MCU goes to the crystal” — and they notice when the artifact in front of them disagrees with that intent. The mismatch between artifact and intention is where the real bugs live, and it’s exactly where rule-checkers are blind.

LLM-authored designs are unusually rich in this failure class. Agents don’t hallucinate rules violations; rules are mechanical and the model gets them right. They hallucinate wiring — a label typo’d one time in one place, a pin mapped from memory instead of the datasheet, a debug header quietly omitted because it wasn’t in the reference design the model half-remembers.

The failure isn’t sloppiness. It’s the difference between producing something plausible and producing something correct.

The fix: declare intent before you wire

The workflow that came out of this — implemented in fiducial — inverts the usual order. You write down what “correct” means before the schematic exists:

ref,pin,expected_net
U1,20,/XIN
U1,21,/XOUT
C7,1,/XIN
C7,2,GND
C8,1,/XOUT
C8,2,GND

That’s an intent file, written from the datasheet: every critical pin and the net it must land on. Then the agent authors the schematic against an instruction library, and you prove the result mechanically:

ref     pin    expected          actual            result
*U1     20     /XIN              Net-(U1-XIN)      WRONG
58/64 connections verified

There it is. U1 pin 20 was expected on /XIN and actually landed on Net-(U1-XIN) — a stray auto-generated net from that one-character label typo. Twenty-eight characters of intent specification caught, in seconds, what a fully-passing ERC could not.

Verification as agent gates

The other half of the design: the checks aren’t something a human runs when they feel nervous. They’re gates in the agent’s own loop.

Each tool — lint, erc, check-intent — exits 0 clean, 1 violated, 2 environment error. Those exit codes slot directly into an agentic workflow: the agent writes a schematic, runs the gauntlet, reads the failure, fixes it, runs it again. The verification loop closes without a human in it.

This is the same shape as go vet or a type checker for code agents: the model doesn’t need to be trusted, it needs to be checked by something that can’t be hallucinated. A mismatch report generated from the schematic file itself is ground truth in a way no model self-assessment can be.

Two properties made this workable:

  1. Zero dependencies. The verifier reads the KiCad file format (s-expressions) with the Python stdlib alone. No fragile dependency chain, no “works on my machine” — it drops into any repo as a submodule and runs.
  2. Diagnosis, not just verdicts. wire-trace, label-map, pin-positions — tools that answer why a net is wrong, because an agent that can’t localize a failure will thrash.

What it doesn’t catch — yet

Honesty about scope: intent checking verifies connectivity, not electrical correctness. If your intent file itself says the crystal caps go to the wrong pins — because you misread the datasheet — the checker will happily verify your mistake. It checks artifact against intent, never intent against reality. The datasheet remains your problem.

Layout-side is the next front: DRC and board rendering work but aren’t yet regression-covered, which in a post about verification is exactly the kind of thing I’m obliged to admit out loud.

The general shape

Step back from EDA and the pattern is portable to every domain where an agent produces a physical artifact:

  1. Encode intent as data, from primary sources, before generation
  2. Let the agent build against instructions, not vibes
  3. Prove the result mechanically, with exit codes the agent loops on

The same architecture applies to mechanical CAD, wiring harnesses, FPGA constraints — anywhere “it compiles” is a weaker guarantee than “it is what I asked for.”

The agents are going to keep hallucinating pinouts. The fix isn’t better models. It’s giving them something to be wrong against.