Inbox Management

Email

Ongoing Gmail inbox management via scheduled runs. Archives known noise, flags urgent items, drafts replies in-thread (never auto-sends), and catches stale follow-ups.

Install
assistant skills install inbox-management

compatibility:Designed for Vellum personal assistants
metadata.vellum.includes:["gmail"]

Inbox Management Skill

Companion to inbox-cleanup. Cleanup drains the backlog once. Management keeps the inbox clean on a schedule — archiving noise, flagging urgents, drafting replies, and catching stale follow-ups.

Runs as a scheduled task (via the schedule skill). Each run should be silent unless something is worth interrupting the user for.

Default posture: high recall on noise archiving, high precision on user interruption. Archive aggressively on known-safe patterns. Ping sparingly. Never auto-send a reply. When unsure, flag instead of archiving.


Trust Ladder

A single wrong archive of an important email kills trust. Earn autonomy in stages:

StageArchive behaviorDraft behaviorAlerts
0 — Flag-only (default)Nothing archived. All archive calls use --dry-run. Summary shows what would be archived for user review.Drafts created in-thread, listed in summary.Urgent scan active.
1 — StandardSilent archive of known-safe categories only (calendar responses, no-reply, newsletters). Cold outreach still flagged. Batches > 1,000 ops auto-dry-run.Drafts created in-thread, summarized per run.Urgent scan active.
2 — AggressiveAbove + cold outreach archived by LLM judgment (default archive, flag only when relevant to user). All ops logged for reversal.Same as Stage 1.Urgent scan active.

Graduation requires the user to explicitly say "graduate me" or equivalent. Do not infer from silence.

Never auto-send a draft. No toggle for this rule.


Setup (one-time, before enabling schedule)

0. Informed consent

Before anything else, explain what the user is opting into. Be direct:

"Here's what inbox management does: on a schedule you choose (e.g. every few hours on weekdays), I'll scan your inbox and take action based on a trust level you control.

Stage 0 (where everyone starts): I watch but don't touch. I'll tell you what I would archive, show you draft replies I wrote, and flag urgent items — but I won't move or delete anything. This lasts until you explicitly tell me to graduate.

Stage 1 (you opt in): I silently archive obvious noise — calendar responses, no-reply senders, newsletters. Everything else is still flagged for your review.

Stage 2 (you opt in): I also archive cold outreach using my judgment. Higher autonomy, slightly higher risk of a wrong call.

At every stage: I will never send an email on your behalf. I create drafts for you to review. You can pause or stop this at any time."

Wait for explicit confirmation before proceeding. If the user hesitates or asks clarifying questions, answer them — don't rush past this step.

1. Stage

Start at Stage 0. Store via gmail-prefs.ts --action set-management-config --stage 0.

2. Safe-list

Ask for senders/domains that may look like outreach but matter. Seed categories:

  • Financial advisors, lawyers, accountants
  • Active investors and VCs
  • Customer domains
  • Family/personal contacts
  • Paid subscriptions (billing addresses)

Store via gmail-prefs.ts --action add-safelist --emails "...". The safe-list is shared with inbox-cleanup.

3. Interrupt threshold

Default urgency bar for alerts:

  • Customer at risk (churn, renewal, escalation)
  • Investor/board with time-sensitive ask
  • Legal/compliance deadline
  • Team member flagging urgency
  • Explicit markers ("EOD today", "ASAP", "urgent") from real humans

Store threshold level via gmail-prefs.ts --action set-management-config --interrupt-threshold "default".

4. Schedule

Create a recurring schedule via schedule_create:

  • Default: 0 */3 * * 1-5 (every 3 hours on weekdays)
  • Message: "Load the inbox-management skill and run the inbox management pipeline."
  • Mode: execute
  • Set reuse_conversation: true for context accumulation across runs

Confirm cadence with user. Overnight: urgent-scan only.

5. Voice profile

Run messaging_analyze_style on the user's recent sent mail. Store the style profile in the Personal Knowledge Base for draft generation.

6. Draft preference

Confirm the user wants drafts generated. Some prefer flag-only forever.


Pipeline (each scheduled run)

Each step is silent unless something qualifies for interrupt. Run these in order.

Step 0: Missed-run check & resume

Resume interrupted runs first. Before starting a new pipeline pass, check bun run scripts/gmail-runs.ts list. If the most recent run has status: "interrupted", resume it via bun run scripts/gmail-archive.ts archive --resume "<run-id>" before proceeding. Also run bun run scripts/gmail-runs.ts prune to clean up logs older than 30 days.

Read the last-run timestamp via gmail-prefs.ts --action get-management-config. If last-run is more than 2x the scheduled interval ago (e.g. >6 hours for a 3-hour schedule), notify the user:

  • Slack: "📬 Inbox management hasn't run since [time]. I'm catching up now."
  • No Slack: In-app notification.

Then update last-run to now via gmail-prefs.ts --action set-management-config --last-run "..." before continuing.

Step 1: Archive known noise (Stage 1+ only)

Run these queries via gmail-archive.ts --action archive --query "..." and bulk archive results:

subject:(Accepted: OR Declined: OR Tentative: OR "has accepted" OR "has declined") in:inbox
from:(noreply OR no-reply OR donotreply) in:inbox
subject:("newsletter" OR "weekly digest" OR "monthly digest") in:inbox

Cross-check the safe-list before each batch. Use gmail-prefs.ts --action list to load the safe-list. Remove any safe-listed sender from the batch before archiving.

Stage 0: Collect results but do not archive. Include in summary with "would archive" label.

Step 2: Cold outreach judgment (Stage 2: archive / Stage 0-1: flag)

Use gmail-scan.ts --action outreach-scan to identify cold outreach senders. For each result, judge: is this person/offer potentially relevant to the user?

  • Relevant → leave in inbox, include in summary
  • Not relevant → archive (Stage 2) / flag as "would archive" (Stage 0-1)

Step 3: Urgent scan (all stages)

Search in:inbox is:unread newer_than:1d. Scan each for urgency signals:

SignalWhy
"past due", "overdue", "final notice", "balance due"Financial consequence
"will be suspended", "service interruption", "account closure"Operational consequence
"signature required", "agreement", "DocuSign pending" from real senderLegal action needed
.gov domain, "IRS", "state of", "department of"Regulatory
Safe-list sender with deadline languageKnown-important, urgent framing

If any qualify, send one alert:

  • Slack connected: Slack DM with 🚨 urgent email — count + per-item bullets (sender · subject · why)
  • Slack not connected: In-app notification via notification pipeline
  • If nothing qualifies: skip silently. Never ping just to ping.

Step 4: Draft replies (all stages, if enabled)

Search in:inbox is:unread newer_than:7d. Filter out anything caught by Steps 1-2, calendar responses, receipts, no-reply senders, one-way FYIs.

For each remaining email from real humans expecting a response:

  1. Check for existing draft in the thread — call list_drafts, filter results by thread ID. If draft exists, skip.
  2. Read full thread context via get_thread.
  3. Decide: does this need a reply? If no, skip.
  4. Create draft in-thread via gmail-email.ts draft --thread-id "..." --in-reply-to "...". Draft must be fully written in the user's voice (use Personal Knowledge Base style profile), substantive, no placeholders. Never auto-send.

After the pass, send one summary:

  • Slack: [N] drafts ready for review: + per-item bullets
  • No Slack: In-app notification

Step 5: Follow-up scanner (all stages)

Search in:sent newer_than:14d. For each thread where the user sent the last message and no reply has arrived:

Ask: did this email clearly expect a response? Only flag if 2+ signals are present:

  • The email contains a direct question
  • The email proposes a meeting, call, or next step
  • The email requests a deliverable or decision
  • The recipient is on the safe-list (known-important contact)

Do not flag: cold outreach the user sent, intros where silence is normal, thank-yous, FYIs, one-line acknowledgments, or threads where the user's last message was itself a reply to a no-reply sender.

If yes, alert with: recipient, subject, date sent, and a ready-to-send follow-up draft.


Stage 0 Summary

At Stage 0, send one end-of-day summary (last scheduled run of working hours):

📬 Today's inbox (flag-only mode):

Would archive ([N]):
• [category]: [count] — [sample sender/subject]

Cold outreach flagged ([N]):
• [sender] · [subject] · relevant: [y/n]

Drafts ready ([N]):
• [sender] · [subject] — [one-line summary]

Follow-ups suggested ([N]):
• [recipient] · [subject] · sent [date]

User responds with:

  • "approve X" — graduates a category to auto-archive
  • "safe-list X" — permanently protects a sender/domain
  • "graduate me" — advances to Stage 1

Capture every correction — add protected senders to safe-list immediately.


Safe-List Rules

  1. Every batch archive cross-references the safe-list. No exceptions.
  2. Any user correction ("don't archive this") auto-adds to safe-list permanently.
  3. Supports exact sender (name@domain) and domain-level (example.com) matches.
  4. Safe-list entries never expire.
  5. Shared with inbox-cleanup — both skills read/write the same store via gmail-prefs.ts.

Integration

  • Run inbox-cleanup first. Management assumes the backlog is drained.
  • Auto-filters bridge the gap. Cleanup Phase 6 runs gmail-auto-filters.ts generate to propose Gmail filters for safe categories (no-reply, calendar, sketchy TLDs, confirmed newsletters). The user confirms before any filter is created. These filters prevent re-accumulation immediately — management Step 1 handles only what slips through.
  • Shared safe-list and blocklist via gmail-prefs.ts.
  • Filter dedup is automatic. If auto-filters already cover a category, management's archive queries for that category will return fewer (or zero) results. No coordination needed.
CreatorVellum
LicenseMIT
Updated1 month ago
SecurityVerified
View on GitHub

The Personal AI you were promised

GET STARTED