@bkramer/proton-cli
v0.4.3
Published
Unofficial unified Proton CLI (VPN, Authenticator, Contacts, Calendar, Drive, Settings, Mail) with shared Pass-aware sign-in
Maintainers
Readme
proton-cli
Unofficial unified Proton command-line client (VPN + Authenticator + Contacts + Calendar + Drive + Settings + Mail) with one install and shared sign-in UX.
Not an official Proton product. Not affiliated with Proton AG.
Install
Requires Bun ≥ 1.1 at runtime (even when installing via npm).
bun add -g @bkramer/proton-cli
# or
npm install -g @bkramer/proton-cliFrom GitHub:
bun install -g github:brandonkramer/proton-cliFrom a clone
git clone https://github.com/brandonkramer/proton-cli.git
cd proton-cli
bun install
bun linkRequirements
- Bun ≥ 1.1
- Proton account in Single Password Mode
- TOTP if you use 2FA (FIDO2/security keys are not supported). Shared sign-in mints all selected products (default: all seven) — each product needs its own fresh TOTP (codes are single-use; one code cannot cover multiple mints)
- VPN — WireGuard tools (install tries this via Homebrew / winget; or
proton vpn setup)- macOS: Homebrew →
wireguard-tools(sudo for connect/disconnect) - Windows: WireGuard app via winget (Administrator terminal for connect/disconnect)
- macOS: Homebrew →
- Authenticator — CAPTCHA (macOS): native WKWebView helper, built on
postinstallwhen possible (bun run build:captchato retry; needs Xcode CLT) - Optional: Proton Pass CLI (
pass-cli) for credential injection
Close the Proton VPN desktop app before connecting so tunnels do not conflict.
On macOS, VPN connect/disconnect may ask for your Mac login password (sudo), not your Proton password.
CAPTCHA (if Proton requires it on sign-in): solve it in the native WKWebView window, not Safari/verify.proton.me.
Agent plugins (Cursor / Codex / Claude / Pi)
This repo ships host plugin manifests and a thin MCP server (proton mcp) that shells out to the CLI in JSON/agent mode.
proton install-mcp --scope project --host all # Cursor/Codex/Claude MCP + skill + Pi hint
proton install-mcp --scope user --host cursor
proton mcp # stdio MCP (used by hosts)| Host | Install |
|------|---------|
| Cursor | proton install-mcp --host cursor (user or project) — or load .cursor-plugin/ |
| Codex | proton install-mcp --host codex — or load .codex-plugin/ |
| Claude | proton install-mcp --host claude (project → .mcp.json; user → claude plugin marketplace add / install) — or load .claude-plugin/ |
| Pi | pi install git:github.com/brandonkramer/proton-cli (skills via "pi" in package.json); wire proton mcp through your MCP adapter |
Sign-in / CAPTCHA stay interactive on a human TTY. Prefer curated MCP tools (mail/contacts/calendar/drive/vpn/settings reads + common writes) or proton_cli with confirm=true for non-reads. See skills/proton-cli/SKILL.md.
Commands
Run proton with no args (TTY) for the interactive menu (VPN / Authenticator / Contacts / Calendar / Drive / Settings / Mail / sign-in).
Global options: --json, -y / --yes, --sudo (WireGuard on macOS).
Shared
proton # interactive menu (TTY)
proton account pass://Vault/Item # save default Pass login (password + TOTP)
proton account # show saved Pass ref / username
proton account --clear # clear saved Pass ref
proton signin # uses saved Pass ref (or --pass / PROTON_PASS)
proton signin --pass "pass://Vault/Item"
proton signin --products vpn # or auth / ctc / all
proton signin --partial-ok
proton status --json
proton signout
proton update --check
proton update
proton mcp # MCP stdio server for agents
proton install-mcp # wire Cursor/Codex/PiWith 2FA, proton signin / TUI Sign in need a fresh TOTP per product being minted. Prefer proton account pass://Vault/Item (or --pass / PROTON_PASS) so Pass supplies a new code for each mint. Requires pass-cli logged in. Sign-out keeps the saved Pass ref.
VPN (proton vpn …)
proton vpn setup
proton vpn countries
proton vpn servers --country US
proton vpn connect --country US
proton vpn connect --city "New York"
proton vpn connect US#23
proton vpn connect --p2p
proton vpn status --json
proton vpn disconnect| Flag | Meaning |
|------|---------|
| --country <code> | Exit country (e.g. NL) |
| --city <name> | City name |
| --p2p | P2P servers |
| --securecore | Secure Core |
| --tor | Tor over VPN |
| --free-only | Free-tier only |
Country / feature availability depends on your Proton plan.
Authenticator (proton auth …)
E2EE TOTP/Steam seed sync and codes (Authenticator Key; client-side encrypt/decrypt).
proton auth sync
proton auth list
proton auth code github
proton auth status --output jsonProduct-only proton vpn signin / proton auth signin exist; prefer shared proton signin.
Contacts (proton contacts …)
E2EE contact cards, groups, and pinned keys.
proton contacts list
proton contacts get alice
proton contacts create --name "Alice" --email [email protected]
proton contacts groups list
proton contacts pin-key contact-id ./key.ascBare proton (TTY) opens a nested Contacts menu (list / add contact / groups / status). Prefer proton contacts … --json for scripting.
Calendar (proton calendar …)
E2EE calendars and events.
proton calendar calendars list
proton calendar calendars create --name "Work" --color "#8080FF"
proton calendar events list --calendar primary
proton calendar events create --title "Standup" --start 2026-07-24T09:00 --duration 30m
proton calendar events respond EVENT_REF --status acceptBare proton (TTY) opens a nested Calendar menu (list calendars / list events / add event / status). Prefer proton calendar … --json for scripting. Encrypted event operations need account password via --password, --pass, or PROTON_PASSWORD.
Drive (proton drive …)
E2EE files, folders, sharing, trash, and photos.
proton drive status
proton drive items list
proton drive items upload ./file.txt /
proton drive folders create /Projects
proton drive share link /file.txt
proton drive trash list
proton drive photos listBare proton (TTY) opens a nested Drive menu (list items / upload file / list trash / status). Prefer proton drive … --json for scripting. Encrypted operations need account password via --password, --pass, or PROTON_PASSWORD.
Settings (proton settings …)
Account and mail preference settings via Proton’s account/mail API (not Bridge IMAP/SMTP).
proton settings get
proton settings mail
proton settings set
proton settings set view-mode 1
proton settings set hide-remote-images 1 --dry-run
proton settings get --jsonSign in with proton signin --products settings|set|all. Writable keys include view-mode, draft-type, hide-remote-images, and others listed by bare proton settings set.
Bare proton (TTY) opens a nested Settings menu (account / mail / list keys / update). Prefer proton settings … --json for scripting.
Mail (proton mail …)
E2EE list/read/search/send/organize via Proton Mail REST API (not Bridge IMAP/SMTP).
proton mail status
proton mail list
proton mail list --label sent --unread
proton mail sent # shortcut for --label sent
proton mail read MESSAGE_ID # HTML → plain text in the terminal
proton mail read MESSAGE_ID --raw # keep original HTML
proton mail search "invoice"
proton mail send --to [email protected] --subject "Hi" --body "Hello"
proton mail send --to [email protected] --subject "Hi" --body "Hello" \
--attach ./file.pdf --attach ./notes.txt
proton mail organize read MESSAGE_ID
proton mail organize trash MESSAGE_ID
proton mail labels list
proton mail addresses listBare proton (TTY) opens a nested Mail menu (list inbox / list sent / search / compose / status). From a message you can reply / reply-all / forward. Compose can pick To from Contacts or type an address, and accept optional local attachment paths. Prefer proton mail … --json for scripting.
Read/send/decrypt need the account password via saved proton account / PROTON_PASS / --pass, or --password / PROTON_PASSWORD.
Sign in with proton signin --products mail|all (or full proton signin; Mail shares its session with Contacts/Settings).
Proton Pass (optional)
If you use Proton Pass CLI (pass-cli):
pass-cli login # once, if needed
proton account pass://Vault/Item # recommended: persist default login + TOTP
proton signin # uses saved account ref
# or one-shot / env:
proton signin --pass "pass://Vault/Item"
export PROTON_PASS="pass://Vault/Item"Also supported:
export PROTON_PASSWORD='pass://Vault/Item/password'
export PROTON_TOTP='pass://Vault/Item/totp' # optional
pass-cli run -- proton signinVault/Item works too (pass:// prefix optional). If several items share a title, the CLI prefers the one that has TOTP and stores a stable share/item ID. Env aliases: PROTON_PASS, PROTONVPN_PASS, PROTONAUTH_PASS, PROTON_USERNAME, PROTON_PASSWORD, PROTON_TOTP. Interactive prompts remain the default when Pass is unset. Never log resolved secrets. With 2FA, Pass (via proton account / --pass) supplies a new TOTP for each product mint.
Agents / scripting
proton status --json
proton vpn status --json
proton vpn connect --json --country US
proton auth status --output json
proton auth code github --output json| Flag / env | Meaning |
|---|---|
| --json / PROTONVPN_JSON=1 | JSON on stdout (VPN / shared) |
| --output json\|plain\|ink / PROTONAUTH_OUTPUT | Authenticator output format |
| -y / --yes | Non-interactive confirms |
| --sudo | Allow interactive macOS sudo for WireGuard |
| PROTON_AGENT=1 | Root proton agent-friendly (no accidental TUI) |
| PROTONVPN_AGENT=1 | VPN agent mode (JSON-friendly; sudo -n only unless --sudo) |
| PROTONAUTH_AGENT=1 / CI=1 | Auth agent mode (default JSON; no CAPTCHA window / TUI) |
| PROTONCONTACTS_JSON=1 / PROTONCONTACTS_AGENT=1 | Contacts agent mode (JSON; no TUI) |
| PROTONCALENDAR_JSON=1 / PROTONCALENDAR_AGENT=1 | Calendar agent mode (JSON; no TUI) |
| PROTON_DRIVE_JSON=1 / PROTON_DRIVE_AGENT=1 | Drive agent mode (JSON; no TUI) |
| PROTONSETTINGS_JSON=1 / PROTONSETTINGS_AGENT=1 | Settings agent mode (JSON; no TUI) |
| PROTONMAIL_JSON=1 / PROTONMAIL_AGENT=1 | Mail agent mode (JSON; no TUI) |
VPN exit codes: 0 ok · 1 error · 2 usage · 3 not signed in · 4 privilege needed.
CAPTCHA never opens a window in agent mode (captcha_required — sign in interactively once, then reuse the session).
Monorepo
| Path | Package | Owns |
|---|---|---|
| packages/core | @bkramer/proton-core | Shared config, dual-mint sessions, Pass helpers |
| packages/vpn | @bkramer/proton-vpn | WireGuard + vpn-api (proton vpn …) |
| packages/authenticator | @bkramer/proton-authenticator | E2EE TOTP/Steam sync (proton auth …) |
| packages/contacts | @bkramer/proton-contacts | E2EE contacts/groups (proton contacts …) |
| packages/calendar | @bkramer/proton-calendar | E2EE calendars/events (proton calendar …) |
| packages/drive | @bkramer/proton-drive | E2EE Drive files/folders/photos (proton drive …) |
| packages/settings | @bkramer/proton-settings | Account/mail API preferences (proton settings …) |
| packages/mail | @bkramer/proton-mail | E2EE Mail list/read/search/send (proton mail …) |
| src/ | root bins | proton router + legacy wrappers |
Config root: ~/.config/proton-cli/ (account.json for the saved Pass ref; per-product sessions under sessions/).
Shared session model
Most products use different API hosts, so they mint separate sessions. Exception: Contacts, Settings, and Mail all use mail-api.proton.me and share one session after a successful mint for any of them. proton signin still feels like one login: credentials (and Pass TOTP) are collected once, CAPTCHA is solved in the native window when required, then each remaining host is minted (with a fresh TOTP per mint).
Agent skill
End-user usage skill for agents: skills/proton-cli/SKILL.md.
License
GPL-3.0-or-later
