plugin-doctor
| Version | 2026.181.0001 |
| Repo | superproject |
| Plugin | yes — see the plugin reference |
COMPILED-IN charly COMMAND-class plugin that OWNS the externalized charly doctor
CLI — the host-dependency-status surface. The plugin owns the command end to end: the
flag grammar (–json), the ENTIRE check list + group orchestration (container engine /
build infra / service management / VMs / VFIO / encrypted storage / secret storage /
tunnels / merge & registry / shell & TTY / podman machine), the pass/warn/fail verdicts,
the human + JSON report formatting, the exit code, AND the pure host ops it runs itself
(binary probes via exec.LookPath / exec.Command, file reads via os.Stat / os.ReadFile).
No plugin-specific report LOGIC is left in core.
The ONE thing the plugin cannot compute itself is the genuine host-HARDWARE subsystem + core-owned data: the GPU/VFIO/device detection primitives (DetectGPU / DetectAMDGPU / detectAMDGFXVersion / GPURunArgs / DetectVFIO / MemlockLimitBytes / VfioGroupAccessible / vfioPciAvailable / the devicePatterns glob), the credential-store health (credentialHealth → verb:credential, which lazy-connects host-side), and the core install-hint / distro-family / device-description tables. Those STAY core (charly/host_build_hostprobe.go) because they are the genuine host-hardware subsystem the plugin cannot hold + are MULTI-CALLER (the GPU/VFIO shims serve vm/deploy too) — so duplicating them into the plugin would violate R3. The plugin reaches them via the generic “hostprobe” HostBuild seam (spec.HostProbeRequest → spec.HostProbeReply), which runs the detection primitives host-side ONCE and returns RAW FACTS ONLY — zero formatting or verdict logic crosses into core. “hostprobe” is a class-generic action noun, not a provider word (F11). This is the same “plugin owns the report + a generic seam for the genuine host-coupled facts” doctrine the clean + settings command plugins established.
doctor is COMPILED-IN (listed in charly/charly.yml compiled_plugins) BECAUSE its Invoke(OpRun) needs the in-proc reverse channel — threaded by dispatchInProcCommand (“Seam A”) — to call HostBuild(“hostprobe”). The out-of-process CliMain path has no reverse channel, so it errors: doctor cannot run out-of-process, it needs the hostprobe host seam. There is NO hidden core-command forward — the plugin does the report directly, calling back only for the raw host-hardware facts; no core symbol crosses the boundary, no ad-hoc podman.
command:doctor dispatches through the COMPILED-IN registry path (registerCompiledPlugin →
resolve(ClassCommand,“doctor”) → dispatchInProcCommand → Invoke(OpRun) with the threaded
in-proc reverse channel), so NewMeta advertises command:doctor while the served CUE schema
carries no plugin_input (the args are plain CLI tokens). The R10 witness is the disposable
check-doctor-local bed: charly doctor exits 0 and prints the host-dependency report,
proving the externalized command + the in-proc HostBuild hostprobe dispatch end-to-end.
Acceptance plan
Section titled “Acceptance plan”This candy’s plan: — the runnable spec charly check executes against a live deployment. check: steps are idempotent probes; run: steps change state.
| Intent | Step |
|---|---|
check |
the doctor command plugin ships a buildable Go module (go.mod + the provider package) compiled into charly; the full charly doctor end-to-end (the in-proc HostBuild hostprobe dispatch) is exercised by the live R10 (check-doctor-local) |