> ## Documentation Index
> Fetch the complete documentation index at: https://mantle.rasa.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Writing prose

> How to write a skill's description and body so the right skill gets picked and runs the way you meant.

Every skill you write gets read by a model twice:

1. **Choosing.** Your skill's `description` sits in a list next to the
   description of every other skill, with one customer message to go on. The
   model picks one skill.
2. **Working.** Your skill is now running, and the model reads the body to
   decide what to say and what to do next.

Two readings, two jobs. This page covers writing for each.

## The description decides which skill gets picked

The routing list the model reads is built from two things per skill: the skill
id, which is the folder name, and the `description`. The `name` field is a
display label and takes no part in choosing, so the description is where the
work happens.

### Name the thing first, then the action

Lead with the subject the skill covers, then say what it does with it:

```yaml theme={null}
description: Credit card - replacement when lost, stolen, damaged, or not received
```

The opening words carry the most weight. The subject is what tells your skills
apart, and the action is usually what they share, so the subject is what belongs
in front.

Separate the two halves with a dash. A colon reads well too, but a colon has
meaning in YAML, so a description written with one has to be wrapped in double
quotes to load at all. A dash needs no quotes and puts the same word first.

When the action comes first instead, it pulls routing toward itself. Suppose the
same skill opened with the action:

```yaml theme={null}
description: How to replace or cancel a card
```

A customer asks:

> How do I replace my PIN?

The model opens the card replacement skill. Nothing about PINs lives in that
skill, but the question and the front of the description both lead with
"replace", so that is what matches. With the subject in front, the same question
falls through to the knowledge base, which is where the answer is.

| Write | Instead of |
| - | - |
| `Credit card - replacement when lost, stolen, damaged, or not received` | `Replacing a lost or stolen card` |
| `Savings account - closure and final balance transfer` | `How to close an account` |
| `Travel notice - adding and removing travel dates` | `Submitting a travel notice` |

The same ordering helps a tool description, which the model reads the same way
when it is choosing which tool to call:

```python theme={null}
@tool(description="Card replacement order - place one for a given card id")
```

### Use the words your customers use

Fill the description with the phrasings a real customer would type or say:

```yaml theme={null}
description: Credit card - replacement when lost, stolen, damaged, or not received
```

"lost, stolen, damaged, or not received" earns its place, because each one is a
different way a customer arrives at this skill.

Add a phrasing when it brings a genuinely different case. A second word for a
case you already cover, like "misplaced" next to "lost", takes up room without
telling the model anything new.

### Leave out what the skill id already says

The routing list already shows the skill id, so words that repeat it buy
nothing. For a skill in `skills/travel_notice/`:

```yaml theme={null}
description: Travel notice - adding and removing travel dates for a trip abroad
```

Compare that with a description that opens by repeating the id:

```yaml theme={null}
description: The travel notice skill. Use this skill to handle travel notices.
```

Both are one line, but only the first spends it on "adding", "removing",
"travel dates" and "abroad", which are the words a customer's message might
match.

## The body tells the model how to do the job

Once a skill is running, the body is what the model follows.

### Brief it like a new teammate

Write the body the way you would explain the job to someone competent who is new:
what to find out, what to offer, and in what order.

```markdown skills/card_replace/skill.md theme={null}
---
name: Card Replace
description: Credit card - replacement when lost, stolen, damaged, or not received
---

Help the customer replace a credit card.

Work through these in order:

1. Confirm the account is eligible with @tool.card_replace_eligibility.
2. If they hold more than one card, ask which one needs replacing.
3. Ask why they need a replacement. The valid reasons are lost, stolen,
   damaged, or not received.
4. Ask their shipping preference, confirm the order back to them, then place it
   with @tool.order_replacement.

The delivery address and the contact number can be checked at any point.
```

### Number the steps that have to happen in order

Use a numbered list when each step depends on the one before it:

```markdown theme={null}
1. Confirm the account is eligible.
2. Ask which card needs replacing.
3. Place the replacement order.
```

Use bullets when the pieces are independent, so the model is free to take them
in whatever order the conversation reaches them:

```markdown theme={null}
- Check the delivery address is current.
- Check the contact number is current.
- Mention that tracking details follow by email.
```

Where order is free between two things that sit inside a numbered run, say so
in a sentence: "The delivery address and the contact number can be checked at
any point." That way nothing is left to be guessed at.

### Give a long body headings

A short body reads fine as a few paragraphs. Once it covers several stages, put
each one under its own `##` heading:

```markdown theme={null}
## Account eligibility
## Collect reason and select card
## Handle reason
## Wallet and shipping
```

Headings give you somewhere obvious to put each instruction, which keeps
related lines together instead of scattered down the body. They also make the
skill easier to revise later, because you can see which stage a change belongs
to. A skill that needs no headings is usually a skill that is the right size.

### Put a rule where its cost matches its reach

A rule can sit in three places, and they differ in how often the model is
carrying it:

| Placement | In the prompt |
| - | - |
| `rules:` in [`agent.yml`](/reference/agent-yml) | Every turn, whichever skill is running |
| The opening lines of a skill body | Every turn that skill is active |
| A field in what a tool returns | Only the turn that tool ran |

Put a rule in `agent.yml` when it holds everywhere, such as the language to
answer in. Put it at the top of a skill body when it holds for that job only:

```markdown theme={null}
State card details, transactions and confirmation numbers only as a tool
returned them. Call the tool before you answer.

Help the customer replace a credit card.
```

A rule at the top of a long body is far from the step it governs, so restate it
at the point it applies when it matters. That is the one place repeating
yourself pays.

### Say what to achieve, not which words to use

Describe the outcome and let the model find the wording. It adapts to how the
customer is talking, which is most of the value of writing prose at all.

When the wording has to be exact, for legal or compliance reasons, put it in
[`responses.yml`](/reference/responses-yml) and it is delivered verbatim.

### Say what you want to happen

Write the behaviour you want. Naming a behaviour to avoid puts that very thing
in front of the model, and the "never" is a weak word wrapped around a strong
one, so the ban half-reads as an instruction to do it.

Most prohibitions have a positive form that is also more useful, because it
tells the model what to do instead:

| Write | Instead of |
| - | - |
| State card details, transactions and confirmation numbers only as a tool returned them | Never invent card details, transactions, or confirmation numbers |
| Quote the monthly total | Do not mention fees |
| Say that tracking details follow by email | Never promise a delivery date |

A prohibition earns its place only as a hard guardrail you cannot phrase
positively. Pair it with the positive target when you write one, so the model
still has something to aim at.

### Point at things with `@`

Four kinds of thing can be named in the body, and they share one shape. Each
takes an id, never a display name.

| Write | To |
| - | - |
| `@tool.<name>` | Call a tool |
| `@memory.<namespace>.<entry>` | Drop in a value the conversation already captured |
| `@skill.<skill_id>` | Hand the conversation to another skill and get it back |
| `@block.<block_id>` | Run an ordered block in this skill |

**Tools.** While a skill is running, its tools are already available to the
model, so naming one is enough:

> Ask for their account number, then call @tool.check\_balance.

**Memory.** The namespace is either a skill id or `project`, and there are
always exactly two parts after `@memory.`:

> Confirm the card ending in @memory.card\_replace.selected\_card\_last\_four is the
> right one.

This is the form for the body. Paths like `session.card_replace.…` belong in
conditions such as `requires:` and `if:`.

**Another skill.** Use the folder name under `skills/`, which is the skill id,
rather than the `name:` label:

> Once the card is chosen, run @skill.card\_disambiguation to settle which
> account it belongs to.

The other skill runs, and this one carries on where it left off when that
finishes. That return is guaranteed. Write the reference when this skill still
handles the request, and leave it out when the user changes the subject. See
[Delegate a part of a skill to another skill with `@skill`](#compose-a-related-request-in-place).

**An ordered block.** Use the id you gave the fence in
`:::ordered_block id=<block_id>`:

> Once the reason is recorded, work through @block.pick\_card.

The block runs its steps in order, then hands back to the prose that called it.

`rasa train` resolves `@memory` references against the memory this skill can
read, and `@block` ids against the blocks this skill declares, so a typo in
either surfaces at build time.

<h3 id="compose-a-related-request-in-place">
  Delegate a part of a skill to another skill with `@skill`
</h3>

The referenced skill has its own task. Write `@skill.<skill_id>` when the
skill you are writing still handles the request, including the part the other
skill does. That is a delegation: Mantle runs the other skill and brings this
one back when it finishes. When the user asks for a task this skill does not
handle, leave the reference out. Mantle parks this skill and offers them a
resume.

| User request | Write |
| - | - |
| Asks for something this skill handles | `@skill.<skill_id>`, then what to do when that skill finishes |
| Asks for a task this skill does not handle | Nothing in this body |

For example, a complaint about the replacement fee is still the replacement:

```markdown skills/card_replace/skill.md theme={null}
If the customer pushes back on the replacement fee — they complain about
it, dispute it, question the charge, or ask for it to be removed — that is
still this replacement, not a new subject. Handle it with
@skill.waive_replacement_fee, then carry on with the replacement. Mention
that fee only after they raise it.
```

A balance question during the same replacement, however, is a task this skill
does not handle. Card replacement does not need the balance to finish, so
there is nothing to delegate. Leave `@skill.account_balance` out of the
card-replacement body. Mantle treats the question as a topic change, parks the
replacement, and offers the user a resume once the balance is answered.

How a delegation and a topic change park and resume the parent is in
[skill.md](/reference/skill-md#jumps-to-blocks-and-skills).

### Let the tool result carry what happens next

The model sees what a tool returned, so write what to do with the result:

> Once you have their cards, show the last four digits of each and ask which one
> needs replacing.

Describing the shape of the result, such as which fields it contains, repeats
something the model already has in front of it.

When an instruction only applies after a particular tool has run, the result
itself is a good place for it. Return it as a field alongside the data:

```python theme={null}
return ToolResult(llm_response={
    "cards": cards,
    "next_step": "Ask which card needs replacing before ordering anything.",
})
```

The model reads that on the turn the tool ran, and it costs nothing on every
other turn, which is what the same sentence in the body would do.

## Reference

* [`skill.md`](/reference/skill-md) for the full frontmatter and body syntax
* [Instructions](/concepts/instructions) for how prose fits with control levers
* [When prose is not enough](/best-practices/when-prose-is-not-enough) for memory, tool constraints, responses, and blocks a sentence cannot cover


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