I build an iOS arcade game called T-Minus Zero: Thrust (hold to thrust, land softly).
It's a solo project, and a lot of the code is written by Claude Code.
The part I've learned the most from isn't the prompting.
It's the loop around it: what runs unattended, what it is forbidden to do, and where I step in.
My main features still come from prompting. I describe what I want, work through it in a session, and push.
Improvements go through the loop.
These are the many small things a game needs: new missions, tuning, polish, accessibility passes, tests.
I run a routine called run-task-cycle for a few cycles, and it does three things on repeat:
To Do milestone.dev, then moves the issue to For Review and closes it.When the queue is empty, the loop is done. Then it runs once:
github-ci. The routine fast-forwards dev into the branch that Xcode Cloud watches. It never force-pushes.Features I prompt by hand skip steps 1 to 3 and join at step 4.
Both routes end in the same place: a build on my phone.
Chaining skills together took an afternoon.
What lets me run it without watching is what I forbade it from doing.
Four rules do most of the work.
1. Only bug fixes reach Release.
Every other change - whether a feature, tuning, content or copy - must sit behind #if DEBUG or a flag that is false in Release, until I promote it in a separate task.
The loop can ship all day without changing what the App Store build does.
This is the rule I'd copy first.
2. Park, don't guess.
If an issue is large, has an unresolved open question, touches a protected area (the landing physics, the in-app purchases, the leaderboard IDs) or needs a manual step, the loop moves it to a New milestone with a comment saying why.
It never improvises on the parts of the project I'd hate to get wrong.
3. Checks report, never edit.
The repo has 43 small check scripts: UK English and no dashes in copy, every shown character exists in the font, product IDs match the code, Debug-only switches are off in Release, docs match code.
They only report.
The loop can't pass a check by editing the check.
4. Generate only when the queue is empty.
The task-writing skill refuses to run if To Do already has issues.
Work can't pile up faster than it ships.
All of this lives in written rules, not in anyone's memory.
A CLAUDE.md file holds the business rules, the vocabulary and the commit format, and the skills are told it wins over whatever an issue says.
The loop is designed to run in a cloud environment.
That was a deliberate decision, not an afterthought.
It means the loop does not need my machine, my network connection, or me to be awake.
I can kick off a run before bed. By morning, there are commits on dev, issues moved to For Review, and a TestFlight build on the way.
The rules that make this safe are the same ones above. A loop that runs unattended on my laptop is one thing. A loop that runs while I am genuinely not there has to be more careful about what it is allowed to touch.
The cloud environment is also stateless. There is no half-open file, no half-remembered context from the last session. Each run starts clean, reads from the repo and the issue tracker, and does exactly what the skills say.
That constraint turned out to be a feature. It forced me to write everything down.
The loop can build a mission. It can't tell me whether the mission is fun.
Game balance numbers are marked in my own notes as "playtest this", and the loop respects that: it will add the content, but only my hands on a TestFlight build can judge it.
It's also honest about what it didn't verify.
It can't run the unit tests in a simulator, so its reports say "build and tests not run" rather than claiming they passed.
I run the full suite from Xcode, and the final check is the build on my phone.
I'm the verification step at the end of the loop, and I think that's the right place for a person to be.
Over roughly a year of history there are about 1,000 commits and 212 tasks filed as issues.
Most of that came in the last few weeks, once the loop existed.
The loop works, but it is nowhere near finished.
A few things I want to add:
Self-healing. Right now, if a build breaks, the loop stops. A better version would catch the failure, read the error, fix it, and keep going - without waking me up. The check scripts already report exactly what went wrong. The next step is letting the loop act on that report.
Agent-based verification. The loop currently skips simulator tests because it can't run them in a cloud environment. What I want is a separate agent that takes the finished build, installs it, exercises the key paths, and files an issue if something looks wrong. Verification by agent, not by assumption.
Smarter task generation. Right now the task-writing skill picks from a roadmap file or spots things in the code. It could also look at crash reports, user feedback, or TestFlight comments and generate tasks from those. Closing the feedback loop automatically.
Tighter scope per cycle. Some cycles try to do too much. I want the loop to estimate the size of a task before it starts and skip anything too large rather than parking it mid-way through.
None of these are hard in isolation. The interesting part is adding them without making the loop harder to trust.