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

# Conditions

> The memory expression language used by requires, if:, complete_when, and next:.

A **condition** is a single-line expression string, evaluated against the
current memory values whenever the runtime needs it. The same grammar is used
everywhere a condition appears.

```yaml theme={null}
requires: "session.project.authenticated"
```

## Where conditions appear

| Site             | Where it is written                       | What it controls                                |
| ---------------- | ----------------------------------------- | ----------------------------------------------- |
| `requires:`      | `skill.md` frontmatter, top level         | Whether the orchestrator may route to the skill |
| `requires:`      | A `tool_constraints` entry in frontmatter | Whether a tool is offered to the LLM            |
| `if:`            | First line of a prose paragraph           | Whether the paragraph is included in the prompt |
| `complete_when:` | Frontmatter, or an `instructions:` step   | Whether the step is already satisfied           |
| `if:`            | A `next:` branch list on a step           | Which step runs next                            |

## Memory references

Every memory reference has three segments:

```
session.<namespace>.<entry_name>
```

`<namespace>` is a **skill id** or the literal `project`. `<entry_name>` is the
bare field name as declared in `memory.yml`.

```yaml theme={null}
session.card_replace.replacement_reason    # declared in skills/card_replace/memory.yml
session.project.selected_card_id           # declared in the project-root memory.yml
```

The namespace is the skill's **directory name**, which is also its catalog id. A
skill in `skills/card_replace/` with `name: Card Replace` is referenced as
`session.card_replace.<entry>`.

## Operators

| Category   | Available                                          |
| ---------- | -------------------------------------------------- |
| Comparison | `==` `!=` `<` `<=` `>` `>=`                        |
| Boolean    | `and` `or` `not`                                   |
| Grouping   | `( )`                                              |
| Literals   | strings, integers, floats, `True`, `False`, `None` |

Comparisons chain, so `session.a.x < session.a.y < 10` behaves as it does in
Python. These are the operators the expression parser accepts.

To test membership in a set, write it as a disjunction:

```yaml theme={null}
requires: >
  session.card_replace.replacement_reason == 'lost'
  or session.card_replace.replacement_reason == 'not_received'
```

## Truthiness

An unset memory entry reads as `None`, and the whole expression is coerced with
`bool()`. A bare reference is therefore a presence test:

```yaml theme={null}
requires: "session.project.selected_card_id"              # set and non-empty
requires: "not session.card_replace.replacement_reason"   # unset, empty, or false
```

This matters for a boolean with three meaningful states: unset, `True`, and
`False`. Compare explicitly to tell them apart:

```yaml theme={null}
requires: "session.card_replace.wants_lock == None"    # we have not asked yet
requires: "session.card_replace.wants_lock == False"   # the user said no
```

<Note>
  `0`, `0.0`, `""`, and `[]` are falsy. For a numeric entry that may legitimately
  be zero, compare against `None` rather than relying on truthiness.
</Note>

## Which entries you may reference

A condition on a skill can read:

* that skill's own `public` **and** `private` fields
* other skills' `public` fields
* project fields, declared in the root `memory.yml`

minus anything listed in the skill's `access.deny_read`. These are the same
rules the runtime applies when it assembles memory for a turn, so a reference
that passes validation resolves at runtime.

## Writing long conditions in YAML

Conditions are often longer than a line. Use a folded scalar (`>`), which joins
the lines with spaces into a single-line expression:

```yaml theme={null}
tool_constraints:
  - lock_card:
      requires: >
        not session.card_replace.card_locked_this_flow
        and (
        session.card_replace.replacement_reason == 'stolen'
        or session.card_replace.wants_lock == True
        )
```

Two quoting rules:

* Quote or fold a condition containing `:` followed by a space, so YAML reads it
  as a string rather than a mapping.
* Use **single** quotes for string literals inside a condition, so the whole
  expression can sit in double quotes:
  `"session.card_replace.replacement_reason == 'stolen'"`.

## Gates fail closed

Every condition guards access to something: a skill, a tool, a paragraph. When a
condition does not hold, the thing it guards is withheld:

| Site                           | When the condition is false                                                    |
| ------------------------------ | ------------------------------------------------------------------------------ |
| Skill `requires:`              | The skill is not offered for routing                                           |
| `tool_constraints` `requires:` | The tool is absent from the LLM's schema, and blocked if dispatch is attempted |
| Prose `if:`                    | The paragraph is left out of the prompt                                        |
| `next:` branch `if:`           | Evaluation moves to the next branch                                            |

Withholding is also the outcome when a condition cannot be evaluated at all.
This is deliberate: offering a tool and then refusing the call would waste a
turn, so the safe direction is to keep it hidden.

## What `rasa train` checks

Prose `if:` conditions are verified before packaging, so branching errors surface
at build time rather than mid-conversation:

| Code                                             | Meaning                                  |
| ------------------------------------------------ | ---------------------------------------- |
| `calm_v2.validation.prose.empty_if_condition`    | An `if:` marker with no expression       |
| `calm_v2.validation.prose.invalid_if_expression` | An expression the parser does not accept |
| `calm_v2.validation.prose.unknown_memory_key`    | A key the skill cannot read at runtime   |

The last one is the useful one: it catches a mistyped entry name or a reference
to a field the active skill has no access to.

The Inspector's tools panel shows the current gate result for every declared
tool, which is the quickest way to confirm a `requires:` expression behaves the
way you intended.

## Worked examples

Inline `requires:` patterns (same shape as tool constraints in a banking card-replace skill):

```yaml theme={null}
# record the reason only while it is still unset
- set_replacement_reason:
    requires: "not session.card_replace.replacement_reason"

# gate on a value another skill wrote into project memory
- check_number_of_transactions_returned:
    requires: >
      (
      session.card_replace.replacement_reason == 'lost'
      or session.card_replace.replacement_reason == 'not_received'
      )
      and session.project.selected_card_id
      and not session.card_replace.transaction_review_complete

# a tri-state boolean: offer the lock question only before it has been asked
- record_lock_choice:
    requires: >
      session.card_replace.wants_lock == None
      and not session.card_replace.card_locked_this_flow
```

Prose scoping:

```markdown theme={null}
if: session.card_replace.replacement_reason == 'stolen'
Lock the card immediately and tell the customer it was locked to protect
their account.
```

Branch routing inside an ordered block, where `else:` provides the fallback:

```yaml theme={null}
- id: gate_card_selected
  noop: true
  next:
    - if: "session.project.selected_card_id and session.project.selected_card_label"
      then: check_card_eligible
    - else: card_not_found
```

## See also

* [`skill.md` reference](/docs/maestro/reference/skill-md): where each condition site is declared
* [`memory.yml` reference](/docs/maestro/reference/memory-yml): declaring the entries conditions read
* [Tool Constraints](/docs/maestro/build-guide/tool-constraints): gating tools with `requires:`
* [Scoped Instructions](/docs/maestro/build-guide/scoped-instructions): `if:` markers in prose
