II · Planning & Control FlowEmerging

Deterministic Control Flow, Not Prompt

also known as Own Your Control Flow, 12-Factor Control Flow

Branching decisions live in deterministic application code while the LLM is invoked at strategic points to produce structured signals that the code branches on.

Context

A team has an LLM-driven agent. The default temptation is to put branching logic in prompts ('if X then do Y, else do Z'). This makes control flow stochastic, hard to test, and hard to debug. The Polish/12-Factor-Agents 2026 source explicitly names this as a factor.

Problem

LLM-driven control flow is unreliable: the model may take the wrong branch, skip a branch, invent a branch. Tests cannot enumerate the paths. Debugging requires reading prompt traces. Distinct from spec-driven-loop (which specifies what the agent does at each step) by being specifically about keeping if/else logic out of prompts.

Forces

  • LLM-driven branching is convenient — write 'choose action' in the prompt.
  • Deterministic control flow requires the engineer to enumerate paths.
  • Some branching legitimately depends on LLM judgment (intent classification).

Example

A support agent has paths: refund / technical / sales / escalate. Naive: prompt says 'choose path A/B/C/D'. With this pattern: LLM is asked 'classify intent as one of {refund, technical, sales, escalate}'. The deterministic router reads the enum and dispatches. Tests cover all 4 paths; if the LLM classifies as 'other' the deterministic code has an explicit fallback.

Diagram

Solution

Therefore:

Structure: deterministic application code drives the control flow. At each branching point, call the LLM to produce a structured signal (typed enum, numeric score). Deterministic code reads the signal and branches. The LLM never sees 'choose the team's next branch' as a prompt; it sees 'classify this' or 'score this'. Pair with structured-output, json-only-action-schema, spec-driven-loop, stateless-reducer-agent.

What this pattern forbids. LLM is invoked at branching points to produce structured signals only; no if/else logic in prompts.

And the patterns that stand alongside it, or against it —

  • complementsSpec-Driven LoopRun the same prompt against a fixed spec in a deterministic outer loop until the spec is satisfied.
  • complementsJSON-Only Action SchemaAnti-pattern: restrict the agent's action language to JSON tool-call dictionaries even for tasks where code-as-action (functions composing, loops, conditionals over results) would be the natural shape.
  • complementsStructured Output★★Constrain the model's output to conform to a JSON Schema (or similar typed shape).
  • complementsStateless Reducer AgentDesign the agent as a pure function (state, event) → newState; entire execution history is held in an external event log; enables pause / resume / replay / time-travel without bespoke checkpointing.
  • complementsOwn Your Prompts (12-Factor Agents)Every prompt in a production agent is versioned, tested, and owned by the team in the application repo — never inherited as a framework default.
  • complementsHybrid HTN + Generative AgentHierarchical Task Network decomposition provides the procedural backbone; the generative LLM is invoked only at leaf nodes for the parts of the task that are genuinely open-ended.
  • complementsBPMN/DMN Deterministic Shell Around AgentBPMN processes and DMN decision tables form the deterministic spine; LLM-driven agents are invoked only at explicit 'unstructured problem' nodes inside the process.

Neighbourhood

Click any neighbour to follow the language. Scroll to zoom, drag to pan.