# Build a Production AI Agent From First Principles: The Complete Reference Architecture # Book: Advanced Agents From First Principles # Chapter URL: https://programmer.ie/books/advanced-agents-from-first-principles/44-chapter/ # Prose fingerprint (sha256, normalized): 88dccb185c13531c6f31996aa44aae8b5880cbcaf731bea0c9f03ba7f5e50bf7 # Snapshot generated at build time by Hugo. This is the complete rendered prose # of the chapter; it is not a transcript of the source file. 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.