Build a Production AI Agent From First Principles: The Complete Reference Architecture
Build a Production AI Agent From First Principles: The Complete Reference Architecture
We have spent this series adding mechanisms only when a specific failure demanded them.
We started with a model call.
Then we added candidate generation, critique, planning, tool use, memory, search and verification.
Then the system stopped looking like a clever prompt.
It started looking like software.
Then distributed systems problems arrived:
- duplicate work,
- retries,
- leases,
- fencing,
- backpressure,
- dependency failure,
- behavioral drift,
- release compatibility,
- replay,
- incident forensics,
- SLOs,
- authority,
- competence,
- capability acquisition,
- placement,
- handoff,
- stale state,
- stale intent,
- commitments,
- durable workflows,
- transaction recovery,
- trust boundaries,
- multi-agent coordination,
- and finally an explicit control plane.
At this point the architecture is complete enough that adding another isolated mechanism would make the series worse rather than better.
So this chapter does something different.
It assembles the system.
The goal is not to build the largest possible agent platform.
The goal is to answer one practical question:
What does a production AI agent look like when all the important boundaries are made explicit?
The answer is not:
prompt
↓
model
↓
tool
↓
answer
A production agent is better understood as:
a controlled execution path from current intent to externally verified outcome.
Everything else in this chapter follows from that sentence.
The complete architecture
Here is the full reference architecture first.
We will then walk through it one layer at a time.
USER / EXTERNAL REQUEST
│
▼
┌─────────────────┐
│ Intent Registry │
└────────┬────────┘
│
current intent/version
│
▼
┌─────────────────────────┐
│ Goal / Commitment Graph │
└────────────┬────────────┘
│
▼
┌─────────────────────────┐
│ Task / Risk Classifier │
└────────────┬────────────┘
│
▼
┌──────────────────────────────────────────┐
│ CONTROL PLANE │
│ │
│ competence ─ authority ─ security │
│ │ │ │ │
│ placement ─ budgets ─ reliability │
│ │ │ │ │
│ releases ─ ownership ─ escalation │
│ │ │ │ │
│ commitments ─ capability portfolio │
└───────────────────┬──────────────────────┘
│
execution contract
│
▼
┌─────────────────────────────┐
│ Durable Workflow Runtime │
│ │
│ state │
│ timers │
│ waits │
│ retries │
│ events │
│ checkpoints │
│ compensation/reconciliation │
└──────────────┬──────────────┘
│
▼
┌─────────────────────────────────────┐
│ EXECUTION PLANE │
│ │
│ model / retrieval / search / critic │
│ planner / specialist / tool runtime │
│ sandbox / browser / code / API │
└──────────────────┬──────────────────┘
│
candidate operation
│
▼
┌─────────────────────────┐
│ Independent Verification│
└────────────┬────────────┘
│
verifier evidence
│
▼
┌─────────────────────────┐
│ Mutation Gateway │
│ │
│ intent current? │
│ state fresh? │
│ competent? │
│ authorized? │
│ secure? │
│ correct placement? │
│ ownership valid? │
│ budget available? │
│ verifier valid? │
│ release allowed? │
│ idempotency valid? │
└────────────┬────────────┘
│
permitted side effect
│
▼
┌─────────────────────────┐
│ External System │
└────────────┬────────────┘
│
authoritative state
│
▼
┌─────────────────────────┐
│ Postcondition Verifier │
└────────────┬────────────┘
│
▼
┌─────────────────────────────────────┐
│ Provenance / Replay / Reliability │
│ │
│ trajectory │
│ evidence │
│ release identity │
│ costs │
│ outcomes │
│ incidents │
│ SLOs │
└─────────────────────────────────────┘
The important observation is what is not at the center.
The model.
The model is important.
It may do much of the semantic work.
But it is one replaceable execution component inside a larger engineered system.
1. Start with intent, not a prompt
A production agent should not begin with:
response = model(prompt)
It should begin with an authoritative statement of what the system currently intends to accomplish.
That means intent must have identity.
@dataclass(frozen=True)
class IntentRef:
intent_id: str
version: int
objective: str
status: str
Why bother?
Because long-running work creates a new class of bug:
09:00 user says: deploy v4
09:03 agent starts analysis
09:08 user says: stop, deploy v5 instead
09:12 old worker finishes analysis
09:13 old worker deploys v4
The old worker may have reasoned perfectly.
The bug is not reasoning.
The bug is stale intent.
So every consequential operation should be bound to:
intent_id
intent_version
and the mutation gateway should reject operations produced under obsolete intent.
The key rule is:
Current intent is a commit-time invariant.
2. Turn intent into goals, not commands
Intent often describes a desired state.
For example:
Make release v5 available to production users.
That is better represented as a goal than as a fixed sequence of instructions.
@dataclass(frozen=True)
class Goal:
goal_id: str
intent_id: str
intent_version: int
desired_state: str
acceptance_criteria: tuple[str, ...]
This gives the agent freedom to reason about how to reach the goal while keeping success externally testable.
A useful hierarchy is:
intent
↓
goal
↓
subgoal
↓
commitment
↓
task
↓
action
Each layer means something different.
A goal is a desired state.
A task is work to attempt.
A commitment is stronger.
A commitment means the system has created an obligation that survives replanning.
Examples include:
- reserving deployment capacity,
- requesting human review,
- creating a cloud resource,
- scheduling a maintenance window,
- submitting an external batch job,
- promising a callback,
- opening a change ticket that another team now depends on.
That distinction matters because:
Plans are disposable. Commitments are durable.
3. Classify the task before choosing the model
Many agent architectures begin by choosing a model.
That is backwards.
First classify the work.
At minimum ask:
- What capability is required?
- What evidence is available?
- What verifier exists?
- What authority would execution require?
- What is the blast radius?
- Is the action reversible?
- Is the task inside a demonstrated competence envelope?
- Does a deterministic implementation already exist?
A useful classifier might emit:
@dataclass(frozen=True)
class TaskClass:
capability: str
risk_level: str
authority_level: str
verifier_class: str
reversibility: str
data_classification: str
This immediately constrains the architecture.
A read-only summarization task and a production database migration should not enter the same execution path merely because both can be phrased as natural language.
4. Competence is evidence, not confidence
Before execution we ask:
Has this system demonstrated competence for this kind of work?
Not:
Does the model sound confident?
A competence envelope should be evidence-backed.
For example:
@dataclass(frozen=True)
class CompetenceClaim:
capability: str
task_regime: str
state: str
benchmark_id: str
release_id: str
verifier_id: str
success_rate: float
Useful competence states include:
VALIDATED
SUPPORTED
LIMITED
UNVALIDATED
EXCLUDED
The system can then make an exact decision:
if claim.state == "EXCLUDED":
return HUMAN_REQUIRED
or:
if claim.state == "UNVALIDATED":
return SANDBOX_ONLY
Competence should also be specific to the execution path.
A model that performs well with repository access, a specific verifier and a particular toolchain may not retain the same competence when any of those dependencies change.
So competence is not just:
model X can code
It is closer to:
release R
on task regime T
using tool environment E
with verifier V
achieved measured performance P
5. Authority is separate from competence
Even if the agent is competent, that does not mean it is authorized.
This separation is one of the most important in the entire architecture.
capability
= can it sometimes do this?
competence
= do we have evidence it can do this reliably?
authority
= may it do this here, now, under this scope?
A highly competent coding agent may be authorized to:
create patch
run tests
open pull request
but not:
merge to main
deploy production
rotate secrets
modify billing
Authority should therefore be represented as structured policy.
@dataclass(frozen=True)
class AuthorityGrant:
principal: str
capability: str
scope: str
max_effect: str
expires_at: datetime
policy_version: str
The mutation gateway evaluates the grant.
The model does not.
6. Security boundaries surround the model
Production agents consume large volumes of untrusted text.
That includes:
- user messages,
- web pages,
- retrieved documents,
- source code,
- issue comments,
- logs,
- tool responses,
- generated files,
- messages from other agents.
The dangerous mistake is allowing those inputs to share the same conceptual channel as authority.
The security principle is:
Data does not become authority because an LLM interprets it as an instruction.
So instead of this:
web page
↓
model
↓
privileged tool
we want:
untrusted content
↓
interpretation / extraction
↓
proposal
↓
security + authority gate
↓
scoped credential broker
↓
privileged operation
Credentials should be scoped and preferably kept outside model context.
Generated code should be treated as untrusted candidate software.
Retrieved instructions should remain data.
Inter-agent messages should remain evidence.
Security policy should not be writable through the same uncontrolled channel it governs.
7. Placement comes after hard constraints
Now we can ask where the work should run.
But placement is not simply:
pick cheapest model
or:
send hard tasks to frontier model
A production placement decision may include:
model/runtime
provider
region
compute pool
tool set
data scope
sandbox profile
verifier set
authority ceiling
latency
cost
failure domain
The first phase is constraint satisfaction.
eligible = [
p for p in placements
if competence_ok(p)
and data_residency_ok(p)
and authority_ok(p)
and verifier_available(p)
and security_ok(p)
]
Only then do we optimize among eligible placements.
best = min(eligible, key=expected_cost_per_verified_success)
The principle is:
Placement is a constraint-satisfaction problem before it is an optimization problem.
This also means the correct outcome can be:
NO_FEASIBLE_PLACEMENT
That is not a failure of the architecture.
It is the architecture refusing to invent a safe execution path that does not exist.
8. Allocate budgets before starting search
Advanced agent techniques consume resources.
That includes:
- model tokens,
- wall-clock time,
- tool calls,
- search branches,
- human reviews,
- verifier calls,
- external API quotas,
- reconciliation capacity.
So each run should have a durable budget ledger.
@dataclass
class BudgetLedger:
compute_remaining: float
tool_calls_remaining: int
verifier_reserve: float
reconciliation_reserve: float
deadline: datetime
The reserve matters.
A common anti-pattern is spending the entire budget generating candidates and then discovering there is no budget left to verify the winner.
The system should therefore preserve:
verification reserve
reconciliation reserve
as protected capacity.
A useful rule is:
Max budget is not target budget.
The scheduler should stop when additional computation no longer earns its cost.
9. The durable workflow owns time
Now execution begins.
But the worker process should not own the workflow lifecycle.
The durable workflow should.
Why?
Because real agent runs wait.
They wait for:
- humans,
- external jobs,
- rate limits,
- deployment windows,
- dependency recovery,
- browser sessions,
- async APIs,
- scheduled events,
- other agents.
The LLM should not remain alive for three days waiting for an approval.
A durable workflow runtime persists:
workflow state
activity outcomes
timers
retry counts
wait reasons
external events
intent version
commitments
budgets
checkpoints
operation ledger
The model is invoked only at explicit decision points.
This gives us another foundational rule:
The workflow is durable. The model is disposable.
10. Build model context from durable state
Because the workflow owns state, model context can be reconstructed.
Do not treat conversation history as the database.
Instead:
authoritative workflow state
↓
relevant evidence
↓
current intent
↓
active commitments
↓
recent decisions
↓
bounded model context
This has several advantages.
The model can change.
The worker can crash.
The run can migrate.
The context window can be smaller.
Replay remains possible.
Sensitive data can be omitted unless necessary.
And most importantly:
model context ≠ authoritative state
11. Reasoning is a replaceable execution strategy
Now we finally reach the part most agent tutorials start with.
Reasoning.
The execution strategy might be:
single generation
self-consistency
candidate ranking
critique + revise
planner/executor
beam search
tree search
MCTS
evolution
specialist routing
multi-agent decomposition
But there is no universal best strategy.
The right question is:
What measured failure are we trying to fix?
If one-shot generation already achieves the required verified success rate under the cost budget, adding MCTS is not sophistication.
It is waste.
The architecture therefore treats reasoning strategies as interchangeable policies inside the execution plane.
class ReasoningStrategy(Protocol):
async def produce_candidate(self, ctx: ExecutionContext) -> Candidate:
...
That interface is more important than any particular reasoning algorithm.
12. Search should remain side-effect free as long as possible
Speculative branches are useful.
But they become dangerous when every branch can mutate the world.
Prefer:
branch A → candidate artifact
branch B → candidate artifact
branch C → candidate artifact
↓
compare
↓
verify winner
↓
one authorized commit
instead of:
branch A → mutate production
branch B → mutate production
branch C → mutate production
This is especially important in multi-agent systems.
Search branches should usually operate in:
- isolated worktrees,
- sandboxes,
- simulated environments,
- shadow resources,
- draft transactions,
- read-only external contexts.
Delay irreversible effects until uncertainty has been reduced.
13. Evidence is first-class state
Agents should not merely produce conclusions.
They should produce evidence objects.
For example:
@dataclass(frozen=True)
class Evidence:
evidence_id: str
source_type: str
source_identity: str
observed_at: datetime
state_version: str | None
trust_class: str
content_hash: str
Why does this matter?
Because evidence has properties that prose does not capture safely:
- provenance,
- freshness,
- trust,
- state identity,
- reproducibility,
- dependency relationships.
A model may summarize evidence.
But the summary should not silently upgrade the evidence’s trust class.
14. Uncertainty should be typed
If the agent says:
confidence = 0.63
we still do not know what to do.
Instead distinguish uncertainty such as:
INTERPRETATION_UNCERTAINTY
EVIDENCE_UNCERTAINTY
ROUTE_UNCERTAINTY
STATE_UNCERTAINTY
TOOL_UNCERTAINTY
CANDIDATE_UNCERTAINTY
VERIFICATION_UNCERTAINTY
Different uncertainty types imply different actions.
For example:
EVIDENCE_UNCERTAINTY
→ retrieve more evidence
STATE_UNCERTAINTY
→ re-read authoritative state
ROUTE_UNCERTAINTY
→ compare execution paths
VERIFICATION_UNCERTAINTY
→ strengthen verifier
This avoids the anti-pattern:
low confidence → ask model again
15. Use Expected Value of Information for optional refreshes
Some observations are mandatory.
For example, before committing a patch you may require the target branch SHA to match the expected base.
That is not optional information gathering.
It is a hard precondition.
But other information is optional.
Should we inspect one more file?
Should we call another specialist?
Should we run one more expensive simulation?
Expected Value of Information gives a useful decision framework.
Conceptually:
expected decision improvement
×
probability new evidence changes decision
−
acquisition cost
The exact formula matters less than the discipline:
Buy information when it has a reasonable chance of changing the decision enough to justify its cost.
16. Verification must be independent of generation
A candidate is not success.
The producing model should not get to declare itself correct.
We therefore separate:
generator
↓
candidate
↓
verifier
The verifier should use the strongest available external evidence.
For coding that might be:
- tests,
- static analysis,
- type checks,
- integration tests,
- benchmark deltas,
- policy checks,
- repository invariants.
For browser automation:
- authoritative page state,
- order confirmation,
- transaction ID,
- expected recipient,
- final price.
For research:
- source provenance,
- citation support,
- freshness checks,
- claim-to-source alignment.
For infrastructure:
- provider state,
- resource versions,
- rollout health,
- post-deployment probes.
The essential rule is:
The agent may produce the action. It does not get to define reality.
17. PASS, FAIL and UNKNOWN must remain different
Production verification should not collapse everything into a boolean.
At minimum:
PASS
FAIL
UNKNOWN
UNKNOWN matters.
Suppose an API times out after a purchase request.
Did the purchase fail?
Maybe.
Did it succeed?
Maybe.
The correct state is:
OUTCOME_UNKNOWN
until authoritative reconciliation establishes reality.
Forcing UNKNOWN into FAIL produces duplicate side effects.
Forcing UNKNOWN into PASS produces false success.
So UNKNOWN is not indecision.
It is a correctness state.
18. The mutation gateway is the final authority boundary
This is where the full architecture converges.
Before any consequential external mutation, evaluate hard invariants.
Conceptually:
@dataclass(frozen=True)
class MutationRequest:
intent_id: str
intent_version: int
operation_id: str
capability: str
artifact_hash: str
expected_state: dict[str, str]
placement_id: str
release_id: str
ownership_epoch: int
verifier_evidence_id: str
Then:
def authorize_mutation(req: MutationRequest, state: ControlState) -> ControlDecision:
checks = [
check_current_intent(req, state),
check_state_freshness(req, state),
check_competence(req, state),
check_authority(req, state),
check_security(req, state),
check_placement(req, state),
check_ownership(req, state),
check_budget(req, state),
check_verifier(req, state),
check_release(req, state),
check_idempotency(req, state),
]
failure = next((c for c in checks if not c.allowed), None)
if failure:
return ControlDecision.deny(failure.reason)
return ControlDecision.allow()
The exact implementation will vary.
The architectural boundary should not.
This is the point where probabilistic reasoning meets deterministic policy.
19. Exact facts should beat model interpretation
If the system has an exact fact, use it.
Examples:
branch SHA
policy version
resource version
lease epoch
approval expiry
credential scope
operation id
release id
verifier result
budget balance
Do not ask the model:
Do you think the branch probably changed?
when Git can tell you exactly.
Do not ask:
Does this approval seem current?
when the approval object has an expiry timestamp.
Use models for semantic ambiguity.
Use software for exact state.
20. Temporal consistency protects delayed actions
A plan can be correct when created and unsafe when executed.
So consequential actions should declare temporal dependencies.
@dataclass(frozen=True)
class StatePrecondition:
key: str
expected_version: str
mode: str
For a code change:
candidate patch
├─ base commit = abc123
├─ test evidence bound to candidate hash
├─ branch policy version = 9
├─ review approval bound to candidate hash
└─ target branch head must still equal abc123
If the target branch changes:
old verifier PASS
may no longer apply.
The system may need to:
REBASE
REPLAN
REVERIFY
REAUTHORIZE
The principle is:
Preserved state is not necessarily valid state.
21. Intent consistency protects delayed goals
Temporal consistency protects against the world changing.
Intent consistency protects against the objective changing.
Every delayed activity, retry, timer, resume or handoff should check the current intent version.
A stale worker can continue computing.
It should not retain mutation authority.
This is where fencing matters.
The runtime can advance an ownership or authority epoch when intent is superseded.
Old workers become stale automatically at the mutation boundary.
22. Ownership and leases solve different problems
In distributed execution, ownership changes.
A worker can crash.
A task can migrate.
A lease establishes temporary ownership.
A fencing token prevents a stale owner from continuing to mutate state after ownership has moved.
These are not interchangeable.
lease
= who currently appears to own work?
fencing epoch
= which owner is still authorized to mutate?
This is especially important in long-running agents because a stale worker may wake up minutes later and attempt an old action.
The mutation gateway should reject it using the ownership epoch.
23. Checkpoints preserve continuation, not authority
A checkpoint might contain:
workflow state
search frontier
observations
candidate artifacts
budget ledger
commitments
verifier evidence
operation identities
It should not imply:
still authorized
still fresh
still competent
still correctly placed
still current intent
So resumption is:
load checkpoint
↓
validate schema/release compatibility
↓
reconstruct authority
↓
check current intent
↓
check freshness
↓
check ownership
↓
resume / reverify / replan / reject
The rule is:
Checkpoint possession does not imply mutation authority.
24. Commitments survive replanning
Suppose the agent reserves deployment capacity.
Then it replans and chooses a different deployment path.
The reservation does not disappear because the plan changed.
The system must explicitly decide what to do with each active commitment.
A useful replanning diff is:
KEEP
RELEASE
TRANSFER
REVALIDATE
RECONCILE
This prevents hidden operational debt.
A workflow should not be considered cleanly complete while unresolved commitments remain unless policy explicitly permits that outcome.
25. Transaction recovery handles partial reality
Agents increasingly operate across multiple systems.
For example:
1. create cloud resources ✓
2. update DNS ✓
3. migrate database ✓
4. deploy application ✗
5. notify users
There is no global ACID transaction across those systems.
So classify side effects before execution:
REVERSIBLE
COMPENSATABLE
IRREVERSIBLE
UNKNOWN
Then make recovery explicit.
prepare
↓
commit
↓
observe
↓
verify
↓
if failure:
compensate / roll forward / reconcile / escalate
Two concepts must remain separate:
compensation
= what corrective action should we take?
reconciliation
= what is actually true right now?
A compensation action is itself consequential.
It needs its own:
- authority,
- operation identity,
- idempotency,
- retries,
- verification,
- provenance.
26. Multi-agent coordination should be typed
A production multi-agent system should not primarily look like:
Agent A: what do you think?
Agent B: I disagree.
Agent C: here is another opinion.
It should look like:
shared intent
↓
assignment registry
↓
Agent A owns task A
Agent B owns task B
Verifier C owns verification C
↓
artifacts + evidence
↓
structured conflict resolution
Each assignment should specify:
scope
owner
authority ceiling
budget
input artifacts
required output
acceptance criteria
handoff policy
failure policy
Messages between agents remain evidence or proposals.
They do not become authority merely because another model produced them.
And multiple agents do not automatically provide independent evidence.
If they share:
- the same model family,
- the same retrieval source,
- the same prompt lineage,
- the same verifier,
- the same provider,
then their failures may be highly correlated.
27. The control plane owns invariants
We can now summarize the control plane.
It owns things such as:
intent registry
competence registry
authority grants
security policy
placement policy
budget ledgers
reliability state
behavioral releases
capability portfolio
ownership epochs
commitment ledger
human escalation state
The execution plane owns things such as:
model calls
search
retrieval
critique
candidate generation
tool execution
sandbox work
specialist calls
The verifier establishes whether reality matches the required postcondition.
This yields the central architecture:
execution proposes
control permits
verification establishes outcome
28. The control plane should not become a god object
There is an obvious danger.
Once we identify a control plane, we may build one enormous service containing every policy and state transition.
That would simply replace one bad architecture with another.
Prefer narrow components.
For example:
IntentStore
CompetenceRegistry
AuthorityService
SecurityPolicy
PlacementService
BudgetLedger
ReliabilityController
ReleaseRegistry
OwnershipService
CommitmentStore
MutationGateway
They can expose explicit commands and queries.
CQRS is a natural fit.
For example:
QUERY
get current intent
get competence claim
get active grant
get ownership epoch
COMMAND
supersede intent
promote competence
issue grant
transfer ownership
create commitment
authorize mutation
Events can notify other components.
But delayed events should not replace authoritative current state.
29. Behavioral releases are bigger than model versions
If production behavior changes when any of these change:
model
prompt
tool schema
router
retrieval
memory policy
verifier
threshold
security policy
placement policy
workflow definition
then a release should bind them together.
@dataclass(frozen=True)
class BehavioralRelease:
release_id: str
model_bundle: str
prompt_bundle: str
tool_bundle: str
policy_bundle: str
verifier_bundle: str
workflow_bundle: str
This is essential for:
- rollback,
- replay,
- incident analysis,
- benchmark comparison,
- competence claims,
- staged rollout.
A model version alone is not enough to explain production behavior.
30. Provenance should answer why an action happened
A consequential operation should be traceable backwards.
Conceptually:
external effect
↑
operation
↑
mutation decision
↑
verifier evidence
↑
candidate artifact
↑
reasoning trajectory
↑
assignment / workflow step
↑
commitment / goal
↑
intent version
And sideways into control state:
competence claim
policy version
authority grant
security policy
placement
behavioral release
ownership epoch
budget ledger
This is what makes incident forensics possible.
Without provenance, the question:
Why did the agent do this?
turns into archaeology through logs and prompts.
With provenance, it becomes a query.
31. Replay should reproduce evidence, not hallucinate history
Deterministic replay does not mean the model must produce identical tokens.
For operational replay, we often want to reconstruct:
- what intent existed,
- what evidence was observed,
- what release was active,
- what candidate was selected,
- what policy permitted it,
- what verifier evidence existed,
- what side effect occurred,
- what postcondition was observed.
Historical replay should preserve historical observations.
Do not silently replace them with current state.
For live continuation, current state should be revalidated.
That distinction is critical:
historical replay
≠
live resume
32. Reliability closes the loop
A production agent architecture is incomplete if it cannot answer:
How often does it actually succeed?
Define outcome-oriented SLIs.
Examples:
verified success rate
false-PASS rate
FAIL rate
UNKNOWN rate
cost per verified success
p95 completion latency
reconciliation latency
stale-intent rejection rate
unauthorized-effect rate
Then set SLOs.
And maintain an error budget.
This allows runtime policy to respond to degraded behavior.
For example:
error budget healthy
→ normal autonomy
error budget burning rapidly
→ reduce rollout
→ increase verification
→ reduce speculation
→ contract authority
→ freeze risky releases
Reliability should affect architecture.
It should not live only on a dashboard.
33. False PASS is more dangerous than visible failure
A system that returns FAIL is inconvenient.
A system that silently returns PASS when the external result is wrong is dangerous.
So metrics should preserve:
PASS
FAIL
UNKNOWN
FALSE_PASS
False PASS deserves disproportionate attention because it destroys trust in the verification boundary itself.
A permissive verifier can make every upstream component appear healthy.
That is why verifier behavior must itself be monitored for drift.
34. Incident analysis should find the earliest divergence
When something goes wrong, the last visible error is often not the root cause.
Suppose:
wrong repository state read
↓
incorrect plan
↓
valid implementation of wrong plan
↓
tests pass against wrong assumption
↓
deployment fails
The deployment failure is the symptom.
The earliest meaningful divergence was the stale repository observation.
A useful incident pipeline therefore asks:
Where did the actual trajectory first diverge from a trajectory that could have produced a verified successful outcome?
Then any remediation should be replayed against the original incident.
A plausible fix is not enough.
35. Learning happens after evidence
Agents can learn from trajectories.
But trajectories are not automatically training labels.
A successful outcome does not prove every intermediate decision was good.
A failed outcome does not prove every intermediate decision was bad.
So learning should preserve:
- outcome evidence,
- causal uncertainty,
- decision context,
- alternative choices,
- verifier quality,
- release identity,
- task regime.
Learned routing or control policies should then go through their own:
benchmark
shadow
canary
promotion
monitoring
rollback
cycle.
Do not let the agent silently rewrite its own control system from production trajectories.
36. Capability acquisition happens outside authority
The platform may discover that it lacks a useful capability.
For example:
can inspect Terraform
cannot safely plan Terraform changes
The next step is not:
give production credentials and see what happens
Instead:
sandbox capability acquisition
↓
benchmark
↓
verification design
↓
competence claim
↓
controlled promotion
↓
limited authority
The principle remains:
Learn outside the authority boundary before expanding the authority boundary.
37. The platform should choose what not to own
Not every capability belongs inside the agent platform.
For each capability ask whether the best strategy is:
1. build agent capability
2. implement deterministic software
3. keep human in control
4. route to external specialist
5. explicitly do not support
This is the capability portfolio.
It prevents the platform from treating universal autonomy as the objective.
The objective is useful, verifiable capability.
38. Shared primitives create both leverage and correlated risk
A capability dependency graph helps identify shared components.
For example:
repository snapshot
├─ code review
├─ refactoring
├─ migration planning
└─ dependency analysis
Improving that primitive may unlock many capabilities.
But failure can also invalidate many capabilities at once.
So the graph should model dependencies such as:
REQUIRED
OPTIONAL
PERFORMANCE
VERIFICATION
AUTHORITY
OBSERVABILITY
RECOVERY
Then ask both:
How much leverage does this primitive provide?
and:
How much correlated failure does it create?
39. The same architecture works across domains
This reference architecture is not specific to coding agents.
Coding agent
intent
↓
change request
↓
repository snapshot
↓
competence + authority
↓
isolated worktree
↓
patch candidate
↓
tests/static analysis
↓
PR creation gateway
↓
GitHub authoritative state
↓
postcondition verification
Browser agent
intent
↓
purchase goal
↓
product evidence
↓
price/inventory freshness
↓
authority + spending limit
↓
checkout candidate
↓
recipient/price verifier
↓
payment gateway
↓
order confirmation
↓
transaction reconciliation
Research agent
intent
↓
claim set
↓
source acquisition
↓
provenance + trust
↓
claim/source graph
↓
verification
↓
current-state freshness checks
↓
final report
↓
citation provenance
DevOps agent
intent
↓
change goal
↓
cluster/deployment snapshot
↓
competence + authority
↓
plan
↓
policy/verifier checks
↓
fenced mutation
↓
rollout observation
↓
postcondition verification
↓
rollback / roll-forward / reconcile
The domain changes.
The control structure remains recognizable.
40. A production run, end to end
Let us walk through a concrete coding example.
The user asks:
Fix the authentication regression and open a pull request.
Step 1: create intent
intent_id = INT-8841
version = 1
objective = fix authentication regression and open PR
Step 2: classify
capability = repository_change
risk = medium
authority = create_branch + push_branch + open_pr
production_merge = forbidden
Step 3: check competence
The active behavioral release has validated competence for:
small repository bug fixes
with tests
under isolated worktree execution
Result:
SUPPORTED
Step 4: choose placement
The repository is private and policy requires local processing.
Eligible placements:
local coding model
local deterministic tools
local verifier
Frontier provider is excluded by data policy.
Step 5: establish workflow
DISCOVER
↓
REPRODUCE
↓
PLAN
↓
IMPLEMENT
↓
VERIFY
↓
OPEN_PR
↓
VERIFY_PR
Step 6: gather evidence
The agent reads:
- failing test,
- relevant implementation,
- recent commit history,
- call graph,
- configuration.
Each observation receives provenance and state identity.
Step 7: produce candidates
The reasoning strategy generates two patch candidates in isolated worktrees.
No external mutation occurs.
Step 8: verify candidates
Candidate A:
unit tests PASS
integration test FAIL
Candidate B:
unit tests PASS
integration test PASS
static checks PASS
Candidate B wins.
Step 9: revalidate current state
Before opening the PR:
target branch still equals expected base?
intent still current?
authority still valid?
release still permitted?
ownership epoch current?
All pass.
Step 10: mutation gateway
The proposed operation is:
push branch + open PR
The gateway verifies:
intent PASS
state freshness PASS
competence PASS
authority PASS
security PASS
placement PASS
ownership PASS
budget PASS
verifier evidence PASS
release PASS
idempotency PASS
Operation permitted.
Step 11: external effect
The branch is pushed and PR created.
Step 12: postcondition verification
The platform queries GitHub authoritatively.
It verifies:
PR exists
head SHA correct
base branch correct
expected files changed
Outcome:
VERIFIED_SUCCESS
Step 13: persist provenance
The run records:
intent
release
repository base SHA
observations
candidate hashes
verifier results
authority grant
operation ID
PR identity
final postcondition
cost
latency
Now the result is not merely:
agent says done
It is:
externally verified outcome with reconstructable evidence
That is the difference between a demo agent and a production agent.
41. What happens if the user changes their mind?
Suppose just before the PR is opened the user says:
Do not open a PR. Just show me the patch.
Intent version becomes:
INT-8841 v2
The old mutation request is bound to:
INT-8841 v1
The mutation gateway rejects it.
The patch artifact may still be reusable.
The side effect is not.
This is scoped supersession.
No model obedience is required for correctness.
42. What happens if the branch moves?
Suppose another developer merges a change after tests pass.
The old candidate was verified against:
base = abc123
Current base is:
def456
The gateway detects the exact state mismatch.
Possible outcome:
REBASE_REQUIRED
After rebasing, the candidate hash changes.
Therefore old verifier evidence may no longer apply.
The workflow returns to verification.
Again, no model guess is required.
43. What happens if the provider times out?
Suppose PR creation is sent but the API times out before returning a response.
The correct outcome is not immediately:
FAILED
It is:
OUTCOME_UNKNOWN
The workflow enters reconciliation.
It queries GitHub using the stable operation identity or expected branch/head state.
If the PR exists:
COMMITTED
If not:
SAFE_TO_RETRY
This prevents duplicate side effects.
44. What happens if verification disappears?
Suppose the integration-test service becomes unavailable.
The architecture should not quietly lower the truth standard.
Depending on policy:
DEFER
UNKNOWN
HUMAN_REQUIRED
READ_ONLY_ONLY
may be correct outcomes.
Graceful degradation may reduce capability.
It must not silently redefine success.
45. What happens if reliability degrades?
Suppose the coding agent’s false-PASS rate starts rising after a release.
The reliability controller can respond:
contract authority
require stronger verifier
reduce rollout
route harder tasks to humans
freeze new release promotion
This is why the control plane consumes reliability evidence.
Reliability is not merely reporting.
It changes what the system is allowed to do.
46. What happens if a model disappears entirely?
The system should still preserve:
- workflow state,
- commitments,
- ownership,
- intent,
- security grants,
- operation identities,
- unresolved transactions,
- reconciliation requirements.
The platform may not make progress.
But it should remain correct.
That is a strong test of architecture.
If losing the model also causes you to lose your understanding of what the system has already done, the model was holding state it should never have owned.
47. What not to put in the model
Some state belongs in prompts because the model needs it to reason.
That does not mean prompts should be authoritative storage.
Avoid making the model the sole owner of:
current intent
workflow state
authority grants
retry count
commitment state
operation identity
lease epoch
policy version
budget ledger
approval validity
transaction state
These belong in deterministic state stores.
The model receives views of them.
It does not define them.
48. What belongs in the model
The model is valuable where the system faces semantic uncertainty.
Examples:
- interpreting ambiguous requirements,
- proposing candidate plans,
- generating code,
- summarizing evidence,
- identifying likely root causes,
- comparing alternatives,
- explaining conflicts,
- constructing hypotheses,
- decomposing open-ended problems.
A useful design question is:
Is this fact difficult because it is semantically ambiguous, or because we have failed to model exact state?
If the latter, fix the software model.
Do not ask the LLM to approximate a database.
49. Hard decisions and soft decisions
A production architecture benefits from dividing decisions into two classes.
Hard decisions
Examples:
intent version matches
lease epoch current
credential scope permits action
budget remains
region allowed
artifact hash matches approval
verifier PASS exists
These should usually be deterministic.
Soft decisions
Examples:
which implementation strategy is best?
which source is most relevant?
is this change conceptually equivalent?
which decomposition is likely to work?
These may benefit from models.
The control plane can accept model evidence for soft decisions while preserving deterministic hard constraints.
50. The architecture should support saying no
A mature agent runtime needs explicit refusal states that are operational rather than conversational.
Examples:
NO_FEASIBLE_PLACEMENT
OUTSIDE_COMPETENCE_ENVELOPE
AUTHORITY_REQUIRED
SECURITY_POLICY_DENY
STATE_CONFLICT
INTENT_SUPERSEDED
VERIFICATION_UNAVAILABLE
BUDGET_EXHAUSTED
HUMAN_REQUIRED
UNKNOWN
These are not embarrassing failures.
They are evidence that the system can represent boundaries.
A platform that always produces an action has probably hidden uncertainty somewhere.
51. Complexity should be earned incrementally
The complete reference architecture is intentionally broad.
That does not mean every agent should implement every layer on day one.
A sensible progression is:
Stage 1
model + typed tool + verifier
Stage 2
+ trajectory logging
+ authority gate
Stage 3
+ durable workflow
+ idempotency
Stage 4
+ competence / releases / reliability
Stage 5
+ distributed ownership / handoff
Stage 6
+ commitments / transactions
Stage 7
+ explicit control plane
Only add a stage when your workload exposes the corresponding failure mode.
The reference architecture tells you where a capability belongs.
It does not tell you that you need every capability immediately.
52. A compact implementation skeleton
Here is a deliberately small Python sketch showing the architectural boundaries.
from dataclasses import dataclass
from enum import Enum
from typing import Protocol
class Outcome(str, Enum):
PASS = "PASS"
FAIL = "FAIL"
UNKNOWN = "UNKNOWN"
@dataclass(frozen=True)
class RunContext:
run_id: str
intent_id: str
intent_version: int
release_id: str
placement_id: str
ownership_epoch: int
@dataclass(frozen=True)
class Candidate:
artifact_id: str
artifact_hash: str
proposed_action: dict
@dataclass(frozen=True)
class VerificationResult:
outcome: Outcome
evidence_id: str
artifact_hash: str
@dataclass(frozen=True)
class ControlDecision:
allowed: bool
reason: str
class Reasoner(Protocol):
async def produce(self, ctx: RunContext) -> Candidate:
...
class Verifier(Protocol):
async def verify(self, candidate: Candidate) -> VerificationResult:
...
class ControlPlane(Protocol):
async def authorize(
self,
ctx: RunContext,
candidate: Candidate,
verification: VerificationResult,
) -> ControlDecision:
...
class Executor(Protocol):
async def commit(self, candidate: Candidate, operation_id: str) -> dict:
...
class PostconditionVerifier(Protocol):
async def verify_external_state(self, operation: dict) -> VerificationResult:
...
Then the workflow:
async def run_step(
ctx: RunContext,
reasoner: Reasoner,
verifier: Verifier,
control: ControlPlane,
executor: Executor,
postcondition: PostconditionVerifier,
operation_id: str,
):
candidate = await reasoner.produce(ctx)
verification = await verifier.verify(candidate)
if verification.outcome is not Outcome.PASS:
return verification
decision = await control.authorize(ctx, candidate, verification)
if not decision.allowed:
return decision
operation = await executor.commit(candidate, operation_id)
return await postcondition.verify_external_state(operation)
This is not a full platform.
That is the point.
The architecture lives in the boundaries.
The implementations behind those boundaries can evolve independently.
53. What this architecture buys you
The point is not elegance for its own sake.
The architecture buys specific properties.
Replaceability
You can change models without rewriting authority, workflow or provenance.
Recoverability
Workers can crash without erasing what happened.
Verifiability
Success is grounded in external state.
Audibility
You can reconstruct why an operation was allowed.
Security
Untrusted content cannot directly promote itself into authority.
Scalability
Workers can distribute while ownership remains explicit.
Adaptability
Intent, state and placement can change without silently invalidating correctness.
Controlled learning
Policies can improve without bypassing release and validation mechanisms.
Bounded autonomy
The platform can express exactly where autonomy stops.
54. What this architecture does not buy you
It does not guarantee intelligence.
It does not guarantee the model will solve novel problems.
It does not make weak verifiers strong.
It does not make irreversible actions reversible.
It does not eliminate incidents.
It does not eliminate human judgment.
It does not make uncertainty disappear.
What it does is make those limitations visible and governable.
That is more valuable than hiding them inside a prompt.
55. The architecture in one table
| Concern | Owner | Model role | Enforcement |
|---|---|---|---|
| Intent | Control plane | Interpret objective | Version check |
| Goals | Workflow/control | Propose decomposition | Goal state |
| Commitments | Control plane | Suggest obligations | Commitment state machine |
| Competence | Control plane | None/self-assessment not authoritative | Benchmark-backed claim |
| Authority | Control plane | Propose action | Policy/grant |
| Security | Control plane | Interpret content | Capability/security gate |
| Placement | Control plane | Optional recommendation | Constraint solver |
| Budget | Control plane/workflow | Choose spend within bounds | Durable ledger |
| Workflow | Durable runtime | Decision worker | State machine |
| Reasoning | Execution plane | Primary | None beyond sandbox |
| Search | Execution plane | Primary | Budget/isolation |
| Evidence | Evidence store | Interpret/summarize | Provenance/freshness |
| Verification | Verifier | Optional semantic verifier | External evidence |
| Mutation | Gateway/executor | Propose | Hard control checks |
| Postcondition | Verifier | Optional interpretation | Authoritative external state |
| Reliability | Control plane | None | SLO/error budget |
| Releases | Control plane | Component of release | Promotion/rollback |
| Replay | Provenance layer | Historical artifact only | Recorded state/evidence |
| Recovery | Workflow/control | Suggest strategy | Operation ledger + verification |
The recurring pattern is obvious.
The model is heavily involved in semantic reasoning.
It is deliberately not the owner of operational truth.
56. The full control decision
If we compress the entire series into one pre-mutation decision, it looks something like this:
Can this action happen?
1. Is this still the current intent?
2. Are the action's state assumptions still fresh?
3. Has this system demonstrated competence here?
4. Is the action authorized?
5. Does it satisfy security policy?
6. Is the chosen execution placement allowed?
7. Does this worker still own mutation authority?
8. Is enough budget left, including recovery reserve?
9. Is verifier evidence valid for this exact artifact/state?
10. Is this behavioral release permitted?
11. Has this logical operation already happened?
12. Are unresolved commitments or transaction states compatible?
If any hard answer is NO:
do not mutate.
If required truth is UNKNOWN:
preserve UNKNOWN or escalate.
No model needs to memorize that list.
That is what the platform is for.
57. The deepest lesson from the series
At the beginning of this series, advanced agents looked like increasingly sophisticated reasoning structures.
chain of thought
↓
self-consistency
↓
tree search
↓
MCTS
↓
multi-agent systems
Those techniques still matter.
But they are not where production correctness ultimately comes from.
Production correctness comes from the surrounding engineering:
state
identity
ownership
authority
verification
recovery
provenance
reliability
security
The frontier of agent engineering therefore shifts from:
How do I make the model think harder?
into:
How do I engineer a system in which uncertain reasoning can be useful
without silently becoming unbounded authority?
That is a much more interesting problem.
58. The model is not the operating system
A useful final mental model is this:
ENGINEERED AUTONOMY PLATFORM
CONTROL PLANE
│
intent / policy
competence / authority
security / placement
reliability / releases
│
▼
WORKFLOW PLANE
│
durable state / waits
retries / commitments
handoff / recovery
│
▼
EXECUTION PLANE
│
models / tools / search
retrieval / critics / agents
│
▼
VERIFICATION
│
▼
MUTATION GATEWAY
│
▼
EXTERNAL WORLD
│
▼
POSTCONDITION EVIDENCE
│
▼
PROVENANCE + RELIABILITY
The model is powerful.
But the model is not the operating system.
It is a process running inside one.
59. Do you actually need this architecture?
Probably not all of it.
And that is exactly where the series should end.
The reference architecture is useful because it shows where production concerns belong when they become necessary.
It should not become a checklist that forces every prototype to build a distributed control plane before making its first useful tool call.
The next and final chapter asks the opposite question:
What is the minimum production agent architecture that still preserves the most important correctness boundaries?
We will start with the smallest useful system:
model
+
typed tools
+
authoritative state
+
external verifier
+
simple authority gate
+
trajectory log
Then we will add nothing unless a measured failure earns it.
That final inversion is important.
After spending an entire series learning how to build sophisticated agent systems, the last skill is learning when not to.
Final principle
A production agent is not defined by how many agent techniques it contains.
It is defined by whether it can move from intent to outcome while preserving the boundaries that make the outcome trustworthy.
So the complete reference architecture can be summarized in one sentence:
A production AI agent is a controlled execution path from current intent to externally verified outcome, with authority, state, provenance, recovery and reliability enforced outside the model.
That is the architecture.
Everything else is implementation detail.