> ## Documentation Index
> Fetch the complete documentation index at: https://maestro.rasa.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Execution Loop

> The deterministic-first loop that runs every turn.

Every turn runs a deterministic-first loop:

1. **Execute deterministic steps first**: ordered-block steps that need no
   model call (`execute_tool:`, `noop:`, `set_memory:`, `action:`, and
   `collect:` steps whose value is already known). The framework also narrows
   what the LLM may do next, filtering routable skills by `requires:` and hiding
   gated tools, though the routing choice itself is made by the LLM in step 3.
2. **Build a scoped prompt from live state**: the active skill's instructions
   filtered by `if:` markers, the tools whose `requires:` conditions currently
   hold, and the memory values readable in scope.
3. **Call the LLM.**
4. **If the LLM returns a tool call**: dispatch it, apply any memory writes the
   tool makes as it runs, check for newly-available deterministic steps, and
   loop back to step 1.
5. **Otherwise**: send the response and wait for the user.

One user message can go around this loop several times.

## State tracked per control level

| Control level            | What the framework tracks                                         |
| ------------------------ | ----------------------------------------------------------------- |
| Skill routing            | The dialogue stack (parent frames, sub-skill frames, interrupts)  |
| Ordered block            | A step pointer: the current step in the block                     |
| Prose with `if:` markers | Memory state, which determines which paragraphs are in the prompt |

These coexist. A hybrid skill, meaning prose with `if:` markers that also
references an ordered block, tracks both a step pointer and memory state at
once.

## Tool execution

A tool may be invoked by the LLM (a tool call) or by the framework (an
`execute_tool:` step). The function does not know or care which.

`tool_constraints` are checked in both cases, and in two places:

* when the tool schema is built, deciding whether the LLM sees the tool at all
* again at dispatch, before the function runs

Both **fail closed**. A `requires:` condition that cannot be evaluated hides
and blocks the tool rather than allowing it.

## Knowledge search changes the loop

When `search_knowledge` runs during a turn, the tool list for the remainder of
that turn collapses to `activate`, `search_knowledge`, and `cannot_help`, plus
`resolve_tool_confirmation` when a confirmation is pending so the pending gate
is never stranded. The active skill's lifecycle, collect, and builder tools are
dropped so a grounded answer does not re-drive the skill. They return on the
next turn.

Relatedly, `cannot_help` is withheld until a search has run whenever a knowledge
base is configured, so the model cannot decline before retrieval could have
answered.

## Where conditions are evaluated

| Condition                      | Evaluated                                         |
| ------------------------------ | ------------------------------------------------- |
| Skill `requires:`              | When building the routable-skill list, every turn |
| `tool_constraints` `requires:` | At schema build and again at dispatch             |
| Prose `if:`                    | At prompt build, every turn                       |
| `next:` branches               | When a step advances                              |
| `complete_when:`               | When checking whether a step is already satisfied |

See [Conditions](/reference/conditions).

## See also

* [The Runtime Loop](/maestro/runtime-loop): the same loop, explained
* [Constraint Table](/reference/constraint-table): framework vs. LLM at each level
* [Tools reference](/reference/tools): the built-in framework tools
