Skip to content
Yassir Halaoui

AI engineering · 7 min read

A signed Mac app in four days, built with AI coding agents

By Yassir HalaouiPublished

In short

AI coding agents can take a real product from first commit to a signed release in days, provided a person owns what the agents can't: what the product refuses to do, which numbers are true, and when a result is good enough. Kempt, a native macOS app, went from first commit on 13 October 2026 to a notarized 1.0 with Stripe licensing and Sparkle updates on 17 October, across 154 commits, with one agent building and a second reviewing.

I made Kempt's first commit on Tuesday 13 October 2026. On Saturday the 17th, version 1.0 was live: a native macOS app, signed with a Developer ID, notarized by Apple, updating itself through Sparkle, and selling licence keys through Stripe. The Mac App Store edition went to review the same day.

That's 154 commits over five calendar days. Today the app is about 20,000 lines of Swift with 122 tests. I didn't type most of it. AI coding agents did, mostly Claude Code, with OpenAI Codex reviewing. People ask how that works in practice, so here is the honest version, with the parts that went wrong.

Day one was four commits, and one of them was an eval harness

The first day produced four commits. The first was the skeleton: a menu bar app, a drop zone in the notch, and AI file naming. The second was called "facts-first classification, slot-based naming, eval harness".

That ordering mattered more than anything else in the week. Kempt reads people's payslips and bank details with Apple's on-device model, which is small. Before there was any interface worth showing, there was a way to measure whether a change made naming better or worse. Everything that came after could move fast because it could be checked.

If I had to pick one habit to copy from this project, it's that one. An agent that can run a test set will tell you when it broke something. An agent that can't will tell you it's done.

Day two was seventy-three commits

The 14th was the day the agents ran wide. Several sessions worked in parallel on separate Git worktrees, each on its own branch, so they couldn't trample each other's files: search over every document on the Mac, answers grounded in their sources, a rules engine you write in plain English, a clean-up tool for old installers and duplicates, onboarding, settings, and App Intents so Siri and Shortcuts could use all of it.

That last one is a good example of where agents shine. Exposing App Intents normally assumes an Xcode project, and Kempt's direct edition doesn't have one. Working out the metadata extraction by hand, with the right compiler flags, is fiddly, well-documented-nowhere work. An agent will grind through it without getting bored.

The same day, one commit reads "Add independent review brief for Codex". A second agent, from a different vendor, reviewed the business case and the code with no access to the first one's reasoning. Some of its advice I took. Its main recommendation, to position Kempt purely as an accountant tool, I didn't. A reviewer's job is to disagree with you. It's still your call.

What the agents couldn't own

Volume came from the agents. Three things never did.

What the product refuses to do. On the 15th I decided Kempt would ship without analytics. No PostHog, no crash reporter, no SDKs. On the 16th I decided the only network request in the whole app would be a daily update check that sends the version number. An agent will happily add telemetry because telemetry is normal. Saying no is a product decision, and it has to come from whoever answers for the product.

Which numbers are true. At one point a revenue figure, $136k a month, made it into a planning document. Nobody could find where it came from. It read like a fact, it was formatted like a fact, and it was wrong. Kempt's handoff file now has a line that says don't trust a number you haven't verified. I wish I'd written it on day one.

When something is good enough. On the 14th, the accountant pack, which pulls a month of receipts into a merged PDF and a CSV, scored 14 of 16 on inclusion, 3 of 5 on amounts and 2 of 5 on dates against hand-verified labels. A few commits later it was 16 of 16, 5 of 5 and 5 of 5. The agents did the fixing. Deciding that 3 of 5 wasn't shippable, and that 50 labelled examples were enough to trust the next result, was mine.

What nearly broke

None of these were in a tutorial.

macOS kept revoking the agent's access to the Desktop. The project started in ~/Desktop, and macOS privacy controls kept pulling the agent's file access mid-session. The fix was dull: move the repository to ~/Developer, which isn't a protected folder.

The release build hung when Kempt was running. With the app open and naming files on the on-device model, a release build took 285 seconds, and once sat at 2% CPU for over an hour. With the app quit, it took about 26. The build script now starts with pkill -x Kempt.

Notarization waits break when the laptop sleeps. Apple's notarization can take minutes. If the Mac goes offline in the middle, the script used to start over. It now takes KEMPT_RESUME=<submission id> and carries on waiting for the submission that's already in flight.

The first payment provider said no. Lemon Squeezy declined the store. Rather than wait, licensing moved to a Stripe webhook running as a Vercel function: a paid checkout mints an Ed25519 licence key and Resend emails it once per order. That took part of the 16th.

The performance work was measured, not guessed

Two commit messages from the 15th say more than a paragraph would:

ChangeBeforeAfter
Clean-up scan8.2 s, 1.74 GB0.86 s, 83 MB
First answer from Ask202 ms25 ms
Finder tags, per file600 ms0.1 ms

The agents found these because the app had benchmarks to run. Without a number before and after, "make it faster" produces code that's different, not faster.

If your team is about to adopt coding agents

What I'd keep from this week:

  1. Build the evaluation before the feature. It's what turns an agent's "done" into something you can check.
  2. Run agents in parallel on separate worktrees. One task, one branch, one session. Conflicts drop to almost nothing.
  3. Have a second agent review the first. From a different vendor if you can. Then disagree with it where you know better.
  4. Write the handoff file as you go. Kempt's CLAUDE.md records every product decision with its date. Every new session starts by reading it, which is why day five still respected decisions made on day two.
  5. Keep the review bar where it was. Agents write a lot of code quickly. That's exactly why a person still has to read it.

Four days is fast. It wasn't careless, and the difference is mostly the evaluation harness from the first afternoon. The same approach applies to an AI feature in any product; I've written up the answer-grounding side separately in making a small on-device model safe for money questions.

Written by Yassir Halaoui, Senior Fullstack Java / React Developer in Paris. Nine years across banking, payments and insurance, and three products built and operated solo. Get in touch.

More on ai engineering