The Newsletter Agent
Before this, read:
- The deep-research agent — supplies the AI-news sweep component
- Root-cause-first as a build process — the newsletter audit is a textbook application
The Agent Brief is a weekly newsletter for the AgentTree Army list — real subscribers, real sends via Resend, real deliverability requirements. It was one of the first pieces of the growth infrastructure to get built and, for four weeks, barely shipped anything. The audit that found this is worth as much as the system that fixed it.
What the pipeline does today
Section titled “What the pipeline does today”After two rounds of root-cause work (2026-06-05 audit, 2026-06-06 v2 rebuild, 2026-06-06 Phase 2 grounding), the pipeline runs as:
-
Daily AI-news sweep (6pm MT,
agents/growth/ai_news_sweep.py)Pulls from Brave News API + Socrates X fetcher. Deduplicates. Runs a grounding-guarded LLM pass to extract what’s significant. Writes a dated digest to
~/clawd/state/ai-news/YYYY-MM-DD.mdwith real source URLs. -
Thursday draft (Thursday 7pm MT,
newsletter-thursday-draft.py+scripts/cron-newsletter-thursday-draft.sh)Reads the last 7 days of AI-news digests. Picks ONE item per section with its real source URL. Generates the draft issue in the
newsletter_issuesSupabase table (status=draft). -
Telegram ping (same cron)
Pings JD with a preview of the draft. Reachable as
/nl-statusin the command palette. -
One-tap approve (
newsletter_approval_gate.py, triggered by JD/nl-yes)Marks the issue approved → fans out to the subscriber list via
newsletter.py send. Real sends to 11 active subscribers (as of 2026-06-06).
The audit
Section titled “The audit”Before the v2 rebuild, the CHANGELOG entry at 2026-06-06 07:22 recorded what the audit found:
“14 ranked issues. Headline — barely ships (4 of 26 issues sent, last 5/22), NO send automation (the ‘Friday send’ cron is a commentless stub).”
Four sends in four weeks from a weekly newsletter. The root-cause list:
- Broken unsubscribe link (404, CAN-SPAM violation) — every email had a dead unsubscribe URL.
- Missing
List-Unsubscribeheader — required by Gmail and Outlook for bulk senders. - Image-heavy template — 8 PNG images hosted on raw Supabase storage URLs, which spam filters flag.
- SPF
From-misalignment — the From address was on the root domain; sending happened from a subdomain not covered by the SPF record. - The “Friday send” cron was a stub — it existed in the crontab as a comment, never actually called the send function.
- 22 rotting draft issues in the database from months of Thursday draft runs that never got approved or sent.
Items 1–4 explain spam landing. Item 5 explains the zero automation. Item 6 explains the 22 orphaned drafts.
The v2 rebuild
Section titled “The v2 rebuild”The one-pass fix addressed every item on the audit list:
- Template rebuilt to zero images (live text only, light/dark, mobile responsive). ~22KB down to ~10KB.
- Unsubscribe link fixed — now routes to
docs.agenttree.army/api/unsubscribe?email=with a real handler. List-Unsubscribeone-click header added.newsletter_approval_gate.pyrestored (it had been lost in a codebase cleanup — found by checking the RUNBOOK, which referenced it).- Thursday draft cron fixed — the stub was replaced with a real call.
- 22 draft orphans pruned. 16 test subscribers audited down to 11 real ones + 5 test addresses removed.
- Disabled the broken Wednesday cron that was generating duplicate drafts.
The test-send verification: draft UUID a2421abe sent to JD, confirmed delivered (likely landed in Promotions/Spam — the reputation signal takes a few issues to build, which is expected for a new sending domain).
Phase 2: grounded AI-news section
Section titled “Phase 2: grounded AI-news section”The v2 rebuild fixed the sending problems. The content had a different problem: the AI-news section was generated from model memory — the LLM writing “recent AI news” from training data, not from actual recent sources. An agent brief with “AI news” that is 6–12 months stale is worse than no AI-news section.
Phase 2 (committed 2026-06-06, 3dcc714) added the daily AI-news sweep as the grounding layer. The Thursday draft now reads last week’s digests and picks ONE item with its real source_url instead of asking the model to recall what happened in AI. Verified end-to-end: the 2026-06-06 digest produced 10 real linked items; the Thursday dry-run used one of those links verbatim.
The RUNBOOK lesson
Section titled “The RUNBOOK lesson”This project is the canonical example of CLAUDE.md’s “RUNBOOK first, draft second” rule. When JD asked for a newsletter issue on 2026-06-06, the first action was: check ~/clawd/projects/agent-tree-growth/newsletter/ for the pipeline. It existed. The issue was drafted by running:
bash ~/agent-system/scripts/newsletter-friday-draft.py# → sections JSON → newsletter.py draft → send.py --to JDNot by hand-writing a new format. The working pipeline and the proper Supabase-backed flow were already there; the issue was that nobody had run the audit to find out it was broken.
If the RUNBOOK had been read at the start of every session that touched the newsletter, the spam and stub-cron problems would have been caught weeks earlier. The lesson added to CLAUDE.md: “If a project has no RUNBOOK and you can’t find tooling, create the RUNBOOK as part of finishing the work.” The newsletter project now has one.
Current state
Section titled “Current state”- 11 active subscribers
- Weekly cadence: Thursday draft → Friday send (one-tap approve)
- Two sections: BUILD (what shipped this week) + AI NEWS (one grounded item with source URL)
- Open/click tracking: deferred to a future phase (no webhook yet)
- Archive pages: deferred (no static archive route yet)
The pipeline is small and honest. It produces one real email per week with one real AI-news item, a description of what shipped, and a working unsubscribe link. That’s the baseline that works. Sophistication can be added on top.
This concludes Group F. For the agents that manage JD’s life domains — school, health, family, finance — see Group G starting with the expert professor agent.