This guide explains how to work with the pvetui plugin system, including enabling existing extensions and authoring new ones.
- Plugins are discovered through static registration in
internal/ui/plugins/loader.go. - At startup pvetui loads the plugin identifiers listed under
plugins.enabledin your configuration file. - When
plugins.enabledis omitted or empty, no optional functionality is activated.
The repository currently ships with the following built-in plugins:
community-scripts: exposes the community script installer from the node context menuguest-insights(legacy alias:demo-guest-list): adds Guest Insights actions for the selected nodecommand-runner: execute whitelisted commands on Proxmox hosts via SSHansible: generate inventory from current nodes/guests and run Ansible workflows
plugins:
enabled:
- "ansible"
- "community-scripts"
- "guest-insights" # Legacy alias: demo-guest-list
- "command-runner"Restart pvetui after editing the configuration to apply the change. If an unknown plugin ID is listed, the application prints a warning similar to ⚠️ Unknown plugins requested: my-plugin during startup.
The ansible plugin adds an Ansible Toolkit entry to the global actions menu when enabled.
- Inventory generation: Builds inventory from currently loaded Proxmox nodes and guests in YAML (default) or INI format.
- Inventory style modes:
compact: shared ansible vars are lifted toall:vars/all.vars.expanded: host-level vars are kept per-host.
- Inventory export: Preview and save generated inventory to a user-selected path.
- Ad-hoc connectivity tests: Run
ansible -m pingwith configurable scope, limit, target picker, extra args, and timeout. - Playbook execution: Run
ansible-playbookwith configurable scope, limit, target picker,--check, extra args, and timeout. - Limit UX: Ping/Playbook/Bootstrap forms include:
Scope(all,nodes,guests)Limit(manual/custom)Targetpicker (inventory groups and host aliases) that fillsLimit.
- Bootstrap Access workflow:
- Direct mode: bootstraps via SSH /
pct exec/ QEMU guest agent (transport chosen by host type). - Ansible mode: runs a generated bootstrap playbook.
- Supports dry-run and streamed output.
- Direct mode: bootstraps via SSH /
- Bootstrap diagnostics:
- dry-run plan markers (
would_*,plan_*) - apply markers (
applied_*) - pre/post SSH reachability hints in report (
before/afteron port 22 for IP targets).
- dry-run plan markers (
- SSH Setup Guide: Shows practical key-based setup examples.
- Settings UI: General settings and bootstrap-specific settings are editable from the toolkit.
- Safe defaults: Commands run without shell interpolation; temporary files are created with
0600permissions.
ansibleandansible-playbookmust be available in yourPATH.- SSH access must be configured for targets for Ping/Playbook and for direct bootstrap node access.
- Direct bootstrap uses pvetui SSH users (
ssh_user/vm_ssh_user) and system SSH defaults.
The plugin reads optional settings from plugins.ansible:
plugins:
enabled:
- "ansible"
ansible:
inventory_format: "yaml" # yaml|ini
inventory_style: "compact" # compact|expanded
inventory_vars: # optional vars merged into each host/all vars
ansible_python_interpreter: /usr/bin/python3
default_user: "ubuntu" # optional ansible_user override
# default_password: "secret" # optional sensitive field
ssh_private_key_file: "~/.ssh/id_ed25519"
default_limit_mode: "selection" # selection|all|none
ask_pass: false
ask_become_pass: false
extra_args: [] # appended to ansible and ansible-playbook
bootstrap:
enabled: true
username: "ansible"
shell: "/bin/bash"
create_home: true
exclude_windows_guests: true # skip Windows guests in direct mode
ssh_public_key_file: "~/.ssh/id_ed25519.pub"
install_authorized_key: true
set_password: false # if true, password below is required
# password: "secret" # optional sensitive field
grant_sudo_nopasswd: true
sudoers_file_mode: "0440"
dry_run_default: true
parallelism: 10
timeout: "2m"
fail_fast: falseNotes:
default_passwordandbootstrap.passwordare treated as sensitive fields and follow the same encryption/decryption handling as other secrets.default_limit_mode: selectionkeeps node/guest selection behavior for prefilled form limits.- Bootstrap settings are edited in Bootstrap Settings from the toolkit.
- The plugin uses nodes/guests currently loaded in the UI to build inventory.
- Cancelling a running command from the plugin cancels the underlying process context.
- Direct bootstrap prepares user/key/sudo access; it does not guarantee SSH daemon/network reachability on guest targets.
The command-runner plugin enables secure execution of whitelisted commands on Proxmox hosts via SSH. When enabled, it adds a Run Command (SSH) action (shortcut: c) to the node context menu that appears when a node is online.
- Whitelisted commands: Only pre-approved commands can be executed for security
- Template support: Commands can include parameters (e.g.,
systemctl status {service}) - Input validation: Parameters are sanitized to prevent shell injection
- Output display: Command results shown in scrollable modal with timing info
- Timeout protection: Commands respect configurable timeout (default: 30s)
- OS-aware guest commands: The VM menu automatically switches between Linux shell and Windows PowerShell snippets based on the guest OS reported by Proxmox.
- Size limits: Output truncated if exceeds max size (default: 1MB)
The plugin uses SSH key-based authentication by default. Ensure SSH keys are configured in ~/.ssh/ for passwordless authentication to your Proxmox hosts.
SSH username is taken from the ssh_user field in your pvetui config, falling back to the Proxmox API username if not specified:
ssh_user: root # SSH username for command executionNote: Stock Proxmox VE installs do not include
sudo. If you configuressh_userto a non-root account, installsudoon each host and grant that account permission to runpct exec/pct enter. When connecting asroot, the plugin skipssudoentirely. If your VM logins differ from the host user, setvm_ssh_userin your config to point VM shells at the right account.
For Proxmox hosts, containers, and Linux VMs:
uptime/df -Th/lsblk/free -h- System, disk, and memory snapshotsps aux,top -bn1 | head -20,ps -eo pid,ppid,cmd,%cpu,%mem --sort=-%cpu | head -20,ps -eo pid,ppid,cmd,%cpu,%mem --sort=-%mem | head -20- Process and resource hotspotssystemctl list-units --type=service --state=running,systemctl list-unit-files --state=enabled,systemctl status {service}- Service visibility (parameterized)journalctl -u {service} -n 50,journalctl -n 100- Targeted vs general logsdpkg -l | grep {package}- Quick package presence check (parameterized)ip addr show,ip route show,ip link show- Interface & routing statess -tulpn,ss -s,netstat -tulpn- Socket listeners and summariescat /etc/resolv.conf,resolvectl status 2>/dev/null || systemd-resolve --status 2>/dev/null- DNS configuration / systemd resolver statuswho,last -n 20- Active and historical sessions
Host-only extras:
pveversion -v- Proxmox build detailsiostat -x 1 5- Block device performance stats
For Windows guests:
Get-ComputerInfo,Get-Volume,Get-NetAdapter,Get-NetIPAddress,Get-NetIPConfiguration- System, disk, adapter, and address inventoryGet-Process | Sort-Object CPU/PM -Descending- CPU vs memory burnersGet-Service | Sort-Object Status, DisplayName- Service inventoryGet-EventLog -LogName System -Newest 50- Recent system log entriesGet-NetRoute- Routing table snapshotGet-DnsClientServerAddress,ipconfig /all- DNS servers and general interface infonetstat -ano | findstr LISTEN- Listening portsTest-NetConnection -ComputerName {hostname} -InformationLevel Detailed,Resolve-DnsName {hostname} -Type A- Connectivity & DNS resolution probes (parameterized)
- Commands are validated against a strict whitelist before execution
- Parameters cannot contain shell metacharacters (
;,|,$,`, etc.) - SSH uses
InsecureIgnoreHostKeyin the initial implementation (TODO: implement proper known_hosts verification) - All output is size-limited to prevent memory exhaustion
- Enable the plugin in your config (see above)
- Restart pvetui
- Navigate to a node in the Nodes view
- Press
c(or select from context menu) to run a command - Choose from the list of whitelisted commands
- If the command has parameters (e.g.,
{service}), fill in the form - View the output in the scrollable result modal; closing it drops you back into the command list so you can run another command immediately.
The guest-insights plugin (legacy alias: demo-guest-list) is the fully supported Guest Insights experience. When enabled it adds an I shortcut (and node context menu entry) to launch a modal that shows live metrics for every guest on the selected node. The table supports filtering (/), sorting (n/c/m/u/i), toggling stopped guests (a), and jump-to-guest navigation (enter/g). Refresh with r to pull fresh CPU/memory stats, and press enter or g on a row to close the modal, switch to the Guests page, and focus the highlighted VM.
- Implement the
components.Plugininterface (seeinternal/ui/components/plugins.go):ID() stringmust return a stable identifier used in configuration files.Name()andDescription()provide user-facing metadata.Initialize(ctx, app, registrar)is called once at startup. Register UI contributions (for example node actions) through the providedregistrar.Shutdown(ctx)should release resources acquired during initialization.
- Place the implementation in
internal/ui/plugins/<yourplugin>/and expose a constructor (for examplefunc New() components.Plugin). - Register the plugin in
internal/ui/plugins/loader.goby adding an entry to theregistrymap. - Add unit tests in
internal/ui/pluginsthat cover registration logic and any behaviour that can be exercised without the full TUI runtime.
Plugins may use the components.App helper methods passed to Initialize to access configuration, API clients, and UI primitives. Keep long-running work cancellable by respecting the provided context.Context.
Run go test ./internal/ui/plugins/... to execute plugin-level unit tests. For end-to-end validation launch pvetui with a configuration that enables your plugin and verify the contributed UI pieces (such as context menu entries) appear and behave as expected.