| name | pvetui-cli |
| description | Use when querying or managing a Proxmox VE cluster via the pvetui CLI — listing nodes, guests, and tasks; creating and migrating VMs and LXC containers; managing storage content, downloading templates and OCI images, and restoring backups. Requires pvetui to be installed and configured. |
| license | MIT |
| metadata | {"author":"github.com/devnullvoid/pvetui","version":"1.1"} |
pvetui CLI
pvetui is a terminal UI and CLI for Proxmox VE. When invoked with a subcommand it runs non-interactively, making it suitable for scripts and AI agent workflows.
Installation
go install github.com/devnullvoid/pvetui/cmd/pvetui@latest
npx skills add devnullvoid/pvetui
When to Use
- Querying node status, resource usage, or uptime
- Listing, filtering, or inspecting VMs and LXC containers
- Starting, stopping, shutting down, or restarting guests
- Creating VMs and LXC containers
- Migrating guests between nodes
- Executing commands inside a running guest without needing SSH to it
- Opening interactive shells on nodes or inside guests
- Listing and managing storage content (ISOs, templates, backups, disk images)
- Downloading ISOs, appliance templates, or OCI images into storage
- Restoring guests from vzdump backups
- Listing recent cluster task history
- Scripting or automating Proxmox operations without root access to a node
Prerequisites
pvetui installed and on $PATH
- Config at
~/.config/pvetui/config.yml with at least one profile
- API token or password auth configured in the profile
- For
guests exec / guests shell on LXC containers: ssh_user configured in the profile
- For
guests shell on QEMU VMs: ssh_user (and optionally vm_ssh_user) configured
Quick Reference
| Command | Purpose |
|---|
pvetui nodes list | List all cluster nodes |
pvetui nodes show <node> | Show details for one node |
pvetui nodes shell <node> | Open an interactive SSH shell on a node |
pvetui guests list | List all VMs and containers |
pvetui guests show <vmid> | Show details for one guest |
pvetui guests start <vmid> | Start a guest |
pvetui guests stop <vmid> | Force stop a guest (power off) |
pvetui guests shutdown <vmid> | Graceful ACPI shutdown |
pvetui guests restart <vmid> | Graceful restart |
pvetui guests delete <vmid> | Permanently delete a guest and its disks |
pvetui guests exec <vmid> <cmd> | Run a command inside a guest |
pvetui guests shell <vmid> | Open an interactive shell inside a guest |
pvetui guests create vm | Create a QEMU VM |
pvetui guests create lxc | Create an LXC container |
pvetui guests migrate <vmid> <node> | Migrate a guest to another node |
pvetui tasks list | List recent cluster tasks |
pvetui storage list | List storages across the cluster |
pvetui storage show <node> <storage> | Show details for a storage |
pvetui storage content list <node> <storage> | List content in a storage |
pvetui storage content delete <node> <storage> <volid> | Delete a content item |
pvetui storage download url <node> <storage> <url> | Download from a URL |
pvetui storage download template <node> <storage> <template> | Download an appliance template |
pvetui storage download oci <node> <storage> <reference> | Pull an OCI image |
pvetui storage restore <node> <storage> <volid> <vmid> | Restore a guest from backup |
Global Flags
These flags work with every subcommand:
| Flag | Short | Description |
|---|
--profile <name> | -p | Use a specific connection profile or aggregate group |
--output <format> | -o | Output format: json (default) or table |
--config <path> | -c | Path to config file (default: ~/.config/pvetui/config.yml) |
--no-cache | -n | Disable caching |
Output Format
Default (JSON): structured output to stdout; errors as JSON to stderr; non-zero exit on failure.
Table (--output table): aligned human-readable output to stdout.
All commands default to JSON — prefer JSON when parsing output in scripts or agents.
Task-Producing Commands
Commands that trigger a Proxmox task (guests create, guests migrate, storage content delete, storage download *, storage restore) block until the task completes by default, then include status and exit_status in the output. Pass --no-wait to return the task UPID immediately without waiting.
{
"vmid": 105,
"node": "pve01",
"upid": "UPID:pve01:...",
"status": "complete",
"exit_status": "OK"
}
A non-"OK" exit_status causes a non-zero process exit.
Nodes
pvetui nodes list
pvetui nodes list --output table
pvetui nodes show pve01
pvetui nodes show pve01 --output table
pvetui nodes shell pve01
JSON shape — nodes list:
[
{
"name": "pve01",
"ip": "10.0.0.10",
"online": true,
"cpu_usage": 0.12,
"memory_used": 7.238216400146484,
"memory_total": 31.174354553222656,
"uptime": 864000,
"version": "8.2.2",
"kernel_version": "6.8.4-2-pve",
"source_profile": "prod"
}
]
cpu_usage is a fraction (0.0–1.0). Memory values are in GiB. uptime is seconds. source_profile is populated in aggregate group mode.
Guests (VMs and Containers)
pvetui guests list
pvetui guests list --node pve01
pvetui guests list --status running
pvetui guests list --type qemu
pvetui guests list --node pve01 --status running --type lxc
pvetui guests show 100
JSON shape — guests list:
[
{
"id": 100,
"name": "web-server",
"node": "pve01",
"type": "qemu",
"status": "running",
"ip": "10.0.0.100",
"template": false,
"tags": "prod;web",
"source_profile": "prod"
}
]
type is "qemu" or "lxc". status is "running", "stopped", or "paused". ip may be empty if the guest agent is not running. template: true guests cannot be started/stopped.
Lifecycle Operations
pvetui guests start 100
pvetui guests shutdown 100
pvetui guests stop 100
pvetui guests restart 100
JSON shape — lifecycle:
{
"vmid": 100,
"operation": "shutdown",
"upid": "UPID:pve01:00001234:...",
"node": "pve01"
}
The upid is a Proxmox task ID. Use pvetui tasks list to monitor task completion.
Guest Delete
Permanently deletes a guest and all its associated disks. The guest must be stopped first unless --force is passed.
pvetui guests delete 108
pvetui guests delete 108 --purge
pvetui guests delete 108 --force
pvetui guests delete 108 --no-wait
JSON shape — delete:
{
"vmid": 108,
"node": "pve01",
"upid": "UPID:pve01:...",
"status": "complete",
"exit_status": "OK"
}
Guest Create
pvetui guests create vm \
--node pve01 \
--name myvm \
--disk-storage local-zfs \
--disk-size 32
pvetui guests create vm \
--node pve01 \
--name myvm \
--vmid 105 \
--memory 4096 \
--cores 4 \
--disk-storage local-zfs \
--disk-size 32 \
--iso local:iso/debian-12.iso \
--bridge vmbr0 \
--start
pvetui guests create lxc \
--node pve01 \
--hostname myct \
--rootfs-storage local-zfs \
--template debian-12-standard
pvetui guests create lxc \
--node pve01 \
--hostname myct \
--rootfs-storage local-zfs \
--template debian-12-standard \
--memory 1024 \
--swap 512 \
--cores 2 \
--rootfs-size 16 \
--bridge vmbr0 \
--start
pvetui guests create vm --node pve01 --name myvm --disk-storage local-zfs --disk-size 32 --no-wait
Key flags — guests create vm:
| Flag | Required | Default | Notes |
|---|
--node | yes | — | Target node |
--name | yes | — | VM name |
--disk-storage | yes | — | Storage for the boot disk |
--disk-size | yes* | — | Disk size in GB; required unless --import-from |
--vmid | no | auto | Auto-assigned via GetNextID if omitted |
--memory | no | 2048 | MB |
--cores | no | 2 | vCPU cores |
--iso | no | — | ISO volid for CD-ROM |
--bridge | no | vmbr0 | Network bridge |
--start | no | false | Start after create |
--import-from | no | — | Import disk from volid instead of creating |
--no-wait | no | false | Return UPID immediately |
Key flags — guests create lxc:
| Flag | Required | Default | Notes |
|---|
--node | yes | — | Target node |
--hostname | yes | — | Container hostname |
--rootfs-storage | yes | — | Storage for root filesystem |
--template | yes | — | Full filename or package name (e.g. debian-12-standard) |
--vmid | no | auto | |
--memory | no | 512 | MB |
--swap | no | 512 | MB (0 = no swap) |
--cores | no | 1 | |
--rootfs-size | no | 8 | GB |
--bridge | no | vmbr0 | |
--unprivileged | no | true | |
--nesting | no | true | Enable Docker/nested containers |
--start | no | false | Start after create |
--no-wait | no | false | Return UPID immediately |
JSON shape — guests create:
{
"vmid": 105,
"name": "myvm",
"node": "pve01",
"type": "qemu",
"upid": "UPID:pve01:...",
"status": "complete",
"exit_status": "OK"
}
Guest Migrate
pvetui guests migrate 100 pve02
pvetui guests migrate 100 pve02 --online
pvetui guests migrate 100 pve02 --offline
pvetui guests migrate 100 pve02 --no-wait
Migration mode is selected automatically:
- QEMU running → online migration
- QEMU stopped → offline migration
- LXC (any state) → restart migration
JSON shape — guests migrate:
{
"vmid": 100,
"name": "web-server",
"source_node": "pve01",
"target_node": "pve02",
"mode": "online",
"upid": "UPID:pve01:...",
"status": "complete",
"exit_status": "OK"
}
Guest Exec
Execute a command inside a running guest without SSH access to the guest itself.
pvetui guests exec 100 "uptime"
pvetui guests exec 100 "df -h"
pvetui guests exec 100 "systemctl status nginx"
pvetui guests exec 200 "uptime"
pvetui guests exec 200 "cat /etc/os-release"
pvetui guests exec 100 "apt-get update" --timeout 120s
pvetui guests exec 100 "df -h" --output table
Requirements:
- QEMU: guest must be running with the QEMU guest agent enabled and responding.
- LXC: guest must be running;
ssh_user must be configured in the profile; the agent user needs permission to run pct exec (or be root).
OS detection (QEMU only):
- Windows guests (
ostype starting with win): command is wrapped in powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command <cmd>
- All other guests: command is wrapped in
/bin/sh -c <cmd>
- LXC always uses
/bin/sh -c <cmd>
JSON shape — exec:
{
"vmid": 100,
"command": "uptime",
"stdout": " 10:23:01 up 10 days, 2:34, 0 users, load average: 0.10, 0.08, 0.05\n",
"stderr": "",
"exit_code": 0,
"duration_ms": 412
}
A non-zero exit_code means the command ran but failed. A transport/SSH error causes a non-zero process exit with a JSON error on stderr instead.
Guest and Node Shell
Opens an interactive terminal session. These commands take over stdin/stdout and are not suitable for scripting — use exec for non-interactive commands in agents.
pvetui nodes shell pve01
pvetui guests shell 100
Tasks
pvetui tasks list
pvetui tasks list --recent 50
pvetui tasks list --output table
JSON shape — tasks list:
[
{
"upid": "UPID:pve01:00001234:...",
"node": "pve01",
"type": "qmstart",
"status": "OK",
"user": "root@pam",
"starttime": 1710000000,
"endtime": 1710000005,
"source_profile": "prod"
}
]
starttime and endtime are Unix timestamps. status is "OK" on success or an error string on failure. A task with no endtime is still running.
Storage
pvetui storage list
pvetui storage list --node pve01
pvetui storage list --output table
pvetui storage show pve01 local-zfs
JSON shape — storage list:
[
{
"name": "local-zfs",
"node": "pve01",
"type": "zfspool",
"content": "images,rootdir",
"used": 53687091200,
"total": 214748364800,
"active": true
}
]
Storage Content
pvetui storage content list pve01 local
pvetui storage content list pve01 local --type iso
pvetui storage content list pve01 local --type backup
pvetui storage content delete pve01 local local:iso/old-debian.iso
pvetui storage content delete pve01 local local:iso/old-debian.iso --no-wait
JSON shape — storage content list:
[
{
"volid": "local:iso/debian-12.iso",
"name": "debian-12.iso",
"type": "iso",
"size": 658505728,
"ctime": 1700000000,
"vmid": 0
}
]
Storage Download
pvetui storage download url pve01 local https://example.com/debian-12.iso
pvetui storage download url pve01 local https://example.com/image.bin \
--filename my-image.iso \
--content-type iso
pvetui storage download template pve01 local debian-12-standard
pvetui storage download template pve01 local debian-12-standard_12.7-1_amd64.tar.zst
pvetui storage download template pve01 local myapp --section turnkeylinux
pvetui storage download oci pve01 local registry.example.com/myimage:latest
pvetui storage download url pve01 local https://example.com/debian-12.iso --no-wait
Content type inference from URL extension:
| Extension | Inferred type |
|---|
.iso | iso |
.tar.* (.tar.zst, .tar.gz, etc.) | vztmpl |
.img | import |
| other | must supply --content-type |
JSON shape — storage download:
{
"node": "pve01",
"storage": "local",
"url": "https://example.com/debian-12.iso",
"filename": "debian-12.iso",
"upid": "UPID:pve01:...",
"status": "complete",
"exit_status": "OK"
}
Storage Restore
Restore a guest from a vzdump backup. Destructive — overwrites the target VMID's config and disks.
pvetui storage restore pve01 local local:backup/vzdump-qemu-100-2024.tar.zst 100
pvetui storage restore pve01 local local:backup/vzdump-qemu-100-2024.tar.zst 100 --confirm
pvetui storage restore pve01 local local:backup/unknown.tar.zst 101 --confirm --type lxc
pvetui storage restore pve01 local local:backup/vzdump-qemu-100.tar.zst 100 --confirm --no-wait
Guest type is inferred from the volid prefix: vzdump-qemu-* → qemu, vzdump-lxc-* → lxc. Use --type to override when inference fails.
JSON shape — storage restore:
{
"node": "pve01",
"storage": "local",
"volid": "local:backup/vzdump-qemu-100-2024.tar.zst",
"vmid": 100,
"type": "qemu",
"upid": "UPID:pve01:...",
"status": "complete",
"exit_status": "OK"
}
Profiles and Multi-Cluster
All subcommands respect --profile. The profile can be a single connection profile or an aggregate group name.
pvetui --profile prod guests list
pvetui --profile all-clusters guests list --status running
pvetui --list-profiles
In aggregate group mode, source_profile in JSON output identifies which cluster each resource belongs to. All reads fan out concurrently; write operations (lifecycle, exec, create, migrate) are routed to the correct cluster automatically.
Error Handling
Errors are written as JSON to stderr and the process exits non-zero:
{"error": "guest 999 not found"}
Check exit code to detect failure; parse stderr JSON for the message. Stdout is always valid JSON (or empty) on success.
if ! pvetui guests show 100 > /dev/null 2>&1; then
echo "Guest not found"
fi
err=$(pvetui guests show 999 2>&1 >/dev/null)
Common Agent Patterns
pvetui guests list --node pve01 --status running --type qemu
pvetui guests list --status running | jq '.[].ip'
pvetui guests show 100 | jq -r '.status'
result=$(pvetui guests create lxc --node pve01 --hostname myct --rootfs-storage local-zfs --template debian-12-standard)
vmid=$(echo "$result" | jq -r '.vmid')
pvetui guests migrate 100 pve02
pvetui guests show 100 | jq -r '.node'
pvetui storage download template pve01 local debian-12-standard
pvetui guests create lxc --node pve01 --hostname newct --rootfs-storage local-zfs --template debian-12-standard --start
pvetui storage content list pve01 local --type iso | jq '.[].volid'
pvetui storage content list pve01 local --type backup | jq '[.[] | select(.volid | contains("vzdump-qemu-100-"))]'
for vmid in 100 101 102; do
echo "=== $vmid ==="
pvetui guests exec $vmid "systemctl is-active nginx"
done
pvetui guests list | jq '[.[] | select(.tags | contains("prod"))]'
pvetui nodes list | jq '[.[].memory_total] | add'
pvetui storage list | jq '[.[] | {name, node, used_pct: (.used / .total * 100 | round)}]'
Troubleshooting
| Problem | Likely Cause | Fix |
|---|
{"error": "bootstrap failed: ..."} | Bad config or credentials | Check ~/.config/pvetui/config.yml; verify API token |
{"error": "guest agent is not available"} | Agent not running in VM | Install/start qemu-guest-agent inside the VM |
{"error": "exec failed on LXC ..."} | SSH to node failed | Verify ssh_user is set and SSH key auth works to the node |
{"error": "multiple profiles configured; use --profile"} | No default profile set | Pass --profile <name> or set default_profile in config |
{"error": "failed to delete guest ... locked"} | Guest is running or locked | Stop the guest first, or pass --force |
{"error": "cannot infer guest type from volid ..."} | Backup filename not standard | Pass --type qemu or --type lxc explicitly |
{"error": "cannot infer content type from URL ..."} | URL extension not recognised | Pass --content-type iso (or vztmpl/import) |
ip field empty in guest list | Agent not running or no IP yet | Check guest agent; ip populates only for running QEMU VMs with agent |
| LXC exec fails with permission denied | Non-root user needs sudo | Add NOPASSWD: /usr/sbin/pct exec * to sudoers on node |
| Template name not resolved | Package not in aplinfo catalog | Use the full filename from pvetui storage content list |