It started with that question. My family has a box of recipe cards, handwritten, typed, clipped from magazines, and often written on both sides. I gave it a shot. Within two days most of the box was on a static site simple enough to run on a 2010 iPad, and by the end of the week all 144 cards were there.
The clean cards were done. The rest weren’t: about thirty needed fixes, and each misread ingredient or garbled step meant finding the right file among 144 and editing its Markdown by hand. Now I knew the idea worked, and what it needed next: a place to triage what the model got wrong, so every card could end up a finished recipe. At that moment, Penned & Plated was born.
How a Card Becomes a Recipe
Today, every card takes the same path into the archive:
It’s a web app, an iPhone app, and the pipeline between them, built by one engineer working with AI agents:
- One design system, made in Claude Design, is shared by the web app and the iPhone app, so the two feel like one product.
- The pipeline started as a few local scripts that read most of the box in two days. About three weeks later it moved into the web app, which reads each card with Claude Opus 5 as it’s uploaded.
- The web app is a Rails app. The archive was imported and readable five days after its first commit.
- The iPhone app is a SwiftUI app that scans a card, or a whole stack, front and back, and shows each reading as it happens. It uploads to the web app, which does the reading. Its very first version could already scan and upload a card; 26 days later it was out for testing.
Handling the Cards the Model Gets Wrong
Claude does a good job reading most cards, but I still needed a plan for the ones it gets wrong. I wanted to be confident in what lands in the archive automatically, and just as confident in what gets held for a person to review.
A few safeguards back that up:
- A recipe only shows up in the archive once its reading is settled, so nothing half-finished is ever visible.
- Unreadable words and contradictions go into separate lists, since different people usually handle them.
- Quantities are stored as text. Cards have entries like “1 1/4”, “1 to 2” and “2 [?]”, and converting those incorrectly could turn a teaspoon into a tablespoon.
- Duplicates are caught two ways. Repeat photos are flagged, and a text-similarity check catches the same card photographed differently. Titles alone wouldn’t work – the box has two different guacamole recipes, and we want to keep both.
Keeping the Two Apps in Sync
The web app and the iPhone app were built in separate Claude Code sessions, each with its own codebase. A shared contract for the API kept them in step.
The web app owns that contract: it’s written in TypeSpec, published as OpenAPI, and every request and response in its tests is checked against it. The iPhone app keeps its own copy and builds its connection to the web app from it, so it only picks up a change when it’s ready. The web session changed the contract nine times, and each time it messaged the iOS session, which updated its copy and built its half.
Where AI Needed Correcting
Nearly all of the code in both apps was written by AI agents, with a human in the loop: I reviewed every change before it landed. Some of what that review caught:
- Uploading a card the phone couldn’t read on its own would have crashed the iPhone app every time. The automated tests used a stand-in for the network, so they never saw it – a test against the real thing did.
- The agents left notes in the code explaining why certain approaches wouldn’t work. They sounded convincing, so nobody tried them. They turned out to be wrong.
- The agents sometimes built something by hand that the framework already provided. Those got removed.
- One change deleted a database update that had already been applied, which could have broken the live data. It was restored before it did any damage.
These turned into standing rules for the agents, like “Measure queries, do not reason about them” and “Count duplication, do not estimate it”. Measuring also showed that shrinking photos before sending them to the model saved nothing and made them harder to read, so photos are stored as they arrive.
Where It Stands
The web app has been live since September 2026, invite-only, and the iPhone app went into alpha testing on TestFlight in fall 2026. A closed beta, where testers start their own recipe boxes, is planned for Christmas 2026.
I’m a Rails and back-end engineer by trade. I’m comfortable designing the architecture and schemas that support an interface, but I’ve rarely been the one designing or building the interface itself. This project had me working across the full stack, including the initial design.