Coding Agent Architecture
The point of the Coding Agent architecture is not "wrapping one more API layer outside AgentBuilder", but rather assembling the general agent runtime, workspace semantics, long-running sessions, host interaction, and external tool integration into one stable local delivery chain.
If you do not look at it from the "execution chain" angle, you will underestimate why many of the classes need to exist.
1. Start with the entire main chain
The main chain closest to real execution can be compressed into the following:
CodeCommand / AcpJsonRpcServer
-> DefaultCodingCliAgentFactory
-> CodingAgentBuilder
-> CodingSession
-> CodingAgentLoopController
-> built-in tools / approval decorators / MCP tools / delegate tools
-> Agent / AgentSession / model client
If you add session management and persistence back in, the more complete picture is:
host runtime
-> session manager + session runtime
-> coding runtime
-> tool surface + approval + MCP
-> base agent runtime
These layers are not abstract divisions on paper, but rather real responsibility boundaries separated in the current code.
2. The bottom layer is still Agent, but it is not exposed directly to users
The bottom layer is still the general Agent capability:
AgentAgentBuilderAgentSessionAgentRuntimeAgentModelClientAgentToolRegistryToolExecutor
What this layer is responsible for remains:
- model call
- tool loop inside a step
- basic memory
- tool call abstraction
But what Coding Agent cares most about is not here yet:
- workspace path boundary
- session persistence
- approvals
- process management
- auto-continue
- compact / checkpoint
- CLI / TUI / ACP integration
So the architecture of Coding Agent does not replace it, but rather stacks multiple layers of runtime semantics on top of it.
3. CodingAgentBuilder is the real fork point
The first key fork when switching from a "general agent" to a "coding agent" is CodingAgentBuilder.build().
What it does is not simple assignment, but rather a complete assembly:
- Validate
modelClientandmodel - Normalize
WorkspaceContext - Call
CodingSkillDiscovery.enrich(...) - Prepare
CodingAgentOptions,AgentOptions - Prepare
CodingAgentDefinitionRegistry - Prepare
CodingRuntime - Create the built-in tool registry
- Create the built-in tool executor
- Merge external tools, e.g. MCP
- Merge subagent tools
- Prepend the workspace prompt to the system prompt according to the configuration
- Finally call the general
AgentBuilderto build the underlyingAgent
So the real responsibility of CodingAgentBuilder is:
- Compress the "peripheral semantics needed for repository delivery" into an ordinary
Agent
If you want to determine whether a capability should land in Agent or Coding Agent, a practical question is:
- Does this capability depend on workspace / session / host / coding tool policy?
If it does, usually it should not be stuffed directly into the general Agent layer.
4. Why the workspace layer must be independent
WorkspaceContext is the boundary baseline of the entire coding architecture.
It currently defines at least the following:
- root path
- excluded paths
- whether explicit out-of-workspace access is allowed
- skill directories
- allowed read roots
- available skills
More critically, it has two sets of path resolution semantics:
resolveWorkspacePath(...)resolveReadablePath(...)
This shows that the current architecture explicitly distinguishes:
- where it can write
- where it can read
The reason skill roots can be placed outside the workspace is precisely because allowedReadRoots only expands the read surface, not the write surface.
If this layer were not independent, many coding-specific rules would have to be scattered across various tool executors, eventually becoming very hard to maintain.
5. The tool layer is not a single registry, but a multi-source merge
The currently visible tool surface comes from at least four sources:
- built-in coding tools
- externally injected tools, e.g. MCP
- delegate / subagent tools
- tool abstractions already supported by the lower
Agentlayer
CodingAgentBuilder first generates the built-ins, then merges the external registry / executor.
This means the core of the tool architecture is not "listing which tools exist", but rather:
- how tools from different sources are merged
- where conflicts are handled
- how the host mounts its own tool surface during assembly
This is also why MCP integration is designed so the host layer first prepares CliMcpRuntimeManager, then plugs its toolRegistry / toolExecutor into the builder, instead of being hardcoded in the built-ins.
6. CodingSession is the real runtime container for long-running tasks
If you only look at the API name, it is easy to treat CodingSession as a "chat session wrapper".
That would misjudge its responsibility.
What it currently takes on:
- bind workspace context
- bind process registry
- bind coding runtime
- support state export / restore
- record loop decisions
- aggregate compact results
Its position is closer to:
- "a persistent, resumable, forkable local work session container"
rather than the "conversation id" in an ordinary chat product.
This is why the session architecture is lifted separately in Coding Agent, rather than being hung off the host layer as a small utility class.
7. Why the outer loop forms its own layer
The general Agent is closer to a "tool loop within a single call".
Coding Agent also needs to handle a higher level of task continuity:
- whether the current turn should auto-continue
- for what reason to continue or stop
- when to compact
- how to record when blocked
This responsibility should not be stuffed into the CLI, nor into the general Agent.
The more appropriate location right now is the coding session / loop layer, with core classes including:
CodingAgentLoopControllerCodingLoopDecisionCodingStopReason
The point of this layer existing is:
- to separate the semantics of "one user task may span multiple model calls" into its own layer
Otherwise the host layer would be forced to guess on its own when to continue and when to stop.
8. DefaultCodingRuntime is not a UI runtime, but a delegation runtime
DefaultCodingRuntime is easily misread as "the overall runtime of the entire coding agent".
More accurately, its most important responsibility right now is:
- manage delegated tasks
- create child session
- track
CodingTask - maintain
CodingSessionLink - apply per-definition tool policy
From createChildSession(...) you can see the real position of this layer:
- Inherit the runtime and context skeleton of the parent session
- Recreate the child's built-in tools and process registry
- Merge custom tools, subagent tools
- Apply tool policy per definition
- Create a brand-new child
CodingSession - Restore seed state on demand
This shows that what DefaultCodingRuntime solves is:
- "how a subtask runs as an independent unit of work"
rather than:
- "how the terminal displays"
So it is not on the same layer as CLI/TUI/ACP.
9. DefaultCodingSessionManager solves persistence and lineage, not execution
DefaultCodingSessionManager is responsible for:
createresumeforksaveloadlist- event append / list
Note that it is not responsible for:
- running the model
- continuing the outer loop
- executing tools
It solves a different class of problem:
- how a running work session gets named, persisted, resumed, forked, and leaves behind an event ledger
So architecturally it should be seen as:
- session lifecycle management
rather than:
- runtime core
This is also why HeadlessCodingSessionRuntime and CodingCliSessionRunner still need it, but cannot have it replace the execution layer.
10. Why approval sits in the executor decorator layer
Current approval is not an OS hook, nor JVM instrumentation.
It is a decorator in the ToolExecutor assembly process.
The CLI/TUI path uses:
CliToolApprovalDecorator
The ACP path uses:
AcpToolApprovalDecorator
The architectural judgment behind this is very clear:
- approval belongs to "host decisions before tool execution"
- not to the model layer
- nor to the underlying OS interception layer
Placing it this way has three benefits:
- The underlying tool executor can keep pure execution logic
- CLI/TUI and ACP can share approval semantics but use different host channels
- The approval policy can vary with the host without polluting the general coding runtime
11. Why MCP forms its own live runtime layer
MCP is not a set of static tool definitions in the current architecture.
CliMcpRuntimeManager is responsible for:
- read resolved config
- establish connections
- pull tool definitions
- perform built-in / cross-server conflict checks
- maintain state snapshots
- generate tool registry / executor
In other words, it is a runtime with connection state, not a builder that helps you parse JSON on the side.
This is why it is reasonable to single out MCP in the architecture diagram.
Otherwise you would mistakenly think:
- "MCP is just a configuration form of tools"
In fact, the current implementation is clearly heavier:
- it is an external capability integration layer
- it has its own error model and runtime state
12. Why the host runtime is not "pure UI"
The layer of CodeCommand, CodingCliSessionRunner, JlineCodeCommandRunner, AcpJsonRpcServer is often underestimated.
But what they actually take on:
- parse runtime options
- choose CLI / TUI backend
- create session manager
- create and switch session runtime
- emit MCP startup warnings
- respond to slash commands
- relay permission requests and structured events in ACP
These behaviors already go far beyond "displaying text".
So the accurate understanding of host runtime should be:
- product entry point and interaction orchestration layer
rather than:
- the thinnest shell that renders UI
13. From an extension perspective, which layer to change first
This question is very important in actual development.
Want to change model call or basic tool loop
Look at ai4j-agent first
Want to change workspace semantics, coding tools, session state, delegation
Look at ai4j-coding first
Want to change CLI/TUI/ACP interaction, approval channels, MCP config, session storage
Look at ai4j-cli first
Want to add team rules or task workflow descriptions
Prefer the skill system, do not change the runtime first
The most common architectural mistake is not "cannot write it out", but rather "writing host logic into runtime" or "hardcoding general logic in CLI".
14. How this page divides work with adjacent pages
overview: establish the global mental model firstwhy-coding-agent: explains why an independent product line is neededarchitecture: explains layers, responsibilities, the main execution chainruntime-architecture: breaks down runtime components in finer detailsession-runtime: explains long-running tasks, events, save and resumetools-and-approvals: explains the execution surface and approval interceptionmcp-integration: explains the MCP integration chain in coding scenarios
If you now want to keep chasing "why long-running tasks can auto-continue and how they get saved", the next page you should look at is session-runtime.
15. The conclusions most worth remembering on this page
CodingAgentBuilderis the key assembly point where the generalAgentforks intoCoding AgentWorkspaceContext, tool merge, skills, MCP, approval are all architecture-level components, not scattered featuresCodingSessionowns long-running work container semantics,DefaultCodingSessionManagerowns persistence and lineage managementDefaultCodingRuntimefocuses on delegation and child session, not UI- host runtime owns real product interaction orchestration, not the pure display layer