Elixir · Phoenix · Postgres · Oban · Rust
A production content system, built and run by one engineer.
Alter drafts, illustrates, voices, renders and publishes video for two YouTube channels, then measures what happened and writes it back against every decision that went into the upload. It has shipped every week since August 2026 on infrastructure its author owns.
Live. The always-on collector has been sampling competitor uploads hourly since 13 September.
86
migrations, every one run on a live database
2,505
tests, 44k lines of them against 111k of code
31
background workers across 8 queues, on two nodes
647
commits since 31 July 2026
One pipeline, from a topic to a measured upload.
A topic becomes an 800-line episode specification, checked by the same builders that render it. The spec drives picture generation, voice synthesis and the render, and the three agree on file names through one function, so nothing is stitched by hand. A human approves once, on a review page. Then the upload is scheduled, published, and read back.
01 · Draft
Spec from topic
LLM drafting through plain tool use, never constrained decoding: measured 6 usable sets in 6 against 2 in 12 the other way.
02 · Make
Pictures, voice, render
Image generation with a receipt per candidate, ElevenLabs voice, and a Rust document renderer on Skia/Metal at 5 ms a frame.
03 · Approve
One human step
A review page is the only gate. Approving runs the brand's publish rule; nothing goes public by accident and nothing waits on a person twice.
04 · Measure
Outcome joined to choice
Retention curves land on the exact scene timeline the render recorded. Impressions, velocity and the public label are read back on a schedule.
How it's built.
Release discipline
Every push passes mix compile --warnings-as-errors,
a format check and the full suite. Lessons that cost money are
pinned as tests, not written in a wiki: the node-role test that
stops the collector from ever holding a publish queue, the
fidelity probes that read pixels back from the renderer, the test
that keeps renders out of the Desktop root. A regression has to
get past the thing that already caught it once.
Migrations on live data
86 migrations across 44 tables, including a rename of the core tenant model (personas to brands) and a swap of a column's meaning under running jobs, both applied to a production database with users on it. Append-only where history matters: picture decisions are a log, never an update.
Infrastructure, owned
Two Elixir nodes on one Postgres: an always-on collector restricted by role to the queues it's allowed, and an app node that renders and publishes. Deploys through Kamal to hosts the author runs, EU hosted, with secrets, access control and logging owned end to end. Query logging is off in production by design, so OAuth tokens can never reach a log file.
Measurement and prediction
A competitor corpus of about 750 videos across 15 channels, sampled for view velocity at 1 h, 6 h, 24 h, 48 h and 7 days from upload, with an LLM structure pass over every public transcript run through the Batch API under a cost cap. A production ledger records each generation, each picture decision and each upload choice so it joins to the outcome. Hypotheses are first-class rows with arms. More on the about page.
Security and scope
Multi-tenant from the first migration: organisation, then brand, with every context query scoped. Magic-link login with a rate limit, HMAC-verified inbound webhooks, and a content security policy built at request time so the media host is the only third-party origin allowed.
Written with AI assistants, under review
Most of this code was drafted with an AI coding assistant and none of it shipped unread. The project file that steers the assistant holds the invariants that were paid for the hard way, and the rule is that a fix names its root cause or it doesn't merge.
The measurement is allowed to say no.
The corpus was built to find what predicts a video's reach. Across 713 videos it found that nothing about the video does: within one channel the spread from the 10th to the 90th percentile is 15x to 500x, and neither hook, title, length nor time-to-first-round moves it. Two "measured" claims in an earlier plan were wrong, and the plan says so now.
That readout changed the strategy from tuning openings to raising production rate, which is a cheaper answer and a truer one.
Alter runs its author's channels and isn't taking new accounts.
The engineering notes explain the system, the decisions, and what's being built next.
Engineering notes