Skip to content
Blog

Anatomy of an Agentic Loop: The ORAE Cycle

Explore the fundamental Observe-Reason-Act-Evaluate cycle that powers modern autonomous AI agents, state persistence, and termination strategies.

Published on 2026-07-30

AI Assistant

The Core Cycle: Observe → Reason → Act → Evaluate

Every agentic loop, regardless of complexity, instantiates the same fundamental cycle. An agent observes its environment, reasons about what to do next, acts by executing a tool or producing output, and evaluates the result to decide whether to continue or terminate. This is the ORAE cycle — the atomic unit of loop engineering.

flowchart TD
    A["<b>OBSERVE</b><br/><small>(Read environment, tool outputs,<br/>previous state, feedback signals)</small>"]
    B["<b>REASON</b><br/><small>(Analyze observations, plan next<br/>action, reflect on previous steps)</small>"]
    C["<b>ACT</b><br/><small>(Call a tool, write a file,<br/>make an API request, produce output)</small>"]
    D{"<b>EVALUATE</b><br/><small>(Check termination conditions,<br/>assess output quality, detect errors)</small>"}
    E["<b>TERMINATE</b><br/><small>(Exit loop, return result)</small>"]
    A --> B
    B --> C
    C --> D
    D -- "Continue" --> A
    D -- "Terminate" --> E
    classDef observe fill:#e0f2fe,stroke:#0284c7,stroke-width:2px,color:#0f172a;
    classDef reason fill:#f3e8ff,stroke:#9333ea,stroke-width:2px,color:#0f172a;
    classDef act fill:#fef3c7,stroke:#d97706,stroke-width:2px,color:#0f172a;
    classDef evaluate fill:#fce7f3,stroke:#db2777,stroke-width:2px,color:#0f172a;
    classDef terminate fill:#dcfce7,stroke:#16a34a,stroke-width:2px,color:#0f172a;
    class A observe;
    class B reason;
    class C act;
    class D evaluate;
    class E terminate;

Every pattern in loop engineering — ReAct, Plan-and-Execute, Maker/Checker — is a specialization of this cycle. The differences lie in what each phase contains, how state flows between phases, and who or what performs the evaluation.

Observe

The Observe phase gathers all information the agent needs to make its next decision:

  • Tool outputs from the previous action step — file contents, API responses, command output
  • Environment state — current working directory, running processes, available resources
  • Persisted memory — results from earlier loop iterations, accumulated context
  • External signals — user interrupts, timeouts, incoming messages
  • Feedback from the Evaluate phase — error messages, validation results, quality scores

The quality of the Observe phase determines the ceiling on agent performance. An agent that cannot observe its own mistakes will repeat them. An agent that cannot observe its environment will act blindly.

Reason

The Reason phase is where the LLM processes observations and decides what to do next. This is the only phase that involves a model call in most architectures. The reasoning may take many forms:

  • Direct reasoning: “The test failed with error X. I need to fix the import statement.”
  • Planning: “I need to do three things: fix the import, update the schema, and add a migration.”
  • Reflection: “My last approach didn’t work because I forgot to handle the null case.”
  • Decomposition: “This task is too large. Let me break it into subtasks A, B, and C.”

The reasoning step produces an action plan — a structured specification of what the agent will do next, which tool it will use, and with what parameters.

Act

The Act phase executes the action plan. Actions fall into several categories:

  • Tool execution: running a shell command, calling an API, querying a database
  • File operations: reading, writing, editing, or deleting files
  • Communication: sending a message to a user, another agent, or an external system
  • State mutations: updating the agent’s own internal state, committing to memory
  • Output production: generating the final deliverable

Each action produces an observation — its stdout, stderr, return code, or result data — which feeds back into the next Observe phase.

Evaluate

The Evaluate phase determines whether the loop should continue or terminate. It checks:

  • Goal criteria: Has the agent produced a correct solution? Does the output pass all tests?
  • Error conditions: Did the last action fail critically? Is the agent stuck in a cycle?
  • Budget limits: Has the agent exceeded its step limit, token budget, or time allowance?
  • Quality thresholds: Does the output meet the required quality bar?

The Evaluate phase may involve automated checks (test suites, linters), LLM-based evaluation (LLM-as-a-Judge), or human review. Its output is a continuation decision: continue the loop, terminate with success, terminate with failure, or escalate to a human.


State Management & Persistence

The ORAE cycle generates state at every step. Without deliberate management, that state accumulates without bound, degrading performance and increasing cost.

What Is Agent State?

Agent state includes:

  • Conversation history: the full transcript of model calls and responses
  • Tool call records: which tools were called, with what parameters, and what they returned
  • Accumulated context: files read, code generated, research gathered
  • Execution metadata: step count, tokens consumed, elapsed time
  • Goal state: the original objective, success criteria, and current progress

Persistence Strategies

In-memory state is the simplest approach. All state lives in a data structure passed through each loop iteration. It is fast, simple, and suitable for short-lived loops. It fails catastrophically when the process crashes or when the loop runs long enough to overflow the context window.

Checkpointed state serializes state to persistent storage after each step. If the process crashes, the loop can resume from the last checkpoint. This is essential for long-running loops. Common checkpoint stores include local files, databases, and object storage. Each checkpoint should include a step number, a timestamp, the full state snapshot, and the termination decision that led to the next step.

Worktree isolation uses Git worktrees to give each loop iteration its own filesystem sandbox. When an agent modifies files in a worktree, the changes are isolated from the main branch and from other concurrent loops. This is particularly valuable for autonomous coding agents, where one loop’s file edits should not interfere with another’s.

class AgentState:
    step: int
    messages: list[dict]
    worktree_path: str | None
    tokens_used: int
    goal: str
    evaluation: str | None

def run_loop(initial_state: AgentState):
    state = initial_state
    while not should_terminate(state):
        state = observe(state)
        state = reason(state)     # model call
        state = act(state)        # tool execution
        state = evaluate(state)
        save_checkpoint(state)    # persistent storage

State Graphs

For complex loops with branching, conditional logic, or parallel execution, a state graph provides a more expressive model than a linear state variable. Nodes represent phases or sub-loops; edges represent state transitions with conditions. LangGraph popularized this approach, but the pattern is framework-agnostic: a directed graph where each node reads and writes to a shared state object, and edges carry guard conditions that determine which node executes next.

The state graph makes the loop’s control flow explicit and inspectable. It also enables powerful debugging: you can replay any path through the graph from a saved checkpoint, inspect the state at each node, and identify where the loop diverged from the expected path.


Feedback Mechanisms

Feedback is what makes a loop converge. Without it, the agent operates open-loop — generating output with no information about its correctness. Feedback mechanisms close the loop by providing signals that the Reason phase can act on.

Linter and Compiler Feedback

For code generation tasks, the most valuable feedback signal is the linter or compiler. A linter catches style violations, type errors, and common bugs. A compiler catches syntax errors, type mismatches, and structural problems. Both produce structured error output that the agent can parse and act on:

$ flake8 solution.py
solution.py:15:9: F841 local variable 'result' is assigned to but never used
solution.py:23:17: E225 missing whitespace around operator

The agent reads this output in the Observe phase, reasons about the errors in the Reason phase, and acts to fix them. This creates a tight inner loop — lint, fix, lint, fix — that converges rapidly.

Test Suite Feedback

Test suites provide a higher-level correctness signal. A passing test suite indicates functional correctness within the tested behaviors. A failing test provides a concrete failure case that the agent can debug:

FAIL: test_parse_csv_missing_values
  AssertionError: parse_csv("a,,c") returned ['a', '', 'c']
  expected ['a', None, 'c']

The agent can then inspect the test, understand the expected behavior, and modify its code accordingly. This is significantly more informative than a vague “your code is wrong” signal.

LLM-as-a-Judge

For tasks without formal correctness criteria — creative writing, summarization, code review — an LLM can serve as the evaluator. The judge model receives the agent’s output along with evaluation criteria and produces a structured assessment:

Judge output:
  Score: 7/10
  Issues:
    - Missing edge case: empty input not handled
    - Variable naming inconsistent (camelCase vs snake_case)
    - Documentation incomplete (no docstring)
  Recommendation: Fix edge cases and add docstrings before next iteration

Using an LLM as a judge introduces a meta-loop: the judge’s output must itself be reliable. Techniques like multi-judge ensembles, rubric-based evaluation, and judge calibration help mitigate this concern.

Structured Logs and Human Feedback

In production systems, feedback may come from structured logs (error rates, latency, cost per task), dashboards, or direct human review. Human-in-the-loop feedback is the most expensive signal but also the most reliable for subjective quality assessment. The Evaluate phase should route ambiguous or high-stakes outputs to a human reviewer before continuing.


Termination Conditions & Exit Strategies

A loop that never terminates is a bug. Every agentic loop must have explicit, testable termination conditions.

Goal Criteria

The ideal termination condition is goal satisfaction: the agent has produced a correct solution that meets all success criteria. Goal criteria should be:

  • Verifiable: A test, linter pass, or structured evaluation must confirm success
  • Specific: “Fix all failing tests” is better than “improve the code”
  • Bounded: The criteria should be achievable within the loop’s constraints
def goal_achieved(state: AgentState) -> bool:
    return (
        all_tests_pass(state.test_results)
        and linter_clean(state.lint_output)
        and state.evaluation_score >= 8
    )

Max Steps

A hard step limit prevents infinite loops. The limit should be generous enough for typical success but strict enough to bound cost and time. Typical values range from 10 steps for simple tool-use tasks to 100+ steps for complex autonomous coding.

When the step limit is reached, the loop should not silently terminate. It should log a warning, save a final checkpoint, and return the best result achieved so far along with a status indicator:

Status: STEP_LIMIT_REACHED
Steps taken: 25/25
Best score: 6/10
Output: (partial solution)

Token and Cost Budgets

Token budgets prevent cost explosions. Track cumulative input and output tokens across all model calls in the loop. When the budget is exhausted, terminate and return the current state. Cost budgets are a higher-level constraint: terminate when total cost exceeds a threshold, regardless of steps or tokens.

Fallback Strategies

Not all loops succeed. A fallback strategy defines what happens on failure:

  • Retry with different parameters: Restart the loop with a different model, temperature, or prompt template
  • Escalate to human: Route the problem to a human operator with the full execution trace
  • Degrade gracefully: Return a simpler solution or a partial result
  • Roll back: Undo all changes made by the loop (e.g., git checkout the worktree)

Timeouts

Wall-clock timeouts protect against hangs caused by slow tool execution, network failures, or model latency. The timeout should be set relative to the expected task duration, with a generous buffer.


Key Takeaways

  1. Every agentic loop follows the ORAE cycle — Observe, Reason, Act, Evaluate. All patterns are specializations of this fundamental cycle.
  2. State management is the defining engineering challenge of long-running loops. Choose between in-memory, checkpointed, or worktree-isolated persistence based on your reliability requirements.
  3. Feedback closes the loop. Linters, test suites, LLM-as-a-Judge, and human review provide the signals that drive convergence.
  4. Termination must be explicit and testable. Every loop needs goal criteria, step limits, budgets, and fallback strategies — not just a prompt that says “stop when you’re done.”
  5. A well-designed loop terminates deterministically: given the same inputs and environment, it reaches a termination condition in a predictable number of steps.