Skip to content

Bot features, brain track: email triage buttons + morning report actions + finance tool, 2026-06-09

Worker brief. Justin approved the full 9-item bot feature menu ("do all 9"); this track owns items 2, 3, 4. Another session (forge-audit, the spawner) concurrently owns the POLLER layer (tg() consolidation, heartbeats, voice capture) and will do the latency rewire LAST, after you land.

File ownership (hard boundary, prevents merge conflicts)

YOURS: scripts/forge_telegram_inbox_brain.py (tool layer only), scripts/forge_telegram_callbacks.py, scripts/forge_morning_report.py, new files you create. NOT YOURS: the five poller scripts (forge_telegram_capture_bot.py, _coordinator_bot.py, _general_purpose_bot.py, _notify_bot.py, _remote_bridge.py), forge_telegram_format.py, scripts/forge_monitor.py. The spawner session is editing those right now. Restarts: you may restart forge-inbox-capture and forge-lifeos-coordinator, one at a time, verify active + 30s clean journal. Pull/rebase before committing; the other track commits to main too.

Context (read first)

  • memory/handoffs/telegram-fleet-audit-brief-2026-06-09.md: today's fleet audit + what already shipped.
  • Commit 0b3e1b5: the bots' Gmail layer is now scripts/forge_gmail.py (direct API, both accounts, search/read/archive/clear/star/mark_read/apply_label/drafts/unsubscribe/block). USE IT; never call the retired n8n email webhooks.
  • forge_telegram_format.py: kv_block, mono_table, inline_keyboard, callback patterns, boundary sanitizer. Telegram playbook: memory/general/reference_telegram_bot_playbook.md.
  • Memories: feedback_email_actions_confirm.md (per-batch approval for mutations; one-tap inline confirm satisfies it), feedback_telegram_no_tables.md, feedback_telegram_bot_ux_reactions.md, feedback_em_dash_sanitize_at_boundary.md, feedback_date_today_banned_in_forge_scripts.md.
  • Morning report (forge_morning_report.py) was rebuilt today (commit c6994f8); email/calendar/tasks sections are Gmail-API/GCal/n8n-notion direct. It routes through the coordinator bot via forge_coordinator_proactive.send_coordinator.

Item 2: Email triage with inline buttons (coordinator)

New coordinator tool email_triage_digest(account="personal", window="1d", limit=10): pulls inbox via forge_gmail.search, sends ONE message per email batch chunk with per-email inline buttons: Archive / Star / Unsub / Task. Buttons fire callbacks that call forge_gmail (archive, star, unsubscribe) or tool_email_to_task. Confirmation model: the tap IS the per-item approval (satisfies the email-actions-confirm rule; mutations happen only on tap, never in bulk). Register tool schema + handler. Also consider an evening digest timer ONLY if trivial; otherwise leave on-demand.

Item 3: Morning report quick actions

Per-task / per-section inline buttons on the 8:50 report message: Ack (react + no-op), Snooze 1h (reuse the existing snooze marker mechanism, see reference_morning_report_snooze_check.md; note its 15-min timer is "not auto-installed", verify before relying on it), Open task (deep link to tasks.justinsforge.com or the Notion page URL from the row). Callback handlers in the coordinator-owned callback dispatcher.

Item 4: Finance answers in chat (read-only)

New tool finance_query(question_type, ...) reading forge/data/finance/finance.db directly (SQLite, READ-ONLY connection: sqlite3.connect("file:...?mode=ro", uri=True)). Cover: monthly spend by category, recurring/subscriptions list + total, net worth current. Check forge/data/finance/COORDINATION.md and do NOT write to the DB or alter schema; the finance sessions own it. Tabular data to Telegram via mono_table/kv_block, never markdown tables.

Verification bar

Live-test each tool function directly through TOOL_HANDLERS (the spawner did this today; pattern in memory/daily/2026-06-09.md). For button flows you cannot tap yourself: verify callback handlers by invoking the handler functions with synthetic callback payloads, and confirm the message+keyboard renders by sending ONE real test digest to the coordinator chat marked clearly as a test. Commit in logical chunks; update this handoff with outcomes; register new tools in MEMORY.md.

[Claude Code, forge-audit session]


Outcomes (2026-06-09, brain track complete)

All three items shipped, live-tested, committed (8e47bf1, 0a8a2d3, dd031d1; plus fce58d4 carrying the other track's coordinator tg-shim as-is per Justin).

Item 2, email triage buttons. New scripts/forge_email_triage.py: coordinator tool email_triage_digest(account, window, limit) sends chunked digests (5 emails per message) with per-email Archive / Star / Unsub / Task buttons; callback data etriage:<action>:<p|b>:<gmail_id>. The etriage prefix registers via a lazy shim at the bottom of forge_telegram_callbacks.py (which the coordinator already imports), so no poller edits were needed. Evening digest timer: skipped, not trivial; on-demand only as the brief allowed.

Item 3, morning report quick actions. Keyboard is now two rows: [Ack] [Snooze 1h] [Mark done] / [Open tasks] [Full plan]. morning:ack sets an eyes reaction (no text bubble); Open tasks is a url button to tasks.justinsforge.com (section-level deep link; per-task Notion URLs would need the synthesis pipeline to carry page URLs through, punted). The snooze-check timer flagged as "not auto-installed" is now installed and enabled (forge-morning-report-snooze-check.timer, 15-min cadence, verified idle-clean). Coordinator env parsing consolidated into forge_coordinator_proactive.load_coordinator_env (single source of truth; morning report delegates).

Item 4, finance_query. New scripts/forge_finance_query.py, strict mode=ro sqlite, zero writes. Covers monthly_spend (excludes transfers + CC payments), recurring (47 active, ~$7,625/mo monthlyized), net_worth (matches forge_finance_networth.networth_sections to the dollar: $192,808 combined). Net-worth logic duplicated read-only because the canonical module connects read-write via forge_finance_db; noted in the module docstring.

Verification run. finance_query: all three question_types through TOOL_HANDLERS, plus month override. Email triage: one real [TEST] digest sent to the coordinator chat (a second may exist from a timed-out first attempt, both marked TEST); star/arch/task actions live-tested via synthetic callback payloads against a real email, all mutations verified then reverted (test Notion task archived). Unsub action not live-fired (rides forge_gmail.unsubscribe shipped today in 0b3e1b5; same dispatch path as the verified actions). morning:ack dispatched synthetically against a test message; reaction visually unconfirmed. forge-lifeos-coordinator restarted once, active, clean journal. forge-inbox-capture not restarted (capture tool set untouched).

[Claude Code, bot-features brain track]