I recently found myself in a deep state of flow while coding — the kind where time melts away and you gain real clarity about the software you’re building. The difference this time: I was using Claude Code primarily.
If my recent posts are any indication, I’ve been experimenting a lot with AI coding — not just with toy side projects, but high-stakes production code for my day job.
I have a flow that I think works pretty well. I’m documenting it here as a way to hone my own process and, hopefully, benefit others as well.
- set the stage
- plan with the agent (no really 🤮)
- spawn your agents
- verify and refactor
- the final review
Many of my friends and colleagues are understandably skeptical about AI’s role in development. That’s ok. That’s actually good. We should be skeptical of anything that’s upending our field with such ferociousness. We just shouldn’t be cynical1.
You know what’ll definitely get you out of the flow? Having to constantly repeat basic instructions to your agent.
These are all very important instructions that you shouldn’t have to repeat to your agent every single time. Invest a little upfront in your master ai instructions file. It makes a big difference and gets you up and coding quickly with any agent.
Of course, I also recommend consolidating your ai instructions to a single source of truth, so you’re not locked in with any single vendor.
I won’t lie. The idea of this step did not exactly spark joy for me. There are times where I plan my code out in a neat list, but rarely. More often than not, I peruse the code, formulate the plan in my head and let the code guide me. Yeah, that didn’t work at all with the agents.
Two phrases you’ll hear thrown around a lot: “Context is king” and “Garbage in, garbage out.” This planning phase is how you provide high-quality context to the agent and make sure it doesn’t spit garbage out.
After I got over my unease and explicitly spent time on this step, I started seeing dramatically better results. Importantly, it also allows you to pause and have the agent pick up the work at any later point of your session, without missing a beat. You might be in the flow, but if your agent runs out of tokens, it will lose its flow.
Here’s my process:
- All my plans live in an .ai/plans/ folder. I treat them as fungible; as soon as a task is done, the plan is deleted.
- Say I’m working on a ticket JIRA-1234 and intend to implement it with a stack2 of 4 PRs.
- Each of those PRs should have a corresponding one plan file: JIRA-1234-1.md, JIRA-1234-2.md, etc.
- The plan (and PR) should be discrete and implement one aspect of the feature or ticket.
- Of course, I make the agent write all the plans and store it in the folder. (I came this far in my career without being so studious about jira tasks and stories; I wasn’t about to start now).
This is the exact prompt I use:
I have this prompt saved as a “plan-tasks.md” command in my .ai/commands folder so I don’t have to type this all the time.
What follows now is a clean back-and-forth conversation with the agent that will culminate with the agent writing down the task plan. Sometimes I may not understand or agree with the task or sequencing, so I’ll ask for an explanation and adapt the plan. Other times I’m certain a task isn’t needed and I’ll ask for it to be removed.
This is the most crucial step in the entire process.
A note on software engineering experience
If the future of software engineering is going to be AI reliant, I believe this planning step is what will distinguish the senior engineers from the junior ones. This is where your experience shines: you can spot the necessary tasks, question the unnecessary ones, challenge the agent’s assumptions, and ultimately shape a plan that is both robust and efficient.
I intently prune these tasks and want them to look as close to the sequence I would actually follow myself. To reiterate: the key here is to ask for the plan to be written so that another agent can execute it autonomously.
Step 2: The Fun Part - release the Agents!
After committing all the plans (in your first PR), the real fun begins and we implement JIRA-1234-1.md.
You would think my process now is to spawn multiple agents in parallel and ask them to go execute the other plans as well. Maybe one day, but I’m not there yet. Instead, I start to parallelize the work around a single task.
Taking JIRA-1234-1.md as an example, I’ll spawn three agents simultaneously:
- Agent 1: The Implementer. Executes the core logic laid out in the plan.
- Agent 2: The Tester. Writes meaningful tests for the functionality, assuming the implementation will be completed correctly.
- Agent 3: The Documenter. Updates my project documentation (typically in .ai/docs) with the task being executed.
Notice that with this approach, the likelihood of the agents causing merge conflicts is incredibly slim. Yet, all three tasks are crucial for delivering high-quality software.
This is typically when I’ll go grab a quick ☕. When I’m back, I’ll tab through the agents, but I spend most of my time with the implementer. As code is being written, I’ll pop open my IDE and review it, improving my own understanding of the surrounding codebase.
Sometimes I might realize there’s a better way to structure something, or a pattern I’d missed previously. I don’t hesitate to stop the agents, refine the plan, and set them off again.
Eventually, the agents complete their work. I commit the code as a checkpoint (I’m liberal with my git commits and use them as checkpoints).
Step 3: Verify and Refactor
I run the tests, and more often than not, something usually fails. This isn’t a setback; it’s part of the process. I analyze whether the code was wrong or the test was incomplete, switch to that context, and fix it.
This is also where I get aggressive with refactoring. It’s a painful but necessary habit for keeping the codebase clean. I still lead the strategy, devising the plan myself, and then direct the agent to execute it or validate my approach. While it usually agrees (which isn’t always comforting 🙄), it can sometimes spot details I might have otherwise missed.
Once I’m satisfied and the checks pass, I do a final commit and push up a draft PR.
Step 4: The Final Review
I review the code again on GitHub, just as I would for any other PR. Seeing the diff in a different context often helps me spot mistakes I might have missed in the IDE. If it’s a small change, I’ll make it myself. For anything larger, I’ll head back to the agents.
All the while, I’m very much in the flow. I may be writing less of the boilerplate code, but I’m still doing a lot of “code thinking”. I’m also not “vibe coding” by any stretch. If anything, I’m spending more time thinking about different approaches to the same problem and working to find a better solution. In this way, I’m producing better code.
I’ve been building like this for the past few weeks and it’s been miraculously effective. Deep work beats busywork, every time. Let agents handle the gruntwork, so you can stay locked in on what matters most.