Skip to content

Instantly share code, notes, and snippets.

@mfellner
Created June 22, 2026 21:58
Show Gist options
  • Select an option

  • Save mfellner/fb908b9210d0ca793150dbdc96d32a71 to your computer and use it in GitHub Desktop.

Select an option

Save mfellner/fb908b9210d0ca793150dbdc96d32a71 to your computer and use it in GitHub Desktop.
hermes-proton-mail-runbook.md
# Hermes ⇄ Proton Mail Runbook
Set up the **Hermes agent** to **read and send Proton Mail**, on macOS, via
**Proton Mail Bridge** + the **himalaya** CLI (driven by Hermes' bundled
`himalaya` skill).
> Last verified: 2026-06-22 · macOS (Apple Silicon/arm64) · himalaya 1.2.0 · Hermes Agent v0.17.0
---
## How it fits together
```
Hermes agent ──runs──▶ himalaya CLI ──IMAP/SMTP(STARTTLS)──▶ Proton Mail Bridge ──▶ Proton servers
(himalaya skill) (config.toml) on 127.0.0.1 (self-signed cert)
```
- **Why himalaya, not the Email gateway:** Hermes' Email *gateway* is an inbox-bot
(people email the agent) and connects with implicit TLS (`IMAP4_SSL`) + cert
verification — it **cannot** talk to the Bridge (STARTTLS-only, self-signed cert).
The **himalaya skill** is a real IMAP/SMTP client the agent drives on demand =
"read/send my mail". This is the supported path.
- **Bridge runs on `127.0.0.1`**, so **Hermes must run on the same machine** as the
Bridge. (Remote Hermes would need an SSH tunnel to the Bridge ports.)
---
## ⚠️ Per-machine values (DO NOT copy blindly)
These three things are **different on every machine / Bridge install** — always
re-read them, never reuse the values below:
| Thing | Example value | Where to get the real value |
|---|---|---|
| **Your Proton address** | `you@proton.me` | Your own Proton account (may be `@proton.me`, `@protonmail.com`, or a custom domain). |
| **SMTP port** | `1026` (default is 1025 — but may differ!) | Bridge GUI → Settings, or `lsof -nP -iTCP -sTCP:LISTEN \| grep bridge`. Bridge auto-increments if the default port is already in use. |
| **IMAP port** | `1143` | same |
| **Bridge password** | *(per-install secret)* | Bridge GUI → click the account → "Mailbox configuration". **NOT** your Proton login password. |
| **TLS certificate** | self-signed, `CN=127.0.0.1`, `SAN: IP 127.0.0.1` | Unique per Bridge install; regenerated on cert reset. Step 3 always exports the *current* one. |
Stable values: host `127.0.0.1`, both IMAP+SMTP use **STARTTLS**, himalaya
account name **`proton`**. (Your Proton address goes in `config.toml`, Step 5.)
---
## Setup from scratch (new machine)
### 1. Proton Mail Bridge
Install <https://proton.me/mail/bridge>, launch it, log in to the Proton account,
and let it finish the initial sync. Note the IMAP/SMTP **host, ports, username,
password** from the Bridge GUI (Settings → the account → Mailbox configuration).
Confirm it's listening:
```bash
lsof -nP -iTCP -sTCP:LISTEN | grep bridge # note the IMAP + SMTP ports
```
### 2. Install himalaya
```bash
brew install himalaya # installs 1.2.0+
himalaya --version
```
### 3. Trust the Bridge's self-signed cert (macOS login keychain)
himalaya 1.2.0 has **no in-config cert option**; it uses `rustls-platform-verifier`,
which trusts the macOS keychain. The Bridge cert has `SAN: IP 127.0.0.1` + `CA:TRUE`,
so trusting it works. This step grabs whatever cert the Bridge is currently serving:
```bash
mkdir -p ~/.config/himalaya && chmod 700 ~/.config/himalaya
# Export the LIVE bridge cert (adjust 1143 if your IMAP port differs)
openssl s_client -connect 127.0.0.1:1143 -starttls imap </dev/null 2>/dev/null \
| openssl x509 -outform PEM > ~/.config/himalaya/proton-bridge.pem
# Trust it for SSL in the login keychain (may pop a Touch ID / password dialog — approve it)
security add-trusted-cert -r trustRoot -p ssl \
-k ~/Library/Keychains/login.keychain-db \
~/.config/himalaya/proton-bridge.pem
# Verify
security verify-cert -c ~/.config/himalaya/proton-bridge.pem -p ssl -s 127.0.0.1
# → "...certificate verification successful."
```
### 4. Store the Bridge password (0600 file, no newline)
```bash
printf '%s' 'PASTE-BRIDGE-PASSWORD-HERE' > ~/.config/himalaya/proton-bridge-password
chmod 600 ~/.config/himalaya/proton-bridge-password
```
### 5. Write `~/.config/himalaya/config.toml`
Adjust `email`, IMAP `port`, and SMTP `port` for this machine.
```toml
[accounts.proton]
email = "you@proton.me"
default = true
# --- IMAP (reading) ---
backend.type = "imap"
backend.host = "127.0.0.1"
backend.port = 1143
backend.encryption.type = "start-tls"
backend.login = "you@proton.me"
backend.auth.type = "password"
backend.auth.cmd = "cat ~/.config/himalaya/proton-bridge-password"
# --- SMTP (sending) ---
message.send.backend.type = "smtp"
message.send.backend.host = "127.0.0.1"
message.send.backend.port = 1026
message.send.backend.encryption.type = "start-tls"
message.send.backend.login = "you@proton.me"
message.send.backend.auth.type = "password"
message.send.backend.auth.cmd = "cat ~/.config/himalaya/proton-bridge-password"
# --- Folder aliases (himalaya canonical names -> Proton folder names) ---
folder.aliases.inbox = "INBOX"
folder.aliases.sent = "Sent"
folder.aliases.drafts = "Drafts"
folder.aliases.trash = "Trash"
```
```bash
chmod 600 ~/.config/himalaya/config.toml
```
### 6. Test himalaya (note: account flag goes AFTER the subcommand)
```bash
himalaya folder list -a proton # should list INBOX, Sent, Drafts, ...
himalaya envelope list -a proton --page-size 5
himalaya message read <id> -a proton
```
> A harmless `WARN ... Rectified faulty continuation request` from imap_codec is a
> Proton Bridge quirk — ignore it.
### 7. Install Hermes — use the OFFICIAL installer (not Homebrew)
The official uv-based installer ships the full Python deps and seeds all bundled
skills, avoiding the Homebrew breakages (see Troubleshooting).
```bash
# Fresh machine (lets it run the setup wizard for API keys):
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash
# Re-install on an ALREADY-configured machine (skip the wizard):
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash -s -- --skip-setup
# If migrating off Homebrew first:
brew uninstall hermes-agent # ~/.hermes and ~/.config/himalaya are NOT touched
```
Installs to `~/.hermes/hermes-agent`, command linked at `~/.local/bin/hermes`.
Then `source ~/.zshrc` (or open a new terminal).
### 8. Confirm the bundled himalaya skill is enabled
The official installer seeds it automatically as a **builtin** skill:
```bash
hermes skills list | grep himalaya # → himalaya │ email │ builtin │ builtin │ enabled
```
If it's missing: `hermes skills opt-in --sync`
### 9. End-to-end verification
```bash
# himalaya reaches the mailbox
himalaya folder list -a proton
# Hermes agent uses the skill (one-shot, read-only):
hermes -z "Using himalaya with account 'proton', list my Proton email folder names."
```
---
## File inventory
| Path | What |
|---|---|
| `~/.config/himalaya/config.toml` | himalaya account config (no secrets) |
| `~/.config/himalaya/proton-bridge-password` | Bridge password, `chmod 600` |
| `~/.config/himalaya/proton-bridge.pem` | exported Bridge cert (trusted in keychain) |
| `~/.hermes/` | Hermes config (`config.yaml`), secrets (`.env`), sessions, skills — **survives reinstalls** |
| `~/.hermes/skills/email/himalaya/` | the bundled himalaya skill (`SKILL.md` + `references/`) |
| `~/.local/bin/hermes` | the `hermes` command (official install) |
---
## Troubleshooting / recovery after an update
### Bridge cert no longer trusted → himalaya TLS errors
Symptom: `verify-cert` shows `CSSMERR_TP_NOT_TRUSTED`, or himalaya fails to connect.
Cause: Bridge was reinstalled / cert reset → new cert. **Re-do Step 3** (re-export +
re-trust). Optionally remove the stale entry first:
```bash
sudo security delete-certificate -c 127.0.0.1 ~/Library/Keychains/login.keychain-db 2>/dev/null
```
### IMAP/SMTP port changed
After a Bridge reinstall the ports can move (esp. SMTP). Re-check with
`lsof -nP -iTCP -sTCP:LISTEN | grep bridge` and update `config.toml`.
### himalaya skill shows source `url` instead of `builtin`
(Happens if it was hand-installed from a URL.) Make it the bundled one:
```bash
hermes skills reset himalaya --restore --yes
# If it STILL shows 'url', remove the stale hub entry:
python3 - <<'PY'
import json,os
p=os.path.expanduser("~/.hermes/skills/.hub/lock.json")
d=json.load(open(p)); d.get("installed",{}).pop("himalaya",None)
json.dump(d,open(p,"w"),indent=2)
PY
hermes skills list | grep himalaya # → builtin
```
### `No module named 'websockets'` (Homebrew installs only)
The Homebrew formula omitted it; the official installer includes it. Quick fix:
```bash
<hermes-venv>/bin/python -m pip install 'websockets==15.0.1'
```
Better fix: reinstall via the official installer (Step 7).
### `agent-browser` → `Volta error: Could not execute command` (Homebrew installs)
Volta's shim symlink dangles into a deleted temp dir. The official installer
reinstalls agent-browser cleanly. Manual repair if needed:
```bash
ln -sf ~/.volta/tools/image/packages/agent-browser/lib/node_modules/agent-browser/bin/agent-browser-darwin-arm64 \
~/.volta/tools/image/packages/agent-browser/bin/agent-browser
agent-browser --version
```
### Gateway started but shows tool warnings
Restart it after fixing the above so it reloads modules:
```bash
hermes gateway # or: hermes gateway install (run as a service)
```
---
## Quick reference
```bash
himalaya envelope list -a proton # list inbox
himalaya envelope list -a proton from x@y.com # search
himalaya message read <id> -a proton # read
himalaya message write -H "To:x@y.com" -H "Subject:Hi" "body" # send
himalaya folder list -a proton # folders
# Ask Hermes naturally: "summarize my 5 latest Proton emails", "reply to ...", etc.
```
Key gotchas: **SMTP port ≠ 1025** (check it) · **Bridge password ≠ Proton password** ·
**cert must be trusted in keychain** · **himalaya `-a proton` goes after the subcommand** ·
**use the official Hermes installer, not Homebrew**.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment