MalloryEstate Briefing
M·022Approved
← All briefings

Notifications & Nudges

Mention Nudges

Rewriting the last prose-only Wave 4 job into structured fetch → deterministic jq, so unanswered Slack/Gmail threads become permanent-dedupe batch nudges.

Dated 2026-06-13Programme Notifications & Nudges

Situation

jobs/slack-email-monitor.sh today only writes prose to the daily note and emits no nudges. This design replaces it with the calendar-sync.sh pattern: quarantine the LLM to a single structured fetch (Slack + Gmail ball-in-court items as a JSON array), then run every downstream step — normalise, dedupe, emit, render — as deterministic jq. It's the last open slice of Wave 4 (Proactive & Notifications).

Unlike calendar-sync, mention-nudges needs no local membership store: the Worker's nudges table is already a permanent dedupe ledger, so each unique mention/thread id nudges at most once, ever, and the Hub just emits current candidates on every run.

Key decisions

Ball-in-court rule, LLM-judged

Include a thread only if the latest message isn't from Alex (by Slack id / GMAIL_SELF_ADDRS) within a 7-day lookback; wants_action is the LLM's secondary judgment of whether it's a real ask vs FYI.

Always batch, never urgent

Every mention nudge is batch urgency, held for the existing 2h flush cron — no keyword-triggered now escalation.

Permanent dedupe, asymmetric keying

Slack keys on channelId:messageTs (a new @mention re-nudges); Gmail keys on threadId (a same-thread follow-up won't re-nudge) — a documented, intentional limitation.

Overwritten artifact, not appended

_generated/needs-response.md is fully overwritten each run rather than appended, avoiding 4x/day daily-note clutter; empty results render an 'all clear' body and emit no nudges.

Multi-account ready but not built

GMAIL_SELF_ADDRS is a comma-list from day one so a second Google account (MK Community Energy) is a config-only addition later, not a rearchitecture.

Architecture

A single LLM structured pull feeds a deterministic jq pipeline, dedupe against a permanent Worker-side ledger, and an overwritten vault artifact.

jobs/slack-email-monitor.sh
Rewritten orchestrator: lock + pause-check → claude -p structured pull → tolerant JSON extraction → jq normalise/dedupe → post_nudge → render → vault_commit.
Structured LLM pull
One claude -p call outputs only a JSON array (source/id/from/channel/subject/summary/wants_action/permalink/last_ts) — no prose, no fences.
nudges table (Worker, existing)
Permanent dedupe ledger — nudgeSeen(dedupeKey) makes every id fire at most once across all runs.
_generated/needs-response.md
Deterministic vault artifact, sorted by last_ts, committed only when content changes.
config.env
MENTION_LOOKBACK_DAYS (default 7), SLACK_SELF_ID, GMAIL_SELF_ADDRS drive the ball-in-court check without hardcoding identity.

Risks & guardrails

Gmail follow-ups go silent

Keying Gmail dedupe on threadId means a second ask in an already-nudged thread never re-fires — accepted as a documented limitation, not fixed in this build.

Unparseable LLM output kills the run safely

A non-array or unparseable pull triggers log+alert+record_status fail and exit 1 — no nudges, no render, artifact left untouched, mirroring calendar-sync's error handling.

Wide lookback is safe only because dedupe is permanent

A 7-day lookback would double-nudge under a diff-based model; it's safe here specifically because nudgeSeen never forgets an id.

Delivery

Config + pure jq transforms (TDD)

Config vars added, then lib/mention.jq and a tolerant JSON-array extractor built test-first against fixtures.

Orchestrator rewrite

jobs/slack-email-monitor.sh replaced end-to-end with the fetch → jq → emit → render pipeline; README schedule updated (08/11/14/17 weekdays).

PR + VM deploy

Merged via the alexhansford identity, then deployed to the VM crontab — both authorized steps for this wave, distinct from the usual 'held for Alex' pattern.

Out of scope

MK Community Energy calendar sync (separate follow-up, gated on connecting the second Google account)Urgent-keyword → now escalation (decided: always batch)Re-nudging Gmail follow-ups within an already-nudged threadAsana/Notion mentions (Slack + Gmail only)
spec · docs/superpowers/specs/2026-06-13-mention-nudges-design.md
plan · docs/superpowers/plans/2026-06-13-mention-nudges.md
Mallory · Estate briefing