Designing Deterministic AI Agent Loops: Architecture, Verification, and Replay State Machines A developer has designed a deterministic AI agent execution runtime in TypeScript that replaces the naive LLM agent loop with a Finite State Machine architecture built around four phases: Observe, Propose, Verify, and Commit (OPVC). The runtime uses Zod-typed tool contracts and a Verification Gate that validates model-proposed actions against schemas and business invariants before execution, with event-sourced journaling to enable replay and prevent runaway loops. The approach targets common production failures such as infinite retry loops, hallucinated tool arguments, and invariant violations that inflate API costs and erode user trust. Most software engineers building with Large Language Models LLMs eventually hit the exact same wall: the naive agent loop problem . You start with a straightforward loop: In demos, this works brilliantly. In production, it breaks in infuriatingly subtle ways. The agent gets stuck in infinite loops repeating failing tool calls, hallucinates arguments when tool output schema changes slightly, or produces intermediate outputs that violate domain invariants—costing hundreds of dollars in API credits while degrading user trust. The core issue is architectural: we treat AI agents like deterministic functions, while executing their state mutations non-deterministically without real boundary validation. To move from fragile AI prototypes to mission-critical infrastructure, we must treat the agent runtime as a Finite State Machine FSM with isolated verification gates and event-sourced replay capabilities . In this article, we'll design and build a deterministic, production-ready AI agent execution runtime in TypeScript, step by step. A common fix for agent unreliability is "prompt-based self-correction"—telling the LLM in the system prompt: "If your tool execution fails, reflect on your mistake and try again." This fails in production for three distinct reasons: Instead of relying on the LLM to govern its own control flow, we decouple execution into four deterministic phases: Observe, Propose, Verify, Commit OPVC . php flowchart TD A State Machine Engine -- |1. Observe Current State| B Context Assembly B -- |2. Propose Action| C LLM Planner C -- |Candidate Transition| D{3. Verification Gate} D -- |Invalid / Invariant Violations| E Synthesize Error Event E -- |Inject Guidance| A D -- |Valid Transition| F 4. Commit Execution F -- |Execute Tool / Mutate State| G Append Event to Journal G -- A Let's construct a type-safe runtime that enforces this architecture. First, we establish strict typed contracts for our execution journal and tool schemas using Zod and TypeScript. js import { z } from "zod"; // Representing immutable events in our agent's history export type AgentEvent = | { type: "USER INPUT"; payload: string; timestamp: number } | { type: "ACTION PROPOSED"; tool: string; args: unknown; timestamp: number } | { type: "VERIFICATION FAILED"; error: string; timestamp: number } | { type: "ACTION COMMITTED"; tool: string; result: unknown; timestamp: number } | { type: "AGENT HALTED"; reason: string; timestamp: number }; export interface AgentState { history: AgentEvent ; status: "IDLE" | "AWAITING PROPOSAL" | "VERIFYING" | "EXECUTING" | "COMPLETED" | "FAILED"; consecutiveFailures: number; maxRetries: number; } // Definition for a verifiable tool export interface VerifiableTool