Panio — Requirements & progress tracker
Source of truth for what panio must do and how far along each capability is.
Panio is a device-control layer (power, serial, deploy/netboot, video, HID); test
orchestration and results stay above it (§9).
Design: docs/dev/ci-integration/; per-feature docs under
docs/. Update the Status column as work lands.
Last updated: 2026-10-17.
Status legend
| Symbol |
Meaning |
| ☑ |
Done / shipped |
| ◐ |
In progress |
| ☐ |
Not started |
| ⤵ |
Deferred (planned, later) |
| ⊘ |
Out of scope (recorded, not planned) |
Pri = M(ust) / S(hould) / C(ould). Source/Notes cites the driving need or contract
(in §9, Source is LAVA, FX = Fuchsia/botanist, BOTH = LAVA and FX, or OWNER = the project
owner's own need).
| ID |
Requirement |
Pri |
Status |
Notes |
| CORE-1 |
Daemonless target config readable by every command; single target is the default |
M |
☑ |
was per-target targets/<name>.toml (_config.py); superseded by CORE-7 |
| CORE-2 |
CLI (panio) over subcommands; SSH-drivable from a dev machine into the control host |
M |
☑ |
Remote-control pattern (README) |
| CORE-3 |
Run on macOS 10.14+ and Linux (x86-64/arm64) |
M |
☑ |
panio setup installs daemons/tools |
| CORE-4 |
Rust daemons (hdmicap, serialcap) + Swift visionocr helper build & install |
M |
☑ |
panio setup |
| CORE-5 |
Predictable runtime paths (configs, daemon discovery, capture logs) |
M |
☑ |
architecture.md §4 |
| CORE-6 |
Agent-oriented guidance kept current (AGENTS.md) as the surface changes |
M |
◐ |
track §9 power/serial changes |
| CORE-7 |
One-file lab model (--lab/PANIO_LAB): hosts + targets, per-channel host binding |
S |
☑ |
cli/src/model.rs, labfile.rs; distributed-control (no legacy targets dir) |
| CORE-8 |
Transparent re-exec of host-operating commands on a target's remote control host over SSH |
S |
☑ |
cli/src/dispatch.rs (ships a lab slice + --lab); cli/src/ssh.rs transport |
| CORE-9 |
Tunnelled console for a remote target (dashboard reachable locally) |
S |
☑ |
remote_console in cli/src/main.rs; ?serialws= stitch |
| CORE-10 |
Multi-host targets (one target spanning control hosts) |
C |
◐ |
per-channel dispatch (dispatch.rs); console requires co-located channels |
| CORE-11 |
Remote setup --host + discovery-assisted configure |
C |
☑ |
panio setup --host, discover, configure (cli/src/main.rs) |
| CORE-12 |
Carry a helper's required secrets to its remote control host, without exposing them in the host's process list |
S |
☑ |
AMT_PASSWORD (ssh::FORWARDED_ENV) is forwarded on every non-interactive dispatch (power-*, power set hooks) over stdin, not argv, so ps never shows it (ssh::stdin_prelude/ssh::launch in cli/src/ssh.rs, wired in cli/src/dispatch.rs). run_interactive (e.g. serial connect) forwards nothing: its stdin is the user's terminal. See distributed-control.md and power.md |
| CORE-13 |
Re-image path for a control host: one human action from blank media to agent-reachable (the disposability principle, made real) |
C |
◐ |
pi-sd shipped and hardware-validated (packaging/host-seed/, control-host.md). x86-usb (Ubuntu autoinstall) and the argument-taking generator are unbuilt; design in notes/control-host-provisioning.md |
2. Netboot / deploy
| ID |
Requirement |
Pri |
Status |
Notes |
| NET-1 |
Built-in DHCP + TFTP over a direct USB-Ethernet link |
M |
☑ |
netbootd/ (Rust engine, default); 192.168.99.1/24 |
| NET-2 |
netboot start/stop/status, tftp-root, logs (filterable, followable) |
M |
☑ |
cli/src/netboot.rs |
| NET-3 |
Bare-link up/down/status for interface testing |
M |
☑ |
netif mode link/off + netif status (carrier); netif down-hard forces a real carrier drop (WoL off + admin-down). Replaced netboot link-up/down/status |
| NET-4 |
TFTP root configurable per target (--tftp-root) |
M |
☑ |
required for netboot start |
| DEPLOY-USB-RAM |
Document guarded RAM-only USB fastboot staging with fresh per-artifact entry, separate bounded USB readiness, exclusive ownership and retained evidence |
S |
☑ |
Workflow and external runner contract (#285); documentation shipped, no bundled fastboot channel or staging runner |
| NET-5 |
netif mode netboot\|link\|ffx\|off — atomic, idempotent link-mode switch; link = bare host IP (no daemon) for link testing; stops netboot before SD boot, sets up host fe80::1/64 for ffx; netif status probes the active mode + carrier |
S |
☑ |
cli/src/netif.rs; from rpi5 ffx bring-up |
3. Serial console
A capture epoch identifies one serial supervisor lifetime; RX and TX mean
received bytes and driver-accepted transmitted bytes. See the
glossary.
| ID |
Requirement |
Pri |
Status |
Notes |
| SER-WAIT |
Finite fresh serial acquisition after an epoch/RX boundary, with raw/output caps, complete-row follow and explicit incomplete outcomes |
S |
☑ |
serial wait, MCP serial_wait; task verdict stays with the caller (#281) |
| SER-HEALTH |
Read-only configured/active identity, process/port state, epoch, reconnect and RX/TX/capture progress through CLI and MCP |
S |
☑ |
serial status, MCP serial_status; task-specific response remains the caller's judgment (#279) |
| SER-EVIDENCE |
Immutable exact-byte receive evidence with original timestamps, epoch/generation cursors, byte caps and explicit retention/fault diagnostics |
S |
☑ |
serial evidence, MCP serial_evidence; separate from line/pending view (#280) |
| SER-A |
serialcap daemon owns the port exclusively; supervisor fans out reads |
M |
☑ |
serialcap/; lockfile |
| SER-B |
Timestamped rolling JSONL capture log, addressable by seq; rotation |
M |
☑ |
capture.rs; serial log |
| SER-C |
Interactive terminal via tio (serial connect) |
M |
☑ |
|
| SER-D |
Bidirectional live /stream (WebSocket) — read + write-back |
M |
☑ |
server.rs (used by dashboard) |
| SER-E |
serial add/set/rm/devices/show, multi-interface per target |
M |
☑ |
|
| SER-F |
DTR control: serial dtr, serial reset (soft-reset semantics) |
M |
☑ |
cli/src/power.rs |
| SER-G |
Power-sense read via modem-control input (--power-sense cts\|dsr\|dcd\|ri) |
S |
☑ |
/status → power_on |
4. Power control
| ID |
Requirement |
Pri |
Status |
Notes |
| PWR-A |
power-cycle via configurable script (--power-cycle-cmd) |
M |
☑ |
superseded by [power] hooks (--cycle-cmd et al.), PWR-5 |
| PWR-B |
power-state (read-only on/off via sense signal) |
M |
☑ |
power-state |
| PWR-C |
DTR-based hardware power-button toggling (J2 header): ≤500ms soft / ≥3s hard |
M |
☑ |
cli/src/power.rs |
5. Video / OCR
| ID |
Requirement |
Pri |
Status |
Notes |
| VID-1 |
HDMI/USB capture via warm-stream hdmicap daemon |
M |
☑ |
hdmicap/; Linux V4L2 + macOS |
| VID-2 |
video watch/preview/shot/read/devices/show/stop; stable & changed-since capture |
M |
☑ |
|
| VID-3 |
On-device OCR (video read): Apple Vision (macOS), Tesseract (Linux) |
S |
☑ |
ocr/ helpers via hdmicap GET /ocr (no legacy --json flag) |
| VID-4 |
Change detection sensitive enough for small-region edits |
C |
☐ |
--changed-since compares a 64-bit aHash over an 8x8 grid, so a sub-cell change (moved cursor, one BIOS checkbox) reads as "unchanged". Wants an opt-in finer comparison (region-of-interest or a second hash), not a bigger default. Distinct from the signal bugs fixed in #103 |
6. HID injection
| ID |
Requirement |
Pri |
Status |
Notes |
| HID-1 |
USB keyboard/mouse injection via KB2040 injector (dual-board "dumb pipe": host composes, control board CDC → I2C1 → target HID) |
S |
☑ |
hidrig/ crate (this repo) + hidrig-kb2040/firmware/ (paniolo-hardware repo) |
| HID-2 |
Device-independent HID serial protocol (v1) so other microcontrollers can implement the injector |
S |
☑ |
docs/dev/hid-serial-protocol.md |
| HID-3 |
Generic hid lab channel: panio hid set/rm/send appends args to an opaque helper cmd |
S |
☑ |
mirrors power hooks; SSH dispatch |
| HID-4 |
Absolute mouse (moveabs, advertised capability) for click-where-you-point |
S |
☑ |
abs-pointer HID descriptor in firmware |
| HID-5 |
hidrig serve daemon: owns the control link, re-exposes the command vocabulary over a WebSocket; one-shots route through it |
S |
☑ |
panio hid serve/stop |
| HID-6 |
KVM in panio console: stream web keyboard + absolute mouse, intermixed with CLI injection |
S |
☑ |
hardware-verified (pi5 Linux) |
| HID-7 |
KVM latency: HID frames fire-and-forget over USB-CDC (no per-frame round-trip), coalesce mouse moves (per-frame); floor is the target's USB bInterval (~8 ms) |
S |
☑ |
macOS IOSSDATALAT floored for control-frame replies |
6.1 Openterface deep control (OTF)
The Openterface Mini-KVM (USB KVM dongle) has open hardware (v1.9). Its switchable USB-A port
and CH340 (USB-serial chip) modem lines make it a small programmable USB fixture. Details and
bench checklist:
openterface-deep-control.md.
- OTF-1 verified 2026-08-18 as far as the bench allows: DTR/
SW_GND and RTS/HIDRESET
characterized, DATAFLIP not observable, EEPROM dumped.
- The MS2109 (capture chip) GPIO write is unblocked (2026-08-30): the mux is a register
write over the HID config interface.
- The lab host is a VM with USB passthrough; verify USB observations on the hypervisor.
| ID |
Requirement |
Pri |
Status |
Notes |
| OTF-1 |
Bench-verify the control paths on our unit: PCB rev; MS2109 GPIO write for the A-port mux; DTR→SW_GND replug polarity + hold time; RTS→CH9329 reset; DATAFLIP semantics; serial-open DTR-pulse side effects; EEPROM backup dump |
M |
☑ |
done: v1.9; DTR asserted = disconnected; serial-open does replug the A-port; RTS resets the CH9329 (threshold 20–50 ms, ~700 ms boot, A-port undisturbed); DATAFLIP not observable (1,956 samples); EEPROM dumped (sha256 9b46336d…); switch is software-monitored. blocked: MS2109 GPIO write |
| OTF-2 |
RTS hardware reset of the CH9329 (HIDRESET line) as a recovery verb in the shipped ch9329 backend; guard against serial-open modem-line pulses disturbing the A-port (see OTF-1) |
S |
☐ |
unblocked: pulse RTS low ≥50 ms, wait ≥800 ms for boot. Route through the existing session (opening the tty asserts DTR+RTS, replugging the A-port). No status comes back (DATAFLIP unreadable). A reconnecting watchdog should force the baud, not autodetect (#81) |
| OTF-3 |
usb attach-host / usb attach-target: software flip of the A-port mux (MS2109 GPIO) — hands-free physical media (image stick host-side, boot it target-side, BIOS-visible) |
S |
☐ |
unblocked 2026-08-30: no 8051 patch needed. Read-modify-write XDATA 0xDF01 bit 0 (bit 4 on capture firmware < 24081309) over the MS2109 HID config interface with XDATA opcodes 0xB5/0xB6 (already working in findings 7–9, which stopped one address past 0xDF00). Protocol: openterface-usb-mux-spec.md. Untested on the Mini-KVM |
| OTF-4 |
usb replug [--hold-ms]: soft surprise-unplug/replug of the A-port device via CH340 DTR ground-float — scripted hot-plug exerciser for USB driver testing |
S |
☐ |
mechanism confirmed. Off the VM the blockers did not reproduce (28/28 cycles at 480 Mbps, finding 10); they look like USB-passthrough artifacts. Before shipping: repeat on bare-metal Linux (run was macOS) and re-check whether opening the tty alone unplugs the A-port (not on macOS /dev/cu.*) |
| OTF-5 |
EEPROM serial-stamping utility (AT24C16 via MS2109) → unique USB serials → stable by-id paths on multi-unit benches |
C |
☐ |
premise corrected: the ???????? serial is a RAM-resident string descriptor at XDATA 0xC676, not an EEPROM field, so it needs a firmware patch (OTF-3 does not). CH340 stays serial-less; use by-path |
| OTF-6 |
Extension-pins target-side gadget slot (spare downstream port of each hub on pads): MCU mass-storage gadget (true virtual media) or analyzer tap |
C |
⤵ |
solder mod; revisit after OTF-3/4 prove out |
| OTF-7 |
KVM-Go microSD mux (USB_SW via the CH32V208): usb attach-host / attach-target / state over the existing CDC control port |
S |
☑ |
done 2026-08-30, hardware-verified. The generic usb channel + the ch9329 helper's usb verb. Serial opcode 0x17; query and both directions verified by a nonce round-trip across the mux. The reply reports the resulting position; compare it to the request. An unimplemented opcode is silent, so gate "unsupported" on VID/PID (1A86:FE0C) plus a query timeout, never the chip-version table. RTS on this device is an MCU hardware reset — deassert RTS+DTR on open. Protocol: openterface-usb-mux-spec.md |
7. Dashboard
| ID |
Requirement |
Pri |
Status |
Notes |
| DASH-1 |
Combined video + serial web UI (panio console); auto-starts daemons |
S |
☑ |
preselect serial via -i |
| DASH-2 |
Dashboard power-cycle control |
S |
☑ |
|
8. Cross-cutting / non-functional
| ID |
Requirement |
Pri |
Status |
Notes |
| NF-1 |
Interactive/agent bring-up workflow (dashboard, OCR, HID, tio, JSONL) never regresses |
M |
◐ |
guard every change, esp. §9 serial |
| NF-2 |
Changes land as smallest reversible steps, each with tests |
M |
◐ |
|
| NF-3 |
Core power/serial path stays functional on both macOS and Linux |
M |
☑ |
CI-only features may be Linux-only (see §9) |
| NF-4 |
External contracts re-verified against upstream before relying on them |
M |
◐ |
re-check Fuchsia device.go (FX-4) |
| NF-5 |
Failures are machine-classifiable: exit code by kind, optional one-line JSON object on stderr |
M |
☑ |
error contract, errors.md; shipped in 0.5.0 (#242) |
9. Hardware-CI integration (KernelCI/LAVA + Fuchsia/botanist)
Goal: make panio's primitives consumable by LAVA (KernelCI's board-test lab) and
botanist+testrunner (Fuchsia's device-test tools), without owning orchestration or
results. Analysis:
ci-integration/gap-analysis.md; design:
ci-integration/design.md.
Focus: the owner's Fuchsia port. No other users, so breaking changes are free. M1 leads
with the Fuchsia path (PTY + power); botanist before LAVA.
9.0 Decisions (locked 2026-05-29)
| ID |
Decision |
Resolution |
| D-1 |
KCIDB results path |
⊘ Out of scope — LAVA-lab path only for KernelCI |
| D-2 |
Fuchsia serial ownership |
PTY proxy; panio keeps the physical port (JSONL/dashboard stay live) |
| D-3 |
Serial write arbitration |
Cooperative last-writer-wins + advisory lock in /status + opt-in --exclusive, auto-released on client disconnect (+ optional --lock-timeout) |
| D-4 |
JTAG in v1 |
Extension point only (schema + verb stubs); OpenOCD backend deferred |
| D-5 |
CI control-host OS |
Linux-only for CI; macOS stays first-class for interactive bring-up |
| D-6 |
Deploy ownership in CI |
Orchestrator owns deploy (LAVA TFTP / botanist pave); panio netboot stands down |
| D-7 |
Serial TCP endpoint |
Native Rust TCP listener in serialcap; ser2net-on-PTY as LAVA fallback |
| D-8 |
[power] config |
Breaking change accepted — clean [power] block, no power_cycle_cmd alias; update AGENTS.md |
9.1 Agnostic device-control API — Power
| ID |
Requirement |
Source |
Pri |
Status |
Notes |
| PWR-1 |
panio power on — applies power; DUT begins booting unattended |
LAVA |
M |
☑ |
on_cmd hook (2026-06-04) |
| PWR-2 |
panio power off — cuts power |
LAVA |
M |
☑ |
off_cmd hook (2026-06-04) |
| PWR-3 |
panio power reset — off+delay+on (hard reset) |
LAVA |
M |
☐ |
verb is power-cycle; cambrionix cycle does off+delay+on |
| PWR-4 |
panio power state — read on/off |
BOTH |
M |
☑ |
power-state, state_cmd-backed when configured; rename only |
| PWR-5 |
[power] config block w/ backend = script\|dtr\|pdu\|jtag + on/off/reset cmds |
BOTH |
M |
☑ |
landed 2026-06-04 as generic hooks (cycle/on/off/state_cmd); no backend enum, logic in helpers |
| PWR-6 |
Power commands usable as plain shell cmds (string or list) from a generator |
LAVA |
M |
☑ |
hooks are plain sh -c strings |
| PWR-7 |
Update AGENTS.md for the new [power] config + verbs |
OWNER |
M |
☑ |
done with the hooks change |
9.2 Agnostic device-control API — Serial (core gap)
| ID |
Requirement |
Source |
Pri |
Status |
Notes |
| SER-1 |
serialcap exposes a raw bidirectional TCP listener (ser2net-equivalent) |
LAVA |
M |
☐ |
backs connection_command = telnet host port |
| SER-2 |
serialcap exposes a PTY whose slave path is a real device file |
FX |
M |
☐ |
handed to botanist as DeviceConfig.serial |
| SER-3 |
New endpoints tee off the existing supervisor (JSONL/WS/dashboard unaffected) |
OWNER |
M |
☐ |
preserves NF-1 |
| SER-4 |
panio serial send <bytes\|-> one-shot write (agent feature) |
OWNER |
M |
☑ |
same write_tx channel; shipped as serial send [target] <text> with --pace-ms and --no-newline (no --hex or stdin) |
| SER-5 |
Write arbitration per D-3 (lock, /status holder, --exclusive, auto-release) |
OWNER |
M |
☐ |
|
| SER-6 |
Stable socket/PTY paths under $XDG_RUNTIME_DIR/panio/<target>/ |
BOTH |
S |
☐ |
predictable for adapters |
| SER-7 |
Existing JSONL log, /stream, tio, serial log/dtr/reset unchanged |
OWNER |
M |
☐ |
regression guard / tests |
9.3 Agnostic device-control API — Deploy / boot / debug
| ID |
Requirement |
Source |
Pri |
Status |
Notes |
| DEP-1 |
netboot stands down under CI; no DHCP/TFTP contention |
BOTH |
M |
☐ |
guard netboot start under CI attach |
| DEP-2 |
netboot remains available for interactive/non-CI use |
OWNER |
M |
☑ |
exists (NET-1..4); not the CI path |
| DEP-3 |
(Full) panio-serves-images as a non-standard LAVA deploy method |
LAVA |
C |
⤵ |
only if a board can't use LAVA TFTP |
| BOOT-1 |
panio serial wait --match <regex> [--timeout] boot-detect helper |
OWNER |
S |
⤵ |
ergonomics; neither orchestrator needs it |
| JTAG-1 |
[jtag]/[debug] config schema + panio debug {halt\|resume\|reset\|gdb} stubs |
OWNER |
C |
☐ |
extension point only per D-4 |
| JTAG-2 |
OpenOCD backend: reset, flash-deploy, GDB :3333 / Tcl :6666 sockets |
OWNER |
C |
⤵ |
deferred |
9.4 Adapter A — LAVA lab
| ID |
Requirement |
Source |
Pri |
Status |
Notes |
| LAVA-1 |
Device-dictionary + device-type template generator (panio lava device-dict) |
LAVA |
M |
☐ |
power_* → panio power …; connection → telnet |
| LAVA-2 |
Generator supports list-valued power commands |
LAVA |
S |
☐ |
|
| LAVA-3 |
"First device" onboarding doc (Debian worker, ser2net/TCP wiring, tokens) |
LAVA |
S |
☐ |
internet-reachable lab; tokens to KernelCI admins |
| LAVA-4 |
Verified on a Debian LAVA worker against a real board |
LAVA |
S |
☐ |
macOS unsupported (D-5) |
9.5 Adapter B — Fuchsia / botanist
| ID |
Requirement |
Source |
Pri |
Status |
Notes |
| FX-1 |
botanist device-config emitter (panio botanist device-config) → PTY path |
FX |
M |
☐ |
{network,keys,serial}; serial = PTY (SER-2) |
| FX-2 |
Bot-host/recipe power wrapper calling panio power {on\|reset\|off} |
FX |
M |
☐ |
power is NOT a device-config field |
| FX-3 |
bot_config.py get_dimensions() snippet advertising device_type:<board> |
FX |
S |
☐ |
+ bots.cfg, platforms.gni (upstream) |
| FX-4 |
Verify DeviceConfig/power plumbing against a real Fuchsia checkout |
FX |
M |
☐ |
confirm tools/botanist/target/device.go |
| FX-5 |
Document RFC-0130 Experimental tier (self-hosted CI) |
FX |
C |
☐ |
community board is not "Supported" tier |
9.6 Adapter C — Redfish provider
Decision (D-9, 2026-05-29): Redfish (DMTF server-management REST API) as provider:
panio exposes Redfish in front of BMC-less boards. Not client. Redfish is the common
bare-metal control API (Ironic/Metal3; LAVA can curl it), so one provider beats
per-ecosystem adapters. Sequenced after M1; consumes PWR-1..6 and SER-1. Design:
ci-integration/redfish-provider.md. Verified against
DMTF CSDL (DSP0266 v1.22.0, DSP8010 2025.2), OpenBMC, Ironic/sushy.
| ID |
Requirement |
Source |
Pri |
Status |
Notes |
| RF-1 |
Redfish provider service: ServiceRoot → ComputerSystem → Manager (→ VirtualMedia) resource tree |
OWNER |
S |
⤵ |
after M1; provider, not client |
| RF-2 |
#ComputerSystem.Reset → power verbs (On→on, ForceOff→off, PowerCycle/ForceRestart→reset); PowerState → power-state |
OWNER |
S |
⤵ |
depends on PWR-1..6 |
| RF-3 |
Boot.BootSourceOverrideTarget=Pxe + BootSourceOverrideEnabled=Once → netboot |
OWNER |
S |
⤵ |
maps to existing netboot |
| RF-4 |
VirtualMedia InsertMedia/EjectMedia → image deploy |
OWNER |
C |
⤵ |
open: needed vs. Pxe-once sufficient? |
| RF-5 |
SerialConsole advertises out-of-band SSH/console endpoint pointing at panio raw-serial socket (metadata only) |
OWNER |
S |
⤵ |
depends on SER-1; Redfish carries no serial bytes |
| RF-6 |
Accurate per-node ResetType@Redfish.AllowableValues / ActionInfo for the supported subset |
OWNER |
S |
⤵ |
relay/DTR boards lack some ResetTypes |
| RF-7 |
Implement via a sushy-tools-style emulator + panio backend driver (not a hand-rolled OData service) |
OWNER |
S |
⤵ |
open: dependency footprint (the core CLI is a single Rust binary) |
| RF-8 |
Document/decide whether Redfish provider replaces or complements LAVA/botanist adapters |
OWNER |
S |
⤵ |
botanist PTY serial still needs the direct path → not a full replacement |
10. Security
TODO — owner to populate. Panio grants physical-equivalent control of a target (power,
raw serial, netboot/TFTP, HID), is SSH-driven into the control host, and §9 adds
network-facing serial endpoints. The threat model needs first-class requirements.
| ID |
Requirement |
Pri |
Status |
Notes |
| SEC-0 |
Define panio's threat model and security requirements |
M |
☐ |
Placeholder — to be written. |
Open questions (not yet requirements):
- Serial endpoint exposure (§9): SER-1 mirrors serialcap's loopback bind (
127.0.0.1). Who
may connect from a LAVA worker / Swarming bot: auth, bind address, TLS, or SSH tunnel +
isolation?
- Write arbitration (SER-5/D-3): is
--exclusive only cooperative, or a safety guard?
- Netboot/DHCP/TFTP: read-only, single-client; rogue-DHCP risk on a shared network vs. the
assumed direct link?
- Power/HID authority: control-host access means power-cycle and HID; what bounds that
(host access, per-target ACLs)?
- Secrets: LAVA tokens,
$FUCHSIA_SSH_KEY, CIPD/Swarming creds: storage and handling.
- Supply chain:
panio setup builds/install Rust + Swift + Homebrew components.
11. Milestones
| Milestone |
Contents |
Status |
| M0 — Analysis & design |
gap-analysis, design, this tracker, decisions |
☑ |
| Shipped baseline |
§1–§7 capabilities (netboot, serial, power, video, HID, dashboard) |
☑ |
| M1 — Agnostic device-control core |
SER-2, SER-4, PWR-1..7, SER-5, SER-1, DEP-1, JTAG-1 (Fuchsia path first) |
☐ (awaiting go-ahead) |
| M2 — Adapters |
FX-1..4 (first), then LAVA-1..3 |
☐ |
| M3 — Verify on hardware |
FX-3/FX-5, LAVA-4, BOOT-1 |
☐ |
| Security |
§10 (SEC-*) |
☐ (to be defined) |
| M4 — Full (deferred) |
DEP-3, JTAG-2 |
⤵ |
12. Open implementation questions
| ID |
Question |
Status |
| SER-Q1 |
Native TCP listener vs. ser2net-on-PTY |
✓ Resolved (D-7): native listener; ser2net fallback |
| SER-Q2 |
Write-lock lifetime |
✓ Resolved (D-3): auto-release on disconnect + optional --lock-timeout |
| PWR-Q1 |
[power] shape + power_cycle_cmd migration |
✓ Resolved (D-8): clean breaking block, no alias |