FILED / Sep 12, 2026

I automated the send. I forgot to automate the draft.

Last issue I wrote that a human gate belongs only where the judgment is genuinely mine, and that everything after the "yes" should belong to a scheduler. Then I built exactly that: approved issues now send themselves at 8am on their day, no session required. And this issue is late anyway — because nothing scheduled the drafting. I moved the gate upstream and called it removed. The machine did every job it was given this week; it was not given this one.

What we built

1. The fleet moved to a new model in one command — after the binary said no. The model launched Tuesday; my config already named it; the first request came back "requires a newer version." The model wasn't the gate, the eight-week-old binary was. One package upgrade, one test prompt ("reply with exactly: OK, then your model name"), and every worker dispatched since runs on the new model. Steal this: when a model launches, check the client version before the model name. And keep a one-line smoke prompt around — "say OK and name yourself" is the fastest way to prove which model actually answered.

2. Scheduled sends, for real. "Approved" and "scheduled" are now different states in the newsletter platform: a scheduled_send_at column, an operator route to set it, and a daily cron that sends anything approved and due through the exact same code path as a manual send — so a double fire is a no-op. A coding agent built it from a one-page brief; I reviewed the diff, ran the migrations on both production databases, and deployed both letters. Steal this: a cron should never have its own send logic. Point it at the same function a human would click, and let the existing state machine make it idempotent.

3. One codebase, two products, one migration. The second letter runs on a copy of the first letter's code that had drifted just enough that a git merge wouldn't take. Porting by hand was eight files and one hunk — and it surfaced that the drifted clone had its own migration sequence, so the "same" change needed a different migration number on each side. Steal this: a forked copy is a second product with a maintenance bill. Either merge it back into one repo with a config switch, or budget the port every time.

4. Five repos moved to the company. Every repo I'd created this month had landed under my personal GitHub account. Five transfers later they live under the company organization; old URLs redirect; local checkouts were repointed. Ten minutes, and it should have been the default from the first commit. Steal this: decide which account owns new code before the first git init, and write it down where the agents will read it.

What it cost

Item Cost
Model upgrade $0 (subscription; binary update)
Scheduled-send build one agent run, flat-rate
Repo transfers $0
Web analytics on the letter's site $0 (platform tier)

What broke

Two things, both silent.

The first: this issue. The send was automated; the draft was not, and no alarm existed for "the draft hasn't been written by Monday." Third late issue, same root cause each time — a step that lived in my intentions instead of a schedule.

The second, in the family app: the assistant was dead on staging for five days with "credit balance exhausted." The runtime was using a July key from an account nobody was funding, and the replacement key created on the 6th had its secret saved to a zero-byte file — a key that exists and can never be used. Nobody noticed because the failure was a quiet refusal, not a crash. Fixed with a fresh key and a check that a saved secret actually has bytes in it.

One lesson: automation is a chain, and a chain has a first link

It's easy to automate the last step. The last step is concrete: send, deploy, post. It has a button, so you replace the button with a cron and feel done.

The first step is the one that stays manual, because it's the creative one — deciding, drafting, choosing. It feels like it should be yours. But if the first link is manual, the whole chain waits on you, and the automated links downstream just wait faster.

The rule I'm adopting: a recurring output isn't automated until a machine owns the calendar for its first step. For this letter that means a scheduled agent that drafts on Monday, stages the draft, and hands me a link — my job shrinks to reading and saying yes. Approval stays human. Initiation doesn't.

Decided this week: the drafting agent

Design, not a result — first run reports next issue. A cloud-scheduled agent wakes every Monday morning, reads the week's operations log and the signal desk's open calls, drafts both letters against their style specs, stages them as approved-pending drafts on each platform, and posts one message with two links. The human gate is a single word. If the word doesn't come by Wednesday night, the agent sends a reminder, not the issue. Kill criterion: two drafts in a row that need more than light edits, and it goes back to being a Monday chore with a calendar alarm.

Also this week: the app-store path for the family app reopened after a two-week lockout, and the parallel session running that project has two reviewed pull requests waiting. That's next issue's story if it ships.


written by the machine · judged by the human