Agent-controlled target machine wrangler for low-level software development.
The name reads as "Pan I/O". For bootloader, firmware, and OS bring-up work, it lets an AI agent netboot the target, watch its output, send it input, and power-cycle it, with no human in the loop.
An agent on a laptop drives an Intel NUC's firmware setup in another room: it
exits setup, catches F2 during POST through the KVM's emulated keyboard,
confirms by OCR that it is back in setup, then clicks with an absolute mouse:
$ panio hid send -t lab-nuc-1 key ENTER # discard & exit → the NUC reboots
$ for i in $(seq 30); do panio hid send -t lab-nuc-1 key F2 >/dev/null; done
$ until panio video read lab-nuc-1 | grep -q -i "bios version"; do sleep 2; done
$ panio hid send -t lab-nuc-1 moveabs 19583 5871 ; panio hid send -t lab-nuc-1 click leftMore on the demos page.
| Subsystem | Commands | What it does |
|---|---|---|
| Netboot | panio netboot |
DHCP + TFTP + HTTP netboot over a direct USB-Ethernet link (Raspberry Pi; UEFI PXE / HTTP Boot) |
| Remote labs | panio --lab … |
Drive targets on remote control hosts over SSH from one git-tracked lab file |
| Target leases | panio lease |
Reserve a whole target for one holder (shared lab, parallel agents): others can read but not change it; leases expire on their own and clean the target up |
| Control hosts | panio skill control-host |
Blank Raspberry Pi to agent-reachable control host in one human action (stock Pi OS plus a cloud-init seed) |
| Link mode | panio netif |
Switch the link between netboot, ffx-over-IPv6, link, and off modes; down-hard adds WoL off + admin-down (many USB adapters keep link anyway) |
| Video | panio video |
HDMI capture daemon (or a network RFB source such as a JetKVM); on-device OCR |
| Serial | panio serial |
Serial console: interactive (tio), timestamped line log, read-only health, immutable receive evidence, bounded fresh wait/follow, locked request/response transactions |
| Power control | panio power on/off, panio power-cycle, panio power-state, panio serial dtr/reset |
DTR power button (J2 header) and shell-command hooks, with optional named levels (--level hard) for targets with several power layers; helpers cambrionix (hub ports), dsdrelay (USB serial relay boards), zigplug (Zigbee plugs), shellyplug (Shelly Gen2+), amt (Intel AMT/vPro, verified HTTPS by default), dsdble (Bluetooth LE relay boards; wireless fallback, no state read-back), phidget (Phidgets VINT relay modules over USB, no state read-back) |
| Named actions | panio action |
Per-target named controls that are not power (reset, recovery, boot straps), each a hook command, discoverable by agents |
| HID injection | panio hid |
USB keyboard/mouse injection via a helper (hidrig KB2040 injector, ch9329 for Openterface Mini-KVM / KVM-Go and Sipeed NanoKVM-USB, or jetkvm for the JetKVM network KVM) |
| Switchable USB media | panio usb |
Switch a KVM-Go's microSD card, or any device behind a toggle-only USB sharing switch (usbtoggle + a relay), between control host and target |
| adb (Android targets) | panio adb |
Drive an Android DUT over one USB cable: console (shell/run), screen (screencap), input |
| Dashboard | panio console |
Video (noVNC, type and click in the page) + serial web UI; auto-starts daemons; -i <name> preselects a serial interface |
| MCP server (experimental) | panio mcp |
Runtime commands as MCP tools over stdio for agent harnesses; screenshots come back as images |
| Agent skills | panio skill |
List the bundled agent guides, or print one's SKILL.md |
| Lab config & diagnostics | panio target/host/config, panio discover, panio configure, panio doctor, panio daemons |
Manage the lab file, discover hardware, check config against reality, list and restart daemons |
| Exit status and errors | panio --json-errors … |
Exit codes name the failure kind; --json-errors adds a one-line JSON object |
A target (DUT, device under test) is the machine being developed on; a control host is the machine cabled to it.
For Openterface devices using USB virtual serial ports on Linux, see the startup compatibility warning and workaround.
For RAM delivery through an existing USB fastboot client, see the guarded staging workflow. It defines an external runner's ownership, readiness and verification contract; panio does not bundle a fastboot channel.
The tap pours prebuilt binaries: universal on macOS (Apple Silicon and Intel), and x86-64 or arm64 on Linux. No Rust toolchain needed:
brew tap curtisgalloway/tap
brew install panioUpgrade with brew upgrade. Run panio setup once after installing: on
macOS it setuid-installs netbootd-bpf-helper (one sudo); on Linux it checks
dialout/video group membership. Both install the optional zigplug helper.
On a Linux host that runs capture daemons for days at a time (a control host),
prefer the apt repository below. The .deb also installs a tmpfiles.d rule
that keeps systemd from deleting the daemons' discovery files after ten days
(#187); Homebrew cannot
install files outside its prefix.
brew install --HEAD panio builds main from source, the same path as
make install below.
On Debian 12+ / Raspberry Pi OS (amd64/arm64), use the signed apt repository;
upgrade with apt upgrade:
sudo install -d /etc/apt/keyrings
sudo curl -fsSL -o /etc/apt/keyrings/panio.asc https://panio.dev/apt/panio.asc
sudo tee /etc/apt/sources.list.d/panio.sources >/dev/null <<'EOF'
Types: deb
URIs: https://panio.dev/apt
Suites: stable
Components: main
Signed-By: /etc/apt/keyrings/panio.asc
EOF
sudo apt update && sudo apt install panioFor a blank Pi, skip the steps above: flash stock Raspberry Pi OS, drop four
seed files on its boot partition, and power on. It comes up with SSH
authorized and the release .deb installed. See
standing up a control host;
the exact commands, including how to pick the right SD card, are in
panio skill control-host.
Each GitHub Release has
a .deb and a tarball: sudo apt install ./panio_<version>_<arch>.deb.
After the apt repository or a release package, run panio setup once: it
sets group membership and installs the optional zigplug helper.
Requirements:
- macOS 10.14 (Mojave) or later, or Linux (x86-64 / arm64)
- On macOS: Homebrew
- Rust toolchain (
brew install rustupon macOS, orrustup.rson Linux) - On Linux:
sudo apt-get install pkg-config libudev-dev libclang-dev cmake nasm(make installchecks for these and tells you what's missing)
git clone https://github.com/curtisgalloway/panio ~/src/panio
cd ~/src/panio
make install # panio CLI + daemons + OCR helper, in one stepmake install bootstraps the CLI with cargo install --path cli, then runs
panio setup, which builds and installs the rest. Where things land:
- The
panioCLI is the only thing on PATH (~/.cargo/bin). - Daemons and helpers (
hdmicap,serialcap,netbootd,cambrionix,dsdrelay,dsdble,phidget,usbtoggle,hidrig,ch9329,shellyplug,amt) and the OCR helper (visionocron macOS viaswiftc,linuxocron Linux) go in~/.local/libexec/panio/bin, off PATH. Run one withpanio helper <name> [args…](no name lists them;-t <target> --channel <kind>or--host <labhost>before the name runs it on that host). Everything after the name goes to the helper, sopanio helper serialcap --helpshows the helper's own help. - Bundled agent skills go in
~/.local/share/panio/skills(the.deb/tarball ship them under/usr/share/panio/skills).panio skill [NAME]lists or prints them. - Out-of-tree helpers and skills can stay in their own checkout: list its
prefix in
PANIO_PLUGIN_PATH(a lab host'splugin_pathfor a control host). Plugins add helpers and skills but never shadow bundled ones; see plugin roots. - On macOS,
setupalso installsnetbootd-bpf-helpersetuid-root (one sudo) fornetbootd. - Configuration is one CLI-managed lab file
(
~/.config/panio/lab.toml); see notes/config-redesign.md.
The only Python component is the optional zigplug helper, which setup
installs as a uv tool. After pulling or editing, re-run:
make install # rebuilds and reinstalls everything (idempotent)make rust rebuilds only the Rust crates (no OCR/setuid/zigplug steps);
make help lists every target. To install one component directly, helpers
need --root so they land in libexec:
cargo install --path ~/src/panio/cli # if the CLI changed
cargo install --path ~/src/panio/hdmicap --root ~/.local/libexec/panio # if hdmicap changed
cargo install --path ~/src/panio/serialcap --root ~/.local/libexec/panio # if serialcap changed
cargo install --path ~/src/panio/netbootd --root ~/.local/libexec/panio # if netbootd changed (re-run `panio setup` to re-setuid the helper on macOS)
cargo install --path ~/src/panio/cambrionix --root ~/.local/libexec/panio # if cambrionix changed
cargo install --path ~/src/panio/dsdrelay --root ~/.local/libexec/panio # if dsdrelay changed
cargo install --path ~/src/panio/dsdble --root ~/.local/libexec/panio # if dsdble changed (Linux build needs libdbus-1-dev)
cargo install --path ~/src/panio/phidget --root ~/.local/libexec/panio # if phidget changed
cargo install --path ~/src/panio/usbtoggle --root ~/.local/libexec/panio # if usbtoggle changed
cargo install --path ~/src/panio/hidrig --root ~/.local/libexec/panio # if hidrig changed
cargo install --path ~/src/panio/ch9329 --root ~/.local/libexec/panio # if ch9329 changed
cargo install --path ~/src/panio/shellyplug --root ~/.local/libexec/panio # if shellyplug changed
cargo install --path ~/src/panio/amt --root ~/.local/libexec/panio # if amt changed
UV_TOOL_BIN_DIR=~/.local/libexec/panio/bin uv tool install --force ~/src/panio/zigplug # if zigplug changedAn agent or script on a dev machine SSHes into the control host:
# Configure target once
ssh control-mac "panio target add target-machine"
ssh control-mac "panio netboot set -t target-machine --interface en3 --tftp-root ~/pxe"
ssh control-mac "panio power set -t target-machine --cycle-cmd /path/to/power-cycle.sh"
# Deploy a new kernel and boot
TFTP_ROOT=$(ssh control-mac "panio netboot tftp-root target-machine")
scp out/kernel.img control-mac:"${TFTP_ROOT}/kernel_2712.img"
ssh control-mac "panio netboot start target-machine"
ssh control-mac "panio netboot logs -f target-machine"
# Interact with the console
ssh control-mac "panio serial log -t target-machine -i console --tail 50"
# Power cycle and repeat
ssh control-mac "panio power-cycle target-machine"Full documentation:
panio.dev
(source in docs/).
- User guides: linked in the capabilities table.
- Recommended hardware: what to buy to get started.
- Demos and tested hardware.
- Glossary: the hardware, protocol and panio terms these docs use.
- Developer docs: start with the
architecture overview,
then the requirements tracker.
Source in
docs/dev/.
notes/ holds point-in-time design records and bring-up
findings. They are not kept current and not published.
Apache 2.0 — see LICENSE.
Terminology is defined in the glossary. Serial capture also exposes read-only health snapshots via CLI and MCP.
