Agentic Engineering II: Best practices to avoid slop and actually improve productivity with coding agents
By Julian von der Goltz
If you're an AI engineer, data scientist, ML practitioner, or developer, you might already be using coding agents in your day-to-day work. Or maybe you tried one, were unhappy with the results, and wondered whether it was worth the effort.
The following article is a technical guide to getting more value from coding agents without sacrificing the quality or security of your software. We share the best practices that made the biggest difference in our own work: how to manage context, structure your project, use tests and feedback loops, check the agent’s output, and avoid the productivity traps that come with fast-moving tools.
In early 2025, Anthropic released Claude Code – a terminal-based assistant that can write code and execute commands on your computer autonomously. Until then, AI in software engineering was mostly limited to copy-pasting snippets from chat interfaces or using simple autocomplete tools inside IDEs.
We have been experimenting and using coding agents for quite some time now. With the release of GPT-5 and Claude Opus 4.1 in the summer of 2025, the threshold was crossed: coding agents became genuinely useful for serious software engineering, data science, and machine learning work. At KickstartAI, we’ve been experimenting with coding agents for quite some time and we believe that we are now at a point where it doesn’t make sense to not use them if one wants to keep up with the current and accelerating pace of technology.
For KickstartAI, this means that we can have a much, much larger impact as a small organization. However, there are certain pitfalls to watch out for and best practices to follow so that the coding agent actually makes you more productive without sacrificing the quality and security of your software.
This is our second article in our Agentic Engineering series. It contains actionable tips for engineers who want to get the most out of their coding agent in practice. If you've been using one for a while, some of this advice might feel obvious. If you just started, or if you tried it and gave up because the output was not great, these are the things that made the biggest difference for us.
None of the following best practices requires a complicated setup. Most of it is just about how you work with the agent: what you instruct, how you structure your project, and when you step in versus when you let it run on its own. As an addendum to this blog post, we have open-sourced a repository containing agent configurations that we use at KickstartAI for new projects.
How coding agents work
In the first article of our Agentic Engineering series, where we provide a non-technical guide for project managers and business leads, we have already described how coding agents work. You can find it here.
To provide a short recap: A coding agent is an LLM that has access to certain tools (search files, read files, write files, execute commands) and runs in a loop. It can autonomously decide which actions to perform (tool execution, thinking, or reply to the user) and make new decisions based on the outcome of previous actions. Coding agents such as Claude Code, – Codex, Gemini CLI are terminal-based interfaces, but they can often be used through IDE extensions or directly in AI assistant apps like Claude or ChatGPT.
By default, the amount of information that coding agents have about your project or your code is very minimal. There is no RAG and no knowledge base; it is really just an LLM with tools. The philosophy behind it is that the LLM is able to decide for itself which files to read and pull into context based on the task at hand.
You can improve this process by giving the agent more structure and guidance. In the following sections, we focus on the customizations that make the biggest difference in practice.
The starting point: AGENTS.md or CLAUDE.md
One of the few files that coding agents read automatically is the AGENTS.md file (or for Claude Code, CLAUDE.md). This is a markdown file that contains the instructions for your agent. It's the most important knob you can turn before moving to anything more advanced such as MCP servers or skills. You can find the example KickstartAI AGENTS.md in our github repository here: https://github.com/Kickstart-AI/agent-ready-template/blob/main/AGENTS.md
The AGENTS.md is where you instruct the coding agent about your preferences and conventions, ranging from coding style to agent personality. You can have a single agent for all projects, or one agent per project, or even specific agents for sub-folders like your frontend and backend. Whatever the case, do not write a massive instruction document upfront; let it grow organically. Start with minimal basic instructions first. Later, if the agent performs an action you don't like, ask it to add a correction or addition to the markdown file so it won't repeat the mistake. Over time, you will slowly build an assistant that gets better and better at working the way you want it to.
For standard repositories, you don't have to describe the structure of the codebase . The agent knows that a JavaScript project has a package.json and a components folder. Focus only on the things that are different, personal, or custom to you or your project.
Example AGENTS.md instructions:
```
- Be professional and concise, but use full sentences to communicate.
- Eliminate acknowledgments ("Got it!", "You're right!"), banter, and small talk.
- Present and explain your plan before any implementation.
- Give modules, functions and classes descriptive names.
```
Use the best model
Use the most capable model available, at high thinking or reasoning effort, even if it is slower. The goal is to minimize the time you spend arguing with the AI, correcting it, and going back and forth. A slower but smarter model that gets it right the first time is worth more than a fast model that you have to babysit.
The right model depends on the use case and what works best for you personally. At the time of writing, some models seem better at complicated tasks requiring a lot of reasoning like GPT-5.5, while others are faster and more pleasant to work with in general, like the Claude models. Experiment and find what works for your type of work. It's worth considering a coding assistant that is independent of the model provider – such as OpenCode or Pi – so that it is easy to switch between OpenAI, Google, Anthropic, and others.
Use plan mode
Most coding assistants have a plan mode. When you turn it on, the agent doesn’t immediately start writing code. Instead, it asks you clarifying questions, points out elements that are unclear, and together you make a plan before any code is written. Once the plan is solid, the agent can work through it in one go.
This is probably the single most effective way to avoid the vibe coding trap. You start with a vague instruction, the agent produces an output, you're not quite happy and try to fix it with another instruction. Before long, you are stuck in an endless loop of small corrections that takes more time than thinking the task through upfront.
For small changes, like moving a button or fixing a typo, you don’t need plan mode. Just ask and let the coding agent do it. But for anything that involves multiple files, new architectures, or a feature with several moving parts, take the time to plan first. You invest a bit more time upfront but you save a lot of time down the road.
Context management
Keep each agent session focused on one topic, bug, or feature. Start a new session when you move on to a new task. This helps in two ways. First, the agent is less likely to get distracted by unrelated details in the session history or make strange assumptions based on previous work Second, you won't run out of context as fast.
When the context window gets full, coding assistants do something called "compaction:" they summarize the session history and start a new session with that summary as the first message. In theory, you can continue where you left off. But in practice, a lot of information gets lost and it's not always clear what has been kept and what not. Especially after multiple compactions in one session, a lot of key context can get lost. The easiest way to avoid this is to keep sessions short and focused from the start.
If you do get stuck and need to continue in a new session, write a short summary or handover prompt – or ask the agent to draft one – and use that as the starting point. This gives you more control than relying on automatic compaction.
Context management is also about avoiding contradictory information. For example, when code documentation and actual code are out of sync, the agent can get confused. It’s best to have one single source of truth like code + docstrings + comments that are all in the same place.
Make your codebase navigable
Coding gents don't have the complete codebase in their context. They do very targeted text searches (such as grep) to find what they need. This means they might not be aware of the best spot in your code to implement a certain feature or fix a certain bug. You need to make it easy for them to find their way around the project.
This starts with the basics that you would also do for human developers: clear repository structure and descriptive naming for files, variables, functions, and classes. These are language models, after all. Precise language makes it easier for the model to understand what is going on. And if the agent is writing more of the code, good naming also helps you understand what it produces.
Documentation helps too, but keep it targeted and specific. Don't let the agent write elaborate documentation that nobody reads. Don't allow README spam everywhere. Scattered documentation across your entire repository will get out of sync quickly and do more harm than good. A few well-maintained files in the right places are much more useful.
You also need to keep your own mental model of the codebase. Some agents are better than others at reading through all the relevant files before making a change. Sometimes you need to nudge the agent to do the right thing in the right place, because it simply didn't look at the file that you know is relevant.
This is also why coding agents tend to work better on new projects than on existing codebases. In a new project, the agent builds the structure itself and knows where everything is. In an existing project, however, the agent has to find its way around an unfamiliar codebase every time a new session starts.
If you are introducing an agent into an existing project, it can help to have the agent create a structured overview of the codebase for you. Don't ask it to document everything at once. Go module by module, service by service, and guide it to produce something that is actually useful for onboarding – both for the agent and for new team members.
Write the skeleton yourself
When you want a very specific style or coding philosophy, and you don't fully trust the AI to get it right, write the first implementation or a template yourself. For example, you can create a class, define all the methods and properties with the names you want, and add a comment on what each method should do. Leave the method bodies empty. Then let the AI agent fill them. (This is actually how I wrote this blog: I provided the section headers, let the AI write the content, and then a human editor shaped the text into the final version you’re reading now).
This works especially well for test-driven development. Write the tests first (or have the agent write them under close supervision) and let it implement the code needed to make the tests pass.
For bugs, prompt the AI agent to first write a test that reproduces the issue. The test should fail against the existing code because of the bug. Only then should the agent fix the implementation. This is the classic red/green approach to test-driven development – something developers have been advised to do for years but often skip because it feels like too much extra work. But with a coding agent the overhead of writing the test first is almost zero.
When agents write tests, always review them. Make sure they test meaningful behavior and not trivial assertions, such as 1 is bigger than zero. You may still need to add edge cases and less obvious scenarios yourself. A good pattern is to let the agent set up the boilerplate, and then you can add the tricky cases manually.
Give the assistant immediate feedback
The more tools the agent has to verify its own work, the better the results. The most obvious tools are unit tests, a linter, and a formatter. If the agent can make changes, run the tests, see what fails, and correct itself, that feedback loop is worth more than any amount of careful prompting.
Those tools need to be fast. If it takes minutes to run your test suite, the agent's feedback loop slows down to a crawl. Focus on unit tests – not necessarily end-to-end or integration tests. Save those for your CI pipeline.
Beyond tests and linters, you can connect external tools to your coding agent through MCP servers. MCP, or Model Context Protocol, is a way to give your agent access to other applications and APIs. For example, we connected our MLflow experiment tracking server to our coding agent. The agent can now run evaluations, read the results through MLflow, see which test cases failed, and adapt the code or prompts accordingly. The whole loop that we previously did manually (change a prompt, run evaluation, read results, change the prompt again) is now automated.
For web development, you can connect Chrome through its MCP server so the agent can interact with your website directly. Before MCP servers existed, I used to paste screenshots of my front-end into the coding assistant and ask it to interpret them. That still works, but having the agent interact with the browser directly is definitely a step up.
You can also create "skills" for recurring workflows. A skill is basically a separate prompt only loaded when you want to execute a specific type of task. It describes the steps the agent should take, which commands to call, how to connect to a server, and so on. The concept is simple but it makes recurring workflows reusable without having to explain them every time from scratch.
The number of features you use – custom commands, skills, subagents, MCP servers, hooks – is something you have to figure out for yourself. I personally don't use sub-agents much. I prefer to talk directly to the agent that does the work instead of adding another layer. Similarly, I work with two coding agents at most, simply because I can’t keep track of more.
Others may be running eight agents in parallel using git worktrees or multiple checkouts. Find your own optimum.
Stay in control
Don't outsource thinking to the coding agent. It’s there to help you write the code, but the responsibility for the output stays with you. You should be able to vouch for every single line of code that your assistant produces. You don't have to write it yourself, but you do have to understand it and be able to explain it.
Sometimes people use a separate “review agent” to check the AI’s work. This can help, but you should always validate anyway. Pay particular attention to business logic, assumptions, and user experience-related code. For low-level technical details and algorithms, you can be a bit more lenient. With front-end code, for example, I mostly check in the browser whether it works. If it does, I move on – as long as the code is reasonably structured and not all dumped into one file.
That being said, If you use an AI assistant for review, do it in a new session. And, if possible, with a different model.
Personally, my review process has two stages. First, I do all the git commits myself. I don't let the AI commit changes. I choose what to commit, and while staging each file, I read through what changed. The second review takes place once I open a pull request. I go over the entire diff again and, occasionally, another person checks it too. This was already my process before coding agents, and it still works well.
This doesn't mean I approve or reject every single action the coding agent takes in real-time. For most tasks, I let it operate with a fairly high autonomy. Only for really critical features or difficult bugs do I follow along closely and approve every step.
When I reach a point where the implementation works, I commit. That gives me a safe place to return to. If I then want to let the agent try something more experimental, I can always roll back if it does not work out.
Don't be afraid to delete code
Code is now essentially free. You can throw it away. It does’t matter.
Compare working with an AI agent to working with a junior programmer in a pair session. If your junior colleague puts a lot of time and effort into their code, and it doesn't quite work, you may feel reluctant to reject it outright. Maybe you keep it in the codebase and tell yourself you’ll fix it later. With an AI agent, you don’t have that problem, You’re not hurting anyone’s feelings by rejecting its code. So if it’s not good, just delete it.
If you find a better approach, discard the old one. If you have spent too long trying to get something to work and it still does not, roll back to where you started and move on. Do not fall into the sunk-cost trap. The more code the AI has generated that doesn't work, the more tempting it is to try to salvage it. Resist that temptation. Delete it and start fresh. You might give the agent a better instruction next time – or try a different approach altogether.
Know when to stop
If the agent gets stuck and you can't figure out why, stop. Don't waste time on it. There's no point hammering against a wall with a toy hammer.
What I do in this situation is ask the agent to write me a summary of what it tried and what did and didn't work. Then I copy that summary into a new session and continue from there, sometimes with a different model. A fresh context often helps because you might have ended up in some edge case of the probability distribution that the model can't escape from.
If the agent still doesn't work after both a fresh session and a different model, let it be. Try it yourself, and try again on a different day. Maybe you'll write a better instruction with a clearer mind. Or a new model might come out a week later and the problem will solve itself. That sounds like a joke, but it genuinely happened.
The AI agent is supposed to help you, not make your life harder. If you notice that you're spending more time fixing what the AI did wrong than it would have taken to do it yourself, abort the mission and move on.
Productive vs. feeling productive
There's a subtle trap with coding agents. Because things move fast and the agent is constantly busy, it can feel like you're being very productive when you're actually not. Watch out for these patterns:
Writing specifications that do not survive implementation: You write very elaborate specifications for the AI to implement, but once the actual implementation starts, the spec no longer makes sense because you didn't think it through well enough.
Refactoring for the sake of refactoring: The code doesn't look "clean enough" so you spend time reorganizing it, and ask the agent to refactor code. But it adds zero value to the product.
Configuring productivity instead of being productive: You set up features like plugins, MCP servers, skills, sub-agents, and hooks. Some repositories come with dozens of sub-agents for different tasks, and they look impressive, but they're very generic and won't necessarily help your specific case. You end up spending your time configuring tools for productivity instead of actually being productive.
Going in circles with the agent: You go back and forth with the AI assistant, trying out different approaches. But you end up in the same place as where you started.
Overall, do try to ship things. Try to get things done. But if an activity doesn't directly move you closer to a working feature or a fixed bug, question whether it's worth your time.
Red flags
When reviewing AI-generated code, watch out for these patterns:
Excessive try-except blocks: The agent wraps everything in try-except to avoid errors, but this hides bugs instead of surfacing them. If something unexpected happens, you want an error, not silent failure.
Imports inside try-except blocks: The agent isn’t confident about a dependency and is working around it instead of fixing the root cause.
Unnecessary backwards compatibility: You rename a function and the agent keeps the old function name around as a wrapper around the new one "for backwards compatibility."
Excessive fallbacks: The agent tries to cover every possible edge case or failure case and creates very convoluted and bloated code.
Very long functions with no abstractions: The agent dumps everything into one function instead of breaking it into smaller, well-named pieces.
Overdocumentation: Verbose comments and documentation strings on every trivial helper. Nobody will read them and they clutter the codebase.
When you spot any of these patterns, ask the agent to fix it and add the correction to the AGENTS.md so it won't repeat the mistake.
Conclusion
Coding agents are good enough to make a real difference in your productivity if you use them correctly. That being said, the practices in this article aren’t in stone. Technology is moving fast and what works today might be different six months from now. Experiment, stay critical, and build your own workflow over time. And if all else fails, wait a week. A new model might just solve your problem.