Turns the recent changelog into a written newsletter and leaves it as a draft in Resend. A human reads it and presses send.
| Step | ||
|---|---|---|
fetch_changelog | native | Curated changelog entries published in the window |
fetch_editorial | native | Voice, editorial rules and the last two issues, from a GitHub repo |
write | AI agent step | The issue, as JSON — structure enforced by output_schema |
create_resend_draft | native | Renders the branded HTML, creates the draft |
Monthly schedule, shipped disabled.
It cannot send. Resend sends on POST /broadcasts/{id}/send, and no step
here builds that URL — not behind a flag, not disabled. The worst case of a bad
run is a draft nobody opens.
The repo is the brain. How the newsletter reads lives in a GitHub repo as markdown, not in these scripts. Tuning it is a reviewed pull request rather than a deploy.
newsletter/
├── skills/voice.md how it sounds
├── skills/editorial.md what earns a section, what gets one line
└── issues/2026-08.md past issues — the writer reads the last two
There is no format file: the email's structure is fixed by the flow's
output_schema and rendered by code, so the writer and the renderer cannot
disagree.
init_newsletter_repo with dry_run: false — creates the repo, skills
included.repo, ai_resource (a $res: path, not a resource
picker), segment_id, from_address, plus the gh_auth and resend
resources.dry_run: false. A draft appears in Resend.dry_run (the default) renders the whole email from samples — no GitHub, no
model call, no Resend.
Fix the skill that produced it, not the scripts.
voice.mdeditorial.mdskip is for, and a padded
issue is worseDrop each issue you send into issues/YYYY-MM.md. Past issues show the
judgement calls instead of describing them, and they beat any rule file.