Sitemap

Process Over Magic

How To Define Your Daily Flow with AI Assistants

--

I’m back to blogging after spending some time working on my book about AI assistants for developers.

Press enter or click to view image in full size
Book cover https://pragprog.com/titles/ubaidev/process-over-magic-beyond-vibe-coding/ubaidev.jpg

As the title of the book suggests, I believe that the key to using AI assistants effectively is having a solid process, rather than relying on “magic prompts”.

I describe this in more detail in the book, but I will try to capture the main ideas in this post.

I do not think you can simply copy an AI workflow from somewhere else.
You need to build your own process and refine it over time.

Still, it is useful to compare approaches.
So in this post I will describe my current workflow, and explain the reasoning behind each step.

In my daily work, I deal with a large codebase in a fairly standard setup: a team, a ticketing system, pull requests, and access to several AI assistants.

What follows is the workflow I currently use day to day.
I will also explain how I arrived at each decision, so you can adapt it to your own context.

So you need to build your own process, and refine it over time.

What follows is the approach I currently use in my day-to-day work on a large codebase.

The Three Files

I usually start by picking up a ticket.

The first step is to use AI to fully understand it.
Is the problem clearly defined?
What exactly needs to change?
What are the possible design options, and their consequences?

Personally, I find Junie (the JetBrains assistant) very effective for understanding the existing code.
Being inside the IDE (PyCharm in my case) seems to give it an advantage. It can navigate the codebase and find relevant parts faster than tools like Claude Code (Sonnet) or Codex.

In parallel, I also use AI to search documentation and summarise Slack discussions when needed.

At the end of this exploration phase, I should have a clear idea of what needs to be done and why.
Sometimes I need to go back and ask more questions, but let’s assume a typical happy path.

To reduce the ̶p̶a̶i̶n̶ friction of working with pull requests, I use git worktree.
This allows me to keep multiple branches open in parallel and switch between them quickly.

So the next step is to create a new branch for the PR and prepare the working context for the AI.

I take the output from Junie and use it as the starting point.
Since it is already saved in a temporary file, I can just pass that file to the AI assistant (Claude Code, Cursor, Junie itself, and others — I often switch between them).

This becomes my spec file, the first of the three markdown files that are central to my process. One critical part of a ticket, and therefore of the spec file, is the acceptance criteria.

We need to explicitly define how we measure a successful implementation. In practice, I expect these criteria to translate directly into automated tests.

I have always been a fan of TDD, but with AI this becomes even more important. Tests provide immediate feedback on whether the implementation is on the right track, and they help reduce hallucinations.

The second file is agents.md. This file defines how I want the code to be written:
project structure, coding standards, architectural rules, and so on.

On top of a main agents.md, I can also add more specific versions for individual modules or folders, with more detailed instructions.

These files are independent from any specific ticket.
Keeping them updated and refining them is a separate activity, outside of the normal ticket workflow.

I am currently experimenting with generating parts of these files automatically from git history and PR comments, but that is a topic for another post.

To avoid making the file too large (and consuming too much context), you can split rules into smaller “skills” or use tools like MCP to provide focused instructions for different areas (UI, database, tests, etc.).

The important point is that these files should not be based on guesswork.
They should be refined over time, ideally using evaluation tests (for example, LLM-as-judge setups). I will write more about this separately.

The third file is the plan + diary. Before starting implementation, I ask the AI to read the agents.md and the spec, and produce a plan: a sequence of small, concrete steps. Then, as the work progresses, the AI updates the diary after each step, recording what was done and why.

This becomes very useful when something goes wrong, or when I need to resume work after an interruption.

So why using these 3 files? The main reason is that they make prompts much less important. Most of my prompts are very simple: “please implement the next step in the plan”.

Get Uberto Barbini’s stories in your inbox

Join Medium for free to get updates from this writer.

The spec explains what needs to be done.
The agents.md defines how it should be done.
The plan + diary provides the current state and the next step.

Together, these files give the AI a structured and persistent context. I do not need to restate everything in each prompt, and I do not rely on clever wording.

Moreover if I switch tools, restart a session, or come back later, I can resume from the files without losing direction.

The Small (Agentic) Steps

Now we move into the actual implementation.

Once the AI assistant starts working, I usually do not watch the code being modified. It is too fast and difficult to follow. Instead, I switch to another task or take a short break, and come back after a few minutes to check if things are going in the right direction.

For changes that are well understood, this is often enough. The AI follows the plan and produces a set of changes (I do not allow agents to commit).

If the result looks reasonable, I commit it locally and ask the assistant to proceed with the next step, or move to the final polishing phase.

For more complex changes, things can go wrong in predictable ways:

1. The loop of death
The AI fixes A, breaks B. Then it fixes B, and breaks A again. This can continue indefinitely, sometimes across multiple steps.

2. Misunderstanding the requirement
The AI works on the wrong part of the code. This often happens in codebases with poor naming or duplicated logic. This is also why code quality and Domain-Driven Design matter even more when working with AI.

3. “Desperate” changes
When the AI cannot find a solution, it sometimes escalates. It starts rewriting large parts of the system, ignores design constraints, or even modifies external libraries.

In all these cases, I stop the agent as soon as I notice one of these patterns and roll everything back. It is usually not worth the time to investigate or try to fix the current attempt.

Instead, I go back to the plan and make it more explicit and more detailed.

To be fair, sometimes the AI is not wrong. The problem itself may not have a clean solution within the current constraints. In those cases, this becomes a useful signal. I go back to discuss the feature with the rest of the team.

Once finished, including tests etc I go to the next final phase.

The Final Review

The last phase is the final polishing. This is usually where I spend most of my time, especially for tickets that are easy to implement.

I start by squashing all the commits so far. Then I go through the code line by line, until I am confident that I fully understand it, I am happy with it, and I am ready to explain it in a code review.

Reorganising the commit history, with clear and meaningful messages makes the work easier for reviewers and improves the long-term readability of the project.

Even with current state-of-the-art agents, the code is rarely at the level we expect. It may work, but there are often issues: unrequested changes, unnecessary checks, weak assertions in tests, poor naming, duplication, overly long methods.

For these small refactorings, it is often faster to edit the code directly rather than asking the assistant. I wish there was a way to say “just refactor this method in three smaller ones” without triggering a full planning cycle, scanning the whole project, and spending minutes on something I can fix in a few seconds. So far, I have not found a good way to do that.

Where I do use AI in this phase is for an additional review. I ask the assistant to review the changes from different angles: performance, security, observability, and other non-functional aspects. It does not always catch the obvious issues, but it is very good at spotting things that humans often miss. So for me, the best approach is to combine both.

Call me crazy, but I still think it is important to keep ownership of the code. AI or not, I am the one signing the commits.

This phase also helps me understand the domain better and keep my coding skills sharp. When I have doubts, I ask the assistant, so it also becomes a way to learn about the domain and the technologies involved.

What’s next

First, I would like to reduce the time spent in the third phase. I am quite sure models can do better, but they are mostly trained on average codebases, and it is difficult to push them toward stricter internal standards.

Skills.md are a step in the right direction, especially if we use evaluation frameworks to refine agents over time.

Another direction I am exploring is involving non-technical product people earlier, during the implementation phase. Since the whole cycle can often take less than an hour, it becomes possible to refine the feature together in real time. Vindicating the old Extreme Programming practice of having stakeholders on site. AI simply makes the feedback loop much faster.

Finally, a word about mental health. This way of working means often stepping away while the AI writes code, and then coming back mainly to review. It is easy to lose focus or feel less engaged.

On the other hand, it creates more space to think about design and business rules, and removes a lot of repetitive typing. It also gives small breaks during the day, good chance for a short walk or a coffee.

For me, this is a good trade-off. But please take care of your mental health. Our job does not have to turn into mechanical, repetitive work where a human just follows the machine’s rhythm. Use AI in a way that makes you feel empowered, not squeezed out.

In practice, this shifts the effort from writing prompts to maintaining good artifacts. And those artifacts are easier to review, refine, and share with others.

--

--