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
- Declare a
categoricalmemory entry inmemory.yml - Put an
if:marker on the line above each branch paragraph - Once the entry is set, the framework strips the non-matching paragraphs
skills/card_replace/skill.md
skills/card_replace/memory.yml
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:
next: branches, where
else: provides the fallback.
How it works at runtime
- The LLM reads all instructions (every paragraph is visible while the entry is unset) and gathers information conversationally
- The user says “it was stolen”
- The LLM records
replacement_reason = "stolen"viaset_fields - On the next prompt build, the
damagedandlost/not_receivedparagraphs are gone - The LLM continues with only the stolen path plus every unmarked paragraph
Boundary rule
Anif: 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:
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 areif: markers in the body and a categorical entry in memory.yml. Zero ordered
blocks, and a framework-enforced guarantee.