Jun 14, 2025
Armin Ronacher (creator of Flask) has a great piece on agentic coding patterns, insightful throughout but largely centered on the uplift you get from effective tool use:
Agentic coding’s inefficiency largely arises from inference cost and suboptimal tool usage. Let me reiterate: quick, clear tool responses are vital.
For this reason, he tends to avoid MCP:
The reason I barely use it is because Claude Code is very capable of just running regular tools. So MCP for me is really only needed if I need to give Claude access to something that it finds too hard to use otherwise. A good example for this is the playwright-mcp for browser automation. I use it because I haven’t found anything better yet. But for instance when I want my agent to poke around in my database, I just uses whatever it finds to be available. In my case it loves to use psql and that’s more than good enough.
He also sets out some key rules for selecting tools:
Anything can be a tool. A shell script can be a tool, an MCP server can be a tool, a log file can be a tool. If the agent can interact or observe it, it counts.
Tools need to be fast. The quicker they respond (and the less useless output they produce) the better. Crashes are tolerable; hangs are problematic.
Tools need to be user friendly! Tools must clearly inform agents of misuse or errors to ensure forward progress.
Tools need to be protected against an LLM chaos monkey using them completely wrong. There is no such things as user error or undefined behavior!
Tools need to provide the right debuggability and observability.
Critical tools are placed in a makefile, and he’s careful with the basics:
I had to protect the process manager against being spawend a second time when it’s already running. I use a fork of shoreman which writes a pidfile. When spanwed a second time it errors and logs “services already running”. Why does that matter? Because the agent sometimes does not know if the server is already running and otherwise happily spawns it a second time resulting in two version of the service bound to the same port.
I am not only printing the output to my terminal, I’m also always logging it to a file. This allows the agent to read the log file to diagnose what’s happening.
Tips on effective logging is a theme that repeats throughout:
Balancing log verbosity is crucial: informative yet concise logs optimize token usage and inference speed, avoiding unnecessary costs and rate limits. If you cannot find the balance, provide some easy to turn knobs for the AI to control.
In an ideal setup you get useful log output as a natural byproduct of the agent writing code. Getting observability from the first shot of code generation beats writing code, failing to run it and only then going back to a debug loop where debug information is added.
There’s just loads of wisdom scattered throughout, here’s a few hot takes I pulled out:
I strongly prefer more code generation over using more dependencies.
Agents make dependency upgrades so “cheap” that it’s tempting to just let the AI do it and see if tests still pass. I do not find this to be a successful path at all.
Stable ecosystems are what you really want. LLMs are great with Go and they love to use Flask, because those are quite stable ecosystems with little churn.
Agents aren’t exceptionally fast individually, but parallelization boosts overall efficiency. Find a way to manage shared states like the file system, databases, or Redis instances so that you can run more than one. Avoid them, or find a way to quickly segment stuff out.
Agentic coding alters refactoring priorities. Agents handle tasks effectively until project complexity surpasses some manageable thresholds. Too big here is defined by the total amount of stuff that it has to consider. An agentic workflow encourages good code maintenance and refactoring at the right moment. You don’t want to do it too early and you definitely do not want to do it too late.
Lastly, he also recommends that we have the agent do “the dumbest possible thing that will work”:
Prefer functions with clear, descriptive and longer than usual function names over classes.
Avoid inheritance and overly clever hacks.
Use plain SQL. I mean it. You get excellent SQL out of agents and they can match the SQL they write with the SQL logs. That beats them min-maxing your ORM’s capabilities and getting lost in the SQL output in a log.
Keep important checks local. You really want to make sure that permission checks are very clear to the AI, and that they are taking place where it AI can see it. Hiding permission checks in another file or some config file will amost guarantee you that the AI will forget to add permission checks in when adding new routes.
There’s also quite a detailed argument for selecting Go as your agentic language of choice. Great piece with novel insights. Worth a read.
Armin Ronacher's Agentic Coding Recommendations