Building SwimKeeper
I am still not a software developer, but SwimKeeper is in both app stores. What a swim parent was missing, what Claude built, what I decided, and the two weeks Apple sat on it.
Our daughter (our only child) started with swim lessons as a baby and loved being in the water. So we looked at swim teams, and by the summer of 2021 she was swimming on one at just six years old. Somewhere along the way I wanted a better way to keep track of all of it: meets, races, splits, best times, and how close she was to her goals. At the time I had the idea, there really wasn’t anything out there that did the things I wanted.
What was already out there
I tried the usual suspects. Meet Mobile only has the meets that get published to it, and it is not uncommon for a meet to not be published (this was particularly true five years ago). SwimCloud is primarily USA Swimming results, so nothing from our local winter and summer leagues ends up on there. Neither one tracks goals or cut times.
That left a spreadsheet. The problem was never getting answers out of it; it was the pain of maintaining it, and how inconvenient it was to get at on a phone.
So I built SwimKeeper, a private-by-default swim journal for families. Parents log meets, races, splits and notes, and the app works out all-time PBs, season bests and progress toward goals. There are no public profiles of kids and no third-party syncs. The privacy is enforced in the database itself, with row-level security.
Building it with Claude Code
Ten years ago I wrote here that I am not a software developer. That is still true. I am an SRE. I have written plenty of scripts and configuration in my career, but I had never built a mobile app. Frankly, I did not have the time to hand-code something like this even if I wanted to. AI is the reason SwimKeeper exists at all, and I am not going to pretend otherwise.
With that said, I want to be clear about what that actually looked like, because “I built an app with AI” has come to mean something pretty lazy. Claude Code wrote the vast majority of the code; 1,203 of the 1,275 commits are co-authored by it. I made every product call: what the app does, what it does not do, how private it is, and what had to be in a 1.0 versus what could wait. And I ran the project the way I would want any team to run a production service:
- Every change went through a pull request. There were 1,049 of them, against 679 issues I filed and worked through (547 are closed).
- Nothing merged without CI passing. There are 658 automated tests (about 12,000 lines, against roughly 65,600 lines of app code) and six CI workflows. Those include a scheduled smoke test and a check that flags drifting dependencies.
- Before the beta, and again in July, the code went through adversarial reviews: fresh passes whose only job was to find what was wrong. I fixed what they found.
- Changes got tested on an actual phone before they merged.
Part of my job was saying no. More than once I had to stop and ask: are we over-engineering and being overly cautious for a simple swim app with zero users? Error reporting is a good example. The plan for Sentry stripped out so much that I asked whether we were being a little extreme with the privacy. SwimKeeper is private by default, but I am not selling anyone’s data, and I did not want troubleshooting to be any harder than it needed to be.
All in, I worked on it on 104 separate days over seven months, from the first commit in April to opening sign-ups this month. The self-hosted setup behind all of it is a post of its own.
Everything around the app
I am not a designer either. An app on its own is not a product, though. SwimKeeper needed a look, a website, help pages and something to post on launch day. None of that is my field, but with Claude I could get it to a standard I am happy with.
The look comes from a design system called swimkeeper-design: warm paper, a deep lane blue, and a brass accent for medals and personal bests, set in Geist and Instrument Serif. The app and the website both build from it. CI fails if the site’s copy of it falls behind the app’s.
The website is a static Astro site on Cloudflare Pages, with five help guides. There are no stock photos. The phone mockups are built in HTML. A script retakes the help screenshots by driving the real app against test data, and another does the same for the App Store and Google Play listings.
The launch videos were made without a video editor. There is a 56-second intro, a shorter cut and five how-to videos. Each one is rendered frame by frame from real app screens in a browser and stitched together with ffmpeg. The family in them is test data, not anyone real.
Even the business side has a plan now. SwimKeeper belongs to KCB Systems, the LLC I formed in June, and a small ops repo maps out running it in three to six hours a week.
App store review
The thing that caught me off guard was the app stores. The Google Play and Apple developer accounts were set up under KCB Systems by September. The first TestFlight build went out on October 6th, and I submitted to Apple for review on October 20th. Review was just much slower than I anticipated, Apple delayed me over two weeks. In retrospect I would have submitted a much earlier version and used TestFlight a lot more, if I knew then what I know now.
Where it stands
SwimKeeper is live on the App Store and Google Play, and as of November 12th anyone can sign up on the web at swimkeeper.app. The next step is getting real users.