> ## 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 any text. Then either wait for the user or loop back to
   step 1. See [When the engine waits](#when-the-engine-waits).

One user message can go around this loop several times.

## When the engine waits

The engine waits for the next user message when:

* The stack is empty after a delivered response (the skill or block finished).
* An engaged `collect:` needs the user's answer.
* An ordered-block `action: action_listen` step runs.
* The LLM calls `listen()` alone (not mixed with text or other tools).

The `listen` tool lets the LLM end its turn silently after it already asked a
question and now needs the user's answer. It sends no message, makes no stack
or memory change, and has no side effects. It is a reserved framework tool
name; builder tools cannot be defined with that name.

The engine offers `listen` on main LLM calls. It withholds `listen` on guided
collect rephrase calls, on the answer call that runs after `search_knowledge`,
and while a tool confirmation is pending. The engine resolves mixed model
outputs as follows:

* `listen` alone: the turn ends in silence.
* Text plus `listen`: the text wins. The engine sends the text and drops
  `listen`.
* `listen` alongside other tool calls: the engine drops `listen` and runs the
  other tools.

## 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, builder, and `listen`
tools are dropped so a grounded answer neither re-drives the skill nor ends
silently before presenting the retrieved information. 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.

If the model still mixes `listen` with a user-facing answer after a search, the
engine ignores `listen` and treats the text as the grounded reply.

## 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.