I needed to work through an issue with 5 subtasks in the Aurora backend — all related, but each one independent enough to deserve its own PRPull Request (PR) A formal request to fold your changes into the main codebase. Other developers review, comment, and approve before it's accepted. It's the quality control layer for code.. The kind of task where, if you do everything in a single branchBranch A parallel copy of the code where you make changes without touching the main version. When it's ready, you merge it back. It's like a draft that doesn't ruin the original document., you end up with a monstrous PR that's impossible to review. And if you split it into separate branches off main, you lose the context that they're all part of the same effort.

I did the whole thing with Claude CodeClaude Code Anthropic's command-line tool. You build software by talking to AI right in the terminal — it reads your code, edits files, and runs tests.. And the experience taught me something that's now standard in my workflow: when AI does the work, you need checkpoints.

The problem: AI has no "save progress"

When you ask Claude Code to run a complex task — five sequential changes to a backend, say — plenty can go wrong along the way. The context windowContext window The AI's "short-term memory" — how much text it can consider at once. When it overflows, it forgets the start of the conversation. can overflow. The AI can make a mistake on the third task that invalidates the fourth. Or it can simply deliver something different from what you expected.

If everything was in a single branch, with loose commitsGit commit Saving a "snapshot" of your project's current state. Git is the most widely used version control system in the world — it lets you go back in time and collaborate without stepping on each other's work. and no review, you're left in the dark. Where exactly did it stop? What's already been tested? What still needs doing? The answer, most of the time, is: you don't know.

The problem isn't the AI. It's the lack of structure to track what it did.

The solution: a release branch with sequential PRs

The solution is an old friend from software engineering — just applied in a new context. I created a release branchRelease branch A temporary branch that groups several changes before they go to production. It works as a staging area — everything lands there first, and only then goes into the main code. — and each subtask became a complete cycle:

  1. Create a branch off the release
  2. Implement the subtask
  3. Open a PR against the release branch
  4. Squash mergeSquash merge A technique that compresses several commits into a single one when a PR is accepted. The history stays clean — one line per change, instead of dozens of intermediate commits.
  5. Next subtask

In the end, a single PR from the release against main shows everything consolidated.

Why it works so well with AI

Every merged PR is a checkpoint. If the context overflows, if the AI makes a mistake somewhere along the way — you know exactly where it stopped. PR #14 merged? Subtask 1.1 done. PR #15? 1.2 done. It's documented, incremental progress.

Without this structure, I'd have one giant commit or, worse, I'd lose track of where the AI stopped and what was already done. With the release branch, each change has its own PR with a description, an isolated diffDiff The visual comparison between two versions of a file, showing exactly what changed — line by line, in green (added) and red (removed)., and a merge history. If I need to pick things back up in a new session, I just look at the state of the release branch.

Traceability completely changes the dynamic. Instead of "the AI did something and I hope it's right," it becomes "the AI did subtask 1.2, there's a reviewable PR, the tests passed, and it's isolated from the other changes." You're back in control.

Pros and cons

Pros:

  • Real traceability — each subtask is a documented checkpoint
  • Small, reviewable PRs — nobody has to read 800 lines at once
  • Granular rollbackRollback Undoing a change and returning to the previous state. Like a "Ctrl+Z" for production code — if something breaks, you revert without losing everything. — I can revert one subtask without affecting the others
  • Clean history — main gets a single squash merge at the end
  • Easy resumption — a new session continues from where the last one stopped

Cons:

  • The overhead of creating branches and PRs for each subtask — but with automation it's trivial
  • The risk of conflicts between subtasks if they touch the same files — in practice, with well-defined subtasks, conflicts are rare

Tip: build an agentAgent An AI that acts autonomously — instead of just answering questions, it carries out tasks on its own: reads code, creates files, runs tests. Think of it as a very fast digital intern. so you don't repeat instructions

If this workflow makes sense for your context, it's worth building a custom agent in Claude Code that encodes these rules. Instead of explaining the flow every time — "create a release branch, open a PR per subtask, do a squash merge" — you write it once and the agent follows the protocol.

In Claude Code, you just create a .claude/agents/release-manager.md file in your project (or in ~/.claude/agents/ for global use) describing the flow: how to name branches, when to open PRs, which commit format to use, how to report progress. The agent then becomes invokable right from the terminal.

The point isn't having the perfect agent — it's not repeating manual instructions every session. If the flow works, automate it.

Why not just local files?

You can solve this problem other ways. You can keep a TODO.md in the repo, use task lists inside Claude Code itself, or create local documentation that tracks progress. All of that works — and for solo projects, it may be enough.

But the deliberate choice of issues and PRs has an advantage no local file offers: the documentation is public and peer-reviewable. A PR isn't just a checkpoint — it's an invitation for someone else to look, question, and approve. The diff is there, the context is there, the motivation is there. Any teammate can understand what was done without having to ask.

Local files die with the context of whoever wrote them. PRs live on in the project history. When someone — including future you — needs to understand why that change was made, the PR tells the whole story. A TODO.md updated by the AI doesn't carry the same evidentiary weight.

The underlying lesson

The more autonomy you give the AI, the more structure you need around it. It's not a paradox — it's pragmatism. Release branches with sequential PRs aren't bureaucracy. They're trust infrastructure.

Every merged PR is a guarantee that that piece is done, tested, and documented — no matter what happens afterward. That's what lets you give the AI more and more rope without losing control.

Trust in AI doesn't come from faith. It comes from checkpoints.

If you use Claude Code (or any AI assistant) on complex tasks, give this workflow a try. The principle holds regardless of the tool: structure the work into checkpoints, always.