The Four Loops, Clearly Explained Loop engineering is a pattern with multiple implementations, varying by who starts a run and decides when work is done. The four types of agentic loops in iii are turn-based (user is the loop), scheduled (triggered by time), event-driven (triggered by events), and hybrid (combining triggers). The turn-based loop is a REPL where the human controls each step, suitable when requirements are still forming. The Four Loops, Clearly Explained From how loop engineering is being talked about online, it may seem that there is just one way to do it right. But in reality, loop engineering is just a pattern, and there are a number of ways to implement it, with different levels of ownership on the user vs the orchestrator. Interested in more background on loop engineering? Read this post https://iii.dev/blog/loop-engineering-is-just-software-engineering/ first. Each approach to loop engineering is different on two parameters: what starts a run , and what decides the work is done . In a hand-run AI assistant chat session, you both start runs by writing prompts, and decide when work is done by evaluating whether the output meets your expectations. Loop engineering is the discipline of moving the responsibility for starting runs and deciding you’re done out of your head and into a system that runs without you. In this article, we show how you can implement four different types of agentic loops using iii. Background: Workers, Triggers, and Functions iii consists of three primitives: Workers, Triggers, and Functions. Workers register functions. Triggers bind events to functions. The engine routes between them. While in many harnesses loops are a separate concept, in iii you get agentic loops when you register a trigger whose function is another agent turn. Therefore, with iii, every type of agentic loop is a traditional distributed-systems pattern you already know, simply including an LLM turn as part of a run. The base case Before the four types of loops, it helps to name the thing they’re all working around. A turn is one pass through the agent: it reads context, triggers functions, and ends when the model ends it. The turn ending means the model decides it’s done for now and can’t proceed, but not necessarily because the task is done . It could be that it needs more input from a user or a loop to continue. 1. Turn-based: you are the loop Trigger: a prompt you write. Ends when: you say so. Here is the turn-based loop running end to end: In traditional terms: this is a REPL, a human at an interactive session. You run a command, read the result, decide the next command. No scheduler, no daemon, no shared state between runs, because you are the control loop. The agent gathers context, acts, and checks its own work inside one turn, then hands it back. You read it, decide what is missing, and write the next prompt. No triggers get registered. Nothing runs later on its own. The loop runs in your head, one exchange at a time. The composability is still there. Any worker function the harness allows filesystem, git, database, HTTP is triggerable inside the turn without extra setup. You control when to continue and when to stop. Technically, this is the simplest case there is: minimal trigger registration, no evaluator, no schedule, no list. The task ends the same way it started, inside a single turn, because a human is the only checkpoint the work needs. Use this when requirements are still forming, when every output changes what you would ask for next. Automating the “what’s next” question here is premature. You do not know it yet either. If you find yourself refining the same prompt structure repeatedly, you are prototyping a worker function. Eventually, this prompt can be extracted and registered as a permanent function. Use iii and Harness to investigate the following task: Describe the feature, bug, or idea. Work inside one turn: 1. Inspect the repository and gather the relevant context. 2. Explain the current behavior and identify ambiguities. 3. Propose the smallest sensible implementation. 4. If the requirements are sufficiently clear, implement it and run focused verification. 5. Review your own changes for regressions, security issues, and unnecessary complexity. Do not invent requirements or begin a recurring workflow. Stop when you either: - have a verified implementation, or - need a product/technical decision from me. End with: - what you learned, - what you changed, - verification performed, - unresolved questions, - the best next prompt for me to send. 2. Goal-based: the check moves off you Trigger: a task with success criteria. Ends when: an evaluator function says to. Here is the goal-based loop running end to end: In traditional terms: this is a retry-until-valid control loop. Do work, run a validator, and either accept the result or feed the failure back and try again, up to a budget. Every CI pipeline that retries a flaky step, every job that re-runs until a health check passes, is this pattern. The validator is a function, the attempt counter is shared state, and the loop is the retry. Here a real trigger appears. Say the goal is a Lighthouse score of 90 on a webpage, five attempts allowed. Instead of you reading the result and deciding, you register a check on the session’s turn-completed event. Each time the LLM’s turn ends, the engine triggers the evaluator function. The evaluator reads the result, checks it against the stated criteria, and returns a verdict: pass, continue, or abort. A continue starts another attempt in the same session, carrying forward what the failed check found. A pass writes the final result to state and removes the check. “ State ” in this case is iii’s scoped key-value store that workers can read and write to. An abort does the same, but records why the attempt was stopped rather than succeeded. The budget is a small counter in state too, decremented on each continue, so the loop cannot outrun what you allowed. The mechanics are two function calls and a state key. engine::register trigger sets up the check. harness::react runs the evaluator as a sub-agent. The budget counter and the terminal verdict sit in state. The stored state survives restarts, so a long-running goal loop does not lose its place. You write the criteria once. The engine runs the exchange between trying and checking as many times as the budget allows, without you reading a single intermediate attempt. Use this when the outcome is measurable and the path to it is not worth your attention. The evaluator you write here is the first iteration of a logic gate. When the criteria stabilize, you can extract this evaluator into a standalone validation function in a worker, turning the loop into a fixed, automated worker. Run a goal-based Harness workflow. Goal: produce a committed security audit of https://github.com/iii-hq/templates at reports/security/