hermes-proton/docs/landscape.md
Templeton Face 0da56b1c7f
docs: landscape scan of 7 Proton third-party client implementations
Systematic study of existing open-source Proton client projects
to extract patterns, pitfalls, and reusable code for hermes-proton.

Projects analyzed:
- hydroxide (Go, SRP, CardDAV/IMAP/SMTP) — complete auth+session ref
- rclone protondrive (Go, Drive only) — encryption patterns
- roman-16/proton-cli (Go, all 5 products) — 3-tier architecture ref
- bscott/pm-cli (Go, Bridge mail) — agent-friendly gold standard
- StollD/proton-webdav-bridge (Go, Drive as WebDAV) — caching pattern
- cdump/proton-tui (Rust, VPN) — standalone SRP auth module
- rvacyber/openclaw-protonmail-skill (TS, Bridge mail) — skill pattern ref

Feeds into T1 (hannibal architecture).

Closes t_3c87cd08
2026-06-08 18:41:46 +02:00

26 KiB
Raw Permalink Blame History

Proton Third-Party Client Landscape

Landscape scan of 7 open-source Proton client implementations — patterns, pitfalls, and reusable code for hermes-proton. Compiled: 2026-06-08 Analyst: Face (kanban t_3c87cd08)


Overview

# Project Lang Stars Auth Scope Key Value for Hermes-Proton
1 hydroxide (emersion) Go 2.1k SRP direct Mail, Contacts, Calendar Complete SRP+2FA+refresh implementation; bbolt caching; NaCl secretbox session persistence
2 rclone protondrive Go 57k SRP direct Drive only Battle-tested Drive encryption (4MB blocks, X25519, gopenpgp v2); most-used third-party client
3 proton-cli (roman-16) Go 17 SRP direct All 5 products Most architecturally mature; clean 3-tier layering; session cache; REF ID system; error classification
4 pm-cli (bscott) Go 14 Bridge pass Mail only Agent-friendly gold standard: --json everywhere, --help-json, idempotency keys, semantic summaries
5 proton-webdav-bridge (StollD) Go 28 SRP direct Drive as WebDAV In-memory tree cache + 5s event poll; Drive encryption via go-proton-api fork (archived)
6 proton-tui (cdump) Rust 12 SRP direct VPN only Standalone SRP-6a auth module (reusable Rust crate); WireGuard key conversion; VPN lifecycle
7 openclaw-protonmail-skill (rvacyber) TS 16 Bridge pass Mail only Closest analogue to Hermes skill pattern; IMAP/SMTP via Bridge; env-var config; search sanitization

1. Project-by-Project Analysis

1.1 hydroxide (emersion/hydroxide)

Location: github.com/emersion/hydroxide Stars: 2.1k | License: MIT | Language: Go 1.24

Auth Approach — Full SRP Direct (No Bridge Dependency)

AuthInfo(username) → POST /auth/info → {srpSession, Modulus (PGP-signed), ServerEphemeral, Salt}
srp(password, info) → bcrypt (cost 10) + expandHash (4×SHA-512) + generateProofs (2048-bit, LE)
Auth(username, password, info) → POST /auth → verify server proof (constant-time compare)
AuthTOTP(code) → POST /auth/2fa (bitmap check: Enabled != 0)
Unlock(auth, keySalts, passphrase) → decrypt keyring with password/token
  • SRP implementation location: protonmail/srp.go — 2048-bit group, little-endian byte order matching Proton web client
  • Password hashing: protonmail/password.gohashPassword(): version 3/4 appends "proton" to salt, bcrypts (cost 10), runs expandHash() — 4 rounds SHA-512 with suffix bytes 0-3
  • Modulus trust: Hardcoded modulusPubkey PGP key in source; modulus response is clearsigned and verified
  • 2FA: TOTP only; bitmap check (Enabled != 0 not Enabled == 1); U2F/WebAuthn not implemented
  • Re-auth chain: AuthRefresh() → POST /auth/refresh; on code 10013 (invalid refresh token) → fallback to full SRP Auth (fails if 2FA enabled)

Token Persistence — NaCl Secretbox

  • Storage: ~/.config/hydroxide/auth.json
  • Format: JSON map map[string]string (username → base64-encrypted blob)
  • Encryption: NaCl secretbox (XSalsa20-Poly1305) with random 24-byte nonce
  • Key: Random 32-byte bridge password (base64), shown once at login, NOT stored by hydroxide
  • CachedAuth struct: {Auth (UID, AccessToken, RefreshToken, ExpiresIn), LoginPassword, MailboxPassword, KeySalts}

Error Handling

Pattern Details
401 auto-retry Client.do() — single retry with ReAuth callback
APIError struct {Code int, Message string} — wrapped from RawAPIError
Refresh failure Code 10013 → full re-auth via SRP (2FA blocks this)
429 rate limit Not handled — no retry-wait logic (gap for production)

Crypto

  • github.com/ProtonMail/go-crypto v1.4.1 (Proton's OpenPGP fork with SHA-512 support)
  • Message encryption: Message.Encrypt(to, signed) → armored PGP via openpgp.SymmetricallyEncrypt
  • Attachment crypto: Attachment.GenerateKey() → AES-256 key → symmetrically encrypted
  • Contact crypto: NewEncryptedContactCard, NewSignedContactCard — dual-card scheme
  • Key derivation: computeKeyPassword() → bcrypt, strip prefix (last 29 bytes)

Project Structure

protonmail/         # Core API client (18 files)
  ├── auth.go       # Auth flows (AuthInfo, Auth, AuthTOTP, AuthRefresh, Unlock, Logout)
  ├── srp.go        # SRP-6a protocol
  ├── password.go   # Key derivation (bcrypt + SHA-512)
  ├── crypto.go     # OpenPGP operations
  ├── messages.go   # Message CRUD + Encrypt/Read
  ├── events.go     # Event polling (GetEvent)
  └── ...
auth/auth.go       # Session persistence, Manager, re-auth, 2FA detection
imap/              # IMAP server backend + bbolt database
smtp/              # SMTP backend (MIME → PGP → send)
carddav/           # CardDAV handler
cmd/hydroxide/     # CLI entry (11 subcommands)

Key takeaway: Most complete SRP+session management reference. The NaCl secretbox pattern for encrypted token storage is directly adoptable.


1.2 rclone protondrive backend

Location: github.com/rclone/rclone/tree/master/backend/protondrive Stars: 57k (rclone project) | License: MIT | Language: Go

Auth Approach — SRP Direct (via archived bridge library)

Uses henrybear327/Proton-API-Bridge (archived Feb 2026) and henrybear327/go-proton-api (archived Feb 2026). Both are single-contributor projects with no upstream development.

  • SRP auth via ProtonMail/go-srp v0.0.7
  • Auth flow: Login → API client creation → keyring unlock → Drive backend init
  • SaltedKeyPass caching: After first login, the salted key pass is cached so subsequent operations don't need password
  • authHandler callback pattern: Transparent token refresh middleware

Encryption — gopenpgp v2 (X25519)

  • Key type: X25519 (Curve25519-based OpenPGP keys)
  • Block size: 4MB blocks
  • Encryption: OpenPGP CFB mode per block
  • Hashing: SHA-256 block hashes + armored detached signatures per block; SHA-1 content digests (Proton legacy)
  • Bootstrap key: HKDF from user key → address key → share key → node key → session key
  • Key library: github.com/ProtonMail/gopenpgp/v2 v2.10.0

Token Management

  • Config stores: UID + AccessToken + RefreshToken + SaltedKeyPass
  • configKey constants hidden in config file
  • Auto-refresh handled by bridge library (opaque to rclone backend)

Error Handling

Pattern Details
shouldRetry Catches API Code=200501 (rate limit?) and 5xx server errors
HTTP retry Deferred to resty (rclone's HTTP client)
Sentinel errors 17 typed error constants in Proton-API-Bridge

⚠️ Critical Risk

Both henrybear327/Proton-API-Bridge and henrybear327/go-proton-api are archived (Feb 2026). rclone vendors them as-is. Any new project relying on this code path inherits the risk of unpatched bugs and API breakage.


1.3 proton-cli (roman-16/proton-cli)

Location: github.com/roman-16/proton-cli Stars: 17 | License: MIT | Language: Go 1.26.1 | Version: v1.4.0 (May 2026)

Architecture — 3-Tier Layered (Best in Class)

cmd/          # Cobra CLI commands (per-product packages)
internal/
  api/        # HTTP client, SRP auth, error types, HV resolver
  services/   # Domain services (mail, drive, calendar, contacts, pass) — per-product packages
  app/        # Wiring container (App struct holding 5 services + API + Renderer)
  session/    # Session persistence (~/.config/proton-cli/sessions/<profile>.json)
  config/     # TOML multi-profile config
  keys/       # PGP key hierarchy unlock
  pgp/        # Card encryption (clear/signed/encrypted/encrypted+signed)
  aead/       # AES-256-GCM for Pass items/vaults
  render/     # Output formatting (text/JSON/YAML/tables/progress)
  idcache/    # Short-ID → full ID cache
  hv/         # Embedded webview CAPTCHA helper

The App wiring pattern is worth adopting directly:

type App struct {
    Profile  string
    Creds    Credentials
    API      *api.Client      // Single session, shared across all 5 services
    Mail     *mail.Service
    Drive    *drive.Service
    Calendar *calendar.Service
    Contacts *contacts.Service
    Pass     *pass.Service
    R        *render.Renderer
    IDCache  *idcache.Cache
}

Auth Approach — Full SRP (Not Bridge)

  • POST /auth/v4/sessions (creates unauth session)
  • POST /core/v4/auth/infogo-srp proofs
  • POST /core/v4/auth → verify server proof (MITM prevention)
  • POST /core/v4/auth/2fa if bit 0 set in TwoFA.Enabled
  • HV (CAPTCHA) via embedded webview helper binary
  • Dependencies: go-srp v0.0.7, gopenpgp/v2 v2.10.0

Session Management

  • Storage: ~/.config/proton-cli/sessions/<profile>.json (0600)
  • SaltedKeyPass caching: Stored in session file → subsequent invocations don't need password
  • Auto-refresh: api.Client.Do() calls POST /auth/v4/refresh on 401, persists via session.Save()
  • Thread safety: sync.RWMutex on client for token reads/writes
  • Multi-profile: Each profile has independent session + config

Error Handling — Typed Hierarchy with Exit Codes

Code Meaning
0 Success
1 User error
2 Auth failure
3 Not found
4 Ambiguous/conflict
5 Network/server error
130 Cancelled (Ctrl+C)

Hierarchy: APIErrorHumanVerificationError (code 9001) → ExitErrorWrongTableError (cross-table probing for message↔conversation confusion) → ErrNotFound / AmbiguousError

Notable: Cross-table probing on 422 errors — if a GET fails, it probes the opposite table (message↔conversation) and returns a precise diagnostic.

Key Design Decisions

  1. Single HTTP client shared across all 5 products — no per-service auth
  2. App-in-context pattern — *app.App stored in context.Context via app.WithApp(), avoids global state
  3. REF ID resolution — prefix matching (8+ chars) from idcache; ambiguous → exit 4 with candidates
  4. Dashed ID protection — auto-inserts -- before Proton base64 IDs starting with -
  5. Render abstractionrender.Renderer handles text/JSON/YAML; commands never call fmt.Println
  6. Dry-run on mutations — global --dry-run flag checked by all mutation commands

Notable Gaps

  • No OAuth — env-var or config-file passwords only
  • No structured logging — slog to stderr only; no log file/rotation
  • CAPTCHA webview only — no stdin-based email/SMS verification

1.4 pm-cli (bscott/pm-cli)

Location: github.com/bscott/pm-cli Stars: 14 | License: MIT | Language: Go | Version: v0.2.5 (April 2026)

Architecture — Bridge Protocol Only

  • Does NOT call Proton API directly — connects to local Proton Bridge daemon
  • IMAP: 127.0.0.1:1143 (STARTTLS) — read/search mail
  • SMTP: 127.0.0.1:1025 (STARTTLS) — send mail
  • Auth: Bridge-generated app password (not Proton password)
  • TLS: InsecureSkipVerify: true (Bridge self-signed cert), v0.2.5 enforces loopback-only

Agent-Friendly Features (Gold Standard for Hermes)

Feature Implementation Value for Agents
Universal --json Formatter struct threaded through all commands; {"success": true, "data": {...}} envelope Always parseable, always on stdout
--help-json Full typed command tree as JSON (flags, args, types, examples) Zero-parsing schema introspection in 1 call
Idempotency keys --idempotency-key on mail send/reply/forward; 24h TTL in ~/.config/pm-cli/idempotency.json Safe retry without double-send
Semantic AI commands mail summarize (sentiment, priority, action_required, summary); mail extract (emails, URLs, dates, phone_numbers, action_items) Pre-digested LLM input
Consistent error envelope {"success": false, "error": "..."} on stdout Always parseable even on failure
Stable IDs Both seq numbers (123) and UIDs (uid:456) in output Stable across invocations
Watch + env vars mail watch --exec exposes metadata as PM_MSG_* env vars Safe agent automation

Error Handling

  • Two-mode: human (stderr, color) vs JSON (stdout, structured)
  • Descriptive messages with actionable guidance
  • Exit code 1 on any error
  • Wrapped errors via %w

Security Hardening (v0.2.5)

  1. SMTP Header Injection — SanitizeHeaderValue() strips CR/LF
  2. TLS Loopback Enforcement — isLoopbackHost() refuses non-localhost
  3. Shell Injection — env vars replace string interpolation in watch mode
  4. ANSI Escape Injection — SanitizeForTerminal() strips escapes

Gaps

  • Bridge required — doesn't work without Bridge daemon
  • Mail only — no Calendar, Drive, Pass, VPN
  • Polling only — 30s poll interval, no IMAP IDLE
  • Single account — one config at a time
  • Local-only — can't be remote/multi-user

1.5 proton-webdav-bridge (StollD)

Location: github.com/StollD/proton-webdav-bridge Stars: 28 | License: MIT | Language: Go

Architecture

  • Purpose: Exposes Proton Drive as a local WebDAV filesystem
  • Daemon pattern: Registers WebDAV handler on localhost:7984, proxies Drive operations
  • Auth: SRP direct via henrybear327/go-proton-api (same archived fork as rclone)

Caching — Pure In-Memory

  • Two map[string]*Link — one for ID lookups, one for path lookups
  • No disk persistence — full re-fetch on restart
  • Event poll: Background goroutine polls Proton share events every 5 seconds via TriggerUpdate()
  • Synchronous cache refresh before every download/upload

Encryption

  • Same gopenpgp/v2 stack as rclone (X25519)
  • Full key hierarchy: User Key → Address Key → Share Key → Node Key → Session Key
  • Reader decrypts blocks on-demand with SHA-256 hash verification
  • Writer encrypts in 4MB blocks with SHA-1 content hashing (Proton API validation)

Critical Issues

  1. Archived dependencies — both henrybear327/go-proton-api and StollD/proton-drive are single-contributor, archived
  2. panic(err) on init failures — no graceful degradation
  3. Headless auth unsupported — interactive --login only
  4. Token expiry = os.Exit(1) — hard abort

1.6 proton-tui (cdump)

Location: github.com/cdump/proton-tui Stars: ~12 | License: MIT | Language: Rust | Version: v0.3.0

Auth — Standalone Rust SRP-6a Implementation

The auth.rs module (~500 lines) is the single most reusable piece for Hermes-proton.

Flow:

  1. POST /auth/info → extract modulus from PGP signed response body
  2. SrpClient::new(modulus) → generate random 256-bit a
  3. Password hashing: bcrypt (cost 10, $2y$) + pm_hash() (4×SHA-512 extend to 2048 bits)
  4. SRP-6a math: u = H(A,B), S = (B - k*g^x)^(a+u*x) mod N, client proof M = H(A,B,K)
  5. POST /auth → verify, handle 2FA

Reusable functions:

  • pm_hash — Proton's custom 2048-bit hash (4 SHA-512 rounds with suffixes 0x00-0x03)
  • hash_password — bcrypt + PMHash combined
  • verify_server_proof — constant-time comparison
  • PGP modulus extraction — parse clearsigned response

Dependencies: num-bigint, sha2, bcrypt, base64, reqwest — all standard crates

VPN Connection — WireGuard Only

  • Key generation: Ed25519 SigningKey → X25519 via SHA-512 + bit clamping
  • Certificate registration: POST /vpn/v1/certificate with ED25519 public PEM
  • Connection: sudo wg-quick up <config> with runtime/saved config targets
  • Disconnection: sudo wg-quick down <config>

Token Management

  • Storage: ~/.config/proton-tui/tokens.json (0o600 on Unix)
  • Struct: StoredTokens { uid, access_token, refresh_token }
  • Clear: Menu option (deletes file)
  • Conversion: impl From<AuthResult> for StoredTokens

1.7 openclaw-protonmail-skill (rvacyber)

Location: github.com/rvacyber/openclaw-protonmail-skill Stars: 16 | License: MIT | Language: TypeScript | Version: v1.0.1 (2026-04)

Skill Structure — Direct Hermes Reference

SKILL.md              # OpenClaw manifest (YAML frontmatter)
src/
  index.ts            # ProtonMailSkill class — orchestrator
  imap.ts             # IMAPClient — read/search operations
  smtp.ts             # SMTPClient — send/reply operations
  tools.ts            # OpenClaw tool registrations + TOOL_DEFINITIONS
bin/protonmail        # CLI entry (Node.js shebang)

Bridge Connection Pattern (Directly Transferable)

// IMAP (read path) — 127.0.0.1:1143, TLS, rejectUnauthorized: false
// SMTP (write path) — 127.0.0.1:1025, STARTTLS (secure: false), rejectUnauthorized: false
// Always enforce localhost-only host validation

Operations

Method What It Does Key Implementation Detail
listInbox(limit, unreadOnly) List recent messages Search ALL or UNSEEN, sort by UID desc, fetch headers
search(query, limit) Search with syntax Parse from:, subject:, body:, newer_than: filters
readMessage(messageId) Full email content UID fetch + mailparser; messageFound + fetch.end hang prevention
send(to, subject, body, options) Send new email Plain text + optional HTML/CC/BCC/attachments via nodemailer
reply(originalMessage, body) Reply with threading RFC 5322 In-Reply-To/References headers

Search Sanitization (Security Pattern)

  • Length limit: 200 chars
  • Character allowlist: [a-zA-Z0-9@._+\-\s:]
  • No CR/LF/control chars
  • Unrecognized queries → safe subject keyword search fallback

Config & Env

# SKILL.md metadata
requires:
  env: [PROTONMAIL_ACCOUNT, PROTONMAIL_BRIDGE_PASSWORD]
PROTONMAIL_ACCOUNT=user@pm.me
PROTONMAIL_BRIDGE_PASSWORD=<bridge-app-password>

Transferable config pattern: env vars with config-override fallback; same naming scheme for Hermes (HERMES_PROTON_ACCOUNT, HERMES_PROTON_BRIDGE_PASSWORD).

Security Evolution (v0.1.0 → v0.1.1)

  • v0.1.0: TLS bypass without localhost enforcement
  • v0.1.1: Hosts validated against ['127.0.0.1', 'localhost', '::1']
  • Hermes-proton must follow the hardened pattern

2. Cross-Cutting Patterns

2.1 Auth Strategy Comparison

Approach Projects Pros Cons
SRP Direct hydroxide, rclone, proton-cli, proton-webdav, proton-tui No dependency; full API access; all products Complex implementation; 2FA handling; CAPTCHA required; token refresh logic
Bridge Protocol pm-cli, openclaw-skill No crypto needed; no 2FA; no CAPTCHA; stable IMAP/SMTP Mail only; Bridge dependency; self-signed TLS; local process only

Recommendation for Hermes-proton: Support both paths — Bridge for mail (fastest path, proven), SRP for Calendar/Drive/Pass/VPN (via go-proton-api or proton-cli patterns).

2.2 SRP Implementation Details (Consensus Across Projects)

  1. Go standard: ProtonMail/go-srp — official library, used by 4/4 Go projects
  2. Rust alternative: num-bigint + sha2 + bcrypt — standalone impl in proton-tui/auth.rs
  3. Key derivation: bcrypt (cost 10, $2y$) → 4×SHA-512 (expand to 2048 bits) → modulus operations
  4. Modulus verification: PGP clearsigned modulus response verified against Proton's hardcoded public key
  5. 2FA: Bitmap check (Enabled & 1); TOTP only in all projects
  6. CAPTCHA: Only roman-16/proton-cli has a solution (embedded webview helper)

2.3 Token/Session Persistence Patterns

Project Location Encryption Format
hydroxide ~/.config/hydroxide/auth.json NaCl secretbox (XSalsa20-Poly1305) JSON map
proton-cli ~/.config/proton-cli/sessions/<profile>.json Filesystem perms (0600) JSON
proton-webdav $XDG_DATA_HOME/proton-webdav-bridge/tokens.json Filesystem perms (0600) JSON
proton-tui ~/.config/proton-tui/tokens.json Filesystem perms (0600) JSON
pm-cli OS keyring (libsecret/Keychain) Platform keyring N/A

Recommendation: Use OS keyring for Bridge password (pm-cli pattern); encrypt cached tokens with NaCl secretbox if stored on disk (hydroxide pattern).

2.4 Error Handling Patterns

Pattern Found In Details
401 auto-retry with refresh hydroxide, proton-cli, rclone Single retry with ReAuth callback
Typed error hierarchy proton-cli, pm-cli, hydroxide APIError, ExitError, WrongTableError
Cross-table probing proton-cli 422 → probe opposite table
Exit code mapping proton-cli 0-130 typed codes
Structured JSON errors pm-cli {"success": false, "error": "..."}
429 not handled All projects Gap for production — no project implements 429 backoff

2.5 Crypto Stack

Component Standard Library Used By
OpenPGP (X25519) go-crypto / gopenpgp v2 hydroxide, rclone, proton-cli, proton-webdav
Symmetric encryption NaCl secretbox (XSalsa20-Poly1305) hydroxide (session storage)
AES-256-GCM Standard library proton-cli (Pass items)
Card encryption OpenPGP + signing proton-cli, hydroxide
Key derivation bcrypt + SHA-512 All SRP-based projects

3. Critical Risks

3.1 Archived Dependencies

Two projects that use SRP direct for Drive (rclone protondrive, proton-webdav-bridge) depend on archived libraries:

  • henrybear327/Proton-API-Bridge — archived Feb 2026
  • henrybear327/go-proton-api — archived Feb 2026
  • StollD/proton-drive — single-contributor

Mitigation: Use roman-16/proton-cli's approach instead (direct go-proton-api from ProtonMail, or use the official Proton Go SDK).

3.2 No 429 Handling

None of the 7 projects implement explicit rate-limit backoff. For a production agent making many API calls, this is a gap that must be filled.

3.3 Headless CAPTCHA

Only roman-16/proton-cli handles CAPTCHA (via embedded webview helper). For headless agent environments, CAPTCHA is a blocker unless using the Bridge path (which bypasses CAPTCHA entirely).

3.4 2FA Limitations

  • Token refresh failure + 2FA enabled = cannot auto-re-auth (hydroxide)
  • Only TOTP supported; U2F/WebAuthn unimplemented in all projects
  • Bridge path avoids 2FA entirely

4. Recommendations for Hermes-Proton

4.1 Architecture

Adopt roman-16/proton-cli's 3-tier layered architecture:

  1. Plugin layer (Komodo plugin) — auth lifecycle, session management, shared state
  2. Service layer (Hermes skills) — per-product tool collections
  3. Transport layer — Bridge (mail) + SRP direct (Calendar/Drive/Pass/VPN)

4.2 Auth Paths

Path A: Bridge (mail only)

  • OpenClaw-skill pattern: IMAP 127.0.0.1:1143 + SMTP 127.0.0.1:1025
  • Env vars: HERMES_PROTON_ACCOUNT, HERMES_PROTON_BRIDGE_PASSWORD
  • Localhost-enforced TLS with self-signed cert acceptance
  • OS keyring for credential storage (pm-cli pattern)

Path B: SRP Direct (all products)

  • roman-16/proton-cli's auth flow as reference
  • go-srp for Go-based components
  • proton-tui's auth.rs for Rust-based components
  • NaCl secretbox encrypted token cache (hydroxide pattern)
  • Cross-table error probing for ID resolution

4.3 Agent-Friendly Output (pm-cli patterns)

  • Universal --json flag with {"success": true, "data": {...}} envelope
  • --help-json for tool introspection
  • Idempotency keys for mutation operations
  • Semantic subcommands (summarize, extract)
  • Consistent exit codes

4.4 Must-Avoid

  • Do NOT vendor archived henrybear327 libraries (use official ProtonMail/go-srp + go-proton-api)
  • Do NOT skip 429 handling
  • Do NOT allow non-localhost TLS bypass (follow openclaw-skill's hardening)
  • Do NOT hard-code single-protocol assumptions (support both Bridge and SRP)

4.5 Key File Locations to Reference

Pattern Source Project File
SRP auth (Go) hydroxide protonmail/auth.go, protonmail/srp.go
SRP auth (Go, idomatic) proton-cli internal/api/auth.go
SRP auth (Rust) proton-tui src/auth.rs
NaCl session storage hydroxide auth/auth.go
Bridge IMAP client openclaw-skill src/imap.ts
Bridge SMTP client openclaw-skill src/smtp.ts
Agent-friendly output pm-cli internal/output/formatter.go
Error classification proton-cli internal/app/app.go
Card encryption proton-cli internal/pgp/cards.go
Drive encryption proton-webdav entire proton-drive library
Session persistence proton-tui src/tokens.rs
Multi-profile config proton-cli internal/config/

5. Dependency Matrix for Hermes-Proton

Component Recommended Library Version Source
Go SRP github.com/ProtonMail/go-srp v0.0.7 Official
Go API Client github.com/ProtonMail/go-proton-api latest Official
OpenPGP/Crypto github.com/ProtonMail/go-crypto v1.4.1 Official
Go OpenPGP (high-level) github.com/ProtonMail/gopenpgp/v2 v2.10.0 Official
Rust SRP num-bigint + sha2 + bcrypt latest proton-tui auth.rs pattern
Node IMAP imap latest openclaw-skill pattern
Node SMTP nodemailer latest openclaw-skill pattern
Node Mail Parse mailparser latest openclaw-skill pattern
OS Keyring (Go) zalando/go-keyring latest pm-cli pattern
Embedded DB go.etcd.io/bbolt v1.4.3 hydroxide pattern
Webview (Go) webview/webview proton-cli HV pattern