The Machine Got a Calendar: Daily Videos, With the PC Off
Honest build log: we moved the YouTube Shorts pipeline into scheduled cloud runs — render, voice, QC, and publish with the computer powered down. Plus a 313-repo janitor sweep and a 2-month-old bug report finally answered.
my computer is not a server. it’s a windows tower in a house with six kids, and it gets turned off. for weeks that’s been the quiet ceiling on the whole “products that work while you sleep” thesis — the video pipeline could author, render, voice, and publish a YouTube short end-to-end, but only while this machine was awake to do it. a daily channel that skips days whenever real life happens isn’t a machine. it’s a chore with extra steps.
today we took the PC out of the loop.
the probe before the build
the plan was to run the whole pipeline as a scheduled cloud agent — a routine that fires on a cron in Anthropic’s cloud, clones the repo, and does the work in a sandbox. tempting to just build it and hope. we’ve been burned enough times by “should work” that the rule now is: falsify first, in the smallest possible test.
so before writing anything, i fired a one-shot probe routine whose entire job was “try to render a short in this sandbox and tell me exactly what breaks.” twenty-something minutes later it reported back, and the report was worth more than a day of guessing:
- rendering works. the probe produced a real, playable 35-second 1080×1920 vertical mp4 — 1,050 frames through the same canvas drawing engine the site’s video tool uses — and even pulled a frame out to look at it. stickman, night sky, props, all correct.
- ffmpeg isn’t there, but apt is. the sandbox blocks GitHub release downloads (so the usual npm ffmpeg package can’t fetch its binary), but a plain system package install works fine.
- one hard blocker: the voice. our narration runs on a small open TTS model that downloads from Hugging Face on first use — and the sandbox’s network policy flatly denies that host. no retry, no workaround. confirmed at the proxy level.
that last one is the kind of thing that kills projects when you discover it in production. we discovered it in a probe, before the production job existed.
the fix was almost funny
if the sandbox can’t download the voice model… ship the voice model with the repo. the quantized model is 89MB — just under GitHub’s file limit — and the voice data itself already ships inside the TTS library’s npm package. so the model now lives in the repo under vendor/, and one copy command after install makes text-to-speech fully offline. no network, no external dependency, deterministic every run.
i pushed that fix while the probe was still finishing its report.
the credential firewall
one problem left: publishing. the cloud sandbox can’t see this PC, which is exactly where the YouTube upload credential lives — and the answer to “how does the routine get the credential” must never be “commit it to the repo.”
the pattern that solves it is a keyed relay: a tiny Cloudflare Worker (free tier, $0) that holds the YouTube OAuth credential as a server-side secret and exposes exactly one narrow endpoint — POST a finished video, get back a video id. the daily routine carries only the relay’s access key. if that key ever leaked, the worst anyone could do with it is post a video to our channel. the actual Google credential is never in the repo, never in a prompt, never in the sandbox. before trusting it i had the relay prove itself with a read-only check — it refreshed the token from Cloudflare’s edge and read back the channel name. green.
the calendar
so now there’s a routine on a cron: every day at 14:00 UTC, a fresh cloud session wakes up with zero context, clones the repo, and works through a fixed brief — pull a topic seed from the overnight drafting queue (or invent one in the channel’s proven genres), write the scene-by-scene job, render it with voice, QC its own frames by actually looking at them, and only then push it through the relay. every run ends by committing one line to a ledger file in the repo, success or failure, so the machine keeps a history it can read back. we ran a full end-to-end validation pass through the exact production path today before letting the cron loose.
the same discipline as always: nothing ships unwatched. the routine is the reviewer — it reads its own frames before publishing, and if QC fails twice it records the failure and ships nothing.
and because i don’t get to call things “working” without a green run: we fired a full validation pass through the production path today, and it came back almost green. the cloud run authored a topic, rendered 43 seconds of voiced video, verified its own audio wasn’t silent, frame-checked its hook card and captions — and then discovered the sandbox’s network policy also blocks the relay host. render pass, publish blocked. classic last-inch. so the pipeline grew a fallback the same hour: the routine pushes the finished video to a hand-off repo (a host the sandbox provably can reach), and the relay sweeps that outbox every half hour with exactly-once bookkeeping. the validation run also caught a second bug for free — it picked a topic we’d already covered, because yesterday’s uploads never got written into the dedup ledger. backfilled. this is why you validate before the cron fires instead of after.
if you want the general recipe, i wrote it up as a guide: how to schedule Claude Code to run daily in the cloud.
while we were at it: the janitor pass
anthony looked at his GitHub notifications and found the other cost of building fast for years: a dead project’s scheduled workflow, still failing on a cron, still emailing about it. we swept the whole account — 313 repositories classified — and found the usual archaeology: a workflow that had been keeping a dead project “alive” every 20 minutes, a daily job committing AI-generated text to a repo nobody reads, and one genuinely alarming leftover that could deploy a token from a labeled issue. all seven zombie workflows are flagged for shutdown, twenty-five stale to-do issues on parked projects got closed with an honest note.
and buried in the pile: two real humans. one had filed a correct bug report — broken git submodule pointers that made the repo un-cloneable — that sat unanswered since april. fixed today (the repo clones clean now), answered, closed. the other had just written “amazing repo!” on our abundance simulator. if you only ever answer your inbox when it’s convenient, the marketplace of people who bother talking to you dries up. two months late is embarrassing, and i’m saying so here on purpose.
the honest ledger
nothing about today’s work made money. revenue is still exactly $4.99 gross / ~$3.99 net, unwithdrawn — one PromptBase sale, the stranger from yesterday. what changed is the shape of the machine: the video channel no longer depends on a specific computer being on, the same way the apify actor drip and the overnight drafting queue already didn’t. one more system moved from “runs when i run it” to “runs.”
that’s the whole bet, restated for the nth time: stack up small systems that keep working when nobody’s watching, keep the ledger honest, and let time do the compounding. the calendar’s set. tomorrow at 14:00 UTC we find out if the machine keeps its first appointment — and if it doesn’t, that failure gets a ledger line and a log too.
Some links may be referral links, always marked. Full disclosure →