28 KiB
Usage
English | 한국어
CLI, GUI, configuration, and health checks. Everything you need after install.
Launch an app
winpodx app run word # Launch Word
winpodx app run word ~/doc.docx # Open a file
winpodx app run desktop # Full Windows desktop
Or just click an app icon in your application menu — WinPodX registers every discovered Windows app as a .desktop entry the first time the pod boots.
CLI reference
# Apps
winpodx app list # List available apps
winpodx app run word # Launch Word (auto-provisions on first run)
winpodx app run word ~/doc.docx # Open a file in Word
winpodx app run desktop # Full Windows desktop session
winpodx app install-all # Register all apps in desktop menu
winpodx app sessions # Show active sessions
winpodx app kill word # Kill an active session
winpodx app refresh # Re-scan the guest and rebuild the app list
# Pod lifecycle (container state only — see `guest` for in-guest ops, `install` for disk / install)
winpodx pod start --wait # Start and wait for RDP readiness
winpodx pod stop # Stop (warns about active sessions)
winpodx pod status # Status with session count
winpodx pod restart
winpodx pod recreate # Stop + remove + start (clean container)
winpodx pod wait-ready --logs # Wait for Windows first-boot with progress + container logs (auto-extends on slow ISO download)
# Guest-side operations (renamed from `pod <x>` in 0.6.0 — old spellings still work through 0.6.x with a deprecation notice)
winpodx guest apply-fixes # Re-apply Windows-side runtime fixes (idempotent)
winpodx guest sync # Push host updates (agent / urlacl / rdprrap / fixes) into the guest — no reinstall
winpodx guest sync --force # Re-sync even when the guest version stamp already matches
winpodx guest sync-password # Recover from password drift (cfg ↔ Windows)
winpodx guest multi-session on # Toggle bundled rdprrap multi-session RDP
winpodx guest multi-session status
winpodx guest recover-oem # Print noVNC PowerShell steps to download + run install.bat manually when dockur's first-boot OEM copy failed (#287)
# Install / disk operations (renamed from `pod install-* / pod grow-disk / pod disk-usage` in 0.6.0)
winpodx install status # Install progress / pending steps (#271 agent-first installs)
winpodx install resume # Resume a deferred install step
winpodx install disk-usage # Show Windows C: size / free / used% + auto-grow status (#318)
winpodx install grow-disk # Add the auto-grow increment (default 32G) to the disk + extend C: (#318)
winpodx install grow-disk 128G # Grow to an absolute size
winpodx install grow-disk --extend-only # Just extend C: into existing unallocated space
# Power management
winpodx power --suspend # Pause container (free CPU, keep memory)
winpodx power --resume # Resume paused container
# Host device passthrough (USB / PCI → Windows guest, #286)
winpodx device list # List host USB / PCI devices + their attach state
winpodx device attach <id> # Attach a host device to the guest (USB hot-plugs live; PCI is boot-added)
winpodx device detach <id> # Detach a device from the guest
winpodx device attach <id> --force # Skip the guest-restart safety confirmation for a PCI device
# Security
winpodx rotate-password # Rotate Windows RDP password (host config + Windows-side guest account)
# Reverse-open (host listener / guest sync)
winpodx host-open status # Show listener daemon + manifest state
winpodx host-open list # List discovered host apps (live or --cached)
winpodx host-open refresh # Rescan host + push manifest to guest
winpodx host-open enable # Turn reverse-open on
winpodx host-open disable # Turn reverse-open off
winpodx host-open add <slug> # Add app to allowlist
winpodx host-open remove <slug> # Remove from allowlist (or --deny)
winpodx host-open start-listener
winpodx host-open stop-listener
winpodx host-open daemon-status
# Maintenance
winpodx cleanup # Remove Office lock files (~$*.*)
winpodx timesync # Force Windows time synchronization
winpodx debloat # Disable telemetry, ads, bloat
winpodx uninstall # Remove winpodx files (keeps container)
winpodx uninstall --purge # Remove everything including config
# System
winpodx setup # Full setup: config + container + wait-ready + discovery + reverse-open
winpodx setup --customize # Wizard: backend / specs / edition / language / region / keyboard / timezone / tuning
winpodx setup-host # Host prep wizard (kvm group, /etc/subuid, kvm module) via one pkexec prompt — AppImage users
winpodx provision # Post-pod-running chain (wait-ready → apply-fixes → discovery → reverse-open) — the single source of truth used by install.sh, setup, migrate, and the GUI bring-up (0.6.0 item B)
winpodx provision --retries N # Override discovery retry count (default 2 — see 0.6.0 item M)
winpodx provision --require-agent # Hard-gate on the in-guest agent (used by fresh installs, #271)
winpodx migrate # Upgrade an existing guest in place (refresh agent.ps1 + scripts, re-apply fixes, re-discover, refresh reverse-open)
winpodx doctor # Read-only health diagnostic with per-check fix hints (deps / pod / RDP / agent / disk / config / install state)
winpodx doctor --json # Same checks, machine-readable JSON array of findings
winpodx doctor --quick # Skip slow probes (container-health, guest exec) — cheap local checks only (< 1 s)
winpodx doctor --fix # Idempotent auto-remediation for warn/fail findings that carry a fixer (dead agent, stale locks, missing desktop entries, OEM-version drift)
winpodx autostart on|off|status # Start the Windows pod on login (opt-in; off by default)
winpodx language # Show the current UI language
winpodx language ko # Set UI language: auto | en | ko | zh | ja | de | fr | it (auto = host locale)
# `winpodx info` and `winpodx check` are deprecated aliases of `winpodx doctor` (work through 0.6.x with a notice; removed in 0.7.0).
winpodx gui # Launch Qt6 main window (Dashboard / All apps / Devices / Settings / Tools / Terminal)
winpodx tray # Launch Qt system tray icon
winpodx config show # Show current config
winpodx config set rdp.scale 140 # Change a config value
winpodx config import # Import existing winapps.conf
GUI
Launch with winpodx gui. The Qt6 main window is a Start-menu-style shell (#460-#471): a left vertical navigation sidebar with one row per page, a hero search bar that doubles as a command bar, an in-house SVG icon set, and responsive layouts that reflow on narrow / fractionally-scaled windows and fit themselves to the screen. The pages:
| Page | What it does |
|---|---|
| Dashboard | Home screen — live Pod / RAM / CPU ring gauges + disk usage, an auto-recovery status card, pinned / recent workspace tiles, a "Running sessions" strip that lists live RDP app sessions with a per-session terminate button, and a reverse-open toggle |
| All apps | Grid / list view of installed app profiles (formerly "Apps"), search + category filter, per-app launch with 3 s cooldown, Add / Edit / Delete app profile dialogs |
| Devices | Two-column host ↔ guest mover for USB / PCI device passthrough (#286) — pick a host device on the left, attach it to the Windows guest on the right (USB hot-plugs live; PCI needs a guest restart with a safety confirmation) |
| Settings | RDP (user / IP / port / scale / DPI / password rotation / multi-monitor), Container (backend / CPU / RAM / idle timeout), and the reverse-open panel (enable toggle, allowlist + denylist, live daemon status, refresh / start / stop buttons) all in one screen |
| Tools | Suspend / Resume / Full Desktop buttons, Clean Locks / Sync Time / Debloat, Grow Disk / Sync Guest, and a one-click Windows Update enable / disable toggle |
| Terminal | Embedded shell limited to a command allowlist (podman, docker, winpodx, xfreerdp, systemctl, journalctl, ss, ip, ping, ...) with quick buttons (Status / Logs / Inspect / RDP Test / Clear) |
| Info | Live Health card (pod / RDP / agent / OEM / disk / password age / app count) + System / Display / Dependencies / Pod / Config snapshot |
The system tray (winpodx tray) is a lighter-weight alternative — pod controls, app launcher submenu (top 20 + Full Desktop), a USB device switcher (#300, attach / detach host USB devices to the guest), maintenance submenu (Clean Locks / Sync Time / Suspend), a running-sessions submenu that can terminate live RDP app sessions, and an optional idle-monitor thread.
Tray auto-spawn + UNRESPONSIVE recovery (v0.5.5)
Since v0.5.5 the tray spawns itself automatically from the GUI window and from every CLI subcommand that touches the pod (everything except setup / gui / tray), so a user who only ever runs winpodx app run still gets the system-tray indicator + the UNRESPONSIVE auto-recovery driver. A flock under $XDG_RUNTIME_DIR/winpodx/tray.lock prevents stacked instances when the user manually re-launches the tray.
The tray context menu now starts with Open Dashboard (one-click to the main GUI window). Quit confirms via a dialog and on confirmation runs stop_pod + pkill -f 'winpodx gui' + app.quit so a stray click can't cycle the pod's ~30 s restart.
To launch the tray at every login, open the GUI → Settings → tick "Launch WinPodX tray at login (system tray icon + idle-stall auto-recovery)". The toggle writes / removes ~/.config/autostart/winpodx-tray.desktop via the XDG autostart spec; portable across KDE / GNOME / XFCE / Cinnamon. The file is the source of truth — you can also drop it by hand to opt out without launching the GUI. Toggle applies immediately; no Save Settings click needed.
The tray watches the pod state every 30 s. On a RUNNING → UNRESPONSIVE transition (container alive long enough that an RDP-port miss can't be confused with a fresh boot) it fires a desktop notification and spawns a background worker that asks the agent to cycle Windows TermService. On recovery a "Pod recovered" notification fires; on failure a "needs manual restart" notification points at winpodx pod restart. While install.sh is running its [3/4] / [4/4] Sysprep + OEM-reboot phases, the marker file ~/.config/winpodx/.install_in_progress suppresses the recovery path so genuine install-time RDP gaps don't fire spurious notifications.
Host device passthrough
Pass a host USB or (non-GPU) PCI device through to the Windows guest (#286). Three surfaces drive the same backend:
- CLI —
winpodx device listshows each host device + its attach state;winpodx device attach <id>/winpodx device detach <id>move one in or out. - GUI Devices page — a two-column host ↔ guest mover (pick on the left, attach on the right).
- System tray — a USB switcher submenu (#300) for one-click attach / detach of host USB devices.
USB devices hot-plug live (cfg.pod.usb_live, default on) — no restart needed. A PCI device is boot-added and only becomes visible after a guest restart, so the attach is guarded by a safety confirmation; pass --force on the CLI (or confirm the dialog in the GUI) to proceed.
Bare-metal compatibility mode (hide the hypervisor)
Some software refuses to run under a detected hypervisor — most notably Nvidia's consumer GPU drivers (they fault with code 43 when they see KVM, the common GPU-passthrough blocker) and apps with launch-gate VM checks. cfg.pod.disguise_level (#246) hides the KVM/QEMU signature from the guest so it presents as a physical PC. It has three levels, default balanced:
| Level | What it does | Performance |
|---|---|---|
off |
No disguise — an honest VM. | Best (and most compatible) |
balanced (default) |
Clears the CPUID hypervisor bit + KVM signature, mirrors the host's SMBIOS/DMI, adds synthetic sensor descriptors, and advertises a bare-metal-looking disk size. | No measurable cost |
max |
Everything in balanced plus emulated virtual hardware — disk → SATA (AHCI), network → e1000 (MTU=1500), GPU → std VGA, no virtio-rng — and HV=N. This removes the virtio (VEN_1AF4) / QXL (VEN_1B36) PCI IDs and the vioscsi/viostor/netkvm drivers that give a KVM guest away. (MTU=1500 is required so dockur omits the host_mtu= flag that an e1000 NIC rejects.) Requires a wipe + reinstall (changing the boot-disk controller makes the existing install unbootable), so switching into/out of max prompts a strong confirmation and reinstalls Windows from scratch. |
Significantly slower — emulated disk + NIC have much lower throughput than virtio, and Hyper-V enlightenments are off |
winpodx config set pod.disguise_level off # honest VM
winpodx config set pod.disguise_level balanced # default — free hiding, applied automatically
winpodx config set pod.disguise_level max # maximum hiding (emulated HW, slower)
# off <-> balanced apply automatically. Switching into/out of `max` changes the
# virtual hardware, so it needs a destructive reinstall — apply it with:
winpodx pod recreate --wipe-storage # WIPES Windows, reinstalls on the new hardware
You can also pick the level in the GUI: Settings → Bare-metal compatibility. Either way it takes effect after a winpodx pod recreate (it edits the QEMU -cpu line, the HV env, and the disk size; recreate keeps your Windows disk).
Advanced — patched-QEMU image (winpodx disguise build-image): a couple of VM markers live in QEMU's compiled-in strings (ACPI OEM BOCHS, disk model QEMU HARDDISK) that command-line args can't reach. Run winpodx disguise build-image — it builds a custom dockur image whose QEMU has those strings patched to your host's real vendor + disk model (read from /sys, no root, nothing committed; ~20–40 min compile, local image only), then sets cfg.pod.disguise_image so max uses it. winpodx ships only the patch recipe (packaging/qemu-disguise/), never a patched binary. PCI vendor IDs are deliberately left alone (spoofing them breaks dockur's virtio-serial). See that directory's README.
Not an anti-cheat bypass. This is signature-level VM hiding for casual detectors and VM-hostile apps (code 43, DRM/launch gates). It does not defeat kernel-mode anti-cheat (EAC / BattlEye / Vanguard) — those anchor on hardware attestation (TPM + Secure Boot) and VM-exit timing the guest can't spoof — and bypassing online-game anti-cheat violates the game's ToS.
The disk bump is gated: the dockur disk is sparse, so a larger advertised size costs ~0 host space up front, but winpodx only raises it when the host has enough free space (keeping a 10 GiB / 10 % reserve). On a small host it leaves the disk as-is and logs a warning. The pre-0.6.x disguise_hypervisor = false key still works — it maps to off.
This is not an anti-cheat bypass. It is signature-level only and does not defeat kernel-mode anti-cheat (EAC / BattlEye / Vanguard). Bypassing anti-cheat in online games violates their terms of service and risks a ban — winpodx does not support that use.
Multi-monitor
Multi-monitor RAIL is on by default (cfg.rdp.multimon, default "span"): a remote-app window keeps working input when you drag it onto a second monitor. Values:
cfg.rdp.multimon |
Effect |
|---|---|
span (default) |
Span the RDP session across all monitors so a remote-app window stays interactive on any of them |
multimon |
Use FreeRDP's discrete /multimon mode (per-monitor geometry) |
off |
Single-monitor only |
Change it with winpodx config set rdp.multimon off or via the GUI Settings page.
Health checks
winpodx doctor runs every probe used by the GUI Health card and prints a one-line verdict for each:
=== WinPodX doctor ===
[OK ] pod_running running (ip=127.0.0.1) (58ms)
[OK ] rdp_port 127.0.0.1:3390 reachable (0ms)
[OK ] agent_health version=0.2.2-rev4 (63ms)
[OK ] agent_auth_ready bearer token available (1ms)
[OK ] oem_version bundle=24 (3ms)
[OK ] password_age 7d remaining (max_age=7d) (0ms)
[OK ] apps_discovered 41 app(s) in /home/.../discovered (3ms)
[OK ] disk_free 401.0/3725 GiB free (0ms)
Overall: OK
Status legend: OK (green) / WARN (yellow — informational, exit 0) / FAIL (red — exit 1) / SKIP (grey — disabled by config). Use --json for machine-readable output.
Changing the Windows password
Use winpodx rotate-password — never reuse winpodx setup for this. The two have very different effects on an already-running install:
| Command | Host config (winpodx.toml) |
Windows guest account |
|---|---|---|
winpodx rotate-password |
Updated atomically (with rollback on failure) | Updated via Windows-side change mechanism |
winpodx setup (rerun) |
Preserved as-is (since v0.5.5) | Not touched |
winpodx setup (fresh install, no prior config) |
Generated / prompted | Applied on first boot via dockur USERNAME/PASSWORD env vars |
Re-running winpodx setup to bump cores / RAM / win_version is safe and will not touch your credentials. On pre-v0.5.5 releases the wizard reprompted for the password every run and silently overwrote winpodx.toml — but dockur honors the password env var only on first boot, so the host config desynced from the Windows guest account and the next RDP launch failed with LOGON_FAILED_BAD_PASSWORD.
Recovering from a desynced password (pre-v0.5.5 lockout)
If you ran winpodx setup on an older release and can no longer log in:
- Restore the old password if you still have it (in a
winpodx.tomlbackup, your password manager, or your shell history):winpodx config set rdp.password '<old-password>' winpodx pod start winpodx rotate-password - Otherwise, the only path is
winpodx uninstall --purge+ reinstall, which loses any in-Windows state (installed apps, documents, settings). Make a freshwinpodx setupyour first step after reinstall, then never touch the password throughsetupagain — userotate-password.
Performance tuning profile
cfg.pod.tuning_profile controls how aggressively WinPodX tunes the dockur compose for the underlying host. It defaults to "auto" — WinPodX probes the host once at compose time and turns on the matching subset of safe Windows-on-KVM tweaks. Look at the [Tuning] block in winpodx doctor to see what was detected and applied:
[Tuning]
invtsc: yes (intel)
io_uring: yes (kernel 6.18, need >= 5.6)
hugepages: no (sysctl vm.nr_hugepages)
dedicated: yes
nested_kvm: yes (/sys/module/kvm_*/parameters/nested)
Profile: auto
+invtsc: yes
io_uring aio: yes
hugepages: no
CPU pinning: yes
platform_tick: yes
no balloon: yes
hv-* + no-hpet: yes
virtio-rng: yes
nested virt: yes
hv-evmcs: yes
Profiles:
tuning_profile |
What it does |
|---|---|
auto (default) |
Detect host capability + apply every safe tuning the host can support, including the Hyper-V enlightenments, virtio-rng, and nested-virt pass-through when /sys/module/kvm_*/parameters/nested is set. CPU pinning + no-balloon gated on dedicated_host (idle CPU + free RAM ≥ 2× VM allocation) so we don't starve other host workloads. Recommended for most users. |
performance |
Same as auto but bypasses the dedicated_host gate: CPU pinning + no-balloon flip on regardless of current host load. Use when the box is mostly dedicated to WinPodX and you want minimum guest latency at the cost of other host workloads. Hard-gated knobs (+invtsc, io_uring) still respect capability detection -- performance can't force a CPU flag QEMU would reject or a kernel feature that crashes. |
safe |
Apply the Windows-guest-only subset that requires no host configuration: +invtsc (when supported), platform_tick BCD tweak, Hyper-V enlightenments (hv-relaxed, hv-vapic, hv-vpindex, hv-runtime, hv-synic, hv-reset, hv-frequencies, hv-reenlightenment, hv-tlbflush, hv-ipi, hv-spinlocks=0x1fff, hv-stimer, hv-stimer-direct, -no-hpet), and virtio-rng. Excludes nested-virt + hv-evmcs which need explicit host-side opt-in. |
off |
Apply nothing; the dockur defaults stand. Use when troubleshooting suspected tuning interaction. |
manual |
Same shape as safe; reserved for future per-knob overrides. |
What each tuning does
+invtsc— exposes invariant TSC so Windows uses TSC as the clock source instead of HPET (lower IRQ overhead).hv-*enlightenments +-no-hpet(#245) — tells Windows it's running under a paravirtualised hypervisor. Cuts spinlock / VM-exit overhead on every workload; doubly noticeable on multi-vCPU guests.hv-spinlocks=0x1fffis the upstream-recommended retry budget.virtio-rng-pcibacked by/dev/urandom(#245) — fills the Windows entropy pool quickly on first boot so CryptoAPI / TLS handshakes don't stall waiting for kernel randomness.+vmx/+svmnested virt (#245) — auto-enabled when/sys/module/kvm_intel/parameters/nestedorkvm_amdreadsY. Required for Hyper-V / WSL2 / Docker Desktop inside the Windows guest. No effect when the host kernel hasn't opted in.hv-evmcs(#245) — Intel-only nested-VMCS optimisation, paired with+vmx. Zero overhead when the guest doesn't run nested VMs.io_uringAIO — kernel ≥ 5.6 disk I/O backend; lower latency than legacy threads.- Hugepages — backs the QEMU memory with 2 MB pages. Requires
vm.nr_hugepagesreserved on the host (WinPodX does not auto-reserve). - CPU pinning — WinPodX flags the host as
dedicatedand applies QEMU vCPU pinning when host idle CPU + RAM ≥ 2× VM allocation.
One-shot override
winpodx pod start --tuning {auto,safe,off,manual} overrides cfg.pod.tuning_profile for the lifetime of that container run only. The user's persisted preference in winpodx.toml is left untouched. Useful for A/B testing — flip back and forth without winpodx config set round-trips.
Items that require host-side setup (not auto-applied)
These are standard Windows-on-KVM tweaks that need operator action on the Linux host before WinPodX can take advantage of them. The [Tuning] block in winpodx doctor will show them as no until the host is set up; flipping to yes happens automatically the next time cfg.pod.tuning_profile = auto runs.
- Transparent hugepages / explicit hugepages. Set
vm.nr_hugepagesviasysctl(or usemadviseTHP) so the QEMU process can back its memory with hugepages. WinPodX detectsHugePages_Total > 0in/proc/meminfoand skips the auto-apply if hugepages aren't reserved. - CPU pinning. WinPodX flags the host as
dedicatedwhen the current idle CPU + RAM is at least twice the VM's allocation. Pinning the QEMU thread to specific cores viataskset(or systemdCPUAffinity=) is then up to the operator; WinPodX will not modify host scheduling. - VFIO GPU passthrough. Out of scope for the RDP-based WinPodX architecture. (Non-GPU USB / PCI device passthrough is supported — see "Host device passthrough" below.) If you need bare-metal GPU performance, run your own GPU-passthrough Windows VM (for example with libvirt / virt-manager) and point WinPodX at its RDP endpoint using the
manualbackend.
Configuration
Config file: ~/.config/winpodx/winpodx.toml (auto-created, 0600 permissions)
[rdp]
user = "User"
password = "" # Auto-generated random password
password_updated = "" # ISO 8601 timestamp
password_max_age = 7 # Days before auto-rotation (0 = disable)
ip = "127.0.0.1"
port = 3390
scale = 100 # Auto-detected from your DE
dpi = 0 # Windows DPI % (0 = auto)
multimon = "span" # Multi-monitor RAIL: span | multimon | off
extra_flags = "" # Additional FreeRDP flags (allowlisted); e.g.
# "+multitouch" — touchscreen / stylus / pen
# passthrough into Windows apps (#623)
# "-gfx" — legacy GDI path (RAIL render workaround)
[pod]
backend = "podman"
win_version = "11" # 11 | 10 | ltsc11 | ltsc10 | iot11 | tiny11 | tiny10 | 2025 | 2022 | 2019 | 2016 — see ARCHITECTURE.md for custom ISOs
keyboard = "en-US" # Windows install locale; also mapped to the FreeRDP session layout (/kbd:layout) so non-US keyboards work in RemoteApp windows (#660)
cpu_cores = 4
ram_gb = 4
vnc_port = 8007
auto_start = false # Opt-in login auto-start: tray starts the pod on login (toggle via `winpodx autostart on|off|status`)
idle_timeout = 0 # Seconds before auto-suspend (0 = disabled)
boot_timeout = 300 # Seconds to wait for first-boot unattended install
image = "docker.io/dockurr/windows:latest" # Container image (override for air-gapped mirror)
usb_live = true # Hot-plug attached USB devices into the running guest (no restart) — see `winpodx device`
# disguise_level = "balanced" # Bare-metal mode: off | balanced (default, free hiding) | max (Hyper-V off, slower) — Nvidia code-43 / VM-hostile apps; not an anti-cheat bypass (#246)
disk_size = "64G" # Virtual disk size passed to dockur (grows via `install grow-disk`)
disk_autogrow = true # Auto-grow C: when it fills past the threshold (idle only)
disk_autogrow_threshold_pct = 80 # Used-% that triggers an auto-grow (50-99)
disk_autogrow_target_free_pct = 30 # Grow is sized to restore this much free (not a flat step)
disk_autogrow_increment = "32G" # Grow granularity / minimum step
disk_max_size = "" # Optional hard ceiling; empty = bounded only by host free space
guest_autosync = true # After a host upgrade, push updated guest artifacts in (no reinstall)
[ui]
language = "auto" # UI language: auto | en | ko | zh | ja | de | fr | it (auto = host locale, falls back to English; change via `winpodx language` or GUI Settings)
[desktop]
mime_associations = true # Discovered apps offer their real file types in the file manager's "Open with" (#545); never set as the default handler
full_app_scan = false # false = Start-Menu-only discovery (clean menu, folder-grouped); true = also scan registry App Paths / Chocolatey / Scoop / all UWP (#581) — for portable apps with no Start Menu entry
[reverse_open]
enabled = true # Default since v0.5.0
allow = [] # Empty = all discovered apps
deny = [] # Apps to exclude from the manifest
[logging]
level = "INFO" # DEBUG | INFO | WARNING | ERROR | CRITICAL | RAW — RAW = DEBUG + pod logs (podman logs -f) interleaved in GUI Terminal
Edit via winpodx config set <key> <value> or directly with your editor — TOML is parsed via the stdlib on Python 3.11+ (tomli on 3.9/3.10).