Owner: TITAN · Status: Phase 1 shipped (voice unified, guards in place), Phase 2 = first live run.
1. Template standard = comic rotation (the current Agent Stack look).
2. Agent Stack = commercial flagship; OpenClaw / Agentic-AI / Claude weeklies stay as free feeders.
3. Audio format = two-host NotebookLM-style dialogue (ALEX + MAYA), via newsletter_to_audio.py.
Voice playback was fragmented across 7 mechanisms:
newsletter_to_polly (Polly Ruth), newsletter_to_audio (Gemini 2-host), newsletter_narrator (Sonnet+Polly)._audio_banner) vs. persona player banner (_player_banner).play.silentinfinity.com vs titan.livegroweveryday.com/play).newsletter_player.py (NEW) — the ONE canonical player. inline_player_html() = cleanGoogle-Podcasts widget (cover, play/pause, scrubber, current/total time, ±15s, 1×/1.25×/1.5×/2×
speed). email_card_html() = email-safe card (cover + native <audio controls> + "Open full
player" link). Cool-blue brand (#6aa9ff, dark cards). Verified live in Chrome — playback works.
build_player_page.py — HUD page replaced with the clean widget + issue rendered below; polly_url param now carries the two-host MP3; dialogue pre-warm removed (redundant).
titan_email.py — both old banners replaced by the single email_card_html; legacy keptonly as fail-soft fallback.
agent_stack_daily, openclaw_/agentic_ai_/claude_newsletter) now use ONE audio path: newsletter_to_audio (2-host) → build_player_page. The parallel Polly
player path is retired.
TITAN_NEWSLETTER_VARIETY turned OFF (locks the comic template as the standard); TITAN_NEWSLETTER_AUDIO=1 explicit.
is_news_item() in agent_stack_daily.py: requires a real external source_url (rejects our own domains), drops infrastructure/promo/self kinds, requires
headline+summary. No news today → no send (filler self-promo seed removed).
newsletter_ledger.find_eligible / mark_sent(SQLite, shared across all 4 newsletters). Verified present and wired.
on-by-default (!= "0") to == "1", so they render exactly once per issue and never alongside
the legacy single-callout block. daily_callouts is deterministic per (slug+date) = one joke/tip
per issue, and different across the day's newsletters.
is_news_item unit check: real news kept, self-promo + no-URL dropped.s3://innerverse-voice-scratch/player/_test/ → HTTP 200,real MP3 streams, play/pause confirmed in Chrome.
TITAN_NEWSLETTER_AUDIO=1 generating a fresh 2-host MP3(cost: Gemini TTS via deepdive, ~$2-3/issue — confirm budget cadence; daily = ~$60-90/mo).
titan.livegroweveryday.com/play (or a play.silentinfinity.com) CloudFront → the player/ S3 prefix so the email "Open full player" link resolves on a branded domain.
separate real-time paradigm — left as-is).
Two production defects found by rendering real issues and fixed:
agent-stack was frequently empty. agent_stack_daily.load_research_for_date now pulls
across ALL topics (agent-stack-native first, then by freshness) — the flagship is genuinely
cohesive/cross-topic.
crescendo.ai/news/latest-ai-news-and-updates was cited 8× in one day. New shared module newsletter_quality.py (is_quality_source + cap_per_source) blocks
aggregator/landing pages (crescendo, google news, github/trending, /tag//category/ etc.),
requires a specific article path, and caps ≤2 stories per domain. Wired into ALL 4 newsletters
(Agent Stack via is_news_item; openclaw/agentic/claude in their gather()).
F:/TITAN/scripts/: newsletter_player.py, build_player_page.py, titan_email.py,
agent_stack_daily.py, openclaw_newsletter.py, agentic_ai_newsletter.py, claude_newsletter.py,
newsletter_templates.py, newsletter_to_audio.py, newsletter_ledger.py, daily_callouts.py.