Builds the proton-vpn skill per ARCHITECTURE.md section 6 with 9 tools: Tools: - proton_vpn_connect — connect with fastest/random/country/city/P2P/Tor/SC selection - proton_vpn_disconnect — disconnect current session - proton_vpn_status — check connection status (parse CLI output) - proton_vpn_servers — list servers with filters (country, features) - proton_vpn_killswitch — enable/disable kill switch - proton_vpn_config — view/modify DNS, NetShield, protocol - proton_vpn_login — initiate browser OAuth login - proton_vpn_logout — clear credentials - proton_vpn_refresh — refresh server list and config Implementation: - Python subprocess wrapper around official protonvpn-cli v1.0+ - Human-readable CLI output parsed into structured JSON - Privilege check (protonvpn group) before privileged operations - 30-60s timeouts with graceful error handling - dispatch() entry point for Hermes tool routing Also includes: - scripts/install.sh — distro-aware dependency installer - references/commands.md — CLI quick reference - .gitignore — exclude __pycache__, env, debug files Deviations from ARCHITECTURE.md noted in docs: - CLI uses 'login' (browser OAuth), not 'init' - No --json output — parsed from tables - Install via Proton repos, not PyPI
12 KiB
| name | description | version | category | platforms | dependencies | metadata | |||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| proton-vpn | Proton VPN management — connect, disconnect, status, server list, kill switch, and config via the official protonvpn-cli | 1.0.0 | infra |
|
|
|
Proton VPN Hermes Skill
A Hermes skill that wraps the official Proton VPN Linux CLI (protonvpn-cli) for agent use. Provides full VPN lifecycle management — connect, disconnect, status, server discovery, kill switch, and configuration.
Installation
Prerequisites
The skill shells out to protonvpn-cli v1.0.0+. Install it via the official Proton repositories:
# Debian/Ubuntu (add Proton repo first)
curl -1sLf 'https://repo.protonvpn.com/debian/dists/stable/main/signed.key' | sudo apt-key add -
sudo add-apt-repository 'deb https://repo.protonvpn.com/debian stable main'
sudo apt update && sudo apt install protonvpn-cli
# Fedora
sudo dnf install protonvpn-cli
# Arch (AUR)
yay -S protonvpn-cli
Post-Install Setup
-
Initial login (requires a desktop session — browser OAuth):
protonvpn-cli loginFirst-time login opens a browser for OAuth. After that, the session persists.
-
Verify installation:
protonvpn-cli status protonvpn-cli servers | head -10 -
Ensure required services:
systemctl status systemd-resolved # should be running
Tools
proton_vpn_connect
Connect to a Proton VPN server.
{
"name": "proton_vpn_connect",
"description": "Connect to a Proton VPN server. Supports fastest, random, country, city, P2P, Tor, Secure Core, and free server selection.",
"parameters": {
"type": "object",
"properties": {
"server": {
"type": "string",
"description": "Server name or ID (e.g., 'US-NY#1'). Omitting uses default selection strategy."
},
"selection": {
"type": "string",
"enum": ["fastest", "random", "country", "city", "p2p", "tor", "free", "secure-core"],
"description": "Server selection strategy. 'fastest' (default): lowest latency. 'random': random server. 'country': fastest in specified country. 'p2p'/'tor'/'secure-core': feature-optimized."
},
"country": {
"type": "string",
"description": "Two-letter country code (e.g., 'US', 'CH', 'JP'). Only used when selection='country'."
},
"city": {
"type": "string",
"description": "City name (e.g., 'New York'). Only used when selection='city'."
},
"protocol": {
"type": "string",
"enum": ["wireguard", "openvpn_udp", "openvpn_tcp"],
"description": "VPN protocol. Default is WireGuard when available."
},
"persistent": {
"type": "boolean",
"description": "Auto-reconnect if the VPN connection drops."
}
}
}
}
CLI mapping:
- Fastest:
protonvpn-cli connect --fastest - Random:
protonvpn-cli connect --random - Country:
protonvpn-cli connect --country US --protocol wireguard - P2P:
protonvpn-cli connect --p2p - Server name:
protonvpn-cli connect US-NY#1
Returns: JSON with connection status, server name, protocol, and IP.
proton_vpn_disconnect
Disconnect the current VPN session.
{
"name": "proton_vpn_disconnect",
"description": "Disconnect the current VPN session and restore normal network connectivity.",
"parameters": {}
}
CLI mapping: protonvpn-cli disconnect
Returns: JSON with confirmation message.
proton_vpn_status
Get current VPN connection status.
{
"name": "proton_vpn_status",
"description": "Check the current Proton VPN connection status — connected server, protocol, uptime, IP information.",
"parameters": {}
}
CLI mapping: protonvpn-cli status
Returns: JSON with connection state, server name, country, protocol, uptime, and local IP.
proton_vpn_servers
List available Proton VPN servers with features and load.
{
"name": "proton_vpn_servers",
"description": "List available Proton VPN servers. Shows country, city, current load percentage, and supported features (P2P, Tor, Secure Core).",
"parameters": {
"type": "object",
"properties": {
"country": {
"type": "string",
"description": "Filter by two-letter country code (e.g., 'US')."
},
"features": {
"type": "array",
"items": { "type": "string", "enum": ["p2p", "tor", "secure-core", "free"] },
"description": "Filter by required features."
},
"format": {
"type": "string",
"enum": ["table", "json"],
"description": "Output format. 'table': human-readable. 'json': machine-parseable."
}
}
}
}
CLI mapping: protonvpn-cli servers (table output, parsed to JSON)
Returns: JSON array of servers with name, country, city, load, features.
proton_vpn_killswitch
Enable or disable the VPN kill switch.
{
"name": "proton_vpn_killswitch",
"description": "Enable or disable the VPN kill switch. When enabled, all internet traffic is blocked outside the VPN tunnel, preventing data leaks if the VPN drops.",
"parameters": {
"type": "object",
"properties": {
"state": {
"type": "string",
"enum": ["on", "off"],
"description": "Kill switch state. 'on': enable (blocks non-VPN traffic). 'off': disable."
}
},
"required": ["state"]
}
}
CLI mapping: protonvpn-cli settings --killswitch on|off
Returns: JSON with kill switch state and confirmation.
proton_vpn_config
View or modify VPN configuration.
{
"name": "proton_vpn_config",
"description": "View current Proton VPN configuration or modify settings like DNS, NetShield, protocol preference, and VPN Accelerator.",
"parameters": {
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": ["view", "set-dns", "set-netshield", "set-protocol"],
"description": "'view' (default): show current config. 'set-dns': set custom DNS servers. 'set-netshield': toggle NetShield ad-blocker. 'set-protocol': set preferred protocol."
},
"value": {
"type": "string",
"description": "Value for the setting. For 'set-dns': comma-separated IPs (e.g., '1.1.1.1,1.0.0.1'). For 'set-netshield': 'on', 'off', or 'strict'. For 'set-protocol': 'wireguard', 'openvpn_udp', or 'openvpn_tcp'."
}
}
}
}
CLI mapping:
- View:
protonvpn-cli config --list - Kill switch:
protonvpn-cli settings --killswitch on|off - NetShield:
protonvpn-cli settings --netshield on|off|strict - DNS:
protonvpn-cli settings --custom-dns <ip>
Returns: JSON with configuration key-value pairs or confirmation message.
proton_vpn_login
Authenticate with Proton VPN (browser OAuth).
{
"name": "proton_vpn_login",
"description": "Authenticate with Proton VPN. Requires a desktop session to open a browser for OAuth login. Proton VPN CLI manages credentials after initial login.",
"parameters": {
"type": "object",
"properties": {
"username": {
"type": "string",
"description": "Proton account username/email."
}
}
}
}
CLI mapping: protonvpn-cli login [username]
Note: First-time login requires a browser for OAuth. The agent should warn users that this won't work in headless environments.
proton_vpn_logout
Log out from Proton VPN.
{
"name": "proton_vpn_logout",
"description": "Log out from Proton VPN. Clears stored credentials and disconnects if connected.",
"parameters": {}
}
CLI mapping: protonvpn-cli logout
proton_vpn_refresh
Refresh server list and VPN configuration.
{
"name": "proton_vpn_refresh",
"description": "Refresh the server list and VPN configuration from Proton's API. Useful after a network change or if servers appear outdated.",
"parameters": {}
}
CLI mapping: protonvpn-cli refresh
Implementation
All tools shell out to protonvpn-cli via Python subprocess. The implementation module lives at scripts/tools.py in this skill directory.
General Pattern
import subprocess
import json
import shlex
def _run_vpn_command(args: list[str], timeout: int = 30) -> dict:
"""Run a protonvpn-cli command and return structured output."""
try:
result = subprocess.run(
["protonvpn-cli"] + args,
capture_output=True, text=True, timeout=timeout
)
if result.returncode != 0:
return {"error": result.stderr.strip(), "exit_code": result.returncode}
return {
"success": True,
"output": result.stdout.strip(),
"command": "protonvpn-cli " + " ".join(shlex.quote(a) for a in args)
}
except subprocess.TimeoutExpired:
return {"error": f"Command timed out after {timeout}s"}
except FileNotFoundError:
return {"error": "protonvpn-cli not found. Install via Proton repos."}
Privilege Check
protonvpn-cli requires either root or membership in the protonvpn group for WireGuard interface creation. All tools should call a privilege check before executing:
import os
def _check_vpn_privileges() -> dict | None:
"""Check if the current user can use protonvpn-cli. Returns error dict or None."""
if os.geteuid() == 0:
return None # root can always use it
import subprocess
groups_result = subprocess.run(["groups"], capture_output=True, text=True)
groups = groups_result.stdout.strip()
if "protonvpn" not in groups:
return {
"error": (
"User not in 'protonvpn' group. "
"Run: sudo usermod -aG protonvpn $USER && logout && login"
)
}
return None
Output Parsing
The CLI outputs human-readable tables (not JSON). The tool parses output into structured JSON:
protonvpn-cli status→ parsed into connection state, server, protocol, uptime, IPprotonvpn-cli servers→ parsed into array of server objectsprotonvpn-cli config --list→ parsed into key-value pairs
Dependencies
| Dependency | Required | Notes |
|---|---|---|
protonvpn-cli (>=1.0.0) |
Yes | Official Proton VPN CLI, v1.0.1 latest (Apr 2026). GitHub |
systemd-resolved |
Recommended | DNS leak protection via systemd-resolved |
gnome-keyring |
Recommended | Credential storage for initial login |
NetworkManager |
Required | VPN connection profiles managed via NetworkManager |
WireGuard |
Recommended | Default protocol; faster than OpenVPN |
OpenVPN |
Fallback | Alternative protocol when WireGuard unavailable |
Limitations
- No headless support — The CLI requires
gnome-keyringandNetworkManager. It does not work on minimal server installs without a desktop environment. - Cannot coexist with Proton VPN GUI — Running both simultaneously causes conflicts.
- Split tunneling not yet available — Feature is planned for a future release.
- Requires internet for login — OAuth flow needs a browser.
- Kill switch uses iptables — May conflict with other firewall rules. Verify carefully.
Security
- Proton VPN CLI stores credentials in
gnome-keyring(encrypted at rest) - Connection logs:
~/.cache/Proton/VPN/logs/ - Configuration:
~/.config/Proton/VPN/ - The skill passes connection results and server lists back to the agent; no credentials are exposed
- Kill switch is system-level (iptables rules), not agent-level
Related
- Official Proton VPN CLI GitHub
- Proton VPN Linux CLI support page
- Hermes hardware keychain skill (example of subprocess skill pattern)
- ARCHITECTURE.md — Hermes-Proton integration design (section 6)