You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This gist is a template for a Hermes email-triage skill and its helper scripts.
What is included
email-triage.SKILL.md — the main skill instructions
email-triage.heuristics.md — categorization heuristics/reference material
email-triage-fetch.sh — fetch unlabeled emails for triage
extract-newsletter-url.sh — extract canonical article URLs from newsletter emails
build-digest-email.sh — build an HTML digest email
fetch-sender-logo.sh — fetch and cache sender logos
How to set up Gmail Multiple Inboxes
In Gmail:
Go to Settings → See all settings → Inbox.
Set Inbox type to Multiple Inboxes.
Add these sections:
label:Login in:inbox → Login
label:Respond in:inbox → Respond
label:Action-Required in:inbox → Action Required
label:Review in:inbox → Review
label:Update in:inbox → Update or Newsletter
Set Maximum page size to 20 conversations.
Set Multiple inbox position to Above the inbox.
Save changes.
How to use the template
swap in your own account names, labels, and workflow choices
adapt the heuristics to your inbox and preferences
use the scripts as starting points for your own automation
Notes
This version uses placeholder identities and dummy addresses such as user@example.com. It is intended as a reusable example, not a live production config.
Setup screenshot
The screenshot file is also included separately in this gist as Z-GMAIL-MULTIPLE-INBOXES-SETUP.svg.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Decision rules for categorizing emails. Every email gets exactly one label.
Senders we've already unsubscribed from or set up auto-archive filters for are handled by Gmail filters — they won't appear in triage. These heuristics are for NEW emails that make it through.
Category Decision Tree
Ask these questions in order:
Is the email FROM the user's own address? (for example: user@example.com or ops@example.com) → SKIP — do not label. This is an outbound/sent email that hit the webhook.
Is it a login link, OTP, 2FA code? → Login
Does the user need to DO something? (pay, renew, fix, file, comply, accept/decline invite) → Action Required
Does the user need to REPLY to a person? → Respond
Is the sender trying to sell something the user didn't ask for? → To Unsubscribe
Is it a recurring machine-generated notification? (receipts, statements, tracking, scores, digests) → To Archive
Is it editorial/opinion content from a publication? → Newsletter
Is it a product changelog, service notification, event confirmation, or receipt? → Update
Is it interesting one-off content worth reading, or you're unsure? → Review
To Unsubscribe — Signals
Marketing from brands the user hasn't bought from recently
Senders with no unsubscribe header → block via auto-archive filter instead
To Archive — Signals
Transaction receipts (crypto, bank transfers, withdrawals)
Statement notifications ("statement is available", "payment scheduled")
Credit score updates (FICO, Experian)
Utility usage reports (electricity, gas)
Flight receipts
Check-in reminders
Bank connection confirmations (Plaid)
Shipping/delivery tracking
Automated monitoring alerts
Social media digest notifications ("recently posted")
Ride receipts (Lyft, Uber, Citi Bike)
Order confirmations and return notifications
Payment confirmations from known services
Class/workout booking confirmations and receipts
Filter rule: If a sender also sends emails the user needs (e.g., bank sends statements AND fraud alerts), the filter MUST include a subject pattern. Never blanket-filter mixed senders.
Newsletter — Signals
Newsletter = someone WROTE an article/essay/analysis you'd sit down and READ. The test: "Could this be a blog post?" If yes → Newsletter. If no → Update.
Editorial/opinion content from publications the user subscribes to
Industry thought leadership essays (AI, crypto, VC, tech)
The distinction: Newsletter has ORIGINAL WRITTEN CONTENT you'd read for insight. Update is a NOTIFICATION from a service/platform about something happening.
Update — Signals
Product changelogs and feature announcements
Service invoices/receipts (Vercel, etc.)
Event invitations and RSVPs (Luma, Cerebral Valley)
Reservation confirmations (restaurants, travel)
Platform migration/policy/ToS changes
Event/community logistics and coordination
Forwarded emails from family members — informational
Triage Gmail inbox — categorize and label every unread email, propose unsubscribes and auto-archive filters for approval. Use when asked to filter emails, triage inbox, clean up email, unsubscribe from senders, or create Gmail skip-inbox filters. Triggers on "filter my emails", "triage my inbox", "clean up my email", "unsubscribe", "email cleanup".
Email Triage
Every unread inbox email gets exactly one label. No email leaves without a category.
Labels
Content labels — one per email:
Respond (Label_58) — needs a reply from the user
Action Required (Label_59) — something to do, not a reply
Review (Label_65) — worth a look but not urgent; use when unsure about category
Important: The gog CLI does NOT handle -label:X syntax correctly — it can actually include matching results instead of excluding them. The script uses NOT label:X (which works) plus a post-filter as belt-and-suspenders.
For pagination, pass --page TOKEN from the previous result's # Next page: line.
2. Categorize
Read email-triage.heuristics.md and assign every email exactly ONE label. Use the decision tree.
3. Present
Show all emails grouped by category. Include:
Sender name + email
Subject line
Category + brief reason
For To Archive: include proposed filter (from:X subject:"Y")
Every email must have a category. No "Keep unlabeled" bucket.
Each newsletter gets: sender logo (inline base64), bold sender name, read time estimate, subject, and a 1-2 sentence AI summary. Links go to the actual article URL (not Gmail), extracted via:
Send via ops@example.com with --from "digest-bot@example.com". Label the digest as Review.
Logo cache
Sender logos cached in ~/.hermes/workspace/data/sender-logos/. Use ~/.hermes/workspace/scripts/fetch-sender-logo.sh <domain> to fetch missing ones. The build script handles base64 encoding inline.
Manual Triage = Full Pipeline
When a user asks to triage emails in a conversation (not the cron), always run the full pipeline — don't just label and archive.
In Hermes, if a personal email-triage cron job exists, trigger it with the cronjob tool after any labeling corrections. If no such job exists, run the digest steps inline yourself. Do not rely on legacy cron CLI commands from the old setup.
This ensures the digest email gets sent. Only do inline labeling for one-off corrections (relabels, unsubscribes, filter creation).
Key Rules
Every email gets a label. No exceptions.
Subject-specific filters. Never blanket-filter a sender that sends mixed email types.
Don't filter login/auth emails. Even if the sender also sends archivable content.
Unsubscribed = actually unsubscribed. Never apply it unless the action succeeded.
Conservative with unsubscribe. If unsure → Newsletter or To Read, not To Unsubscribe.
Archive after unsubscribing. Don't leave dead emails in inbox.
Archive existing matches after creating a new filter. Filters only apply to future emails.
Check for existing filters before creating duplicates: gog gmail settings filters list --account user@example.com --plain
Beehiiv = browser. curl gets 403. Use agent-browser.
POST for one-click. Some providers need POST, not GET. Try GET first, then POST if 404.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters