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

# skill.md

> Complete reference for the skill file: frontmatter properties and body format.

`skill.md` is the only required file in a skill folder. It is YAML frontmatter
followed by a markdown body.

```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"
complete_when: "session.card_replace.replacement_submitted"

import_tools:
  - get_customer_info

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

Help the customer replace a credit card.
```

The file **must** open with `---` on the first line and close the frontmatter
with a second `---`. A missing delimiter fails with
`skill.markdown.invalid_frontmatter_delimiter`.

## The skill id is the folder name

The skill id — used for routing, memory namespacing, and `@skill.` references — is always the **parent directory name**, never the `name:` field.

A skill in `skills/card_replace/` with `name: Card Replace` is:

* referenced in prose as `@skill.card_replace`
* namespaced in memory as `session.card_replace.<entry>`

## Frontmatter properties

| Property           | Required | Type             | Description                                                        |
| ------------------ | -------- | ---------------- | ------------------------------------------------------------------ |
| `name`             | Yes      | string           | Human-readable display name                                        |
| `description`      | Yes      | string           | What the skill does. The orchestrator routes on this.              |
| `requires`         | No       | condition string | Memory condition gating whether the skill can be activated         |
| `complete_when`    | No       | condition string | Condition that marks the skill finished                            |
| `import_tools`     | No       | list of strings  | Tools from the agent-root `tools/` folder                          |
| `tool_constraints` | No       | list             | Per-tool gating, confirmation, and outcome rules                   |
| `utter`            | No       | list             | Verbatim responses fired on skill activation or a memory condition |
| `disabled`         | No       | bool             | Exclude the skill from routing without deleting it                 |

Write `description` as a routing summary, including the phrasings a customer
would actually use. It is the only thing the orchestrator matches against.

### `requires`

A [condition](/reference/conditions) string checked before the orchestrator
offers the skill:

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

### `complete_when`

A condition that, once true, marks the skill's prose flow complete:

```yaml theme={null}
complete_when: "session.card_replace.replacement_submitted"
```

### `import_tools`

Declares tools defined in the agent-root `tools/` folder, so this skill may use
them:

```yaml theme={null}
import_tools:
  - get_customer_info      # from tools/*.py at the agent root
```

Tools in the skill's own `tools.py` or `tools/*.py` are auto-discovered and must
not be listed. A shared tool that is not declared here is not attached to the
skill.

To use the same tool from more than one skill, define it once in the agent-root
`tools/` folder and declare it in each skill's `import_tools`.

### `tool_constraints`

A list of single-key mappings, tool name to options:

```yaml theme={null}
tool_constraints:
  - lock_card:
      requires: "session.project.selected_card_id"
  - process_card_replacement:
      requires: "session.card_replace.order_confirmed == True"
      requires_confirmation:
        enabled: true
        utter_for_confirmation: utter_ask_replacement_confirmation
      on_success: utter_replacement_disclaimer
```

| Option                   | Description                                                                                                                                                                                                                  |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `requires:`              | Condition string. The tool is hidden from the LLM and blocked at dispatch until it holds.                                                                                                                                    |
| `requires_confirmation:` | Mapping. `enabled: true` pauses the call for explicit approval, resumed via `resolve_tool_confirmation`. Optional `utter_for_confirmation` / `utter_on_user_denial` name responses; omit them to let the LLM phrase the ask. |
| `on_success:`            | Response name delivered after the tool succeeds.                                                                                                                                                                             |
| `on_failure:`            | Response name delivered after the tool fails.                                                                                                                                                                                |

See [Tool Constraints](/build-guide/tool-constraints) for worked examples.

An entry that is not a single-key mapping, or whose options are not a mapping,
fails with `skill.markdown.invalid_tool_constraints`.

### `utter`

Fires a verbatim response from `responses.yml` on a skill lifecycle event or
when a memory condition first becomes true:

```yaml theme={null}
utter:
  - utter_recording_notice:
      on: activate
  - utter_stolen_warning:
      when: "session.card_replace.replacement_reason == 'stolen'"
```

| Trigger        | Fires                                                          |
| -------------- | -------------------------------------------------------------- |
| `on: activate` | When the skill becomes active                                  |
| `when:`        | The first time the condition becomes true after a memory write |

An entry may set both. These are distinct from a tool's `on_success:` /
`on_failure:`, which attach to a gated tool in `tool_constraints`.

### `disabled`

```yaml theme={null}
disabled: true
```

The skill loads but is excluded from routing. Useful for parking a
work-in-progress skill without deleting it.

## Body format

The body is markdown. It supports:

### Prose paragraphs

Always visible to the LLM. Blank lines separate paragraphs; each paragraph is a
scoping unit.

### `if:` markers

A paragraph whose **first line** is `if: <condition>` is included only when the
condition holds:

```markdown theme={null}
if: session.card_replace.replacement_reason == 'stolen'
Tell the customer the card will be locked for their protection.
```

The marker scopes only the paragraph directly beneath it, up to the next blank
line. Write one `if:` paragraph per case; for exclusive either/or branching, use
an ordered block's `next:` branches.

### Jumps to blocks and skills

| Token               | Target                             | Behaviour                                            |
| ------------------- | ---------------------------------- | ---------------------------------------------------- |
| `@block.<block_id>` | An ordered block in **this** skill | Enters the block, returns to prose when it completes |
| `@skill.<skill_id>` | Another skill                      | Runs it and returns; parent resumes                  |

Both take the id: `@block.` names a block declared in the same file, and
`@skill.` names the target skill's **directory name**.

Tools are named in plain prose rather than with a token, since they are already
in the model's schema while the skill is active.

#### How the parent is parked

The engine parks the current skill differently depending on what put the new
one on top:

| Trigger                 | Parked as            | Resumes                                             |
| ----------------------- | -------------------- | --------------------------------------------------- |
| `@skill.<skill_id>`     | Delegation           | Automatically, when the referenced skill finishes   |
| `@block.<block_id>`     | Same-skill reference | Automatically, at the prose that entered the block  |
| The user changing topic | Digression           | The engine offers a resume and the customer decides |

A `@skill.` target is offered only while its own `requires:` condition holds.
Public memory is readable across skills in every case, so the difference is
control rather than data: the first two are part of the skill's design, the
third is the customer steering the conversation.

### Ordered blocks

```
:::ordered_block id=pick_card
steps:
  - id: check_eligibility
    execute_tool: check_account_replacement_eligibility
  - id: END
:::
```

The id is a **fence attribute**. Duplicate ids in one file are an error, as is
setting `routable:` inside the block. See
[Ordered Blocks](/build-guide/ordered-blocks) for step types.

Steps inside ordered blocks use the same YAML schema as top-level flow steps.
Unknown step properties are rejected at skill load and during
`rasa data validate` — misspelled or obsolete keys fail with a clear error
instead of being silently ignored.

Two removed collect-step keys have dedicated migration messages:

| Removed key               | Use instead                                                                                                                                                           |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `force_collection`        | `ask_before_filling: true`                                                                                                                                            |
| `tool:` on a collect step | Record values via the `set_fields` framework tool, optionally with a `run_after_setting_<field>` post-write hook in `tools.py`, or add a separate `execute_tool` step |

Any other unrecognized step property produces a generic validation error naming
the unknown key.

## A skill needs prose or a block

A `skill.md` with neither prose instructions nor an ordered block fails with
`skill.markdown.missing_instructions`.

The combination determines routability:

| Body           | Result                                                        |
| -------------- | ------------------------------------------------------------- |
| Prose only     | One routable prose flow                                       |
| Prose + blocks | Prose is routable; blocks are internal, entered via `@block.` |
| Blocks only    | Blocks are routable; a block named `main` is the entry point  |

## Companion files

| File                       | Purpose                                               |
| -------------------------- | ----------------------------------------------------- |
| `memory.yml`               | [Memory schema](/reference/memory-yml) for this skill |
| `responses.yml`            | [Response templates](/reference/responses-yml)        |
| `tools.py` or `tools/*.py` | [Tools](/reference/tools), auto-discovered            |
| `references/*.md`          | Knowledge indexed for `search_knowledge`              |

Each of the first three is scoped to the skill. `memory.yml` declares entries
under this skill's namespace, `tools.py` is attached to this skill, and
`responses.yml` merges into the shared registry under the names it declares.

### `references/` is project-wide

`skills/<id>/references/**/*.md` is indexed into the **same** index as the
agent-root `references/` folder, and `search_knowledge` queries that whole index
on every call whatever skill is active. The folder location decides where the
files sit in your project, and the index a search reads is the same either way.

Two consequences worth designing around:

* Whether `search_knowledge` is offered at all depends on the project having an
  index, not on the active skill having a `references/` folder.
* Each retrieved snippet reaches the model with its `source` file path and a
  `scope` of either `global` or the owning skill id. The model can tell where a
  chunk came from, so write each document to stand on its own rather than
  relying on the skill it sits under to supply the context.

See [References](/concepts/references) for the retrieval flow and the embedding
model.

## See also

* [Conditions](/reference/conditions): the expression grammar
* [Ordered Blocks](/build-guide/ordered-blocks): step types and branching
* [References](/concepts/references): how knowledge is indexed and searched
