Run a repeatable daily and weekly inbox triage operating system on the user's email account: batch windows, a reply/delegate/archive/unsubscribe decision matrix, unsubscribe sweeps with real search operators, and delegation-cue detection. Triggers when someone asks to clean up their email, set up inbox triage, tame newsletters, or keep a mailbox at zero.
./install.sh inbox-zero-systemsname: "inbox_zero_systems" description: "Run a repeatable daily and weekly inbox triage operating system on the user's email account: batch windows, a reply/delegate/archive/unsubscribe decision matrix, unsubscribe sweeps with real search operators, and delegation-cue detection. Triggers when someone asks to clean up their email, set up inbox triage, tame newsletters, or keep a mailbox at zero." metadata: { "includeInPrompt": true }
Give the user an operating system for their mailbox, not a one-time cleanup. The agent runs recurring triage batches against the user's email (Gmail or Outlook style): scan new mail, classify each message with a fixed decision matrix, take the safe actions, draft the rest, and run a weekly unsubscribe sweep. This is the receiver side: what to do with mail that arrives. It does not cover sender-side deliverability (SPF, DKIM, warmup) or writing newsletters.
messages.json (one object per message: id, sender, subject, snippet, days_old, opened_recently, has_unsubscribe, is_promo). Run the triage script to get a first-pass plan, then review every decision yourself. The script is a sketch aid, not a verdict.| Window | When | Timebox | Scope | |---|---|---|---| | Morning sweep | Start of workday | 25 min | Everything since last close; end with inbox empty or an explicit carry-over list | | Midday window | After lunch | 15 min | New arrivals only since the morning sweep | | End-of-day close | End of workday | 10 min | Check the reply queue, set tomorrow's follow-ups, confirm zero or carry-overs | | Weekly sweep | Friday or Monday | 30 min | Unsubscribe queries, filter audit, delegation review |
| Action | When the message ... | Agent does | |---|---|---| | reply | Asks the user a direct question, needs their decision or sign-off, or names a deadline | Draft the reply; priority "today" when an urgency word or date is present | | delegate | Contains an ask that belongs to someone else (see cues below) | Draft a handoff naming the owner, the ask, and the deadline; send only on approval | | archive | Is a notification with no action needed: receipts, shipping, password changes, FYI with no ask | Archive (and label if the user keeps a label system), Tier A | | unsubscribe | Is promo/newsletter mail with an unsubscribe link, unopened for 2+ weeks | Propose it; unsubscribe only on approval or standing directive | | read-later | Is promo the user still opens, or has no clear signal | Batch into a weekly digest read; never archive mail you cannot classify |
Treat as delegation candidates when the snippet contains any of these, or when the user is CC'd and never named:
A delegation draft states three things: who owns it, what the ask is, and by when. Without all three, it stays a proposal.
These operators are stable and safe to quote. Adjust the age windows to the user's tolerance.
"unsubscribe" category:promotions older_than:30d (promo mail piling up)"unsubscribe" -is:starred older_than:90d (old list mail never starred)from:(newsletter OR digest OR deals OR offers) older_than:60dcategory:updates "unsubscribe" older_than:90dFor each hit, check open history: unopened for 2+ weeks and carrying an unsubscribe link goes on the proposal list. Mail the user still opens stays, and gets read in the weekly digest batch instead. Outlook web supports similar filters (from:, to:, subject:, hasattachments:, received:); confirm the exact syntax in the user's client before relying on it, expected shape may differ.
Save the block below as triage_plan.py in your working directory, then run python3 triage_plan.py messages.json. It reads the message list and prints a JSON plan with one action, priority, and reason per message. Review the plan before acting on it.
python
#!/usr/bin/env python3
"""triage_plan.py: turn a message list into a concrete triage plan.
Usage: python3 triage_plan.py messages.json
Input: JSON array of {id, sender, subject, snippet, days_old,
opened_recently, has_unsubscribe, is_promo}
Output: JSON array of {id, subject, action, priority, reason}
Actions: reply, delegate, archive, unsubscribe, read-later
"""
import json
import re
import sys
DELEGATE_RE = re.compile(
r"\b(can you|could you|please (handle|send|review|forward|take care of))\b"
r"|\baction (required|needed) from\b|\bfor your (review|approval|action)\b|\bfyi\b",
re.I,
)
REPLY_RE = re.compile(
r"\b(what do you think|your thoughts|need your (input|sign-?off|approval)|question for you)\b",
re.I,
)
URGENT_RE = re.compile(r"\b(urgent|asap|by (eod|cob|friday|monday|today)|deadline)\b", re.I)
NOISE_RE = re.compile(
r"\b(receipt|order (shipped|confirmed|delivered)|password (reset|changed)|"
r"weekly digest|do not reply|no-reply|shipment tracking)\b",
re.I,
)
BOT_SENDER_RE = re.compile(r"(no-?reply|donotreply|newsletter|digest|deals|offers|promo)", re.I)
def decide(m):
snippet = m.get("snippet", "")
sender = m.get("sender", "")
is_promo = m.get("is_promo", False)
opened = m.get("opened_recently", False)
unsub = m.get("has_unsubscribe", False)
age = m.get("days_old", 0)
if is_promo and unsub and not opened and age >= 14:
return ("unsubscribe", "normal", "promo mail, no opens in 2+ weeks")
if DELEGATE_RE.search(snippet):
return ("delegate", "normal", "message asks for an action that belongs to someone else")
if REPLY_RE.search(snippet):
pri = "today" if URGENT_RE.search(snippet) else "normal"
return ("reply", pri, "direct question or decision addressed to the user")
if is_promo and opened:
return ("read-later", "normal", "promo the user still opens; batch into weekly digest read")
if NOISE_RE.search(snippet) or (BOT_SENDER_RE.search(sender) and not is_promo):
return ("archive", "normal", "notification with no action needed")
return ("read-later", "normal", "no clear signal; needs human eyes")
def main(path):
msgs = json.load(open(path))
plan = []
for m in msgs:
action, priority, reason = decide(m)
plan.append(
{"id": m["id"], "subject": m["subject"], "action": action,
"priority": priority, "reason": reason}
)
print(json.dumps(plan, indent=2))
if __name__ == "__main__":
main(sys.argv[1])
Every batch run returns a short report with these parts, in this order:
A run is finished when the inbox is empty or every remaining message has a named carry-over.
publisher key 2e43c913833850e6d80f939677e3de76e806d47785c0f1caaca90f9d18c98e1e
No ratings yet — be the first to rate it.