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

# Skills

> Build composable skills and add deterministic constraints where required.

# Skills

Voice and chat agents in Rasa are built from composable skills, coordinated at runtime by an orchestrator called [Mantle](https://rasa.com/docs/mantle/overview.md). Progressive control lets each skill start as plain instructions and add deterministic guarantees where the business requires them.This page builds one skill, `card_replace`, from a single file to a constrained procedure. Scroll to follow along.

## Start with `skill.md`

A skill is a folder: instructions for the LLM, plus optional tools and references. At its simplest, the folder holds one file. Frontmatter with a name and description, then instructions in plain language. The folder name is the skill id; see [Project structure](https://rasa.com/docs/mantle/reference/project-structure.md) for the full layout.No flowcharts, no state machine. The LLM interprets the instructions in conversation.

## Add `tools/`

Define tools in a `tools/` subfolder and they are automatically available while the skill is active. No registration. A tool returns structured data to the LLM and can store results in [memory](https://rasa.com/docs/mantle/reference/memory-yml.md) for later steps.

## Add `references/`

FAQs, policies, and other reference material live in a `references/` subfolder. They are indexed at training time and retrieved on demand, so the agent can answer from them without carrying them in every prompt.

## Progressive control

Everything so far is instructions an LLM interprets. Where a mistake is expensive, you constrain it, with tool constraints, skill prerequisites, or ordered blocks.These are framework guarantees enforced by the runtime, not suggestions to the model. A tool whose constraint isn't met is not available for the LLM to call; a jailbreak can't change that.

## Tool constraints

A `requires` condition in the frontmatter gates when a tool becomes available. Until `selected_card_id` exists in memory, `lock_card` is removed from the tool schema entirely. The model can't call a tool it never sees.Enforced before the tool call executes

## Scoped instructions

Different situations need different instructions. `if:` markers scope a paragraph to a memory value: when `replacement_reason` is `stolen`, only the stolen paragraph is visible to the LLM. Non-matching branches are stripped from the prompt entirely.Non-matching branches removed from prompt

## Skill prerequisites

A `requires` block at the root of the frontmatter gates the whole skill: Mantle won't activate `card_replace` until `authenticated` is true. The only contract with the authentication skill is the memory key.Checked before the skill activates

## Ordered blocks

For steps that must run in exact order, add an `ordered_block` to the instructions. The LLM decides when to invoke `@block.pick_card`; the runtime executes the steps inside it in order.Step order enforced by the runtime

card\_replace/

skill.mdtools/tools.py*Optional*references/faqs.md*Optional*

card\_replace/skill.md

\---

name: Card Replace
description: Replace a credit card -- lost,
&#x20; stolen, damaged, or not received

\---

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.

For stolen or not-received cards, offer to lock
the card while a new one ships. Once everything
is gathered, ask their shipping preference,
confirm the order, and process the replacement.

card\_replace/tools/tools.py

from rasa.mantle.tools.decorator import ToolContext, tool
from rasa.mantle.tools.result import ToolResult

@tool(description="List the active bank cards
&#x20;     associated with the customer's account")
async def list\_cards(
&#x20;   account\_id: str,
&#x20;   context: ToolContext = None,
) -> ToolResult:
&#x20;   cards = await call\_cards\_api(account\_id)

&#x20;   # Store in memory for later steps
&#x20;   context.memory.set("user\_cards", cards)

&#x20;   # Structured data goes back to the LLM
&#x20;   return ToolResult(
&#x20;       llm\_response=\{
&#x20;           "cards": cards,
&#x20;           "total\_cards": len(cards)
&#x20;       },
&#x20;   )

card\_replace/references/faqs.md

Q: What if my dog ate my card?
A: That counts as damaged.

Q: Will my replacement card keep the same
&#x20;  number and PIN?
A: The number may change; your PIN stays
&#x20;  the same.

Q: How long does delivery take?
A: 5-7 business days, or 2 with express
&#x20;  shipping.

...

card\_replace/skill.mdhard guarantee

\---

name: Card Replace
description: Replace a credit card -- lost,
&#x20; stolen, damaged, or not received
tool\_constraints:
&#x20; \- lock\_card:
&#x20;     requires: "session.card\_replace.selected\_card\_id"

\---

Help the customer replace a credit card.

Until selected\_card\_id is set, lock\_card is
not in the tool schema at all.

card\_replace/skill.mdscoped

Ask why they need a replacement -- lost, stolen,

damaged, or not received.

if: session.card\_replace.replacement\_reason == 'damaged'
Ask who needs a replacement: only the

customer's card, an authorized user's, or both.

if: session.card\_replace.replacement\_reason == 'stolen'
Tell the customer the card will be locked.
Confirm, then lock the card.

if: session.card\_replace.replacement\_reason == 'lost'
Present recent transactions and ask if they
look familiar. Then handle locking.

card\_replace/skill.mdhard guarantee

\---

name: Card Replace
description: Replace a credit card -- lost,
&#x20; stolen, damaged, or not received
requires: "session.project.authenticated"
tool\_constraints:
&#x20; \- lock\_card:
&#x20;     requires: "session.card\_replace.selected\_card\_id"

\---

Checked by the runtime before the skill
activates.

card\_replace/skill.mdexact order

\## Identify the reason

Ask why they need a replacement -- lost, stolen,

damaged, or not received. Once the reason is
collected, invoke @block.pick\_card

:::ordered\_block id=pick\_card
steps:
&#x20; \- id: check\_eligibility
&#x20;   execute\_tool: card\_replace\_eligibility
&#x20; \- id: fetch\_cards
&#x20;   execute\_tool: get\_customer\_info
&#x20; \- id: select\_card
&#x20;   instructions: show user's cards and let
&#x20;     them pick one
&#x20;   complete\_when: "session.card\_replace.selected\_card\_id"
&#x20; \- id: END
:::

If a whole skill must follow a strict procedure, replace the entire body with an ordered block. Start simple, add control incrementally, and build fully deterministic skills where you need them.

> **[Local Quickstart](https://rasa.com/docs/mantle/getting-started.md)**
>
> Build a skill and run it. 2 minutes.

> **[Build Guide](https://rasa.com/docs/mantle/build-guide/tool-constraints.md)**
>
> The progressive control spectrum, one lever at a time.

> **[Orchestration](https://rasa.com/docs/mantle/orchestration/runtime-loop.md)**
>
> How Mantle runs a turn and what it guarantees.

> **[Reference](https://rasa.com/docs/mantle/reference/skill-md.md)**
>
> File formats, tools contract, runtime internals.


## Related topics

- [skill.md](https://rasa.com/docs/mantle/reference/skill-md.md)
- [Skills & Routing](https://rasa.com/docs/mantle/orchestration/skills.md)
- [Default skills](https://rasa.com/docs/mantle/reference/default-skills.md)
- [Sub-skills & Composition](https://rasa.com/docs/mantle/build-guide/sub-skills.md)
- [Assertions](https://rasa.com/docs/mantle/reference/assertions.md)


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