Agentic Engineering
Until fairly recently, I spent most of my working day writing code. These days, agents write it for me. I spend more time on architecture, defining the work properly and building an environment where I can tell whether the result actually works. People and agents both need to be able to find their way around it.
That doesn't mean I no longer need to understand the code. Quite the opposite. I still regularly see agents propose solutions that don't fit the situation. I need to spot that and steer the work in a better direction.
AI can produce a lot of code incredibly quickly. Good code, but bad code too. And if I give it a bad brief, it will usually follow it without objection and even agree that it's a great idea.
Generating code itself is becoming less interesting. Everything around it matters more.
I don't want to babysit agents
My goal isn't to have twenty agents in terminals, telling each of them what to do every two minutes. I'd produce more code, but I'd still be limited by my own attention span and need for sleep. :-)
I want to hand over a milestone broken down into tasks and let the agents do the work, test it and make the necessary fixes. Then run an independent review, using another model of course, and come back to thoroughly tested work that I can approve without too much trouble.
It sounds simple. There's a lot of work behind it, though. First I need to know what a finished result looks like, what its constraints are and how the tasks depend on each other. I don't want an agent to hide uncertainty in the brief by simply writing something.
An agent can misunderstand the task or drift off in another direction, especially during review. It can get stuck arguing with another model about an insignificant issue. And if it can't test everything properly, it may simply invent a story about how the result meets every requirement. From its point of view, it does.
That's why I spend so much time on the environment agents work in. When they start going in circles, I need to be able to stop the run, make the task smaller or go back to analysis. Retrying forever isn't a strategy. I need limits on time, cost and attempts.
One agent, one workspace
Git worktrees are a great tool, and I think every developer working with agents should get comfortable with them. One branch, one working directory. That way, agents don't tread on each other's toes. git-wt makes setting up and switching between those directories easier for me.
I can run interface exploration and test scenario design in parallel, for example. Two agents changing the same classes need coordination, though, and I still have to verify the combined result again.
A worktree isn't a sandbox. It separates changes in progress, not process permissions. An agent needs enough freedom to complete a whole task. The harness often doesn't give it enough and keeps stopping it. Running it without any limits creates a security risk instead.
I'm working on two approaches to sandboxing: a dedicated machine with restricted access to critical infrastructure, and AgentBox, my tool for isolating agents in configurable containers. It comes from the need to run agents with permissions such as --dangerously-skip-permissions so their harness doesn't keep interrupting them. The surrounding environment then has to provide the boundaries.
I want to give an agent more freedom without letting it access things it doesn't need for the task. So I pay attention to what it can see and reach in its environment. I don't want credentials in its workspace or logs, and giving it more freedom doesn't automatically mean trusting it with production access or publishing.
AgentBox development is still very much about trial, error and real testing. Server execution is still a preview, not a finished orchestrator for arbitrary models.
I don't always need the most expensive model
Architecture design, routine implementation and pull request review don't necessarily need the same model, or the most expensive one available. Often quite the opposite.
I'm interested in orchestration where I choose models by their capabilities, cost and context size. I use a particularly capable model for architecture, but much cheaper models are usually enough for the coding itself. A higher price doesn't guarantee a correct result.
I'm trying to bring this together in Coding Worker MCP. Through it, I can have a more expensive model delegate code exploration, implementation or review to a cheaper worker. That lets me separate assigning and assessing the work from carrying it out.
Choosing a model doesn't settle what the worker is allowed to access, though. I still need to control that through the environment it runs in.
Finishing a task isn't the same as accepting it. I need traceable evidence back, and a way to distinguish a completed run from a change that actually meets the brief. Choosing the model is one part of it. Passing on the context and checking the result are others.
What happens when I close the laptop?
I don't want to depend on an open laptop, which until recently was my main development machine. I still want to use it to discuss implementation details interactively, write an RFC or break a milestone down into tasks. After that, though, the AI needs to work on its own. For me, and ideally around the clock.
So I delegate routine work to a separate machine and try to move as many tasks there as possible. It isn't a fully autonomous dark factory yet, unfortunately, but I think I'm moving in that direction quickly. Individual parts work, and I'm trying out others to fill the gaps and connect them.
I'm experimenting with Hermes, Kandev, Codex, Claude Code with Remote Control, and other tools for milestone management and automatically assigning tasks to agents.
I don't just want remote access to a terminal, though. I need to keep track of the work, be able to stop it and find out what's left after a failure. Moving it to a server won't give me reliable autonomous execution on its own. I'm still putting those pieces together.
Real experience: Keboola
We spent roughly six months refining agent rules in a large repository where a substantial part of the system was built in Zend Framework 1 and is gradually being rewritten in Symfony.
We reached a point where a developer unfamiliar with the project can come in, give an agent a task, and the agent can change the right code or add new code in the appropriate framework. This is a good example of why I need more than a model that can write code. It needs to be able to navigate the project.
We have a range of skills, including automated task processing and code review. We use review both for an agent's own checks and for independent checks by other agents. The environment includes thousands of E2E tests and static analysis with PHPStan and coding-style checks with PHPCS and ECS.
A colleague and I also built CLI tooling that helps developers and agents carry out complex code operations and run tests, including those against BigQuery and Snowflake.
In the end, the code has to work
Even if I left everything else out, what matters most is whether my clients and I can rely on the resulting code. I care about a working change, why each part changed and which tests actually ran.
For me, unit tests are becoming less useful in agentic development. An agent can usually write them to pass against its own implementation, so green unit tests alone don't tell me the solution is correct. Writing them also takes time and context and leaves more code to maintain. I get more value from integration and E2E tests that check how the system actually behaves and how its components work together. I'm not ruling out unit tests: they still make sense for cryptography, security-sensitive code, algorithms or complex isolated logic. But I need to check the implementation against the brief, not just the assumptions the agent came up with. Static analysis is still part of verification, and CI needs to check the same commit that will be approved.
An independent reviewer needs the diff, the original brief and relevant context. A separate session and another model bring another perspective, but they can still share a blind spot. I need to reproduce a finding, verify the fix and have it reviewed again.
For now, I leave final approval to a person. But agents should serve everything up on a silver platter: the changes, check results, remaining uncertainties and evidence for approval. Agentic automation should make work easier, not hide problems behind green buttons.
This is a process I keep building, adjusting and improving. The diagram below shows how the steps fit together, not that I've already automated every one of them everywhere. I publish some tools, keep others to myself, and occasionally write about it on the blog — for example, converting a website to WordPress with an agent or moving CI/CD to GitHub Actions.
And of course, I'm still learning what I can do with agents. Every month they surprise me with something new they help me do better and faster.
The process, step by step
01 / 06 · SPEC
The brief needs verifiable acceptance criteria
Before an agent touches the code, I write down the goal, project context, architectural constraints and acceptance criteria. I also need to know how the result will be verified and what is outside the task’s scope.
An agent can easily fulfil a badly worded goal exactly as written. I resolve uncertainty before implementation; finished code alone doesn’t prove we were solving the right problem.
02 / 06 · TASKS
Tasks need clear boundaries
I break a milestone into tasks with specific outputs, dependencies and interfaces. Each task defines the agent’s responsibility and completion criteria, so it doesn’t need to wait for my instructions at every step.
Independent tasks can run in parallel. Work on shared interfaces or files needs coordination and another check of the combined result. Breaking down the work should reduce the attention it needs from me, rather than just add more agents.
03 / 06 · AGENTS
Worktrees separate code; sandboxes constrain access
I give agents their own Git worktrees and isolated environments with limited access. A worktree keeps changes separate; a sandbox also needs to control what the process can reach. I choose models and tools to suit the task.
I’m moving work to a remote runner too. I’m also trying AgentBox for isolation and Coding Worker MCP for delegating work between models. I use and verify the individual parts; connecting them into reliable autonomous operation is still work in progress.
04 / 06 · TESTS
I test behaviour, not the agent’s assumptions
I check the result against the brief, mainly through integration and E2E tests, static analysis and actually using the application. The checks need to run against the same commit that will be reviewed.
To me, unit tests lose some of their value in agentic development: an agent can easily write tests that confirm its own implementation. They still make sense for security-sensitive logic, cryptography or algorithms. Verification needs some independence from the code author’s assumptions.
05 / 06 · REVIEWS
A finding needs a fix and another check
I ask a different model or a separate context to review the diff, original brief and check results. Another perspective helps, but independent models can still share a blind spot.
I need to reproduce findings, make fixes and run the tests again. If agents get stuck on something insignificant, I stop the run or make the task smaller. The goal is a fixed, verified change, rather than a pile of comments.
06 / 06 · HUMAN APPROVAL
I approve a change with evidence, not a promise
I want a change summary, the diff, test and independent review results, known limitations and remaining risks. Missing verification needs to be visible, rather than hidden behind a green status.
I leave final approval to a person. Good evidence should let me make that decision without repeating every previous check; it doesn’t transfer responsibility to the agents.