Agentic systems / Pattern 01 / Build the working path

Build a bounded execution loop in Python

Walk the actual action gate, fuel limit and evidence events, then identify the storage and deployment work deliberately outside the example.

By Sandeep Belgavi · 23 October 2026 · Architecture and design patterns

Run the original deterministic example

Download pattern_01.py and test_pattern_01.py into one folder. On macOS the command form is python3 -B pattern_01.py; on Windows it is py -3 -B pattern_01.py. Run the tests with the same interpreter and -B -m unittest -v test_pattern_01.py. The code uses only Python's standard library, has no credentials and performs no network or remediation calls.

The expected line is status=complete reads=1. The first adapter decision reads the latency fixture; the next finishes. The files were tested on Windows with Python 3.13. The macOS command is usage guidance, not a claim of execution on that platform. A matching line demonstrates this fixture path, not an evaluation of any language model.

Architecture and request sequence

Component diagram for Build a bounded execution loop in Python
Original reference architecture by Sandeep Belgavi. Arrows show the responsibilities and transitions described below.
Read the architecture as text
  • Local fixture: Synthetic latency observation
  • Decision object: Typed proposal from callable seam
  • run gate: Permission and remaining-step checks
  • Event list: Memory-only successful reads
  • CLI result: Deterministic demonstration output
  • Local fixture → Decision object: supply observation
  • Decision object → run gate: return proposal
  • run gate → Event list: record permitted read
  • Event list → CLI result: print terminal state
Request sequence for Build a bounded execution loop in Python
Illustrative sequence for this design; failure and recovery variants are explained in the article.
Read the sequence as text
  1. Caller → Harness: Call run with fixture
  2. Harness → Adapter: Pass copied observations
  3. Adapter → Harness: Return Decision read latency
  4. Harness → Evidence: Read dictionary entry
  5. Adapter → Harness: Return finish on next call
  6. Harness → Caller: Print complete and one read

Trace the actual adapter seam

Decision is a frozen dataclass containing an action and argument. run receives a callable adapter, an evidence dictionary and a limit. The adapter gets a shallow copy of the observations already collected. The supplied demo_adapter is a deterministic rule: read latency if nothing has been observed, otherwise finish. It is intentionally not presented as a model, planner or reasoning engine. Replacing the callable is the integration seam, but a real integration needs output parsing, request deadlines, usage accounting and error categorization.

The harness catches ordinary adapter exceptions and returns adapter_error. A value that is not a Decision produces invalid. Neither path adds a successful tool event. This distinction matters when debugging: a provider outage and an output-contract violation should not become an apparently completed investigation. The demonstration does not preserve exception text because real exceptions can contain sensitive payloads; a production logger would record a sanitized error category.

Follow permission checks and stopping behavior

Before reading, the loop requires the action to equal read and its argument to exist in the provided inventory. It denies everything else. A repeated reference returns repeated; a finish without any prior observation returns unsupported. Exhausting the configured iteration count returns exhausted, including the case where the last allowed action successfully read evidence but left no decision allowance for finish. This behavior makes completion explicit instead of guessing that the model probably meant to stop.

The limit accepts integers from one through one hundred and rejects booleans, which Python otherwise treats as integer-like values. Each permitted read appends an event containing step, tool and ref. Values remain inside the observed dictionary supplied to later decisions. The event list is an audit of successful reads, not a full distributed trace. The tests deliberately exercise unsupported finish, denied writes, repeated reads, exhausted fuel, invalid outputs and adapter exceptions.

Specify storage before promising restart recovery

The example keeps everything in process memory. Terminating it loses the event list and remaining allowance. For a durable adaptation, persist a run row with incident identity, adapter revision, allowed-reference digest, maximum decisions and terminal status. Append decision and observation events under a monotonically increasing sequence. A resumed worker must claim the run and compare its version before consuming the next allowance; otherwise two workers can spend the same remaining budget.

Store sensitive observation content separately from its stable locator. A reviewer may need access to an event without permission to view every underlying field. Choose retention for the source objects and for audit metadata explicitly. A source object disappearing before review should produce unavailable evidence, not an empty value interpreted as healthy. These are proposed schema and concurrency requirements; the downloadable code does not implement persistence, encryption, worker leases or crash recovery.

Containerize the boundary, not a readiness claim

A reference container for this exercise copies the module into a Python 3.11-or-newer image, selects an unprivileged user, sets a working directory and runs python -B pattern_01.py. Pin the chosen base image by digest in a real build after scanning it. No ports or cloud credentials are needed for the deterministic program. Treat that image as an executable test artifact, not a long-running incident service. A production service additionally needs authenticated admission, health checks, resource limits and graceful shutdown.

If a real adapter is added, pass its credential through the deployment platform's secret facility and restrict outbound access to the required endpoint. Never place a key in the Dockerfile or fixture inventory. Keep the model's proposed tool actions behind the same gate inside the container; packaging does not enforce application authorization. This container layout is a reference design only. No container build, registry push or cloud rollout is claimed by the Windows unit-test result.

Implementation sources and limits

The original module and its linked tests are the sources for every behavioral claim in this walkthrough. The companion design article cites the conceptual agent distinction. Tests establish the deterministic harness contract only. They do not establish model accuracy, resilience to arbitrary prompt injection, durable execution, a hard wall-clock deadline or operational readiness. Add those capabilities with their own acceptance evidence.