hermes-proton/skills/proton-vpn/SKILL.md
Templeton Face da7dac8301
feat(vpn): Proton VPN Hermes skill — CLI wrapper tools
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
2026-06-08 18:29:53 +02:00

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
linux
protonvpn-cli (official Proton VPN Linux CLI)
systemd-resolved (for DNS leak protection)
gnome-keyring (for credential storage)
NetworkManager (for connection management)
hermes
tags auth limitations
vpn
proton
network
privacy
security
independent — protonvpn-cli manages its own OAuth session
Does NOT work on headless setups (requires gnome-keyring + NetworkManager)
Cannot run alongside Proton VPN GUI app
Split tunneling not yet available in CLI v1.0.1

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

  1. Initial login (requires a desktop session — browser OAuth):

    protonvpn-cli login
    

    First-time login opens a browser for OAuth. After that, the session persists.

  2. Verify installation:

    protonvpn-cli status
    protonvpn-cli servers | head -10
    
  3. 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, IP
  • protonvpn-cli servers → parsed into array of server objects
  • protonvpn-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

  1. No headless support — The CLI requires gnome-keyring and NetworkManager. It does not work on minimal server installs without a desktop environment.
  2. Cannot coexist with Proton VPN GUI — Running both simultaneously causes conflicts.
  3. Split tunneling not yet available — Feature is planned for a future release.
  4. Requires internet for login — OAuth flow needs a browser.
  5. 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