Inbox automation worker — three-pass automation. Pass 1 (Automations/archive): upgrades taxonomy filter to skip inbox. Pass 2 (Suppress): creates skip-inbox filter for uncategorized senders. Pass 3 (Automations/sub-label): splits a child label into a deeper sub-label by reading From+Subject heuristics. Trigger on 'triage', 'run automations', 'sub-label this sender', or 'split this label'.
Three-pass automation: archives, creates bare filters for new senders, and splits labels into deeper sub-labels.
Before running: confirm gws can create/delete filters for this account. If not set up or if filter calls return 403, invoke /inbox-atlas:setup first.
Pass 1 — Archive queue (trigger: Automations/archive):
User applies "Automations/archive" to a message
→ Worker finds the taxonomy child label on the same message (e.g. Newsletters/Misc)
→ Finds the filter whose action adds that child label id
→ Deletes filter, recreates with same criteria + action + removeLabelIds:["INBOX"]
→ batchModify: removeLabelIds:["INBOX"] for all matching inbox messages (retroactive backfill)
→ Strips "Automations/archive" from the message (queue drains)
→ If no taxonomy label found: adds "Suppress" label and strips "Automations/archive" (→ Pass 2)
Pass 2 — Suppress queue (trigger: Suppress, fallback for uncategorized senders):
Worker finds message with "Suppress" label
→ Extracts sender email from From: header
→ Creates a bare skip-inbox filter: criteria:{from: sender} + action:{removeLabelIds:["INBOX"]}
→ batchModify: archives all matching inbox messages
→ Strips "Suppress" from the message (queue drains)
Neither label is ever a permanent tag — treat each as a queue that must always empty.
# Preview — no changes
python3 scripts/suppress_worker.py --dry-run
# Process default account (~/.config/gws)
python3 scripts/suppress_worker.py
# Alternate account
python3 scripts/suppress_worker.py --config ~/.config/gws-second
# Custom trigger label name
python3 scripts/suppress_worker.py --label "MySuppressLabel"
Run on a cron (e.g. every 15 minutes via launchd) or on demand. Always dry-run first against a new account.
Automations/sub-label)Apply Automations/sub-label to any message that already has a taxonomy child label (e.g. Operations/Anthropic) to split it into a deeper sub-label automatically.
User applies "Automations/sub-label" to a message with Operations/Anthropic
→ Worker reads From address + Subject
→ Derives sub-label name via heuristics (subdomain patterns, subject keywords)
e.g. from:[email protected] → subdomain "mail" → "Auth"
→ Creates Operations/Anthropic/Auth with parent's color
→ Creates filter: criteria:{query:"from:mail.anthropic.com"} → add Operations/Anthropic/Auth
→ Updates Operations/Anthropic filter to exclude: -from:mail.anthropic.com
→ batchModify: swaps Operations/Anthropic → Operations/Anthropic/Auth on all matching messages
→ Strips Automations/sub-label
Sub-label name heuristics (in priority order):
| Signal | Pattern | Sub-label |
|---|---|---|
| Subdomain | mail, noreply, no-reply, accounts, login, auth, security | Auth |
| Subdomain | billing, invoice, payments | Billing |
| Subdomain | alerts, monitoring, notify, notifications | Alerts |
| Subdomain | updates, news, newsletter | Updates |
| Subdomain | support, help | Support |
| Subject | "log in", "sign in", "verify", "otp", "2fa", "magic link" | Auth |
| Subject | "invoice", "billing", "payment", "charge", "receipt" | Billing |
| Subject | "alert", "warning", "failed", "error" | Alerts |
| Subject | "weekly", "monthly", "report", "digest", "summary" | Reports |
| Subject | "welcome", "get started", "onboarding" | Onboarding |
| Subject | "shipped", "order", "tracking", "delivery" | Orders |
If no pattern matches, the message is left in queue with a warning.
Create it once per account:
# Create the label
gws gmail users labels create --params '{"userId":"me"}' \
--json '{"name":"Suppress"}'
# Add gray color (note: --json for body, --params for userId only)
gws gmail users labels update --params '{"userId":"me","id":"<LABEL_ID>"}' \
--json '{"color":{"backgroundColor":"#c2c2c2","textColor":"#000000"}}'
Color convention: gray (#c2c2c2 / #000000) — visually distinct from the colored taxonomy hierarchy. Name it so it sorts to the bottom of the label list (e.g. Suppress sorts after most category names alphabetically).
Valid gray: #c2c2c2 / text #000000. Other common grays (#999999, #e4e4e4, #b9b9b9, #444444) return 400 — they're not in Gmail's fixed palette.
| Situation | Behavior |
|---|---|
No taxonomy label on Automations/archive message | Moves to Suppress queue (adds Suppress, strips Automations/archive) |
Filter already has removeLabelIds:["INBOX"] | Skip filter upgrade; still run backfill and strip trigger |
| No filter found for taxonomy label | Log warning, leave in queue |
| Multiple taxonomy labels on message | Process all matching filters (additive, not a problem) |
Suppress message — existing filter found | Upgrade it to skip inbox rather than creating a duplicate |
| Large backlog | batchModify chunked at 1000 ids per call — handled automatically |
| Filter was manually edited | Worker reads full criteria + action before deleting — preserves manual edits on recreate |
Automations/archive to messages that already have a taxonomy child label — the worker uses it as the filter lookup key.Suppress directly (or let the worker route there) for senders not yet in the taxonomy.Automations/archive to messages with only system labels — the worker will warn and move them to Suppress anyway.~ as a label name prefix — Gmail rejects it.