Embedded-AI-Harness
Health Pass
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Community trust — 160 GitHub stars
Code Fail
- rm -rf — Recursive force deletion command in .devcontainer/devcontainer.json
Permissions Pass
- Permissions — No dangerous permissions requested
No AI report is available for this listing yet.
AI Closed-Loop Programming for embedded systems — the AI writes, flashes, and tests firmware on real hardware until the tests run clean. Spec to silicon, hands off.
The Harness — AI Closed-Loop Programming for Embedded Systems
Spec to silicon, hands off.
A horse is strong, fast, and willing — and useless for heavy loads until you
harness it. The harness is not a part of the horse and not a part of the cart:
it is the coupling that turns raw strength into pulled weight.
An AI is the same. It can write firmware all day — but it can't flash a board,
can't see it boot, can't know whether its fix actually worked on real
hardware. Unharnessed, it generates code and hopes. This repository is the
harness: strap the AI in, and it pulls — writes the code, compiles it, flashes
it onto a real ESP32, tests it against real WiFi, MQTT, BLE and RF, reads the
failures, corrects itself, and goes again — until the tests run clean.
🔄 AI Closed-Loop Programming
Today's AI coding is open-loop: prompt → code → hope. No feedback, so
errors accumulate uncorrected — which is exactly why people don't trust
AI-written firmware. AI Closed-Loop Programming (AICLP) closes the loop
with reality:
FSD ────── the setpoint: what "done" means
│
▼
┌──── code → build → flash ────┐ forward path
│ ▼
│ real hardware
│ │
└── correct ◄── tests ◄────────┘ feedback path
the loop exits when the error signal is zero: tests green
Every embedded engineer knows this diagram — it's a control loop. The spec
(FSD) is the setpoint, the firmware on the chip is the plant, the tests are
the sensor, failing tests are the error signal, and the AI is the controller
that corrects until the error reaches zero.
True TDD, enabled by AI. For twenty-five years, developers drove and tests
advised — written after the code, skipped under deadline, tuned until they
passed. Here the tests drive for the first time: derived from the spec, run on
real silicon, and the only way the AI gets to stop.
🗺️ The Journey — from idea to shipped product
| Phase | You do | You get |
|---|---|---|
0 · Definition — /define |
Describe the product; answer an interview, one question at a time | An FSD where every requirement already says how it will be proven |
1 · Harness — /harness |
One command; answer the two questions only you can | The project strapped in: docs, test plan, firmware hooks, CI, runner |
2 · Commissioning — /commission |
Plug the board into a slot, wire the rig, hands when prompted | A trusted testbench — a failing test now means the code, not the wiring |
3 · Build — /build |
Start sessions; approve the occasional spec question | Requirements turning green, one by one, on real hardware |
⚑ Shipment — git tag |
Push the version tag — the one act that stays human | A release built in a pinned container and verified on the testbench: the journey runs once more on the exact bytes users download |
Each milestone is derived from project state, never declared — nobody ever
types "phase complete". And after shipment the same journey repeats in
miniature for every new feature: describe it in a sentence, the loop refuses
to code anything no requirement covers, the spec absorbs the delta, and the
phases collapse to minutes. No code without a clause is what keeps the
spec true for the product's whole life.
🧰 What the Harness consists of
- The method — four Claude Code skills, one per phase:
/define(the
FSD: atomic, falsifiable requirements, each with its verification
contract),/harness(one-time setup),/commissionand/build(the
loop's driver: test design, the plan, audit, what's next). - The workbench — a Raspberry Pi test instrument that gives the AI hands
and eyes on real hardware. Described below. - The dev skills — ESP-IDF and PlatformIO lifecycles, logging, WiFi,
BLE, MQTT, debugging, RF, CI — the loop's individual muscles.
🔌 The Workbench — the loop's hands and eyes
Working on an ESP32 normally means being physically attached to it — and an
AI can't hold a USB cable. The workbench puts the boards on a Raspberry Pi
and turns everything into HTTP:
LAN (192.168.0.x)
|
| eth0 (wired)
v
Raspberry Pi ---- wlan0 (WiFi test AP: 192.168.4.x)
workbench.local hci0 (Bluetooth LE)
| UDP :5555 (log receiver)
| USB hub (internal on Pi 3/4/5, external on Zero)
|
+----+----+----+----+
| | | |
:4001 :4002 :4003 :4004 <- auto-assigned (4001 + slot index)
SLOT1 SLOT2 SLOT3 SLOT4 <- one per detected hub port
- Plug in a board → it's ready. Auto-detected in seconds and mapped to a
fixed port by which USB connector it's in — same connector, same port,
always. That's slot-based identity: a slot is a physical hole in the
hub, so scripts andplatformio.ininever go stale when boards swap or the
kernel renames/dev/ttyACM0. - Serial over the network at
rfc2217://workbench.local:4001— esptool,
PlatformIO, ESP-IDF and anything on pyserial speak it natively. - Flash three ways — over the network, locally on the Pi, or over the air.
- Debugging out of the box — OpenOCD starts itself for USB-JTAG chips;
GDB connects to port 3333. - The Pi is the test equipment. Its WiFi becomes the access point your
board joins, its Bluetooth scans and connects, optional SDR and Si5351
hardware receive and transmit on 433 MHz, and boards log to it over UDP
when USB is busy. - It presses the buttons. GPIO wired to reset and boot forces download
mode and rescues boot-looping boards with nobody in the room. - Claude drives all of it through 70 MCP tools or the bundled skills.
Honest limits: one serial client per board at a time (that's RFC2217, not
a choice), the SDR is one dongle, one user, and the API has no
authentication — keep the bench on a network you trust.
🚀 Quick Start — building the bench
You need a Raspberry Pi with onboard WiFi and Bluetooth running Raspberry Pi
OS Lite (64-bit). A Pi Zero 2 W also needs a USB hub and a USB Ethernet
adapter, since wlan0 is reserved for testing; a Pi 3/4/5 has both built in.
An RTL-SDR dongle, an Si5351 + PE4302, and jumper wires to the board's
EN/BOOT pins are all optional.
git clone https://github.com/SensorsIot/Embedded-AI-Harness.git
cd Embedded-AI-Harness/pi
sudo bash install.sh
That installs every dependency (pyserial, hostapd, dnsmasq, bleak, esptool,
OpenOCD, rtl-sdr/rtl_433, mosquitto), sets up the udev hotplug rules, and
starts the portal as a systemd service. Plug in a board and check:
curl http://workbench.local:8080/api/devices | jq
Slots are auto-detected — no config file needed. Create/etc/rfc2217/workbench.json only to rename slots, pin ports, declare GPIO
pins, or register an ESP-Prog probe; sudo rfc2217-learn-slots prints one
for you.
On a Pi Zero 2 W, do the memory hardening first. With 512 MB the board
OOM-crashes under load, and hard crashes corrupt the SD card. See
User Manual §2.2.
🔧 Usage
Watch a board boot — no client library, just HTTP:
curl -X POST http://workbench.local:8080/api/serial/reset \
-H 'Content-Type: application/json' -d '{"slot":"SLOT1"}'
Point your existing tools at it. PlatformIO needs one line
(upload_port = rfc2217://workbench.local:4001); esptool takes the same URL,
and the binaries stay on your machine:
esptool --port rfc2217://workbench.local:4001 --chip esp32c3 \
write-flash 0x10000 firmware.bin
Write a test that uses the whole bench — reset the board, give it a
network to join, wait for it to appear, then talk to it:
from workbench_driver import WorkbenchDriver
wt = WorkbenchDriver("http://workbench.local:8080")
wt.serial_reset("SLOT1")
wt.serial_monitor("SLOT1", pattern="WiFi connected", timeout=30)
wt.ap_start("TestAP", "password123")
station = wt.wait_for_station(timeout=30)
wt.http_get(f"http://{station['ip']}/status")
🤖 Driving It From Claude
An MCP server exposes the whole API as 70 tools, so Claude Desktop or
Claude Code can operate the bench conversationally — "flash this to slot 1
and tell me why it's crashing". Pure Python standard library, so there's
nothing to pip install. For Claude Desktop, dragmcp/universal-embedded-workbench.mcpb
onto Settings → Extensions and enter your workbench URL.
The AICLP skills (/define, /harness, /commission, /build) and the
instrument skills all live under .claude/skills/. Setup for both:
User Manual §15.
🩺 Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Device not detected | Charge-only USB cable | Use a data cable; check lsusb on the Pi |
Wrong boot mode (0x13) when flashing |
Bridge-chip board — RFC2217 can't drive its auto-reset | Flash with POST /api/flash instead |
| Rapid connect/disconnect | Erased or corrupt flash, boot loop | Auto-recovers via GPIO; force with POST /api/serial/recover |
| ESP32-C3 stuck in download mode | DTR asserted when the port opened | POST /api/serial/reset |
| GDB won't connect | Classic ESP32 has no USB-JTAG | Wire an ESP-Prog and declare it in workbench.json |
| SDR decodes noise or all zeros | Transmitter too close, AGC overloading | Add distance, set a fixed gain |
| Pi reboots at random | Out of memory (Pi Zero 2 W) | Apply the §2.2 hardening; check free -h |
Full table, with the diagnostics to run on the Pi →
User Manual §17.
📡 Under the Hood
Serial travels over RFC2217, a
Telnet extension that carries serial line control — baud rate, DTR, RTS —
over TCP. That's why it needs no kernel modules and passes through firewalls,
and why esptool and pyserial speak it natively.
Hotplug is event-driven, not polled: a udev rule fires on USB add/remove
and POSTs to the portal, which starts or stops that slot's proxy. Station
events on the test AP arrive the same way, via dnsmasq DHCP lease
callbacks. Boards with native USB-Serial/JTAG need care — Linux asserts DTR
and RTS the moment the port opens, dropping the chip into download mode
mid-boot — so the portal delays opening and drives the reset sequence itself.
Everything is one JSON HTTP API on :8080; every response carries "ok".
curl -X POST .../api/wifi/ap_start -d '{"ssid":"TestAP","password":"secret"}'
curl -X POST .../api/gpio/set -d '{"pin":18,"value":0}'
curl -X POST .../api/sdr/capture -d '{"freq_hz":433920000,"duration_s":10}'
📚 Documentation
The plane map is docs/00-Overview.md — three
documents, one per question, and everything is in one of them:
| Question | Document | Read it for |
|---|---|---|
| What must be true? | Functional Specification | AICLP, the journey, and what the bench does clause by clause. Appendix D is the complete HTTP API and MCP tool reference. |
| How is it built? | Method | The build contract for contributors and AI agents — workflow, architecture, conventions, testing standard. |
| How do I run it? | User Manual | Building the Pi, wiring, and driving every service — install, serial, flashing, debug, WiFi, RF, test automation, troubleshooting. |
🙏 Attributions
Built on pyserial
(RFC2217),
esptool and
OpenOCD from Espressif,
bleak,
rtl_433,
hostapd / dnsmasq,
mosquitto, and the
Model Context Protocol.
📄 License
MIT — see LICENSE.
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found