ANTIGRAVITY LABJP
Articles/App Development
App Development/2026-05-10Intermediate

How Far Can Antigravity Maintain a 50M-Download App? A 12-Year Indie Developer's Field Test

I have run wallpaper and wellness apps as an indie developer since 2014, accumulating over 50 million downloads. Here is what Antigravity could and could not take over when I let it maintain that codebase, with the boundary lines I drew.

Antigravity338Indie Development6MaintenanceRefactoring2Real ExperienceAdMob12

For the past few weeks I have been running an experiment: pointing today's AI agents at a codebase I started writing 12 years ago, and watching what happens.

I am Masaki Hirokawa, an artist and creator. Since 2014 I have been running wallpaper and wellness apps as an indie developer, with combined downloads passing 50 million. AdMob revenue has touched a peak of around 1.5 million yen per month at certain times. The complication is that the oldest code was written more than ten years ago, and the design choices my younger self made now sit side by side with the choices my current self would make. Same project, two different developers separated by a decade.

After putting Antigravity through real maintenance work on these apps, the line between "tasks I can hand over" and "tasks I still have to own" turned out to be sharper than I expected. Below is what I learned, based on actual exchanges with the agent.

Why I tried agents on legacy apps in the first place

Honestly, I had assumed AI tools would only be useful on fresh code. The trigger to reconsider was a 0.3% crash rate spike in one wallpaper app caused by a deprecated ad SDK API. I knew exactly what to fix, but the same pattern lived in 14 similar apps, and the prospect of repeating the change by hand drained my motivation.

That is precisely the shape of a job an agent could help with. Humans decide, the machine spreads the change. Once I framed it that way, the experiment became clearer.

Both of my grandfathers were temple carpenters. From them I absorbed a habit of respecting the original intent when adding new work to something old. Refactoring, to me, has always been closer to a conversation than to demolition. I wanted to know whether Antigravity could be a partner in that kind of conversation.

Setup and assumptions

The targets of the experiment:

  • Apps in scope: 8 wallpaper titles and 6 wellness titles (14 total)
  • Stack: Swift on iOS, Kotlin on Android, with leftover Objective-C and Java in some apps
  • Average lines of code: about 25,000 per app, with 4 apps over 50,000
  • Oldest code: a wallpaper loader written around 2014
  • Antigravity usage: Manager Surface as the hub, agents based on Gemini

The window was about three weeks. Whenever a maintenance task came up I tried to delegate the work to the agent and reserved final judgment and integration for myself.

What I could hand over: tasks with mechanical breadth

1. Spreading the same fix across 14 repos

The first clear win was updating AdMob SDK delegate methods. Once I locked the fix in one app, I asked Antigravity to "apply this diff to the other repos with similar structure, respecting each app's naming conventions."

What helped was the agent reporting back: "App A uses AdManager, App B uses AdvertisingService, so I adapted the change for each." Doing this by hand I would almost certainly have mismatched a name in one or two apps. This is a clean handoff zone.

// Before — written around 2018 in an iOS wallpaper app
class AdManager: NSObject, GADBannerViewDelegate {
    func adViewDidReceiveAd(_ bannerView: GADBannerView) {
        // Old API, deprecation warnings firing
    }
}
 
// After — Antigravity's spread across 14 apps, names adapted per project
class AdManager: NSObject, BannerViewDelegate {
    func bannerViewDidReceiveAd(_ bannerView: BannerView) {
        // New API. Expected outcome: the 0.3% crash rate spike returned to baseline
    }
}

The crash rate did return to baseline, in roughly half the time my manual estimate predicted.

2. Backfilling tests around blind spots

This worked even better than I expected. Test coverage on the older apps averaged around 30%, with the wallpaper loader sitting in the "it works, do not touch" zone. I asked Antigravity to read existing implementations and write tests that match current behavior. The result was more thorough coverage than I would have written by hand, faster.

The discipline I added: always make the agent's tests fail at least once before letting them pass. Tests that pass on first run too easily can be tests adapted to the implementation, not the other way around.

3. Tidying dependency graphs

Another safe handover. Cleaning up Package.swift and build.gradle, proposing safe minor upgrades, resolving deprecation warnings — agents are more comprehensive at this than I am. As long as humans approve and machines execute, this stays a low-risk delegation.

What I could not hand over: code that carries context

1. Changes that ask "why is this code like this?"

Inside one wallpaper app there is a piece of code that looks redundant but must not be touched. It exists because the app was once rejected in App Store review, and that block is the workaround.

When I asked Antigravity to refactor the area, it naturally tried to clean up the workaround. From the agent's view the code looks unnatural; from my view it carries the weight of a past decision.

The takeaway: communicating why code exists is still a human job. A CLAUDE.md-equivalent context file in each repo, marking "this function must not be modified, reason: App Store review", was enough to keep the agent disciplined.

2. Decisions that touch the core of user experience

In one wellness app I was deciding whether to extend a sound effect's fade-in from 150ms to 200ms. Technically a one-line change. But that 50ms is something I tuned by hand for months, trying to translate the feeling of a luminous ring of light I saw in the night sky over Kichijoji Station in late 2019.

If I ask Antigravity for UX improvement ideas, it returns reasonable suggestions. They are not the same as the breath I wanted to leave in the work as an artist. Numbers that govern the fine grain of sight and sound deserve to stay in human hands.

3. Release notes and apologies

For release notes and replies to users who hit the crash, the agent's draft is competent but uniformly bland. In moments where I want the words to feel like something I could leave to my children, I let the agent draft, then rewrite the final text myself.

Three rules I settled on

After three weeks I distilled three working rules.

First, "if a task repeats three or more times, hand it to the agent." Once or twice it is faster to do by hand. By the third repetition the spreading cost has been earned back.

Second, "if results are measurable in numbers, hand it to the agent." Crash rate, test coverage, build time — anything an agent can measure faster and more consistently than I can is a clear win.

Third, "keep your hands on anything that touches user emotion." Wording, sound, color, timing, apologies. Hand these over and the agent returns the average answer. For an indie developer, the average answer is the worst possible defeat.

A note on documenting "why" for agents

One practical habit that emerged from this experiment was writing very small, very specific context files for each repo. Not a sweeping architecture document, but a flat list of "do not touch this, here is why" annotations. Three or four sentences per item, no more.

What I noticed is that the act of writing these notes was useful even before the agent read them. Code that I had been carrying for years suddenly had a written explanation, which means the next person to look at it (often a future version of myself) does not need to reverse-engineer the past. The agent benefits, but so does the long-term health of the codebase.

This is the part of the experiment I would recommend even to teams that are not yet ready to introduce agents into their maintenance flow. The exercise of explaining your old code in writing is its own reward, and once you have those notes, plugging in an agent later becomes a much smaller jump.

Related reading

What to try next

If you maintain a long-running project, my practical suggestion is to pick one app, identify a single task that repeats three or more times, and let Antigravity spread the change. Start there.

I am still in the middle of this experiment. Bringing a new tool into a 12-year-old codebase has been a richer learning process than I expected, and I hope something here is useful to anyone facing a similar situation.

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.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

App Dev2026-07-14
Protecting Screenshot Tests for AdMob Screens from Ad Nondeterminism
Screens with ads turn red on every screenshot run, and eventually nobody reviews the diffs. Here is a design that seals off AdMob banner nondeterminism and leaves only real layout breaks in your checks, with Compose code and Antigravity-driven diff triage.
App Dev2026-07-05
Keep the Self-Debugging Agent Away From Live Ads: Three Layers Against AdMob Invalid Traffic
When Antigravity 2.0's real-browser self-debug renders a live AdMob unit, every pass counts as an impression, and Google may read it as invalid traffic. Here is a three-layer setup, with measurements, that keeps the agent from ever touching a production ad.
App Dev2026-06-21
A Few Low-Density Phones Lost Their Bundled Wallpaper — The drawable vs nodpi Boundary in Play's Density Splits
App Bundle density splits will happily split images that should never be split, dropping a static resource on one density bucket only. Here is how I reproduced it with bundletool and fixed it by moving to drawable-nodpi or disabling density split — with the decision criteria.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →