logo
Published on

Culture Drop: Using AI to Draft a Daily Reading App Without Letting It Publish

Authors
  • avatar
    Name
    Alberto Montalesi
    Twitter
This article was written with the assistance of AI.

Culture Drop is a three-minute daily ritual: four editorial cards — an artwork, a history entry, a word or concept, and a curious fact — and a fifth card where you write a private reflection. No account, no feed to scroll, no streak shouting at you.

A daily content app needs 365 items a year in four categories. I am one person. AI is the obvious way to make that volume tractable, and it is also the obvious way to end up shipping confident nonsense about a painting that does not exist.

The interesting part of this project is the machinery I built to get the first without the second.

 

The rule: AI drafts, a person approves, the tooling enforces it

The editorial flow is deliberately boring:

  1. An AI brief drafts candidate days as structured JSON, given the existing titles, terms, events and facts so it avoids repeats.
  2. Every draft is checked by a person against a fixed list: factual claims, event date, word count, source URL, image rights, duplicates.
  3. Approved days are saved into the repository as data/feed/YYYY-MM-DD.json. The repository is the editorial source of truth.
  4. A publish step mirrors images, rewrites their URLs, and uploads the validated JSON to object storage, where a Worker serves it.
  5. A verify step checks that every public feed still matches the repository and that every referenced image is served from the app's own CDN.

The load-bearing sentence, which I wrote into the project's own README so future-me could not talk himself out of it, is that the AI draft is never publish-ready by itself.

That is a policy, and policies decay. So the parts that can be mechanical are mechanical.

 

Making the pipeline fail instead of degrade

The failure mode I actually worried about was not a bad fact — it was the pipeline quietly doing something slightly wrong, forever, without telling me. Two specific cases got hard rules:

No image may be uploaded unoptimized. The publisher requires the image tooling to be present on PATH and fails before uploading anything if it is not. Paintings are published as WebP with a 2400px maximum long edge at quality 88; history and fact images at 1600px and quality 82. The optimizer derives target dimensions from the source rather than forcing a box, and rejects any output whose aspect ratio drifts by more than 1% — because silently squashing a painting is exactly the kind of bug nobody files.

No feed may reference someone else's server. Publishing fails outright if a feed entry still points at an external image URL. This one is about rights as much as reliability: an app that hotlinks artwork is both fragile and rude. The original file is kept as a backup, and exactly one stable optimized object is published per card.

Both rules share a shape worth naming: the unsafe path is not available, as opposed to documented as discouraged. A dry-run mode lets me confirm every source can be mirrored before anything is written.

 

Everything personal stays on the device

There is no account system and no user-data backend. Notes, saved cards and reading history live in on-device SQLite. The daily editorial JSON is public static content, so the app fetches only the date you are looking at, and falls back to a cached deck — then to a small bundled deck — when the network is unavailable.

This is partly a privacy position and mostly a simplicity one. A reflection journal is the last thing that should sit in someone else's database, and not having accounts removes an enormous amount of product surface I would otherwise have to build, secure and support.

 

Stack

Expo and React Native with Expo Router, expo-sqlite for local persistence, RevenueCat for purchases, and Sentry for error tracking. The feed is static JSON on Cloudflare R2 served through a Worker. Minimum iOS 16.4.

Notably absent: an application server. The only backend is a CDN serving files that a build step produced from a folder of reviewed JSON in a git repository. For a content app with no social features, that is most of the operational burden gone.

 

What I would keep

The generalisable lesson is not "use AI for content" — it is that if you do, the review step has to be structurally impossible to skip, not merely written down. A checklist in a README is a wish. A publisher that exits non-zero when the optimizer is missing, or when a feed still points at someone else's image, is a guarantee.

I got that right for images and the publishing path. The human review of facts is still a policy rather than a mechanism, and it is the part most likely to erode on a tired evening — which is worth being honest about rather than presenting the whole thing as solved.

You can read more about Culture Drop at culturedrop.montalesi.dev.

Did you find this useful?

0 readers found this helpful