Skills

Coming soon

A skill is a block of instructions the agent loads on demand. Only the skill's name and description sit in the system prompt. The agent reads the body with the built-in skill tool when it decides the skill applies. Use a skill for a procedure that is too long to keep in instructions= and is needed in only some turns.

Warning

This feature is very early in development. Expect API changes

Add a skill

Add a skill

The skills= slot on the Harness takes LocalSkillBundle and RegistrySkill objects. A bundle is a SKILL.md plus the files beside it.

From a directory

Write each skill as its own directory under a skills/ directory in your project. This is the layout every coding agent uses for skills, so an author who has written one before can read yours:

hello_agent/
├── main.py
└── skills/
    └── refund-policy/
        └── SKILL.md

LocalSkillBundle.from_directory() reads one such directory into a bundle:

from pathlib import Path

from mistralai.agents import agents

SKILLS = Path(__file__).with_name("skills")

harness = agents.Harness(
    skills=[
        agents.LocalSkillBundle.from_directory(SKILLS / "refund-policy"),
    ]
)
Warning

skills/ folder and skill directory named after the skill is just a convention for now (from_directory() takes any path you want), but it could become the discoverability standard. Try adopting this convention to save later migration work.

Resolve the path against __file__ rather than the working directory: agents serve and agents deploy import your module from a root you do not choose.

SKILL.md is YAML frontmatter and then the body:

---
name: refund-policy
description: The refund rules. Use when a customer asks for a refund.
---

Refund a customer only when the order is under 30 days old.
...

name must be lowercase letters, numbers and hyphens. description is what the model sees in the system prompt, so write it as what this is, and when to use it. The body must not be empty.

Write each frontmatter field on one line. The harness reads the frontmatter line by line, so a multi-line YAML value such as description: > is not supported.

From code

Warning

This feature may not be supported in the future. Representing skills in memory has some drawbacks, so it's likely that the file-based approach will be the only one.

When the body has no directory to live in — an in-process run, a test, a body you generate — build the bundle yourself:

import base64

from mistralai.agents import agents

SKILL_MD = b"""---
name: refund-policy
description: The refund rules. Use when a customer asks for a refund.
---

Refund a customer only when the order is under 30 days old.
"""

harness = agents.Harness(
    skills=[
        agents.LocalSkillBundle(
            files=[
                agents.LocalSkillFile(
                    path="SKILL.md",
                    content_base64=base64.b64encode(SKILL_MD).decode("ascii"),
                )
            ]
        )
    ]
)

from_directory() produces exactly this, so the two are the same feature. Prefer a directory when the skill can have one: the SKILL.md you edit is the file that ships, and it stays a document rather than a byte string in your source.

Skill files in the sandbox

Skill files in the sandbox

With sandbox=agents.BashkitSandbox(), agents.LocalDockerSandbox() or agents.DangerousLocalSandbox(), each skill is a folder in the sandbox. The folder holds SKILL.md and every file beside it, at /skills/<name>-<digest>/:

/skills/
└── refund-policy-3f2a9c41d07e/
    ├── SKILL.md
    ├── reference/
    │   └── rules.md
    └── scripts/
        └── check.sh

The model loads SKILL.md with the skill tool. It reads reference/ with read_file and runs scripts/ with bash, as for any other file. A script keeps its executable bit.

/skills is outside the workdir, so a skill never lands in files the agent commits. On Bashkit, the model cannot change a skill. The digest in the folder name changes when any file of the skill changes.

Two sandboxes put the folders elsewhere, and the system prompt gives the model the real path:

  • LocalDockerSandbox(): read_file and grep reach only the workdir and /tmp, so the folders are under /tmp.
  • DangerousLocalSandbox(): commands run on your machine, so the folders are under /tmp. A machine without /tmp, such as Windows, uses its temporary directory, and only bash reaches the files there.
from pathlib import Path

from mistralai.agents import agents

SKILLS = Path(__file__).with_name("skills")

harness = agents.Harness(
    sandbox=agents.BashkitSandbox(),
    skills=[agents.LocalSkillBundle.from_directory(SKILLS / "refund-policy")],
)

Without a sandbox

The default NoSandbox() has no place for skill files:

  • A skill with only SKILL.md still loads, from an in-process store, with a DeprecationWarning.
  • A skill with any other file fails while the harness compiles, before any model call.

Use BashkitSandbox() for skills.

Skills from the AI Registry

Skills from the AI Registry

A registry skill is a skill stored in the Mistral AI Registry and named by its UUID. Pass it in the skills= list, next to your local ones:

harness = agents.Harness(
    sandbox=agents.BashkitSandbox(),
    skills=[
        agents.LocalSkillBundle.from_directory(SKILLS / "refund-policy"),
        agents.RegistrySkill(id="0199c5e1-8a3b-7d42-9f10-3c5e7a2b1d84", version=3),
    ],
)

The SDK gets each registry skill with your MISTRAL_API_KEY when the session starts. It writes the skill to /skills like a local one, with its assets. The model cannot tell the two apart. If the registry does not answer within 30 seconds, the session does not start.

version= is required. Every session serves the exact version you name, so two sessions never run different versions of one skill.

A registry skill needs a sandbox that can hold its files: BashkitSandbox(), LocalDockerSandbox() or DangerousLocalSandbox(). With any other sandbox, the harness refuses it while it compiles.

Slots this backend does not serve

Slots this backend does not serve

Harness carries further skill slots that this backend refuses while the harness compiles, before any model call:

SlotWhat happens
skills=[agents.SkillDefinition(...)]Unsupported Agents SDK feature 'skills': inline SkillDefinitions are not supported on this backend; pass local_skills= instead
registry_skills= without a sandbox that can hold filesUnsupported Agents SDK feature 'registry_skills': registry skills are served as sandbox files; use sandbox=BashkitSandbox()
local_skills= with files beside SKILL.md, and no sandboxUnsupported Agents SDK feature 'local_skills': a skill with files other than SKILL.md needs a sandbox to hold them; use sandbox=BashkitSandbox()
registry_skills= in agents serve or agents deployUnsupported Agents SDK feature 'registry_skills': registry skills run in-process with BashkitSandbox only; pass local_skills= instead
Run modes

Run modes

See Run modes

How a skill reaches the image in agents deploy mode ?

agents deploy builds your project's Dockerfile from the revision you pushed, with the project directory as the build context. A skills/ directory in your project is in that context already, so the COPY . /app in the run modes Dockerfile carries it into the image — it needs no COPY of its own.

If you exclude it in .dockerignore, or leave the file untracked, and from_directory() raises while the worker imports your module: the rollout fails.

:::note skills in AI registry agents deploy also uploads each LocalSkillBundle in skills= to the Mistral AI Registry, so it appears in the agent's catalog on the control plane. That copy carries the SKILL.md body only, and the deployed worker does not read it: the worker serves the bundles its own harness builds, from the code that ships in its image. The Registry copy is a catalog entry, not the source of truth.

For the same reason, registry skills a caller asks for when it starts a session are ignored by a worker built with this SDK. :::

See also

See also

  • Harness — the rest of what an agent can use.
  • Run modes — where the same harness runs.
  • Sandbox — where skill files live.