Install
$ agentstack add skill-kevwillow-proxmox-manager-agent-skill-proxmox-manager-agent-skill Open-source listing, not yet scanned by AgentStack. Follow the source repository for install instructions.
Security review
⚠ Flagged1 finding(s); flagged for manual review. · v0.1.0 How review works →
- • Prompt-injection patterns
- • Secret / credential exfiltration
- • Dangerous shell & filesystem operations
- • Untrusted network calls
- • Known-malicious package signatures
- high Destructive filesystem operation.
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Proxmox Manager Agent
Operational skill for managing a Proxmox VE host (single-node or small cluster) from any AI agent — Hermes, Claude Code, Codex, OpenCode, or any headless runner — via scoped SSH access. The security model (dedicated agent user, sudoers allowlist, key-only auth, IP allowlist, audit trail, one-command revoke) lives in the scoped-agent-ssh-access skill. This skill assumes that is already set up. This skill is the operational side: which commands to run, in what order, with what pitfall-avoidance.
When to Use
- User says "manage my Proxmox," "spin up a VM," "add an ISO," "backup the VMs,"
"create an LXC," "add storage," "snapshot before I upgrade," "what's running on my proxmox," or any equivalent.
- A task touches any of:
qm,pct,pvesh,pvesm,vzdump,pve-firewall,
ha-manager, pvecm, qemu-img, on a PVE 8.x or 9.x host.
Don't use for: generic Linux sysadmin (use scoped-agent-ssh-access directly), non-Proxmox virtualization (KVM/libvirt without PVE wrapper, Xen, ESXi), or anything where the user has not yet established scoped SSH access — that's a prerequisite, not a part of this skill.
Architecture
┌─────────────────────────────────────────────────────────────────┐
│ Agent host (where the AI runs) │
│ ~/.ssh/- (private key, 600 perms) │
│ HERMES_HOME=/home//.hermes │
│ skill: proxmox-manager-agent (this file) │
└────────────────┬────────────────────────────────────────────────┘
│ SSH (key-only, scoped user, IP-restricted)
▼
┌─────────────────────────────────────────────────────────────────┐
│ Proxmox VE host (PVE 8.x or 9.x on Debian 12/13) │
│ user: zen-agent (or claude-svc, codex-bot, etc.) │
│ sudoers: /etc/sudoers.d/ (NOPASSWD allowlist only) │
│ sshd: /etc/ssh/sshd_config.d/99-.conf (Match block) │
│ audit: /var/log/auth.log (every sudo invocation logged) │
└─────────────────────────────────────────────────────────────────┘
The agent never logs in as root. It never has a root password. Every action goes through the scoped user with a sudoers allowlist. A leaked key still requires the right source IP and the agent user still exists with the same blast radius.
The Command Surface
Binary locations (PVE 8/9)
| Binary | Path | Purpose | |---|---|---| | qm | /usr/sbin/qm | KVM/QEMU VM management | | pct | /usr/sbin/pct | LXC container management | | pvesh | /usr/bin/pvesh | Proxmox API CLI (preferred for scripted ops) | | pvesm | /usr/sbin/pvesm | Storage manager | | vzdump | /usr/sbin/vzdump | Backup | | qemu-img | /usr/sbin/qemu-img | Raw disk image operations | | pveum | /usr/sbin/pveum | User/permission manager | | pvecm | /usr/sbin/pvecm | Cluster manager | | ha-manager | /usr/sbin/ha-manager | HA (high availability) manager | | pve-firewall | /usr/sbin/pve-firewall | Firewall rules compiler | | pveam | /usr/bin/pveam | Appliance manager (templates, ISOs) | | qmrestore | /usr/sbin/qmrestore | Restore from vzdump backup |
The pvesh and pvesm paths are the gotcha. Most Proxmox docs and tutorials list them in /usr/sbin/, but on PVE 8/9 they live in /usr/bin/. A sudoers rule with the wrong path silently falls through to "ask for a password" — see scoped-agent-ssh-access for the diagnose-and-fix recipe.
Always verify on a fresh host before writing sudoers:
ssh zen-agent@ 'for b in qm pct pvesh pvesm vzdump pveam ha-manager pve-firewall qemu-img pveum pvecm; do echo -n "$b: "; command -v $b || echo MISSING; done'
Output formats
pvesh returns JSON for nested objects and a tabular format for lists. Both are stable across PVE 8/9.
sudo -n pvesh get /version
# {"release":"9.2","repoid":"b9984c6d90a4bd80","version":"9.2.2"}
sudo -n pvesh get /nodes
# ┌────────┬────────┬───────┬─...
# │ node │ status │ cpu │...
# ╞════════╪════════╪═══════╪═...
# │ apollo │ online │ 0.17% │
# └────────┴────────┴───────┴─...
qm list and pct list return empty when there are no VMs/containers. Empty output is not an error — verify with sudo -n -l to distinguish "command worked, no VMs yet" from "command was denied."
Whitelist & Blacklist Commands
This is the core of the safe-by-default design. The agent's blast radius is determined entirely by what's in its sudoers file. Every command below is either explicitly allowed (whitelist) or explicitly denied (blacklist, via NOT being in the allowlist).
Recommended sudoers allowlist (whitelist)
This template goes in /etc/sudoers.d/ on the Proxmox host. Adjust paths and command list to match the actual PVE install.
# /etc/sudoers.d/zen-agent
# Whitelist for an AI agent managing this Proxmox host.
# Each line is one allowed command pattern. Anything NOT in this list
# is denied by sudo at runtime, with an audit log entry.
# --- Proxmox management ---
zen-agent ALL=(ALL) NOPASSWD: /usr/sbin/qm *
zen-agent ALL=(ALL) NOPASSWD: /usr/sbin/pct *
zen-agent ALL=(ALL) NOPASSWD: /usr/bin/pvesh *
zen-agent ALL=(ALL) NOPASSWD: /usr/sbin/pvesm *
zen-agent ALL=(ALL) NOPASSWD: /usr/sbin/vzdump *
zen-agent ALL=(ALL) NOPASSWD: /usr/sbin/qmrestore *
zen-agent ALL=(ALL) NOPASSWD: /usr/sbin/qemu-img *
zen-agent ALL=(ALL) NOPASSWD: /usr/bin/pveam *
zen-agent ALL=(ALL) NOPASSWD: /usr/sbin/ha-manager *
zen-agent ALL=(ALL) NOPASSWD: /usr/sbin/pve-firewall *
# --- Storage observation ---
zen-agent ALL=(ALL) NOPASSWD: /usr/bin/df *
zen-agent ALL=(ALL) NOPASSWD: /usr/bin/du *
zen-agent ALL=(ALL) NOPASSWD: /usr/bin/lsblk *
zen-agent ALL=(ALL) NOPASSWD: /usr/bin/find *
zen-agent ALL=(ALL) NOPASSWD: /usr/bin/ls *
zen-agent ALL=(ALL) NOPASSWD: /usr/sbin/blkid *
# --- Service observation ---
zen-agent ALL=(ALL) NOPASSWD: /usr/bin/journalctl *
zen-agent ALL=(ALL) NOPASSWD: /usr/bin/systemctl status *
zen-agent ALL=(ALL) NOPASSWD: /usr/bin/systemctl list-units *
zen-agent ALL=(ALL) NOPASSWD: /usr/bin/systemctl is-active *
# --- Network observation ---
zen-agent ALL=(ALL) NOPASSWD: /usr/bin/ip *
zen-agent ALL=(ALL) NOPASSWD: /usr/bin/ss *
zen-agent ALL=(ALL) NOPASSWD: /usr/bin/ping *
zen-agent ALL=(ALL) NOPASSWD: /usr/bin/resolvectl *
# --- User/mount management (for storage workflow) ---
zen-agent ALL=(ALL) NOPASSWD: /usr/bin/mount *
zen-agent ALL=(ALL) NOPASSWD: /usr/bin/umount *
zen-agent ALL=(ALL) NOPASSWD: /usr/bin/mkdir *
# --- Read-only sysinfo ---
zen-agent ALL=(ALL) NOPASSWD: /usr/bin/uname *
zen-agent ALL=(ALL) NOPASSWD: /usr/bin/uptime *
zen-agent ALL=(ALL) NOPASSWD: /usr/bin/free *
zen-agent ALL=(ALL) NOPASSWD: /usr/bin/cat /etc/fstab
zen-agent ALL=(ALL) NOPASSWD: /usr/bin/cat /etc/network/interfaces
# --- Audit: every invocation logged ---
Defaults!zen-agent LOG_INPUT
Defaults!zen-agent LOG_OUTPUT
Defaults log_output
Defaults!zen-agent env_reset
A copy of this file is at templates/zen-agent-sudoers — copy to /etc/sudoers.d/zen-agent on the Proxmox host, validate with visudo -c -f /etc/sudoers.d/zen-agent, then test with sudo -n -l as zen-agent to see the loaded rules.
Explicit blacklist (commands the sudoers MUST NOT include)
Even though sudoers defaults to deny for anything not whitelisted, be deliberate about these. The blast radius of each is large, the recovery is hard or impossible, and there is no operational reason for the agent to need them.
| Command | Reason to deny | |---|---| | reboot, shutdown, poweroff, halt | Takes the host down. Agent should ASK, user should run. | | mkfs.ext4, mkfs.vfat, mkfs.xfs, mkfs.btrfs | Destroys filesystem contents. Agent gives instructions, user runs. | | dd | Byte-level disk destruction. Almost no legitimate use case. | | parted, fdisk, sfdisk | Interactive or scriptable partition table rewrites. Agent identifies, user runs. | | cryptsetup | Disk encryption setup/destruction. | | mount /dev/nvme*n* ... with literal device path | Use only UUID= in fstab — but the agent should not be writing fstab directly anyway. | | pvesm remove without explicit --nostart 1 | Destroys storage pool metadata. | | qm destroy, qm stop, pct destroy, pct stop | See "Soft blacklist" below — present in sudoers, but agent's safety policy refuses without user confirmation. | | apt, apt-get, dpkg | Package management. Agent should never install packages without explicit user instruction, and even then the user runs the command. | | visudo | Modifying sudoers is a privilege escalation vector. User-only. | | useradd, userdel, usermod, passwd | Account management. User-only. | | iptables, nft directly | Use pve-firewall API instead. | | rm -rf / | Obviously. Don't include rm at all if avoidable — agents rarely need to delete files. |
The pattern: observe freely, manage Proxmox state freely, but destructive disk operations and host-state changes require a human in the loop. This keeps the blast radius at "VM/container state" not "host state."
Soft blacklist (in sudoers, but agent refuses without explicit user OK)
These are commands that Proxmox admins legitimately need, and the sudoers file permits them, but the agent's safety policy refuses to invoke without asking first. The agent has them in a runtime blocklist, not a sudoers blocklist — defense in depth.
| Command | Why the agent pauses to ask | |---|---| | qm destroy | Deletes the VM and its disks. Irreversible. | | qm stop | Hard power-off. Use qm shutdown first. | | pct destroy | Deletes the container. Irreversible. | | pct stop | Hard stop. Use pct shutdown first. | | pvesm remove | Removes storage registration. Doesn't touch data but breaks the web UI. | | vzdump --remove 0 (with no other flags) | Can wipe the entire backup retention. | | qm snapshot --vmstate 0 on a running VM | Memory snapshot of a live VM. Heavy IO. | | ha-manager add / ha-manager remove | HA changes affect failover behavior. |
The agent's exact wording when refusing: > "I won't run qm destroy 100 without explicit confirmation — this deletes > the VM and its disks irrecoverably. Reply yes destroy 100 if you want me > to proceed."
This matches the trust model in scoped-agent-ssh-access: sudoers says yes, the agent layer says "ask first."
How the agent should think about the whitelist
When the user says "spin up a VM," the agent's actual command sequence is:
- Verify sudoers covers what we need:
sudo -n -l | grep -E '^.*NOPASSWD.*qm '— if this returns nothing, stop and tell the user to install the sudoers file. - Verify SSH works with key-only:
ssh -o BatchMode=yes zen-agent@ 'whoami'— if this prompts for a password, stop. - Verify audit log exists:
sudo -n -l | grep -i 'log_'— if no logging is configured, the sudoers install is incomplete; fix before continuing. - Only then start running
qm,pct,pveshcommands.
If any of those checks fail, the right action is stop and ask the user to install the sudoers file, not to fall back to running things as root.
Common Workflows
Reading host state
# Node health (CPU, RAM, uptime, kernel)
sudo -n pvesh get /nodes//status
# Storage status
sudo -n pvesm status
# Cluster resources (across all nodes if clustered)
sudo -n pvesh get /cluster/resources --type node
# All VMs on the cluster
sudo -n pvesh get /cluster/resources --type vm
# All LXC containers
sudo -n pvesh get /cluster/resources --type ct
The scripts/proxmox-status.sh script runs all of these in one shot and prints a clean summary. Run from the agent host:
scp scripts/proxmox-status.sh zen-agent@:/tmp/
ssh zen-agent@ 'bash /tmp/proxmox-status.sh'
Uploading an ISO from a USB or local path
# Mount the source
sudo -n mount /dev/sdX1 /mnt/source
# Verify perms (sudoers must include /usr/bin/ls)
sudo -n ls /mnt/source/
# Copy. Proxmox default 'local' storage is /var/lib/vz/template/iso
sudo -n cp /mnt/source/*.iso /var/lib/vz/template/iso/
# Verify via pvesh
sudo -n pvesh get /nodes/localhost/storage/local/content --content iso
Always check df -h / before a bulk copy. Ventoy USBs can easily hold 30–60GB; the default local storage backing /var/lib/vz may not have that much free. The scripts/iso-import.sh wrapper enforces this with a hard pre-flight abort.
Strongly prefer copying ISOs to a dedicated NVMe storage pool (/mnt/iso) rather than /var/lib/vz/template/iso/ on the boot disk. A 9-ISO Ventoy stick can easily total 30-60GB; the Proxmox boot disk is typically 60-70GB total, so a single copy fills it from 8% to 100% and breaks the system. See Adding dedicated storage pools below.
Adding dedicated storage pools
When the host has additional NVMe drives that should be Proxmox storage, the full pipeline is: wipe → partition → format → mount → register with pvesm. The agent drives this end-to-end with the user running the destructive steps (the agent's safety policy blocks mkfs, parted, dd by design — see Explicit blacklist above).
Step 1: Identify drives and confirm scope.
lsblk -o NAME,SIZE,TYPE,MOUNTPOINT,MODEL,SERIAL,WWN
Show the user the boot disk's serial and mark it OUT-OF-SCOPE explicitly. Reference drives by serial (e.g. S413NS0RC03383M), NOT by /dev/nvmeXnY — NVMe device numbers shuffle across reboots. The boot disk in the typical homelab config is identifiable by containing /boot/efi and LVM volumes (pve-root, pve-swap, pve-data).
Step 2: User partitions (one fdisk at a time). Agent instructs:
sudo fdisk /dev/nvmeXnY # target drive confirmed by serial
# In fdisk:
g # new GPT table (destroys existing)
n # new partition
1 # partition 1
[Enter] # default first sector
[Enter] # or +119G # full disk, or specify size for splits
w # write and exit
Step 3: User formats.
sudo mkfs.ext4 -L /dev/nvmeXnYp1
Step 4: User mounts.
sudo mkdir -p /mnt/
sudo mount /dev/nvmeXnYp1 /mnt/
df -h /mnt/ # verify the FULL partition size, NOT 458MB
Step 5: Agent adds UUID-based fstab entry (NEVER /dev/nvmeXnYp1).
UUID=$(blkid -s UUID -o value /dev/nvmeXnYp1)
echo "UUID=$UUID /mnt/ ext4 defaults,nofail 0 2" >> /etc/fstab
mount -a
df -h | grep
NVMe device numbers (nvme0n1, nvme1n1, ...) are assigned by kernel discovery order and can shuffle on every reboot, especially after disks are added/removed. The physical identity (model, serial, WWN) is stable; the device path is not. UUIDs are stable. Always use UUID= or LABEL= in /etc/fstab — never /dev/nvmeXnYp1. After a reboot, verify with df -h /mnt/ that the right contents are at the right mount point.
Step 6: Agent registers with Proxmox.
sudo -n pvesm add dir --path /mnt/ --content --is_mountpoint yes
After files are copied into the path, force Proxmox to scan and index the contents:
sudo -n pvesm set --is_mountpoint no
sudo -n pvesm list # verify files are indexed
There is no pvesm scan subcommand on PVE 9.x — its purpose was folded into the set command's --is_mountpoint toggle. Proxmox doesn't auto-scan mount-point-backed storage, which is why pvesm list returns empty even when ls shows files at the path. The web UI's "Create VM → ISO" dropdown won't show the storage's contents until pvesm list does.
The scripts/add-nvme-storage.sh wrapper runs this full pipeline with explicit prompts at every destructive step.
Creating a VM from an ISO
# 1. Pick a VMID (Proxmox convention: 100+ for VMs, 200+ for LXC)
VMID=100
# 2. Create with sensible defaults
sudo -n qm create $VMID \
--name "ubuntu-test" \
-
…
## Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [kevwillow](https://github.com/kevwillow)
- **Source:** [kevwillow/proxmox-manager-agent-skill](https://github.com/kevwillow/proxmox-manager-agent-skill)
- **License:** MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.