One newsletter, twenty-two customers, twenty minutes each
An engineering consultancy of about a hundred and twenty people sent its most important customers a newsletter every Monday. By the standards of the industry it was a good one: real project updates, sector notes, items worth a customer's time. It was also the same newsletter for everyone — a strange thing to send to twenty-two companies that have nothing in common except the firm they hired.
Someone had noticed that years earlier, and the fix had been a person. Every Monday, a marketing coordinator opened the standard edition and adapted it customer by customer: swap the opening, cut the items that didn't apply, rewrite the project references so the reader saw their own interchange instead of somebody else's water treatment plant. Twenty-two adaptations took most of a working day. That is roughly twenty minutes per customer.
Twenty minutes per customer is not personalization. It is find-and-replace with a deadline.
The quality problems were not a mystery, and they were not her fault; they were arithmetic. A milestone got reported as upcoming two weeks after it had slipped, because verifying every project's status does not fit in twenty minutes. One customer received a paragraph about another customer's project, because copy-paste under time pressure does what copy-paste under time pressure does. And in August, or in the weeks when a proposal was due, the adapted versions quietly didn't go out at all. Nobody decided that. The week just ended first.
In the Reverse Demo, the coordinator walked us through a Monday, screen by screen. She kept a private checklist of paste errors to look for before sending. There is almost always a checklist like this, and it is usually the most useful document in the building, because it is a map of exactly where the process breaks.
Monday, a few minutes past seven
The business development director of a rail infrastructure operator gets an email from the same coordinator whose name has been on the firm's newsletters for years. This week it contains: two sector items — a regional infrastructure fund announced Thursday, and a revision to a noise-assessment standard that touches two of the operator's corridors; one item about the operator itself, a press mention of its western extension, source linked; and a projects section reporting that the geotechnical survey on the viaduct package cleared internal review on Wednesday, with revised drawings scheduled for the 14th. Then a sign-off in the coordinator's usual register.
Nothing in it is generic, and nothing in it is invented; every sentence traces to a source the system can show. It reads like twenty minutes of somebody's careful attention. No person spent a minute on it.
One scenario, run unattended
The system is one Make.com scenario scheduled for 06:30 every Monday. It runs with nobody watching: by about 07:15 the batch is done and twenty-seven editions are in twenty-seven inboxes — or, for an edition that failed its checks, deliberately not, which §07 covers.
Editions send through the Outlook module from the coordinator's own mailbox. Her name has been on this newsletter for years and it stays on it. Sends are individual, the HTML is light enough to read as written rather than blasted, and there are no tracking pixels: replies and meetings are the measures, and replies land with a person. Nothing automated ever answers a customer.
Make.com is a deliberate choice here, not a constraint, for two reasons. The first is legibility: a scenario reads as a flowchart. Every client can take the full handover at any point — documentation, every component, training — and the person who inherits this one will open the canvas and see the process drawn as boxes they can follow, test, and change without reading code. We build for that handover even when nobody has asked for it yet. The second is cost discipline: fetching feeds, filtering by date, deduplicating, rendering templates, and sending mail are deterministic work, and deterministic work should not run through a language model. The scenario does the plumbing for fractions of a cent. Claude is called at exactly two points — where editorial judgment happens, and where it is checked.
That split is the design principle of the whole system, and worth stating plainly, because it is the part most builds of this kind get wrong: the orchestration moves data; the Skill holds editorial judgment; the layout is deterministic; the gates decide. Keep those four jobs separate and each one stays simple. Mix them and you get a prompt nobody can maintain.
One Excel row per customer, and it carries the judgment
Everything customer-specific lives in one Excel workbook on SharePoint, in two tables. The first is the account book: one row per customer. The second maps sector tags to RSS feeds, covered in §05.
A row is a profile card:
Fields shown with a fictional customer. The real book holds 27 rows.
The card takes about fifteen minutes to write, and it is the highest-leverage artifact in the system. It is also the least technical. We wrote each one with the account's relationship owner rather than from the customer's website, because the description column is what the Skill later uses to judge relevance, and what an account actually cares about is knowledge that lives in a person until somebody writes it down. The aliases column matters more than it looks: one real customer is known by three names, one of them from before a rebrand, and press coverage uses all three.
Adding a customer is one row and one folder path. That is why the list grew from twenty-two to twenty-seven after go-live: the marginal cost of a customer fell from twenty minutes every week to fifteen minutes, once.
Harvest mechanically, decide editorially
Each run gathers three kinds of material per customer. Every stream has its own error handler: a stream that fails degrades to empty and flags itself in the log, so one dead feed never takes down the batch.
Sector news, by RSS
The feeds table maps each sector tag to a handful of sources: trade press, regulators, standards bodies, tender portals. The scenario's RSS modules retrieve each feed once per run, filter items to the last seven days, deduplicate by canonical URL, and cap the candidate list. Items are normalized to a flat contract:
{ "title": "...", "url": "...", "source": "...",
"published_at": "ISO-8601", "snippet": "...", "stream": "rss" }
Note what is missing: any relevance decision. A rail item enters the candidate pool of every customer tagged rail. Whether it matters to this customer is editorial judgment, and editorial judgment happens in one place only (§06).
Customer news, by Perplexity
The Perplexity module runs one research request per customer, assembled from the profile card. The prompt is a contract too:
Research task. News from the last 7 days only.
Company: {{name}} — {{description}}.
Headquartered in {{hq}}. Sector: {{sectors}}. Aliases: {{aliases}}.
Exclude: {{own_domain}}, social posts, job ads.
Return JSON: items[{ claim, date, source_url }].
Every item carries a source URL and a date inside the window.
If nothing verifiable was published, return an empty list.
An empty list is a correct answer.
Two details earn their keep. The disambiguators exist because company names collide, and a research model given only a name will eventually bring back somebody else's news. And the empty list is declared a correct answer because a model that is not offered an exit will fill the space with something. The scenario then re-checks what comes back anyway: every cited date parsed and confirmed inside the seven-day window, every cited URL fetched and confirmed alive. Items failing either check are dropped. Search-grounded models return confidently stale results at a low but nonzero rate; the checks are deterministic and cost nothing.
Project updates, from SharePoint
The third stream is internal, and it is the one that makes an edition read as account management rather than marketing. The scenario lists files modified in the last seven days inside the customer's client-ready reporting folder and passes them, as documents, to the compose call.
Two boundaries, both structural. The scenario reads one folder per customer: the one holding the client-facing status reports the project managers already produce. Fee schedules, hour tracking, and internal notes live elsewhere in the project tree, and the module is not pointed there; what the automation cannot reach, it cannot leak. Second, the folder convention was the only process change the firm had to make — the weekly status PDF that used to be attached to an email is now saved to the folder the pipeline watches. If nothing changed on a project this week, the stream is empty, and the projects section will collapse rather than pad.
Editorial judgment, packaged as a versioned artifact
The compose step is one Claude API call per customer: the profile card, the three harvests, and the week's documents go in; a finished edition comes out. The editorial logic governing that call is packaged as a Claude Skill — a versioned folder of instructions the model loads — rather than a prompt pasted into a Make module. The distinction is operational, not cosmetic. The Skill is developed and tested in Claude Code against saved sample bundles from the testing weeks: change a rule, replay a past Monday's twenty-seven bundles, read the diff. It is version-controlled, so the run log records which Skill version wrote which edition. And it can be edited by someone who has never opened the Make canvas — the person who owns the voice does not have to be the person who owns the plumbing. Before Skills were an API feature, the same file traveled as a system prompt; the mechanism is not the point, the versioned artifact is.
The Skill does three jobs.
Selection. The harvest is deliberately over-inclusive, and most candidates do not survive it. The Skill keeps the few items that matter to this customer, judged against the description on the profile card — a rail item about rolling-stock finance survives for the operator that leases its fleet and dies for the one that owns its fleet outright. This is the judgment that used to fit in twenty minutes per customer, now applied in one place, against a written description instead of a memory.
Structure. The edition has a fixed skeleton — greeting, intro, sector, customer, projects, sign-off — and hard rules that travel verbatim in the Skill:
— Every claim about the world cites one supplied item, by URL. — Every claim about a project traces to one supplied document. — A section with no material collapses. Never pad a thin week. — No dates, numbers, names, or outcomes absent from the inputs. — Write in the customer's language (account book, column: language). — Subject: concrete, from the strongest item, 55 characters max. — Length 180–320 words. A newsletter is not a report.
Grounding. The output is not an email; it is JSON:
{ "subject": "...",
"greeting": "...",
"intro": "...",
"sections": [
{ "id": "sector" | "customer" | "projects",
"title": "...",
"blocks": [ { "text": "...", "source_url": "..." } ] } ],
"closing": "...",
"notes": [ "anything the checker should know" ] }
The model writes copy. It does not write HTML. A template step renders the blocks into the firm's layout, which means the layout cannot be broken by a model having a strange morning — and the QA gates receive a structure they can check mechanically instead of prose they would have to interpret.
The gates decide
Nothing in this system is reviewed by a person before it sends. That is a design decision, and it obliges the checks to decide rather than annotate. There are two gates, in fixed order. Both fail closed.
Gate one is deterministic. The output is parsed against the JSON structure in §06; a parse failure is retried once with the validator's error appended to the request. Every source_url in the output must be a member of the harvested input set — set membership, not similarity — which catches an invented link outright. The text is scanned for leftover template placeholders, for a short list of banned strings, and for the customer's name spelled correctly; section lengths are checked against bounds; an edition whose sections all collapsed falls below the material floor and is skipped. Any failure surviving the retry: the edition is not sent, its status is failed, an alert goes out.
Gate two is a second model call — Haiku, small and fast — that receives the sources, the profile card, and the draft, maps each factual sentence to the input supporting it, and confirms each cited item is actually about this customer. It returns pass, or a list of flags. Flags trigger one revision: the compose call runs again with the flag details appended, and the recheck must come back clean. A flag that survives revision ends the same way as a gate-one failure: not sent, failed, alert.
The asymmetry behind both dispositions: a customer who does not get a Monday email has lost nothing they will notice. A customer who gets a Monday email with a wrong fact about their own project has lost some trust in the firm. A missed send is recoverable; a wrong send is not. Residual doubt has exactly one safe disposition.
After the batch, the coordinator receives a run report: what went out, what was revised on the way, what failed and why, with preview links. It is monitoring, not approval — by the time she reads it, the editions are in inboxes. Across fifty-six weeks the gates have failed eleven editions closed: eight for thin material, three for flags that survived revision. Eleven emails not sent is the system working.
A year of Mondays, honestly
Fifty-six weeks is long enough for everything characteristic to have happened at least once.
Feeds rot. RSS sources die quietly: a URL changes, a publisher retires the feed, and nothing errors — the stream just goes silent. The run report counts items per feed, and a feed silent three weeks running is flagged for a human. Two have been replaced so far.
Names collide. In the testing weeks, a research pass returned a clean, well-sourced item about a logistics company that shared a customer's name and nothing else. The Skill's selection discarded it against the profile card's description; the aboutness check at gate two exists for the day selection has a bad morning. The disambiguators in the research prompt make the case rare. The gates make it non-fatal.
Thin weeks happen. August exists in every sector. Below the material floor the edition is skipped, and a customer with no news gets no email — which beats an email with no news. Eight of the eleven fail-closed editions were exactly this.
One branch fails alone. Each stream's error handler degrades it to empty-plus-flag. Perplexity being unreachable at 06:30 produces editions without a customer-news section that morning, not a missed Monday. The scenario is idempotent — a re-run skips editions already sent — so one failure can be fixed and re-run without double-sending the other twenty-six.
APIs move underneath everything. Modules update, models version, a feed changes format. This is why maintenance is a phase of the method rather than an afterthought: a system that touches four external services changes when they do.
What a Monday costs now
The weekly run makes twenty-seven Perplexity research calls and about sixty Claude calls: twenty-seven compositions, twenty-seven checks, the occasional revision. Per edition that is roughly a cent of research, seven cents of composition against some fifteen thousand tokens of input, and a cent of checking — under ten cents. The full batch costs about two dollars and fifty cents a week. Make.com operations fit inside a standard plan. There is no server, no database, and no new infrastructure anywhere in the system: the firm's existing Microsoft 365 tenancy, two API keys, and a Make subscription.
The manual version cost twenty minutes of a person per edition, plus the paste errors, plus the Augusts.
The comparison is not close enough to be interesting, which is the point.
Reported, not asserted
Baselined during the Reverse Demo, measured in the systems of record since.
No tracking pixels. Replies and meetings are the measures a relationship email deserves.
During the four testing weeks, every edition was reviewed by the coordinator before sending, and her edits were tracked. The week the edit rate reached zero is the week the review step was switched off — not before. The trust the system runs on was measured, not assumed.
The pattern, if you want to build it yourself
Nothing here is specific to engineering, or to newsletters. The pattern fits any firm where somebody adapts a thing by hand, every week, for a list of accounts that matter. Seven components:
- A profile card per accountWhat they do, how they make money, what they care about — written with the relationship owner. This is the system's judgment, externalized.
- Harvest streams with date windows and dedupOver-collect mechanically. Never decide relevance at this stage.
- Internal change detectionModified-since on an allowlisted, client-ready folder. Report what changed, not what exists.
- One compose step: grounding rules, structured outputCopy, not layout. Package it as a versioned artifact you can test outside the pipeline.
- A deterministic renderThe model never touches the template.
- Fail-closed QA with one revision cycleSet membership on links, schema on structure, a support-and-aboutness check on claims. In doubt, don't send.
- A run log and alertsSo the absence of an email is always intentional and always visible.
Build them in that order. The profile card comes first because it is paper, not software: if nobody can write down what an account cares about, no pipeline will find out for them. Then one customer end to end before any scale. Then the gates, before the list grows. Then supervised weeks with a person reviewing every edition, tracking the edits — the week the edits reach zero is the week the review has earned its removal.
Watch for: name collisions (disambiguate in the research prompt, check aboutness at the gate); feed rot (count items per feed, flag silence); the temptation to pad a thin week (a customer with no news gets no email); the temptation to add tracking (the moment it reads as marketing, the replies stop); and folder scope (point the pipeline at a client-ready allowlist, never at the whole tree).
This system was scoped in a two-hour Reverse Demo and running as a prototype on three customers a week later. The engineering firm owns it outright — documented, versioned, and handover-ready, like everything we build.