Orchestrating Six iOS App Updates in Parallel with Antigravity's Main and Sub Agents
Running six iOS app updates in parallel — new resolutions, Firebase SPM migration, StoreKit 2, and ATT ordering — with Antigravity's Main + 6 Sub agents. The notes on what to parallelize and what to keep serial.
This month, the bulk of my indie iOS work was coordinating four major changes — new iPhone resolutions, Firebase Apple SDK's CocoaPods → SPM migration, StoreKit 2 adoption, and ATT prompt ordering — across six apps in parallel. Beautiful HD Wallpapers, Ukiyo-e Wallpapers, Relaxing Healing, Law of Attraction, Cool Wallpapers, and Fractal Galleria. As a single indie developer who started writing apps in 2014 and has shipped roughly 50 million downloads, holding six apps in flight at once is at the absolute edge of what a single human can do without tooling.
What made it tractable was Antigravity's Main / Sub agent layout — and, more importantly, deciding which work could fan out in parallel and which needed to flow through one human head in series. Below is the orchestration that actually worked.
Start by drawing the dependency graph on paper
Before opening Antigravity, I drew the 6 apps × 4 tasks grid on paper.
New resolutions ──┐
├──→ Build verify ──→ TestFlight ──→ App Store Connect phased rollout
Firebase SPM ─────┤
│
StoreKit 2 ───────┤
│
ATT ordering ─────┘
Everything up to "Build verify" can be parallelized. Everything from "TestFlight" onward serializes through App Store Connect's review queue. If you mix parallel and serial work without marking the boundary, your agents will keep saturating the part that's actually a bottleneck.
The first prompt to the Main agent
I deliberately framed the Main agent as a Producer, not an implementer.
You are the Producer for a 6-app parallel iOS update. You do not write code.You only delegate to Sub agents and monitor progress.Sub agents must complete the following four tasks in order: T1: Support new resolutions (iPhone Air / 17 Pro / 17 Pro Max) T2: Migrate Firebase Apple SDK from CocoaPods to SPM T3: Migrate purchases to StoreKit 2 (SKPayment -> Transaction.currentEntitlements) T4: Re-order ATT prompt (must call before MobileAds initialization)Routing rules: - T1 and T4 have no dependencies and may run in parallel - T2 starts only after T1 builds successfully - T3 starts only after T2's Firebase changes verify in TestFlight - "Complete" means: build success + internal TestFlight distribution acceptedReport format: | App | T1 | T2 | T3 | T4 | Notes |
Defining Main as a Producer who does not implement code was the most important sentence in the prompt. Without it, Main starts patching code itself, and the parallelization story collapses immediately.
✦
Thank you for reading this far.
Continue Reading
What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.
WHAT YOU'LL LEARN
✦Lift the Main / Sub agent layout I used to push Beautiful HD Wallpapers, Ukiyo-e Wallpapers, Relaxing Healing, Law of Attraction and two more apps through a four-task iOS update in parallel
✦Apply the 12-year indie heuristic for which tasks belong in a parallel fan-out vs. which ones must serialize through one human's head, mapped to concrete iOS update gates
✦Adapt the Antigravity Plans naming and diff conventions I rely on to keep six concurrent app projects from clobbering each other's release queue
Secure payment via Stripe · Cancel anytime
✦
Unlock This Article
Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.
Each Sub agent owned one app. Equally important, I gave each Sub a list of areas they were forbidden from touching.
You are the Sub agent for Beautiful HD Wallpapers. Do not modify the following:1. AdMob mediation configuration (revenue-critical; Producer approval required)2. App Store Connect phased rollout percentage3. Stripe pricing plan definitions4. The shared DefineManager.h macro declarations across all six apps5. The tone of any user review replies (these reach existing users from a 50M+ install base)Anything else — code, tests, PR drafts — you may handle autonomously.
In twelve years of indie work, the most expensive mistakes I've seen are revenue-critical settings changed by automation that doesn't understand what's at stake. AdMob eCPM tiers, App Store pricing, the tone of customer-facing copy — letting an agent freelance on these is how a six-figure annual revenue line vanishes in 24 hours. So I wrote the forbidden list explicitly, in plain language.
What actually parallelized
T1 (new resolutions) and T4 (ATT ordering) had no interdependencies, so Main fanned them out to all six Subs at once.
T1 is what I covered in another post — 29 ternary branches in DefineManager.h, repeated per app. T4 was a one-file change in AppDelegate.
// Before: MobileAds initialized before ATT had resolvedGADMobileAds.sharedInstance().start(completionHandler: nil)ATTrackingManager.requestTrackingAuthorization { _ in }// After: wait for ATT, then start MobileAdsATTrackingManager.requestTrackingAuthorization { status in DispatchQueue.main.async { GADMobileAds.sharedInstance().start(completionHandler: nil) Analytics.setUserProperty( status == .authorized ? "authorized" : "denied", forName: "att_status") }}
iOS docs only hint at this between the lines, but if MobileAds initializes before ATT resolves, the mediation chain loses the tracking signal it needs for accurate eCPM. Running T1 and T4 in true parallel across six apps took under 90 minutes of wall clock time.
What needed to stay serial
T2 (Firebase SPM) and T3 (StoreKit 2) needed strict serialization. The CocoaPods → SPM transition is invasive: Podfile gone, Package.swift introduced, and a long tail of synchronization issues with Dropbox if you happen to keep projects in your Dropbox folder like I do.
This pattern is environment-specific enough that I had Main execute it directly rather than handing it to a Sub. The lesson: which tasks belong to agents and which to humans is sometimes a function of your build environment quirks, not of the work itself.
T3, the StoreKit 2 migration, replaces the old SKPaymentQueue.default().restoreCompletedTransactions() with the async sequence form.
// Old StoreKit 1SKPaymentQueue.default().restoreCompletedTransactions()// StoreKit 2Task { for await result in Transaction.currentEntitlements { if case .verified(let transaction) = result { await handlePurchasedEntitlement(transaction) } }}
If you get this wrong, restore-purchases silently breaks for existing customers. I shipped it on Relaxing Healing first, watched 48 hours of restore-purchase telemetry, then propagated to the remaining five apps.
The status table that made Main useful
I locked Main into a single reporting format from the start.
The moment Law of Attraction's T2 hung, I paused T2 on the four remaining apps that hadn't started, in case it was a structural issue rather than an app-specific one. A Main that holds the whole table makes that kind of cross-app halt possible.
Crash-free monitoring across six apps
After phased rollout begins, I pin a single Crashlytics query across all six projects:
project_id IN [bw, uw, rh, loa, cw, fg]
AND app_version >= "3.0.0"
AND fatal == true
AND device_model starts_with "iPhone18"
Thresholds: Crash-free users at or above 99.7%, ANR below 0.20%. If any one of the six dips below, I tell Main to draft a halt PR setting that app's phased rollout to 0%. The actual ship/halt decision stays with me; the mechanical PR doesn't need to.
For digging into individual Crashlytics issues, I hand the issue body to Claude on Xcode using the same template I described in the Glide desugar post on Claude Lab. Producer (Main) for orchestration, Sub for app-level execution, and Claude on Xcode for in-IDE patching. Three layers, each with a different focus.
Forty years and what indie work has taught me about delegation
I started teaching myself programming in 1997, at sixteen, on a dial-up modem. From 2014 onward I've been an indie iOS / Android developer with a portfolio that crossed 50 million downloads. The question I've kept circling for all those years is: how many apps can one person really hold?
Antigravity's Main / Sub layout was the first tooling that made six apps in flight feel sustainable. But what made it work wasn't the tooling — it was being explicit about the two categories of work that I refuse to delegate: revenue-critical decisions (AdMob eCPM tiers, Stripe pricing, App Store thresholds) and copy that lands in front of existing customers (review replies, in-app onboarding text, push notification voice).
My grandfathers were both shrine carpenters. They taught me — by watching, not by speaking — that the parts that no one sees, the joinery hidden inside the structure, decide whether the building lasts a hundred years. The Sub agents' forbidden list is that joinery. Write it explicitly, in plain prose, while you still remember why each line is there.
What I'd try first
If you're holding more than one project at once, the smallest worthwhile experiment is to set up a Main / Sub layout in Antigravity for one app, and write the Producer prompt with the line "You do not write code. You delegate." See how the work redistributes when you take implementation off the Producer's hands.
I hope this is useful for anyone else running a portfolio of indie apps. Thanks for reading.
Share
Thank You for Reading
Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.