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

# Execution loop reference

> Which values the framework tracks at each control level on a turn.

This page lists the state tracked at each control level. For the order of a turn, see [The Runtime Loop](https://rasa.com/docs/mantle/orchestration/runtime-loop.md).

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](https://rasa.com/docs/mantle/reference/conditions.md).

## Tracker events

Mantle appends these events to the conversation tracker. They are what Inspector
and Copilot read; you do not author them in YAML.

| Event | When | Payload |
| - | - | - |
| `skill_activated` | Skill-scoped activation (builder skills and defaults) | `skill_id` |
| `skill_completed` | Skill-scoped completion | `skill_id` |
| `skill_cancelled` | Skill cancelled (one per skill) | `skill_id`, `step_id` |
| `skill_interrupted` | Skill parked for a digression | `skill_id`, `step_id` |
| `skill_resumed` | Skill continues after a pause | `skill_id`, `step_id` |
| `tool_executed` | A local or MCP tool actually ran | `tool_name`, `arguments`, `source` (`local` or `mcp`), `result`, `is_error`, `error_message`; `mcp_server` only when `source` is `mcp` |
| `memory_set` | A declared memory key was written | `key`, `value` |
| `memory_cleared` | A declared memory key was cleared | `key` |

Skill-level `flow_*` events are still written beside `skill_*`. Internals and
ordered blocks emit `flow_*` only.

Each tool run also appends `mcp_tool_executed` (same name, arguments, result, and
error fields; that copy has no replay metadata). Each memory write also appends
`slot_set` with the same key and value. Session-start metadata uses `slot_set`
only. Trackers that stored MCP tool runs or `slot_set` memory still replay.

## See also

* [The Runtime Loop](https://rasa.com/docs/mantle/orchestration/runtime-loop.md): the same loop, explained
* [Skills & Routing](https://rasa.com/docs/mantle/orchestration/skills.md#what-the-inspector-records): how Inspector shows these events
* [Constraint Table](https://rasa.com/docs/mantle/reference/constraint-table.md): framework vs. LLM at each level
* [Tools reference](https://rasa.com/docs/mantle/reference/tools.md): the built-in framework tools


## Related topics

- [The Runtime Loop](https://rasa.com/docs/mantle/orchestration/runtime-loop.md)
- [Skills & Routing](https://rasa.com/docs/mantle/orchestration/skills.md)
- [Events in Rasa](https://rasa.com/docs/reference/primitives/events.md)
- [System Prompt](https://rasa.com/docs/mantle/reference/system-prompt.md)
- [ReAct Sub Agent](https://rasa.com/docs/reference/config/agents/react-sub-agents.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.