the part of shipping an ios app my agent team couldn't do
indebtio now has a native app in the app store, and i wrote almost none of it. the same agent team that runs the backend wrote the swift. the interesting part wasn’t the code — the agents handled that fine — it was everything around the code they couldn’t touch.
indebtio is a bootstrapped danish debt-collection product, run by one person with a pipeline of narrow agent personas and two human gates. until the app, that team had only ever shipped to a web stack where everything is reachable as text. native swiftui was new ground for both of us. i skipped a webview wrapper because a tool people open to check money they’re owed should feel like it belongs on the phone.
the agents wrote the swift
the pipeline barely changed. the same personas — refiner, implementer, then the review and qa gates — picked up swift with a new brief and not much else, and issues came back as draft prs the way they do for the backend.
swiftui was where they showed their age. it moves fast, and the implementer kept reaching for deprecated apis: NavigationView instead of NavigationStack, the old single-closure onChange(of:). code that compiles, warns quietly, and behaves wrong on a current ios. the reviewer persona, briefed on the current apis, caught those. so the code was never the hard part.
where the loop broke
on the web, every step my agents run is text. the issue is text, the code is text, ci prints text, and the result is a pull request i read and merge. nothing in that loop needs a hand on a mouse, which is the whole reason it can run while i’m asleep.
native ios isn’t like that.
web loop (agent-drivable) ios loop (human-gated)
───────────────────────── ──────────────────────
issue → text issue → text
code → files on a branch code → files on a branch
build → ci, prints text build/sign → xcode + a private key
test → ci, prints text test → a phone in my hand
ship → merge + deploy submit → app store connect, then a human
xcode signing and provisioning, a build installed on a phone in my hand, app store connect behind 2fa, a reviewer on apple’s clock. the agents can’t hold the signing key, tap a device, or log into my apple id.
on the web the whole loop is text an agent can act on. on ios, half of it is a console only i can log into and a device only i can hold.
i’d deliberately cut indebtio’s process to two human gates: what’s worth building, and what’s good enough to ship. mobile quietly added a third — get it past apple — and that one i can’t hand back.
apple, not swift
publishing was harder than building. even getting a build to a tester runs through testflight and apple’s processing queue first. then my first submission bounced, and not over code: the reviewer couldn’t get past the login, because i hadn’t left a demo account in the review notes. the next round wanted in-app account deletion, guideline 5.1.1(v). both live in apple’s rulebook, not the codebase, and no persona in my pipeline knew to look there.
the platform also made me think differently than the server ever did. on the backend a request arrives, you check the token, you respond, it’s over. an app is long-lived — backgrounded mid-session, resumed an hour later with a token that expired while it was away — so i learned to refresh when scenePhase goes active, not on a request boundary, because there is no request boundary. the little that touched credentials in the keychain i read line by line myself, the way i keep the threat model next to the code on the backend.
agents collapse the cost of writing software. they do nothing for a platform’s perimeter — signing, store review, a device you have to hold. on the web you can pretend that perimeter isn’t there. mobile won’t let you.