Top section of brief.josephbowens.com (2026-04-22+)
The PWA now shows an Approvals collapsible as the FIRST thing you see — above the Morning Brief. Any pending items from any of four outreach channels surface here with deep-links to the native tool where approval happens.
URL: https://brief.josephbowens.com
Auto-opens if there are pending items; stays collapsed when queue is clear.
Four independent channels
| Emoji | Channel | Source skill | State file | Deep-link target |
|---|---|---|---|---|
| ✉️ | Direct drafts | gmail-deep-scan (Step 5b) | pending_drafts.jsonl | Gmail draft URL |
| 📧 | SmartLead | daily-beenverified-enrichment (future wiring) | pending_smartlead_batches.jsonl | SmartLead campaign URL |
| 📬 | Postcards | grand-county-property-scout (future wiring) | pending_postcard_batches.jsonl | Postcard workbook / Jasmine draft |
| 🤝 | Realtor intros | nightly-consolidation (future wiring) | pending_realtor_intros.jsonl | Gmail search URL for Rachel's intro thread |
project_hubspot_sequences_running.md.
File paths
- State files:
~/Library/Application Support/SkyRun/pwa/data/pending_*.jsonl - Schema doc:
~/Library/Application Support/SkyRun/pwa/data/_schema.md - Renderer:
/Users/josephbowens/Library/Application Support/SkyRun/build_pwa.py→read_approvals()+render_approvals_section()
Item schema (canonical)
json
{
"id": "unique-string",
"channel": "direct_drafts" | "smartlead" | "postcards" | "realtor_intros",
"title": "short summary < 80 chars",
"context": "1-3 line elaboration",
"deep_link": "URL to native tool",
"created_at": "ISO8601",
"urgency": "RED" | "YELLOW" | "INFO",
"source_skill": "skill-name",
"meta": { / channel-specific fields / }
}
Rendering rules
- Sort: urgency DESC (RED → YELLOW → INFO), then oldest created_at first
- RED items open by default via section auto-expand
- Each item: title + context + urgency chip + optional "Xd pending" age chip + "Open in native tool →" button
- Empty queue = renders "No pending approvals. Queue is clear."
Current state (as of 2026-04-22)
- 1 direct draft (Hadank Thursday walkthrough — awaiting Andy reply)
- 1 SmartLead batch (3 campaigns in DRAFTED state — Rachel sign-off pending)
- 0 postcards (no pending batch)
- 3 realtor intros (Leah Bishop, Megan Waymeyer, Katie Fox — all 43d pending from Rachel)
How source skills populate the queues (writer contract)
Each source skill is responsible for:
1. Appending new items when it detects a pending state (e.g., gmail-deep-scan sees a new draft in Gmail → writes pending_drafts entry)
2. Removing items when the pending state is resolved (draft was sent, batch was activated, etc.)
3. Updating urgency based on age + content (e.g., draft to active-deal person > 24h = RED)
Cleanup rules:
- Files are append-mostly but writers may rewrite to remove resolved items
- Items older than 14 days are auto-archived to
_archive.jsonl(stale queue cleanup)
Wiring status per source skill (all 4 wired 2026-04-22)
- ✅
gmail-deep-scan— wired via Step 5b. Maintainspending_drafts.jsonlon every run (9am/1pm/5pm/10pm). - ✅
daily-beenverified-enrichment— wired post-Step 7b. Maintainspending_smartlead_batches.jsonlwith a per-campaign state item (3 items: SWITCH/HOT+WARM/NURTURE+LOW). Removes items when campaign status becomes RUNNING. - ✅
grand-county-property-scout— wired as Phase 7. Adds postcard-batch items topending_postcard_batches.jsonlwhen new postcard targets are created. Auto-clears stale batches on next run. - ✅
nightly-consolidation— wired via Section D2-B. Maintainspending_realtor_intros.jsonlbased on Gmail insights + transcripts. Tracks the 4 realtor contacts (Leah, Megan, Katie, Whitney) through states: awaiting_rachel_intro → intro_sent → realtor_replied → live_engagement.
Architectural decision: smart inbox vs swipe-to-approve
v1 is smart inbox (deep links to native tools for native approval). No backend. v2 candidate (future): swipe-to-approve via Cloudflare Pages Functions + KV, where tapping "Approve" executes the action server-side. Held back until v1 is in daily use and the deep-link friction is the actual bottleneck.How to apply
- When asked "what's in my queue" / "what's pending" → check the 4 JSONL files or point to the PWA URL.
- When adding a new outreach channel, extend
APPROVAL_CHANNELSinbuild_pwa.pyand create matchingpending_*.jsonl. - When debugging "why did X not appear in my approvals?" → check if the source skill's wiring is done (see status above).