Agentic Development / Anatomy of a Coding Agent
Software development has moved to so-called agentic development. We no longer use AI just as a smarter code completion, but we run agents that go through the project on their own, modify files and iteratively fix the code based on error messages.
However, by the word “agent” or “Claude”, developers often mean two structurally different layers of one system. Each of them has a different role and different limitations. And the second one also exists in two different forms.
The Raw Model (LLM)
The first layer is the language model itself. From a technical point of view, it is a stateless function that accepts a context prompt and generates a response based on probability.
The raw model itself has no memory and no access to the disk. Even the seemingly obvious thing, that the agent remembers the beginning of the conversation, is an illusion – with every single call, the whole history so far is sent to the model again as an array of messages. The model remembers nothing, it only receives a longer input every time.
The only thing it can do within agentic development is to return a so-called tool call, i.e. a structured request to call a function with specific parameters.
{
"tool_use": "execute_bash",
"parameters": {
"command": "sbt test"
}
}
It is worth noticing that the model did not run the command. It only generated a text that describes the command. Without the surrounding environment (the so-called harness), the model is just an isolated computing brain.
Harness
The second layer is the harness – the application in which the model runs. It does four things that the model cannot do:
- in every request it describes the available tools to it
- it really executes its tool calls in the operating system
- it puts the result back into the conversation
- it manages the context, i.e. it decides what exactly is sent to the model
The first three steps repeat until the model decides that the task is done, or until you stop it. This cycle is called the agentic loop. The fourth point is a continuous concern that goes through the whole session – and, as we will see in a moment, this is exactly where the official and the agnostic harnesses differ the most.
Official CLI Harness
These are ready-made solutions delivered directly by the authors of the models. The flagships are Claude Code by Anthropic and Codex by OpenAI, or agentic solutions integrated in editors like Cursor. To every request they automatically attach an extensive system prompt – tens of thousands of tokens of instructions with rules for code formatting, security limitations, guides for using the tools and strategies for task planning.
In the same way they automatically solve the overflow of the context window. If the history grows with long outputs from tests or compilation, the harness summarizes or trims the older messages in the background. The advantage is that you do not have to take care of anything. The disadvantage is the loss of control – you cannot modify or turn off the hidden instructions and you do not know what exactly disappeared from the history. Moreover, you are firmly locked in the ecosystem of one provider.
Agnostic Harness
These are open solutions that are independent of a specific provider. The philosophy of an agnostic harness is built on a fully transparent and configurable management of the context and of the behavior of the agent.
Instead of a huge hidden system prompt, you get a tool with guaranteed control over what exactly flows into the model. The conversation can be branched, and when the agent goes into a dead end, you return in the history to the branching point and the context is cleaned from the unsuccessful attempts. And because the harness does not rely on prompts tailored to one provider, you can switch between models of different providers within one session. Typical examples are Pi, OpenCode and others.
Neither of these two ways is better by itself. If you need to work immediately without any setup and it suits you that the provider takes care of the context and of the system prompt, the official harness is a great choice. If you want to see under the hood, to have an overview of the consumed tokens and to adapt the behavior of the agent to your own needs, the way leads through agnostic solutions.
Both layers can be replaced. The project in which the agent works cannot.
Feedback
The model is a generator of probable text and by itself it has no way to find out that it made a mistake. The only thing that keeps it at reality is a deterministic tool that verifies its output and returns a verdict – the compiler, the tests, the linter.
And this is the point where the choice of language stops being neutral. In a statically typed environment, the compiler rejects a large part of the wrong solutions before they even reach you – and directly with the exact position in the file. The price is a few seconds of compilation. In a dynamically typed language, the same typo shows up only at runtime – in the better case in a test, in the worse one over production data. A strong type system therefore works for the agent like rails: the more illegal states cannot be compiled, the less space is left for it to guess. Fast incremental compilation, reliable tests and clear error messages have a bigger influence on the result than the choice of model.