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

# Scoped Instructions

> Deterministic branching with if: markers -- no ordered blocks needed.

Scoped instructions are the first control lever that changes the body of
`skill.md`. They give framework-enforced branching by stripping non-matching
paragraphs from the LLM's prompt. The LLM can't follow the wrong branch because
it isn't in context.

## The problem

The Card Replace skill has reason-based routing: different handling for stolen
vs. damaged vs. lost cards. With pure prose the LLM sometimes picks the wrong
path, skips straight to locking, or blends the stolen and lost workflows.

## The fix: `if:` markers

1. Declare a `categorical` memory entry in `memory.yml`
2. Put an `if:` marker on the line above each branch paragraph
3. Once the entry is set, the framework strips the non-matching paragraphs

```markdown skills/card_replace/skill.md theme={null}
---
name: Card Replace
description: Replace a credit card -- lost, stolen, damaged, or not received
requires: "session.project.authenticated"

tool_constraints:
  - lock_card:
      requires: "session.project.selected_card_id"
---

Help the customer replace a credit card.

Check whether their account is eligible for replacement. If they have multiple
cards, ask which one. Ask why they need a replacement: the valid reasons are
lost, stolen, damaged, or not received.

if: session.card_replace.replacement_reason == 'damaged'
Ask who needs a replacement: just the customer's card, an authorized user's
card, or both.

if: session.card_replace.replacement_reason == 'stolen'
Tell the customer the card will be locked for their protection. Confirm, then
lock the card.

if: session.card_replace.replacement_reason == 'lost' or session.card_replace.replacement_reason == 'not_received'
Present any recent transactions and ask if they all look familiar. Then explain
that the card will be unusable until the replacement arrives, ask for
confirmation, and lock it if they agree.

Once the reason is handled, check digital-wallet eligibility. If eligible and
not already provisioned, offer Apple Pay, Google Pay, or Samsung Pay.

Ask their shipping preference (rush or standard), confirm the order, and process
the replacement.
```

```yaml skills/card_replace/memory.yml theme={null}
schema:
  public:
    replacement_reason:
      type: categorical
      enum_values: [lost, stolen, damaged, not_received]
      llm_settable: true
      description: Why the card is being replaced.
```

## One `if:` per case

Each marker stands on its own, so every branch reads as its own `if:`. To cover
"everything other than X", write the complement:

```markdown theme={null}
if: not session.card_replace.replacement_reason == 'stolen'
Explain the standard replacement timeline.
```

When a section genuinely needs exclusive either/or branching, reach for an
[ordered block](/build-guide/ordered-blocks) and its `next:` branches, where
`else:` provides the fallback.

## How it works at runtime

1. The LLM reads all instructions (every paragraph is visible while the entry
   is unset) and gathers information conversationally
2. The user says "it was stolen"
3. The LLM records `replacement_reason = "stolen"` via `set_fields`
4. On the next prompt build, the `damaged` and `lost/not_received` paragraphs
   are gone
5. The LLM continues with only the stolen path plus every unmarked paragraph

Scoping is re-evaluated on every prompt build, so a corrected value re-scopes
the branch on the next turn.

## Boundary rule

An `if:` marker scopes **only the paragraph immediately following it**, up to
the next blank line. Paragraphs without a marker are always visible. There are
no end markers.

The marker goes on the **first line** of the paragraph, with the text it scopes
directly beneath it.

## What `rasa train` checks

`if:` conditions are verified before packaging, so branching mistakes surface at
build time:

| 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 this skill cannot read at runtime  |

The last one is the useful one. It catches a mistyped entry name, a reference
missing its namespace, or a reference to another skill's `private` field.

## The progressive story

The frontmatter is unchanged from the previous page. The only additions are
`if:` markers in the body and a categorical entry in `memory.yml`. Zero ordered
blocks, and a framework-enforced guarantee.
