Docs · page 09 of 09
The monthly newsletter
The Newsletter tab turns a month you already published into one issue: a recap of your own posts written in your voice, plus a short, fact-checked read on what moved in AI. Nothing publishes to LinkedIn by itself — distribution only writes drafts into your queue.
What an issue is made of
Each issue has two grounded streams:
- My month in posts — an intro in your voice, one signature insight (The one thing), and 3–5 picks, each with a headline and a one-line takeaway. One pick can carry a most-engaged badge. The picks come only from your own posts whose status is
publishedormanualinside the month; the model is shown those posts and told to invent nothing. (A post's month is decided by its scheduled time, falling back to when it was last updated, so an oldermanualpost you edited during the month can appear.) - AI world this month — up to 5 curated news items, each with a summary, a Why it matters line, and its source link. Every summary is written strictly from the text the feed supplied.
Issues move through draft → generating → ready → approved → distributing → distributed, plus failed.
To generate this month's issue
Open Newsletter and click Generate issue in the left rail. The window is always the previous full calendar month (UTC), so a run on 20 September builds the August issue — the tab has no date picker, and a custom window is available only by calling the API with periodStart/periodEnd.
Generation refreshes the news pool, writes both streams, then leaves the issue at Ready for review. The toast reports the outcome, for example Issue generated — 2 item(s) need review (spend $0.4210 / $50.00). If generation fails outright, the issue goes to Failed and the builder shows a Last error: banner.
Two things can leave you with an issue that looks generated but is nearly empty:
- No Anthropic key. The call returns
newsletter generation not configured — add your Anthropic key in Settingsand the tab toastsNewsletter generation isn’t configured (set ANTHROPIC_API_KEY on the server).The key can come from the server environment or from Settings. - Paid model calls are switched off. Unlike drafting a post, the newsletter runs on the billed Anthropic API, and this server blocks billed calls unless
PAID_API_DISABLEDis explicitly set to0— blocking is the default when the variable is absent. When it is on, each step fails withpaid Anthropic API calls are disabled on this server (PAID_API_DISABLED), that message is recorded against the issue rather than shown, and the run still ends at Ready for review with: no AI items at all, no intro, no insight, up to three raw post picks (the post's title, or its first 120 characters), and the fallback titleAugust 2026: AI, and my month. The news pool still refreshes, because fetching feeds costs nothing.
Good to know — there is exactly one issue per month per newsletter. Running Generate issue again for the same month reuses that row and replaces its title and content, so any review work you already did on it is lost. You are warned only if you have unsaved edits open (
Generating starts a new issue. Discard your unsaved edits?); saved work is replaced with no prompt at all.
Where the news comes from
The pool is a config-pinned list of RSS/Atom feeds. The built-in list is arXiv cs.AI, the Hugging Face blog and Google AI (tier 1), then The Verge AI, TechCrunch AI, The Batch and Import AI (tier 2). Setting NEWSLETTER_NEWS_FEEDS replaces that list entirely; anything you put there is fetched, treated as tier 2, and labelled by its hostname — so it is a trusted setting, not a filter.
A dependency-free parser reads both <item> and <entry> documents, items are deduped by URL (the more authoritative tier wins), and each is scored by source tier (60 for tier 1, 30 for tier 2), a high-signal-term boost (4 points per matched term such as "release", "open source", "funding", "regulation", "benchmark", capped at 20) and recency (about 30 points for today, decaying over a month). The top 40 are cached; the top 12 go to the model.
Only the feed URLs on the active list are ever fetched, and the links inside items are stored, never fetched. A feed URL that doesn't parse as a URL is skipped with host not in allowlist (SSRF guard). Each feed gets a 12-second timeout, and a feed that fails is logged and skipped — generation continues on whatever came back.
The fact-check, and the rule it enforces
Two passes run over the candidates. The first writes a grounded summary per item from the supplied text only. The second is adversarial: a skeptical checker re-reads every claim against that same text and tags the item.
- green — every claim is directly supported and the source is tier 1 or 2. Badge: verified.
- amber — thin or partial support, or a single weak source. Badge: needs review.
- red — any unsupported or contradicted claim. Badge: unverified.
Only a green item starts approved. Amber and red arrive with approved: false and needs_review: true, which is the hard rule: an issue cannot be approved, and therefore cannot be distributed, while any AI item is unapproved. If the selection pass fails but the summaries survived, the fallback takes the top three summaries and marks all of them amber with the note auto-selected fallback — verify before publishing — degraded, never silently shipped. If both passes fail, the issue simply arrives with no AI items.
An item with no usable source link shows ⚠ No source link — verify before approving.
To review and edit
Select an issue in the rail. The builder gives you Issue title, Intro, The one thing (insight) and Closing / call to action as plain fields, then the AI world this month items, then My month in posts.
For each news item: Edit opens Title, Summary, Why it matters, Theme and Sources (one per line as url | title; lines without a valid http(s) URL are dropped), then Done. Approve / Un-approve flips the review state, Remove drops the item, and ↑ / ↓ reorder it. Your own posts get Pin as most-engaged / Unpin and the same reorder controls.
Nothing is persisted until you click Save edits. That button stays greyed out until you actually change something, and disappears once an issue is distributing or distributed. Four previews sit below the builder:
| Format | What it shows |
|---|---|
| Email preview | The issue as it reads, live from what is on screen — including unsaved edits |
| Web page | The server's own render in a sandboxed frame, with Open in new tab |
| Article | Paste-ready LinkedIn article text, with Copy article text |
| Carousel | Numbered slide text, with Copy slide text |
Good to know — a standing hint above the four buttons reads
Reflects the last saved issue. Save edits to refresh., but it is only true of the last three: Email preview is built live from what is on screen. When you have unsaved edits, Web page addsShowing the last SAVED version. Save your edits to update the web preview.and Article and Carousel addShowing the last SAVED version. Save to refresh.The carousel here is copyable text, not a rendered PDF.
Editing stops once an issue is out the door: a distributing or distributed issue returns cannot edit a 'distributed' issue.
To approve
Approve issue appears only at Ready for review, and is disabled while you have unsaved edits or any unresolved item. The action bar tells you which: 3 item(s) still need review before approval., Save your edits, then Approve., or All items resolved — ready to approve.
This is re-checked on the server, not just in the UI. Approving from the wrong state returns issue is 'draft', must be 'ready' to approve, and an issue with flagged items returns 2 AI item(s) still need review.
Re-open to edit drops a ready or approved issue back to draft.
Good to know — once an issue is back at draft, the tab offers no button to return it to ready, so Approve issue stays hidden. The only way back is to run Generate issue for that same month, which rewrites the issue's title and content. Finish your edits before approving rather than re-opening a nearly-done issue.
To distribute
Distribute… opens the Distribute issue modal with three destinations: Hosted web page, LinkedIn announce post and LinkedIn Newsletter article. The first two are checked by default; pick none and you get Pick at least one destination.
Confirming writes index.html and issue.pdf into the issue's folder under the files directory, then saves the announce post and the article as drafts in your queue (folders newsletter-announce and newsletter-article), each carrying the public issue URL. The response says it plainly: Announce + article saved as drafts in your queue — publish via the composer-reminder flow (⌘V paste). Distributing from the wrong state returns issue must be 'approved' to distribute (is 'ready').
Nothing auto-publishes. The drafts wait in your queue until you publish them.