agentleFS
larchankalarchanka/skills/email-triage/SKILL.md

email-triage

Skill50 starsChanged 7 days agoMITView on GitHub

Autonomous multi-agent email triage system powered by Google Workspace CLI (gog). Discovers accounts dynamically, prioritizes the default account, delegates each thread to an isolated sub-agent for classification and state management, and safely creates draft replies and applies triage labels without raw CLI execution.

13 other projects use a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

9 rules. 0 are common, 4 are distinctive, and 5 are very specific to this project.

  • 0

    Common

    Most of the 12 edited versions we read keep these.

  • 4

    Distinctive

    This author's own choices. Worth a look.

  • 5

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Multi-Account Discovery: All accounts with active Gmail access are detected via gog auth list --json.

    line 32
  2. Distinctive:

    When a user requests an email triage or inbox sweep, the Orchestrator Agent executes this 4-step protocol:

    line 39
  3. Very specific:

    Run ./scripts/scan_inbox.py across all accounts (or a specific account if explicitly requested by the user):

    line 55
  4. Distinctive:

    If specific query or limit is required:

    line 59
  5. Very specific:

    Prompt: Follow the Sub-Agent Prompt Template below, providing the thread_id, owning account, and subject snippet.

    line 67
  6. Distinctive:

    If an immediate response is helpful, draft a proposed reply (never auto-send!):

    line 95
  7. Distinctive:

    When invoking sub-agents from the orchestrator, pass this exact template:

    line 114
  8. Very specific:

    All scripts support -h / --help and reside in ./scripts/.

    line 148
  9. Very specific:

    Simulation via Dry-Run: All mutating scripts support --dry-run (-n) to preview actions safely.

    line 216

“Common” is measured: kept by at least 6 in 10 of the 12 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Email Triage Skill

An autonomous, multi-account email triage system that organizes, classifies, and processes Gmail inboxes. It orchestrates a multi-agent workflow where an orchestrator agent discovers emails across accounts and delegates individual threads to specialized triage sub-agents.

[!IMPORTANT] Strict Tool Policy: No Direct Raw CLI Fallback Under NO circumstances should an agent invoke raw gog CLI commands directly (e.g., gog gmail ...). All interactions with Gmail MUST be executed exclusively through the curated Python scripts located in: ./scripts/

This safeguards credentials, eliminates accidental bulk deletions or unexpected auto-sends, ensures proper character encoding, strips tracking/boilerplate noise, and standardizes multi-account handling.


Architecture & Multi-Account Protocol

Dynamic Account Discovery

The system avoids hardcoded accounts or aliases. It resolves accounts dynamically:

  1. Default Account Prioritization: The default account is discovered via gog auth status --json (or the GOG_ACCOUNT environment variable) and is always prioritized first.
  2. Account Aliases: Aliases configured in gog are queried via gog auth alias list --json (e.g. work_account, personal_account).
  3. Multi-Account Discovery: All accounts with active Gmail access are detected via gog auth list --json.
  4. All-Accounts Scanning: By default, scan_inbox.py iterates across all configured accounts in order (default account first). Every thread item is tagged with its owning "account".

Orchestrator Protocol

When a user requests an email triage or inbox sweep, the Orchestrator Agent executes this 4-step protocol:

flowchart TD
    A["User Request (Triage Inbox)"] --> B["Step 1: Scan Inboxes<br/>(scripts/scan_inbox.py)"]
    B --> C{"Threads Found?"}
    C -- No --> D["Report: Inbox Zero Reached"]
    C -- Yes --> E["Step 2 & 3: Delegate to Sub-Agents<br/>invoke_subagent for each thread"]
    E --> F["Sub-Agent: Read Thread<br/>(scripts/read_email.py)"]
    F --> G["Sub-Agent: Classify<br/>(references/classification_rules.md)"]
    G --> H["Sub-Agent: Apply Actions & Drafts<br/>(apply_triage.py / draft_reply.py)"]
    H --> I["Sub-Agent: Return Thread Summary"]
    I --> J["Step 4: Master Triage Report<br/>Synthesize Table for User"]

Step 1: Scan Inboxes

Run ./scripts/scan_inbox.py across all accounts (or a specific account if explicitly requested by the user):

python3 ./scripts/scan_inbox.py --json

If specific query or limit is required:

python3 ./scripts/scan_inbox.py --query "is:unread in:inbox" --max 15 --json

Step 2: Delegate Each Thread to an Isolated Sub-Agent

For each thread discovered, launch an independent sub-agent using invoke_subagent:

  • Role: Thread Triage Agent
  • Prompt: Follow the Sub-Agent Prompt Template below, providing the thread_id, owning account, and subject snippet.

Running threads in isolated sub-agents ensures context window efficiency and eliminates cross-thread hallucination.

Step 3: Thread Sub-Agent Workflow

Each sub-agent runs the following sequence:

  1. Read Classification Rules: Consult references/classification_rules.md and references/actions_policy.md.
  2. Fetch Thread Content:
    python3 ./scripts/read_email.py <thread_id> --account <account> --json
  3. Classify: Determine category:
    • SPAM: Unsolicited bulk marketing, phishing, unprompted vendor pitches.
    • REGULAR: Informational notifications, receipts, digests, low-urgency status updates.
    • NEEDS_ATTENTION: Direct requests from colleagues/clients, scheduled meetings, urgent blockers.
  4. Apply Triage Action:
    • For SPAM:
      python3 ./scripts/apply_triage.py <thread_id> --account <account> --trash
    • For REGULAR:
      python3 ./scripts/apply_triage.py <thread_id> --account <account> --mark-read --archive
    • For NEEDS_ATTENTION:
      python3 ./scripts/apply_triage.py <thread_id> --account <account> --add-label "Triage/Action-Needed"
      If an immediate response is helpful, draft a proposed reply (never auto-send!):
      python3 ./scripts/draft_reply.py <message_id> --account <account> --body "Proposed draft text..."
  5. Return Structured Summary: Communicate the result back to the orchestrator.

Step 4: Synthesize Master Triage Report

Once all sub-agents finish, the orchestrator compiles and displays the Master Triage Table:

AccountFromSubjectCategoryAction TakenDraft CreatedWeb Link
work_accountAlice <alice@co.com>Architecture ReviewNEEDS_ATTENTIONLabeled Triage/Action-NeededYes (Draft #1)Open
personal_accountNewsletter <news@info.com>Weekly DigestREGULARMarked read, ArchivedNoOpen
work_accountSpammer <promo@junk.io>Boost your leadsSPAMMoved to TrashNoOpen

Sub-Agent Prompt Template

When invoking sub-agents from the orchestrator, pass this exact template:

You are a Thread Triage Agent for thread `{{THREAD_ID}}` on account `{{ACCOUNT}}`.

Your goal is to inspect, categorize, and triage this single email thread according to the project's email triage policy.

Mandatory Rules:
1. NEVER run raw `gog` commands directly. ONLY use scripts in `./scripts/`.
2. NEVER send emails. Only create drafts if a reply is warranted.
3. For spam, use `--trash` (safe delete to Gmail Trash). NEVER use `--delete` unless explicitly authorized with `--force`.

Steps to execute:
1. Fetch the thread details:
   python3 ./scripts/read_email.py {{THREAD_ID}} --account {{ACCOUNT}} --json
2. Review classification rules:
   Read `references/classification_rules.md` and `references/actions_policy.md`.
3. Categorize into SPAM, REGULAR, or NEEDS_ATTENTION.
4. Execute corresponding action using `./scripts/apply_triage.py` (pass `--account {{ACCOUNT}}`).
5. If NEEDS_ATTENTION and a reply is expected, draft a professional response using:
   python3 ./scripts/draft_reply.py <message_id> --account {{ACCOUNT}} --body "<draft_text>"
6. Send your final report back to the orchestrator with:
   - Account
   - Thread ID
   - Sender & Subject
   - Classification category & 1-sentence rationale
   - Actions taken (labels modified, archived, trashed, draft created)
   - Web link to thread

Script Suite & Flag Reference

All scripts support -h / --help and reside in ./scripts/.

1. scan_inbox.py

Scans Gmail inboxes for matching threads across all accounts or a designated account.

FlagShortDefaultDescription
--query-qis:unread in:inboxGmail search query
--max-m10Maximum number of threads per account
--account-aAll accountsSpecific account alias/email (omit to scan all)
--json-jFalseStructured JSON output

2. read_email.py

Reads and decodes an entire email thread, stripping HTML noise, tracking pixels, and boilerplates.

FlagShortDefaultDescription
thread_id(Required)Gmail Thread ID to read
--account-aDefault accountSpecific account alias or email
--json-jFalseStructured JSON output

3. apply_triage.py

Applies label modifications, read status, archiving, or trashing to one or more threads.

FlagShortDefaultDescription
thread_ids(Required)One or more thread IDs
--mark-read-rFalseRemove UNREAD label
--archiveFalseRemove INBOX label
--trash-tFalseMove thread to Gmail Trash (safe deletion)
--deleteFalsePermanently delete thread (requires --force)
--force-fFalseConfirmation required for permanent deletion
--add-labelNoneOne or more labels to add
--remove-labelNoneOne or more labels to remove
--dry-run-nFalseSimulate action without modifying Gmail
--account-aDefault accountSpecific account alias or email
--json-jFalseStructured JSON output

4. draft_reply.py

Safely creates a draft reply in Gmail (never sends automatically).

FlagShortDefaultDescription
message_id(Required)Message ID to reply to
--body-bNoneReply text content
--body-file-FNoneFile path containing reply text
--reply-all-RFalseReply to all recipients
--dry-run-nFalsePreview draft without creating in Gmail
--account-aDefault accountSpecific account alias or email
--json-jFalseStructured JSON output

5. manage_labels.py

Inspects existing labels and sets up standard triage labels idempotently.

FlagShortDefaultDescription
--list-lFalseList all labels in the mailbox (default action)
--setup-sFalseEnsure Triage/Action-Needed, Triage/Waiting, Triage/FYI exist
--dry-run-nFalseSimulate setup without creating labels
--account-aDefault accountSpecific account alias or email
--json-jFalseStructured JSON output

Safety Guarantees & Policies

  1. No Accidental Send: There is no script to send emails. Only draft creation (draft_reply.py) is provided.
  2. Safe Deletion: Unwanted or spam messages are moved to Trash via --trash. Permanent deletion (--delete) requires explicit --force.
  3. Simulation via Dry-Run: All mutating scripts support --dry-run (-n) to preview actions safely.
  4. Clean Content Extraction: Text extraction strips tracking web bugs (1x1 pixels), CSS styling, script tags, and disclaimers, protecting token context from inflation.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.