TL;DR: I made a home-cooked meal of an app just for my family. It took 3 tries, but they were fast iterations thanks to AI. I did the hard thinking, and let AI do the tedious stuff.

River's wishlist and insight tabs

Why Build It?#

A while back, I read Robin Sloan’s “An app can be a home-cooked meal”. It’s about building software for people you know, not the market. Since then I’ve been looking for a chance to do the same. That chance finally came when I was about to cancel a streaming service but didn’t know if anyone in my family of 4 was using it or not. Wouldn’t it be nice to be sure? Can I be sure without interrupting my family who are often busy with school and work? Looking at this problem through the lens of a “home-cooked meal” app gave me the nudge I needed.

I like to spend on subscriptions when they’re useful, but not when we don’t use them. My family pays for five streaming services but sometimes goes months without watching anything on one or two. These services are easy to turn on or off, so why shouldn’t we be more efficient with our money? What if we had an app to show in real time which shows everyone wants to watch. Furthermore: what if everyone knew exactly which of their shows were “at risk” when a cancellation date looms?

The app is called River, because why not. Rivers are fed by a bunch of Streams, and the app tracks streaming services. Welp, it took you longer to read that sentence than I spent coming up with the name.

River tracks what everyone wants to watch and which services have it. Simple cost-benefit analysis. You still watch your shows in Netflix or Hulu. This isn’t a streaming app, it’s an information tool that supports family decision-making. And it updates in real time whenever anyone makes a change.

Even so, I couldn’t help but do some light market thinking. The core problem isn’t technical—it’s social. We need to negotiate which streaming services to keep or cancel. I learned long ago that technical solutions don’t solve social problems, so River doesn’t even try to participate in the negotiation. Instead, it provides up-to-date shared information so everyone’s on the same page. It even provides insights to help the discussion (like “12 shows on Apple TV Plus at $1.25/show” or “You want to watch 2 shows on Hulu, which will be cancelled on Dec 13th”). From there, we can have a productive conversation.

Even with two complete failures along the way, it came together more quickly with AI assistance than I expected.

I mean, the code is really really bad in places. And the internals have pretty buggy edge cases. But the core flows are reliable, useful, and look pretty good too.

I had a secondary goal to teach myself how to use Apple’s CloudKit to share data between family members, so everyone sees the same view. Core Data + CloudKit sharing is poorly documented by Apple. Even worse, very few in the developer community blog about it. Safe to say there’s very little in any AI training corpus, which made AI assistance super risky. In fact, AI completely failed at it until I deeply learned about it and guided the work in great detail.

Yes, this app could have been a Google Sheet. That just wouldn’t have been as much fun. River has Poster images and knows which shows are available on which services. All thanks to TMDB integration.

Searching for 'Firefly' in TMDB

So how did it go? Well, it took three tries.

Attempt #1: SwiftData (2 days, failed)#

WWDC talks made SwiftData look like the modern choice. Clean @Model decorators, automatic CloudKit sync, modern Swift concurrency.

@Model
final class Show {
    var tmdbID: Int = 0
    var title: String = ""
    // ...
}

Buuuut. After AI built the entire app, including TMDB search, poster grids, and wishlist management. The AI said “I’m sorry, SwiftData doesn’t support CloudKit sharing between users.” You can sync your own data across your devices, but you can’t share a collaborative data space with other iCloud users.

Oops.

Attempt #2: Manual CloudKit Management (5 days, failed worse)#

I had AI rebuild using Core Data. Core Data + CloudKit requires a two-store architecture: one for your private data, one for shared data. Core Data handles this through a properly configured NSPersistentCloudKitContainer.

Then I implemented sharing. This is where things went completely sideways. Looking back, I think this was AI’s naive understanding due to the dearth of documentation. It knew the Core Data API and the CloudKit API, so why not cherrypick the useful bits of both? Well, that’s just a super bad idea if you don’t honor how they’re already working together behind the scenes. When my app was actively reaching underneath NSPersistentCloudKitContainer to monkey with CloudKit directly, this was doomed.

Surprisingly, it compiled. It ran. Individuals could use the app. But unsurprisingly, no sharing would happen.

Study Period (several days)#

I clearly didn’t understand CloudKit sharing. Nor did AI. Time to learn the old-fashioned way. This led to a few days studying without AI. Reading Apple’s docs. Watching WWDC sessions. Tracing through sample code. Really, this was a lot of fun. I highly recommend it as a refreshing antidote to AI-driven workflows. The end result was a markdown file I would eventually feed into the next round with AI as Ivans-Insights.md.

Just as important: I collected sample code, blog posts, and even the code from my two prior failures and put them all in a place accessible to the AI. The Ivans-Insights.md file referenced each specific item and bound them all together.

Attempt #3: Guide the AI (~8 days, success!)#

Once I understood the Core Data architectural requirements, I rebuilt with AI assistance. Claude was pretty darn good at generating SwiftUI views, connecting the data to the views, boilerplate code, logging, etc.

I also managed to fit in time to create a minimal CI using XCode Cloud and a few scripts, even though I promised myself I’d never do the ’toil’ of standing up CI again.1 TestFlight distributes builds to family members for testing and makes it super easy for them to install.

What I Learned#

My family has a useful app that actually solves the problem. Yay!

The “home-cooked meal” attitude unlocked some benefits I didn’t foresee: no market analysis, no pressure to have a “killer app” idea. No security hardening, exploit monitoring, and grief prevention that a public release would require. Woohoo! Maximizing the fun of app creation!

It took just 2 weeks of low-key work — most were evenings, though a few days stretched to 8-ish hours. Pretty low stress, all things considered. The hard part wasn’t the coding. It was the document archaeology around Core Data and CloudKit. Did you know that Core Data has been around a long time at Apple? Furthermore, it borrows concepts from an even older NeXT framework called EOF? I’m not dunking. Far from it. Core Data is powerful, but it takes time to master.2

The code isn’t up to my standards in some places, but I’m learning to live with “good enough.” The app is stable, has a tiny audience (somewhere between 0 to 4 DAU), doesn’t lose data, and actually solves the problem.

What did my family learn about our subscriptions? Well, to my surprise, we use all of our streaming services right now. So no cancellations. For now.

This was my first home-cooked app. With this small win under my belt, I think I’ll be looking for opportunities to make more.


  1. Why build Continuous Integration for a tiny project unless you’re an absolute maniac for CI? I am such a maniac, which is why I had to set this rule for myself. ↩︎

  2. I have not mastered it. ↩︎