feat(preflight): detect and surface Podman machine hypervisor provider - #438
Merged
Conversation
Adds get_podman_machine_provider() (compat.sh) to detect whether a macOS Podman machine is running on "applehv" (vfkit/AVF) or "libkrun" (krunkit), following up on PR #433's process-matching fix. Informational only, no behavioral branch: logged at launch and preflight, and recorded as a new status.json field (machine_provider) per the Dashboard Sync Rule. Adds docs/KRUNKIT-PROVIDER.md as the opt-in adoption guide referenced from Issue #409's research comment (install, migration cost, mitigation status under libkrun). Leaves #409 open — benchmarking and sleep/wake burn-in still need a real libkrun machine, which wasn't available for this change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
CI's dashboard-build "Typecheck server" step (bunx tsc --noEmit) failed on
the 3 test files that build a typed AgentStatus fixture via a
Partial<AgentStatus>-override helper (gist-history, health-rules, health):
without a base value, the merged type inferred machine_provider as
`string | null | undefined`, and `undefined` isn't assignable to the
interface's `string | null`. Other status.test.ts-style fixtures using
untyped JSON.stringify({...}) were unaffected — grepped for AgentStatus
usage across dashboard/{server,ui} tests to confirm these were the only 3.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ht provider report Ensemble review (noncritical): the preflight provider line passed the literal "podman-machine-default" as an explicit argument, overriding get_podman_machine_provider's own KAPSIS_PODMAN_MACHINE fallback chain — inconsistent with the launch-agent.sh call site and with how podman-health.sh / kapsis-cleanup.sh / vfkit-watchdog.sh resolve the machine name. Drop the argument so a custom KAPSIS_PODMAN_MACHINE gets the right provider line. (check_podman's pre-existing inspect/state checks also hardcode the literal — out of scope for this PR.) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- test-compat.sh: cover the no-timeout-cmd fallback branch of get_podman_machine_provider (_KAPSIS_TIMEOUT_CMD empty) - test-compat.sh: assert KAPSIS_PODMAN_MACHINE is resolved as the default machine name via an argv-capturing fake podman - test-status-reporting.sh: validate full status-file JSON with python3 inside both machine_provider tests - test-preflight-check.sh: assert provider line absent on Linux, and add macOS test that check_podman passes without a provider line when the VMType query fails Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ection # Conflicts: # dashboard/server/src/types.ts # dashboard/shared/src/index.ts # scripts/lib/status.sh
This was referenced Jul 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up to #409 (and PR #433's process-matching fix). Adds the provider-detection primitive that was deferred out of PR #433's scope because it wasn't behavioral there:
get_podman_machine_provider()inscripts/lib/compat.sh— detectsapplehvvslibkrunviapodman machine inspect --format '{{.VMType}}', empty/no-op on Linux, never fails the caller.scripts/launch-agent.sh, macOS + Podman backend only) and at./scripts/preflight-check.sh.status.jsonfield,machine_provider(per the Dashboard Sync Rule):scripts/lib/status.sh(setter + JSON field),dashboard/shared/src/index.ts(AgentStatus interface — the actual source of truthdashboard/server/src/types.tsre-exports), and a small display line indashboard/ui/src/views/AgentDetail.tsx.docs/KRUNKIT-PROVIDER.md— the opt-in adoption guide referenced fromdocs/STATUS-TRACKING.mdand added toCLAUDE.md's Documentation Map. Covers requirements, install (brew tap libkrun/krun && brew install krunkit), migration cost (new machine required, caches/images not shared), and which existing mitigations remain active either way.Deliberately out of scope (still tracked on #409)
Per the issue's own research: benchmarking
libkrunvsapplehvon a representative Kapsis workload, and sleep/wake burn-in validation, both require a real macOS 14+/Apple Silicon host running alibkrunmachine — not available in this environment.#409is left open; this PR does not close it.Nothing here changes Kapsis's default behavior or gates any existing mitigation on the detected provider — it's purely observability, consistent with PR #433's guardrail that provider detection should never become a behavioral branch without field evidence.
Test plan
QUICK_TESTS-registered files (norun-all-tests.shregistration changes needed):tests/test-compat.sh(4 cases: libkrun/applehv/Linux-noop/podman-failure, using a fake executablepodmanonPATHsince detection shells out viatimeout),tests/test-status-reporting.sh(2 cases: setter round-trips into JSON, defaults tonull),tests/test-preflight-check.sh(1 case:check_podmansurfaces the detected provider).shellcheck --severity=warningclean on all changed shell files.bun/tscavailable in this environment to typecheck the dashboard TS changes directly; verified by inspection thatAgentStatusfixtures indashboard/server/tests/*.test.tsare untypedJSON.stringify({...})literals (not: AgentStatus), so the new required-but-nullable field can't break existing tests, and no CI workflow currently runstsc --noEmit.🤖 Generated with Claude Code