On Thursday evening at 20:40 I opened an empty folder with a short note: remind me to take my pills, let me confirm I took them, keep a history, count what is left at home. On Friday at about 16:00 the app was submitted to App Store review, for iPhone, iPad and Mac, in four languages. On Monday morning Apple approved it.
The app is Vzato ("taken" in Czech), and it is in the App Store now. It is free, open source under MPL-2.0, has no server and no accounts, and syncs through the user's own iCloud. The code is on GitHub.
I built it with Claude Code. This post is about what that looked like in practice: why I built it, how the day went, what I did and what the AI did, and what it means to write and ship an app like this now. It wasn't magic, and it wasn't a toy either.
Why another medication reminder
There are plenty of them. I tried several before this, and none of them worked for me. Some I did not like. Some I simply did not understand how to use. And most of them missed small things that matter a lot when you actually take pills every day:
- When can I eat? Some medication has to be taken on an empty stomach, 30 minutes before food. So the reminder I need is not only "take your pill", it is also "you can eat now". I did not find an app that did this without me setting a second alarm by hand.
- Will I run out? I want to know how many pills are at home and on which day I need to get more, before the box is empty, not after.
- Half a tablet. Doses like ½ or ¼ tablet are normal. So are drops. Many apps only count whole pills.
- Did I already take it? The worst case is not forgetting a pill. It is taking it twice because you are not sure.
- No account. Most apps wanted an account, a subscription, or both, and kept my data on their servers. For a list of my own pills I don't see why.
So the specification started from my day, not from a feature list.
The main screen shows one big card: the dose that needs attention now, with one big Taken button. Below it the rest of the day. The medication list shows how much is left and when to get more.
What the app does
The short version, as it stands after a day:
- reminders with their own sounds, follow-up reminders if you do not confirm, snooze and skip,
- a "you can eat now" reminder after before-meal doses,
- half and quarter tablets, drops, ml, puffs and other units, with correct plurals in Czech, Slovak, English and Hungarian,
- supply tracking, a run-out warning and a supply check where you count what you really have,
- protection against double doses and an undo after Taken,
- history, and a summary for the doctor as an A4 PDF,
- photos of the package, the pill and the leaflet,
- widgets, iPad and Mac layouts, and sync through the user's own iCloud,
- a first-start guide and in-app help for people who are not comfortable with phones.
The "eat after" setting is one row in the form. When you tap Taken, the app schedules a second notification:
It is a small thing. For me it was the reason to build the app.
The timeline
| When | What |
|---|---|
| Thu 20:40 | First prompt: the rough idea, Czech and English |
| Thu 21:10 | Specification, implementation plan, three design directions to choose from |
| Thu 22:10 | Phase 1: data model, scheduler, notifications, four screens, tests |
| Thu 22:30–00:10 | Photos, iPad and Mac layout, half tablets, drops, Hungarian, iCloud sync, icon, widgets |
| Fri 01:00 | First TestFlight build |
| Fri 06:50 | Website and privacy policy, App Store texts uploaded through the API |
| Fri 07:00–09:40 | Builds 2 to 8, mostly fixes from using it on my phone |
| Fri 12:00 | A reminder did not ring. Bug found and fixed |
| Fri 13:00–16:00 | First-start guide, help, public repo, screenshots, review submission |
| Fri 19:00 | Apple asks for more information; screen recording and answers sent, resubmitted |
| Sat | First crash report from TestFlight, fixed; Skip button in the widget |
| Sun–Mon | Profiles, repeat every N days or months, offline medicines database |
| Mon 09:53 | Version 1.0 approved for iPhone and iPad, then for Mac |
| Wed | Reminders reworked, 1.0.1 submitted |
From the empty folder to the submission was about 19 hours on the clock, with two breaks for sleep. Something like 11 or 12 hours of me actually sitting there. From the empty folder to the App Store, a long weekend.
The result: 31 commits, around 8,000 lines of Swift, 80 unit tests plus UI tests, 11 TestFlight builds, 48 App Store screenshots generated and uploaded by script, and a static website on Cloudflare.
How the day actually went
The first hour was not code. I described the idea and asked for a specification and an implementation plan in phases. Then came questions: what should the app be called so it does not get rejected, which licence, should there be a server, Core Data or SwiftData. I asked for options, picked one, and the decision went into the specification. Only then the first code.
Phases, not one big prompt. Phase 1 was the core: data model, the scheduler that works out which doses are due today, notifications, the four main screens, tests. Then photos, then the iPad and Mac layout, then sync, then widgets. Each phase ended with a build and a commit. Ideas I had in the middle ("half tablets", "drops", "Hungarian for my mother") were added to the plan and done in order.
Then the TestFlight loop. From Friday morning the work looked like this: I used the app on my phone during a normal morning, found something that was wrong or annoying, wrote a short message, often with a screenshot and full of typos, and about 15–30 minutes later there was a new build in TestFlight. Some of what came out of that loop:
- I had 79 pills at home, three a day, and the app's answer to "when do I run out" was wrong. The counting was fixed and the medication list now says "get more by 7 Nov".
- Typing a new amount into the stock field appended to the old value instead of replacing it.
- The Taken button was available for doses four hours ahead. With several medications that is an easy way to take tomorrow's evening dose at breakfast. Now one-tap Taken only works from 30 minutes before the dose. For earlier doses there is "Take early…" with a question, and every Taken can be undone.
None of these would have shown up in a demo. They showed up because I was taking real pills at the time.
Two agents at once. While the main session worked on the app, a second agent built the website in Astro: a landing page, help pages with screenshots and the privacy policy in four languages. It got the same rules as the app: no JavaScript, no cookies, no external requests.
What I did
I wrote about a hundred prompts, most of them short. Looking back, almost none of them were about code. They were decisions:
- No server. The first plan offered a backend for family sharing. I asked what a server would actually give users over iCloud. For one person's medication, nothing, and a server means GDPR, accounts and running costs. So no server, ever. That decision shaped everything else.
- Core Data, not SwiftData, because CloudKit sharing later needs it.
- The name. The working name, MedRemind, already belongs to another app. Vzato came from the button you press.
- The design. I got three directions as mockups and picked one: a single big card for the dose that needs attention now.
- What not to build. The plan has optional phases: sharing with family, a medicines database, profiles for kids. They stay optional until someone asks.
- Testing on a real phone, every build, during my real day.
That last point mattered most.
What went wrong
The reminder that never rang. On Friday at noon nothing happened, no sound, nothing on the lock screen. Every test passed. The cause: the app only asked for notification permission when you tapped a button in Settings. Without permission, iOS accepts scheduled notifications and never shows them. No test caught it, because in the tests everything worked as written. The fix was small: ask as soon as the first medication has a schedule, and show a red warning on the Today screen when reminders are off (left in the picture above). Finding it took a person standing in a kitchen at 12:00, waiting for a sound.
Help text describing a gesture that does not exist. The in-app help said "swipe a dose to change it". In the app those rows are a plain stack, not a list, so there is no swipe, only touch and hold. The text sounded right, and it was wrong.
Advice that would have broken the supply count. The help suggested adding a new package through the supply check. That check compares expected and actual stock, so it would have reported a surplus. The correct path is editing the amount at home. Again plausible and wrong. Both were caught when I read the help, not by tests.
Apple Health. I wanted taken doses to show up in Health. The AI went into the SDK headers and found that third-party apps can read medications in HealthKit but cannot write dose events. The feature is on hold, and the reasons are written in the specification so nobody has to research it again next year.
Apple Watch. I asked whether we could at least test the watch in the simulator and take screenshots. Without a watch app there is nothing to screenshot; notifications mirrored from the phone can't be tested in the simulator. We left it. It was not important.
The pattern: code that compiles and passes tests is the easy part now. The bugs that are left are the ones where the program does what it was told and the instruction was wrong.
What helped
- Specification first. Before any code there was a specification and an implementation plan in phases. Every behavior change updates the spec and the changelog in the same commit. When I came back after sleeping, the state of the project was in the documents, not in my head.
- Hard rules in
CLAUDE.md. No third-party packages, no analytics, no network except Apple, "not a medical device", MPL header on every file, no secrets in git, never pre-create dose records, stock changes in one place only. With these written down I did not have to watch for them in every change. - Ask for options, not answers. Name, licence, design, storage: I asked for two or three options with trade-offs and picked one. That is quick and keeps the decisions mine.
- Debug switches for everything. Demo data, a throwaway store, open a given screen, a fixed window size on the Mac. Screenshots in four languages for iPhone, iPad and Mac are a script now, not an afternoon.
- Automate the store work. App Store Connect has an API. Texts in four languages, age rating, pricing, availability, TestFlight notes and all screenshots go up from a script. Doing this by hand would have taken longer than some of the features.
Shipping is more than code
This is the part people underestimate, with or without AI. After the app worked, there was still:
- a privacy manifest and the App Store privacy answers ("Data Not Collected", and it has to be true),
- the CloudKit schema deployed from development to production in the CloudKit Console, or sync silently does not work for users,
- the age rating, the content rights question, the price and 175 countries,
- the question whether the app is a regulated medical device (it is not, and the app says so in Settings),
- the EU Digital Services Act trader status,
- a support address (info@vzato.app, forwarded through Cloudflare Email Routing),
- a website with help and a privacy policy in four languages, a sitemap, Google Search Console,
- a first-start guide and help written for people who are not comfortable with phones,
- an audit of the git history before making the repository public.
The AI prepared nearly all of it: texts, scripts, API calls, the website. But the consoles, the agreements and the "I confirm" checkboxes were mine, and so is the responsibility for what they say.
So what does it mean now?
Writing the code is no longer the slow part. A universal SwiftUI app with sync, widgets, localization and tests in a day would have been a few months of evenings for me before.
What is still slow, and still mine:
- Deciding. What it does, what it does not do, what it must never do.
- Living with it. Using the app for real days. The best bug reports came from my own day, not from tests.
- Reading. Help texts, translations, privacy policy. Everything a user reads has to be checked by someone who knows what the app really does. The Hungarian still waits for a native speaker.
- Responsibility. It is a medication app. It must not recommend doses or interpret anything, and it says so. The answers in App Store Connect have my name on them.
- Maintenance. The app exists now. iOS will change, Apple will ask new questions, someone will report a bug. That doesn't take a day; it takes years.
I don't think this makes development trivial. It changes which part of the work takes the time. Typing is cheap now. Judgement isn't, and judgement is what you are still responsible for.
It also changes what is worth building. An app for a few people, or for one family, used to be too expensive to make properly. Now it is an evening and a morning. That is the part I find most interesting.
What happened after that
This post sat in a drawer until the app was out, so here is the rest.
Apple came back the same evening with a request for more information, the standard one for a new app: a screen recording from a real phone showing the typical flow, a description of the purpose and audience, the external services the app uses, whether it behaves the same in every region, whether it is a regulated product. I recorded two and a half minutes on my iPhone (adding a medication, the reminder on the lock screen, Taken, the history, Settings), wrote the answers into the review notes and resubmitted. Two days after the first submission, on Monday morning, version 1.0 was approved for iPhone and iPad; the Mac version followed shortly after.
TestFlight brought two crashes, both the same kind: iOS killing the app in the background because it was still writing to the database while iCloud synced. The first fix covered leaving the app; the second report came from a sync that iCloud started on its own. Neither showed up in a test or in the simulator. Both came as crash reports from my own phone.
Then came the first real user feedback, from me, after three days of taking pills with it: with a locked phone some reminders were silent, and then they came all at once. The rules were technically correct and impossible to explain. They are simpler now: one notification per time with every medication due then, a couple of follow-ups, then silence, and the reminders come through Do Not Disturb. A medication is worth that.
Version 1.0.1 went to review four days after 1.0, with profiles for children and animals, repeat every few days or months, and an offline database of Czech and Slovak medicines built from open data. The pattern from the first day held: the code was the quick part. Deciding what the app should do, and using it for real, is where the time goes.
It is free
Every feature, for everyone, including the source code. There are no ads, no subscription and nothing to unlock. I built it because I needed it, and I will keep maintaining it for myself. If it is useful to you too, good. Comments, bug reports and pull requests are welcome, and if you want to, you can buy me a coffee.
- Website: vzato.app
- Code: github.com/kornelko2/vzato.app
- App Store: apps.apple.com/app/id6831807640






