Releases: DustinTrap/kvm-pilot
Release list
v0.1.0b8 — docs, visuals & brand overhaul
Beta 8 — the docs, visuals & brand overhaul (#209). No runtime code changes; this release exists so the refreshed README (the PyPI page), corrected claims, and the new brand reach every published surface.
One line, everywhere: Smart hands for your AI agents — write-capable, multi-plane (KVM + BMC + SSH) MCP server: gated, verified, audited.
Added
- Brand: the
>_ kvm-pilotterminal-prompt wordmark (dark-mode-aware SVG), favicon, and a 1280×640 social card in the docs' house palette - Live demo GIF in the README — a real, unedited GLKVM run: honest preflight, headless snapshot waking the on-demand encoder, gated dry-run power-cycle, and the captured boot console (re-recordable via the committed
docs/assets/demo.tape) - Five diagrams for the hardest concepts: trust ladder, two-machines, snapshot pipeline, evidence→maturity ledger, approval/receipt lifecycle
docs/troubleshooting.md— canonical symptom-first fixes + FAQ (on the wiki sidebar)- Root
llms.txt— an agent-discoverable doc map (llmstxt.org) - Docs guard tests — README version literals must match
__about__.py; SKILL.md's tool list must two-way match the registered MCP surface
Changed / fixed
- README restructured (logo, badges, copy-paste
claude mcp addquickstart on the READ_ONLY first rung, tool-surface-by-plane table, version-agnostic status); GLKVM API warning demoted to a setup note - Honesty fix:
snapshotis verified on RM1PE V1.9.1 only (V1.5.1 fails with an undecodable H.264 frame, #107/#151) — the compat table said otherwise; added the live-verified Dell iDRAC6 (IPMI) row - SKILL.md now lists all 29 MCP tools; the stale "nothing reboots the appliance" claims corrected; MCP README gains the missing
boot_options/set_boot_device/wakerows +ALLOW_CONFIGenv entry - architecture.md brought to the present tense (driver split,
BootConfig, Redfish/IPMI drivers landed) RESUME.mdremoved from tracking (published internal fleet details); orphaneddocs/mcp-tools.svgremoved
Full details in the CHANGELOG.
🤖 Generated with Claude Code
v0.1.0b7 — IPMI driver + serial console (SOL)
Beta 7 — IPMI. A full IPMI 2.0 driver for pre-Redfish BMCs (Dell iDRAC6, older HPE iLO, Supermicro), validated end-to-end against a live Dell iDRAC6 (R710).
Added
- IPMI driver (#62).
--driver ipmiviaipmitool -I lanplus(password through theIPMI_PASSWORDenv, never argv). Power / SystemInfo / BootConfig / Sensors / Logs — sopower/boot-device/sensors/logswork with no new CLI/MCP code. IPMI completeness ≈ Redfish minus VirtualMedia. - IPMI serial console / SOL (#208).
SerialConsole(serial_read/serial_writeover a PTY-backedipmitool sol activate) + akvm-pilot consolecommand for an interactive text console (exit with~.). Gatedipmi.serial_console(HID_INPUT). Text-only — drives Linux/ESXi serial installers, not the Windows GUI installer.
Fixed
- IPMI
get_infomodel now comes from FRUBoard Productwith vendor placeholders skipped, so a Dell R710 reportsPowerEdge R710(not thelocalhostiDRAC hostname Dell puts inProduct Name). - Healthcheck now labels the IPMI driver
ipmi@…(was mislabeledpikvm@…).
Testing / validation
- Cross-checked against an independent OpenIPMI
ipmi_simBMC (tests/integration/test_ipmi_external.py) — the IPMI analogue of the sushy-tools Redfish cross-check. - Live-validated against a real Dell iDRAC6 (R710): power off/on/reset (verified state flips), boot-device round-trips, 105 sensors, SEL, info (14/0); SOL captured the full BIOS boot; F11 over SOL opened the BIOS Boot Manager (bidirectional drive).
Install: pip install --pre kvm-pilot
v0.1.0b6 — remote boot-control + Wake-on-LAN
Beta 6 — remote boot-control + Wake-on-LAN (epic #200), matured on simulators (in-repo Redfish emulator + independent sushy-tools) ahead of real BMC validation.
- Wake-on-LAN (#199):
wol.pycore,kvm-pilot wake+wakeMCP tool,HostConfig.mac;power onfalls back to WoL when the KVM has no wired ATX. Hardware-validated (woke a real host in 52 s). - Redfish boot-device (#28/#201):
BOOT_CONFIGcapability,boot-deviceCLI (one-time/persistent, UEFI/legacy) +boot_options/set_boot_deviceMCP; feature-detects allowable targets + auto-retries without mode on iLO4/iDRAC7. - In-band boot (#150):
boot-device --via sshsets UEFI BootNext via efibootmgr.
~75 new tests; boot-device cross-checked against sushy-tools. Real HPE iLO / Dell iDRAC validation pending (#29) — code is simulator-tested only. Install: pip install --pre kvm-pilot.
Full notes: CHANGELOG.
v0.1.0b5 — calibration fixes from the first live fleet run
Beta 5 — b4's mouse auto-calibration went to real hardware (GL-RM1PE ×2, V1.9.1) hours after release. The algorithm validated live — held-out residual 0.0106 of the screen (~17px at 1600×900) on a RHEL/GDM host, correction applied and visually confirmed — and the run surfaced two functional bugs, both fixed here. If you installed b4, upgrade: calibrations recorded no resolution, and on GL's on-demand streamer the correction was never applied via the CLI path. Details in the CHANGELOG.
v0.1.0b4 — mouse auto-calibration
Beta 4 — mouse auto-calibration.
Fixes the oldest live-hardware complaint (#128): the agent clicks where the button should be and misses. kvm-pilot now measures each host's real commanded→observed mouse mapping and corrects for it transparently.
Highlights
calibrate-mouse(CLI) /calibrate_mouse(MCP). Parks the cursor, commands a 5-point grid, locates the observed cursor by frame differencing, least-squares fits a per-axis scale+offset, and verifies a held-out point within--tolerance(default 0.02 of the screen). One detail that matters: the baseline cursor's departure mark is identified from the data — the blob that recurs across every frame — never assumed to sit at the commanded park corner, because the distortion being measured decides where the parked cursor really landed. Failures are actionable, never partial stores: non-static screens, invisible cursors, implausible fits, and non-linear pointer acceleration each get named with a remedy.- Transparent application. The correction is stored per (host, capture resolution) — a resolution change makes it stale and it is never applied. Percent-space
mousemoves and clicks (MCP and CLI) route through it automatically and reportcalibrated: true/false; pixel/raw coordinates mean "exactly here" and are never adjusted. pip install 'kvm-pilot[calibrate]'brings Pillow for snapshot decoding; the command ships in base and errors actionably without it. The detection/fit math is stdlib and fully tested with synthetic frames — no hardware, no Pillow needed in CI.- Safety: pointer moves only, but gated like HID input (
KVM_PILOT_MCP_ALLOW_HID+ one approval covers the whole ~10–30s run, on a static screen).
Also
docs/cli.mdagain satisfies its "every command must appear here" contract (adds the missingkeep-awake,recover-hid,appliance,pathsrows found by the #194 review).- First release expected to publish automatically to the official MCP registry as
io.github.DustinTrap/kvm-pilot(#197) — b3's job taught us the publisher assets use Go arch names, descriptions cap at 100 chars, and the namespace + PyPImcp-name:marker are case-sensitive. All fixed here.
Install: pip install --pre kvm-pilot · Getting started · Full details in the CHANGELOG.
v0.1.0b3 — externally visible contracts
Beta 3 — the externally visible contracts release.
kvm-pilot's safety internals (effect-class gates, signed single-use approval receipts, typed outcomes, audit trail) were already ahead of the MCP ecosystem. b3 makes them legible from the outside — the contracts agent hosts actually build policy on. Distilled from the 2026-07-13 competitive gap analysis (#194).
Highlights
- Per-tool MCP annotations (#195). Every tool now declares all four hints (
readOnly/destructive/idempotent/openWorld) explicitly, and a regression test fails CI if a tool ever ships without them. Clients auto-approve, parallelize, and render confirmation UI off these bits — and the spec defaults treat an unannotated tool as maximally dangerous and internet-reaching, which misrepresented our LAN-only surface. Notable precision fixes:mount_iso/eject/file_firmware_reportare reversible writes, not destructive ops (their MEDIA / EXTERNAL_WRITE gates and approvals are unchanged);classify_screen/wait_for_stateare flagged open-world because the server-side vision backend may be a cloud VLM — with a local VLM nothing leaves your network. KVM_PILOT_MCP_READ_ONLY=1(#196). A true least-privilege launch posture, enforced by three independent layers: destructive tools are not registered at all, every effect gate is force-closed regardless ofALLOW_*, and every driver is built with a deny-all confirm — so a registration bypass fails closed instead of mutating (tool filtering alone is not enforcement). The documented trust ladder for a new fleet:READ_ONLY→DRY_RUN→ per-effectALLOW_*, one gate at a time.- Official MCP registry (#197). The server publishes as
io.github.dustintrap/kvm-pilot— this release carries the ownership marker and the release pipeline now keeps the registry listing in step with PyPI automatically.
Also
- The getting-started guide now starts new users on the read-only rung and closes the loop:
kvm-pilot test-report+ a two-minute hardware report is how a device+firmware combo earns its row in the Hardware-Compatibility matrix. Success or failure both count. - README links on PyPI are absolute again (#193).
Install: pip install --pre kvm-pilot · Getting started · Full details in the CHANGELOG.
v0.1.0b2 — beta 2: the reliability + evidence-harness release
Beta 2 — the reliability + evidence-harness release. Two hardening
batches in one: the transports can no longer double-fire a destructive action,
MCP approvals became signed single-use receipts with an audit trail, GLKVM
snapshots work headless at native resolution, evidence learned to carry the
conditions it was observed under — and kvm-pilot test-report turns the whole
per-device intake into one command. Everything in this release is
unit/emulator-verified; the first live fleet run of the new paths is the next
milestone (the harness exists precisely to record it honestly). 18 issues
closed.
Added
-
kvm-pilot test-report(#99) — the live-test harness: probes the
device's capabilities and appends one evidence row to the run ledger
(--ledger>$KVM_PILOT_TEST_LEDGER>~/.config/kvm-pilot/test_runs.jsonl;
never the installed package data). Read-only probes (info, snapshot —
stamped with the #156 conditions on pass AND fail — healthcheck, logs,
power_state) run every invocation; destructive probes run only via
--include virtual_media,power,firmware_updatewith a recorded--attest
operator statement, still routed through the normal safety gates. Pass =
assertion + observed effect (power must flip the read-back and restore;
media must report online and the eject must land; a flash passes only via
the driver's #94 verified-state contract) — an unobserved effect records an
honest FAIL. Fake-driver runs (and--synthetic) record
source="synthetic", which never promotes maturity; there is no flag to
forcereal. -
The generated wiki Hardware-Compatibility page now carries a Maturity
column — the #98-derived level per (device, firmware) read from the shipped
registry (—when no live-derived rating exists), completing #103. -
New GLKVM quirk
firmware-flash-webui-only(#177): the GL web console is
the only known-good RM1PE upgrade path (V1.5.1→V1.9.1 live-verified); the
/api/upgrade/*flash was observed to no-op (#94/#95) and no API-driven
flash has ever been verified on any release.firmware-updateoutput now
steers to the web console on affected devices (it never blocks — the driver
already reports a no-op flash honestly), and
firmware-update/driver-features/firmware-registry docs carry the guidance. -
GLKVM headless JPEG snapshot at native resolution (#187): when the
snapshot bytes fail the JPEG guard (H.264 at native/high res, #107) and the
firmware exposesparams.video_format(V1.9.1+), the driver flips the
encoder to MJPEG (POST /api/streamer/set_params?video_format=1), retries,
and restores the prior format — no EDID change, no H.264 decoder, no
browser. Insidestreamer_warm()the flip is held for the whole block and
restored once at exit. Composes with the #142 offline-streamer recovery
(offline → warm → H.264 → flip). V1.5.1 doesn't expose the switch and keeps
the honestSnapshotFormatError(upgrade via the web UI, #177). Mechanism
live-proven on V1.9.1; the auto-path is emulator-verified and awaits its
first live ledger row. New quirksnapshot-h264-at-native-res. -
A firmware change now invalidates the device assessment:
preflight
remembers the firmware each device was last assessed at, forces the stable
checks to re-run live when it differs (out-of-band web-UI flashes included),
and emits afirmware-deltafinding diffing what cleared / regressed /
stayed open (#180). -
Run-ledger capability rows can now record the conditions a result was
observed under (conditions: {resolution, encoder_format, snapshot_cached, jpeg_sink_clients}) — the axes that actually decide a GL snapshot outcome —
and the support-matrix rollup surfaces them aspass_conditions/
fail_conditions, so field reports at different operating points reconcile
from data instead of reading as contradictions. Optional; pre-existing rows
and derived maturity are unaffected (#156). -
CI docs-parity guard:
build_wiki.py --checkfails when adocs/*.mdpage is
not registered in the wikiPAGESallowlist, so a new page can no longer
silently go unpublished; the MCP README tool table gained the missing
access_pathsrow (#175).
Added (MCP)
-
Signed, expiring, single-use approval receipts + audit trail for the
destructive act tools (#72): every approval mints an HMAC-signed receipt
bound to the exact invocation (host, tool, effect, args-hash, dry-run,
approver), re-verified immediately before dispatch and consumed on use —
a bound field changing after approval, an expired receipt
(KVM_PILOT_MCP_RECEIPT_TTL, default 60 s), or a replay fails closed as a
denial-shaped result. Approved results carryreceipt: {id, state}and a
realapproval.expires. Every destructive-invocation terminal (approved,
denied, consumed, expired, mismatched, replayed, dispatch-exception) emits
one JSON audit record on thekvm_pilot.mcp.auditlogger. -
New
file_firmware_reporttool — the MCP twin of CLIfirmware-check's
auto-filing (#189), completing the registry telemetry loop for agent
sessions. Filing a GitHub issue is a new external-write effect class
with its own operator gate (KVM_PILOT_MCP_ALLOW_EXTERNAL_WRITE, off by
default) plus the usual per-invocation approval; the shared helper moved to
firmware_registry.file_firmware_report(#190).
Changed
- The healthcheck's support-evidence finding now labels ledger history as
recorded (vs this run's own tested-now probes), renders the #156
conditions each result was observed under, and flags condition-blind
snapshot passes ("verified only under unknown resolution/encoder") instead
of overclaiming a bareverified (n=N)— the honesty regression that gave
#180 its false confidence (#180).
Changed (MCP)
- Act results now carry a typed
outcomefield (approved/denied/
cancelled/not_confirmed/gate_closed/invalidated) so agents
branch on data instead of matching the human-facingdenied_reasonstrings —
a cancelled elicitation (benign, retryable) is now typed apart from an
explicit denial. TheKVM_PILOT_MCP_ELICIT=offescape-hatch hint moved from
every client-side denial to a one-time hint after ≥2 consecutive
client-side approval kills on the same host — a security trade-off shouldn't
be advertised on a one-off mis-click (#149). - The
powertool now returns a structured result instead of a sentence: it
bumps the frame generation (a stale mouse click can no longer anchor to a
pre-reboot snapshot within the reboot window) and verifies the effect via
the driver's trustworthy signal — Redfish PowerState or a wired ATX LED —
reportingverified: true/falsewith the observed state, or an honest
verified: null+ the reason and remedy when no trustworthy signal exists
(GL units: ATX sensing lies; verify visually) (#168).
Fixed
-
The transports no longer auto-retry a 409/503 that answers a state-changing
request — re-firing a POST whose 409/503 arrived after the device began
acting (e.g. a BMC perturbed by theComputerSystem.Resetit just accepted)
could double-fire a destructive action. Reads (GET/HEAD) keep the bounded
retry; the #164 breaker semantics are unchanged; the Redfish driver's own
at-target reconciliation now sees the surfaced error instead of being
pre-empted by a transport re-POST (#167). -
A JSON endpoint answering with a non-JSON body (e.g. truncated at the
content boundary) now raises a typedProtocolErrorwith a redacted preview
instead of leaking raw bytes into dict-expecting callers as an opaque
AttributeError; an empty 2xx body returnsNone(#170). -
Redfish
mount_isonow verifies the medium actually landed (polls the
VirtualMedia slot forInserted=true, raisingMediaOfflineErroron a
silent no-op — the #78 trap, Redfish edition;verify=Falseopts out), and
a mid-flight 401 re-auth DELETEs the old session before re-login so a
spurious 401 can't strand a live session slot on session-capped BMCs; a
login that yields no session URI now logs the future leak (#169). -
The MCP effect gate now fails closed for an effect class with no
registered enable-flag instead of silently borrowing the CONFIG gate;
APPLIANCE_RESETis now explicitly mapped to
KVM_PILOT_MCP_ALLOW_APPLIANCE(#190).
Install: pip install --pre kvm-pilot
Full diff: v0.1.0b1...v0.1.0b2
v0.1.0b1 — first beta: the telemetry-loop release
First beta — the telemetry-loop release. The registry telemetry loop now closes itself, and the ingest side can no longer spam on malformed input. The beta label follows the support matrix: the GL-RM1PE on V1.9.1 has its core capabilities at beta maturity in the run ledger that ships in the wheel; most other device+capability combos remain unverified, and the Hardware-Compatibility list stays the source of truth. Broader hardware testing is now the ask — PiKVM, BliKVM, other GLKVM models, and Redfish BMCs especially.
Added
firmware-checkauto-files the "Latest known release" report as afirmware-reportissue (via theghCLI) when the registry SSoT is behind the device-reported latest — the emission side of the telemetry loop was fully manual and produced almost no reports (#189). On by default;--no-file-reportopts out,--dry-runpreviews the exact issue body,--source/--date/--repooverride the details. Deduplicated against existing reports and validated with the same rules the ingest applies.firmware_registry.render_issue_form()— the inverse ofparse_issue_form, so auto-filed bodies round-trip through the ingest parser (#189).reconcile()carries the registry entry'ssource(release channel URL) into the suggested submission, so known devices auto-file with no extra input.
Changed
- The hourly firmware-ingest workflow parks invalid submissions: one ❌ comment + the
ingest-errorlabel (remove the label after fixing the body to re-queue). Previously a malformedfirmware-reportissue was re-commented every hour forever (#188). - Status/maturity messaging updated across the README (PyPI page), getting-started, bundled skill, and MCP README; trove classifier bumped to
Development Status :: 4 - Beta.
Install: pip install --pre kvm-pilot (beta is a pre-release; a bare install still picks up nothing).
v0.1.0a14 — interface router
The interface-router release (alpha; pip install --pre kvm-pilot).
Adds an adaptive interface router that picks the fastest interface which will actually produce the result — per device, benchmarked, and self-tuning from real use — across a KVM control plane (in-process/MCP/browser) and an in-band OS plane (SSH / WinRM remote-PowerShell).
kvm-pilot benchmark— per-command latency + capability scorecard across interfaceskvm-pilot route <cmd>/kvm-pilot host-exec <cmd>— seamless interface selection + in-band execution- SSH + WinRM interfaces (WinRM = dep-free PowerShell-over-SSH); persistent SSH (~10× via ControlMaster); dep-free SSH password auth (SSH_ASKPASS)
- Online learning — the scorecard self-tunes from every call
Grounded in live benchmarks across the GL fleet + real Linux hosts (#181, #179, #182, #183). Full changelog: CHANGELOG.md.
🤖 Generated with Claude Code
v0.1.0a13 — the headless-vision release
The headless-vision release. GL's video encoder is on-demand — it runs only while a video client is connected — so a headless snapshot/classify/watch (the flagship AI-agent case) used to 503 forever on an idle unit. This release makes it work, grounded in a full live reliability sweep of the GL-RM1PE fleet (.11/.20 V1.9.1, .39 V1.5.1; findings in #176).
Per the support matrix this line stays alpha: only GL-RM1PE is live-validated (V1.9.1 reaches beta-grade there), while the other drivers remain emulator-only.
Added
- Headless
snapshotnow works on idle GL units (#142) — on astreamer: null503 the driver registers a stream client over kvmd/api/ws, waits for the encoder (~1.5s), and retries. Verified live: recovers a valid JPEG on RM1PE V1.9.1; on V1.5.1 it emits H.264, honestly surfaced (#107), not a false success. GLKVMDriver.streamer_warm()keep-alive (#142) — holds the stream client open in a background thread so everysnapshotin the block is instant (~0.1s vs ~5s cold), no vision/LLM.watchand MCPwait_for_stateuse it.websocket-clientpromoted to a base dependency — headless GL snapshot needs it;eventsnow works out of the box (kvm-pilot[ws]kept as a no-op alias).- GLKVM quirk
snapshot-needs-video-client; driver-features (#171) + reusable hardware test plan (#172) docs, published to the wiki.
Fixed
snapshot503 no longer misdiagnoses an idle streamer as a wedged encoder (#173) — and the matchingvideo-signalhealthcheck remediation.power/power-cycleon unwired ATX returns a clearCapabilityErrorinstead of an opaqueHTTP 500(#174).
Full changelog: see CHANGELOG.md. Install: pip install --pre kvm-pilot.