Back to Mistral Rs

Skills

docs/src/content/docs/guides/agents/skills.mdx

0.8.138.7 KB
Original Source

import { Tabs, TabItem } from '@astrojs/starlight/components';

mistral.rs implements uploaded Skills for both the OpenAI-compatible Responses API and the Anthropic-compatible Messages API. You can upload a skill bundle to /v1/skills, reference it from a request, and let the model use the bundled instructions and files during the run.

This page documents the mistral.rs compatibility surface. For the upstream API shapes and authoring model, see OpenAI's Tools and Skills guide, Anthropic's Agent Skills overview, and Anthropic's Skills API guide.

Start a server with the Skills runtime available:

bash
mistralrs serve --agent -m <model>

--agent is the recommended way to run Skills because it turns on the full local agent runtime: web search, Python code execution, and shell execution. Skills require the shell executor, so the minimum server flag is --enable-shell; use it only when you want Skills without the other agentic tools.

For executor flags, sandboxing, and approvals, see shell execution and permissions and approvals. For request files used alongside Skills, see OpenAI-compatible file inputs.

Compatibility surface

Supported today:

  • OpenAI-compatible skill bundles uploaded to POST /v1/skills.
  • Anthropic-compatible container.skills references on POST /v1/messages.
  • Multipart upload with either one zip archive or one top-level skill directory split across multipart file fields.
  • GET /v1/skills, POST /v1/skills/{skill_id}/versions, and GET /v1/skills/{skill_id}/versions.
  • Responses tools[].type = "shell" with environment.type = "container_auto".
  • Responses skill_reference entries with "version": "latest", an omitted version, or a concrete version.
  • Messages container.skills[] entries with type = "custom", skill_id, and "version": "latest", an omitted version, or a concrete version.
  • Responses output items for shell_call and shell_call_output, so clients can inspect what ran.
  • mistral.rs agentic extensions for Skills requests: max_tool_rounds to bound agentic tool loops, and files to require specific output files and surface them as downloadable File objects.
  • Python and Rust SDK local mounts for in-process users that do not go through /v1/skills.

Not implemented today:

  • Anthropic-managed built-in Skills such as pptx, xlsx, docx, and pdf.
  • Inline zipped skill payloads that create OpenAI containers inside the request.
  • OpenAI local shell environments or local skill paths in server requests.
  • Container reference environments and container lifecycle APIs.
  • Automatic agentskills.io registry installation or .agents/skills scanning.

mistral.rs implements the OpenAI-compatible server/runtime layer. It does not act as a separate skill registry client.

Examples

Use the OpenAI Python package. The current OpenAI package may not expose a typed skills resource, so the example uses the package's low-level client.post(...) helper.

The Python and Rust SDK examples mount local skill directories in-process. That bypasses /v1/skills; server clients should use uploaded Skills and skill_reference.

<Tabs> <TabItem label="OpenAI server">
python
from pathlib import Path
from openai import OpenAI

client = OpenAI(base_url="http://localhost:1234/v1", api_key="not-used")


def upload_skill(zip_path: Path) -> dict:
    with zip_path.open("rb") as handle:
        return client.post(
            "/skills",
            cast_to=dict,
            files={"file": (zip_path.name, handle, "application/zip")},
        )


skill = upload_skill(Path("my-skill.zip"))

response = client.responses.create(
    model="default",
    input="Use the uploaded skill. Read its instructions, then complete the task.",
    tools=[
        {
            "type": "shell",
            "environment": {
                "type": "container_auto",
                "skills": [
                    {
                        "type": "skill_reference",
                        "skill_id": skill["id"],
                        "version": "latest",
                    }
                ],
            },
        }
    ],
    tool_choice="required",
    extra_body={
        "max_tool_rounds": 6,
        "files": [{"name": "report.html", "format": "html"}],
    },
)

print(response.output_text)

Full server example

To upload a new version of an existing skill, post another zip to /skills/{skill_id}/versions with the same client.post(..., files=...) pattern. Requests can reference "version": "latest" or a specific version.

</TabItem> <TabItem label="Anthropic server">
python
import json
import urllib.request

base_url = "http://localhost:1234"
skill_id = "skill_..."

payload = {
    "model": "default",
    "max_tokens": 1024,
    "agent_permission": "auto",
    "max_tool_rounds": 6,
    "container": {
        "skills": [{"type": "custom", "skill_id": skill_id, "version": "latest"}],
    },
    "tools": [{"type": "code_execution_20250825", "name": "code_execution"}],
    "messages": [
        {"role": "user", "content": "Use the uploaded skill to complete the task."}
    ],
}

request = urllib.request.Request(
    f"{base_url}/v1/messages",
    data=json.dumps(payload).encode("utf-8"),
    headers={
        "content-type": "application/json",
        "x-api-key": "not-used",
        "anthropic-version": "2023-06-01",
        "anthropic-beta": "code-execution-2025-08-25,skills-2025-10-02",
    },
    method="POST",
)
with urllib.request.urlopen(request) as response:
    print(json.loads(response.read().decode("utf-8")))

Full server example

To list uploaded custom Skills with Anthropic-shaped objects, call GET /v1/skills?source=custom with anthropic-version: 2023-06-01 and anthropic-beta: skills-2025-10-02.

</TabItem> <TabItem label="Python SDK">
python
from mistralrs import ChatCompletionRequest, Runner, ShellConfig, ShellSkillMount, Which

runner = Runner(
    which=Which.Plain(model_id="Qwen/Qwen3-4B"),
    shell_config=ShellConfig(),
)

resp = runner.send_chat_completion_request(
    ChatCompletionRequest(
        model="default",
        messages=[{"role": "user", "content": "Use my-skill to complete the task."}],
        shell_skills=[
            ShellSkillMount(
                name="my-skill",
                description="Local task-specific skill.",
                source_path="skills/my-skill",
            )
        ],
        max_tool_rounds=6,
    )
)
print(resp.choices[0].message.content)

Full example

</TabItem> <TabItem label="Rust SDK">
rust
use mistralrs::{ModelBuilder, RequestBuilder, ShellConfig, TextMessageRole, TextMessages};

let model = ModelBuilder::new("Qwen/Qwen3-4B")
    .with_shell_execution(ShellConfig::default())
    .build()
    .await?;

let messages = TextMessages::new()
    .add_message(TextMessageRole::User, "Use my-skill to complete the task.");
let req = RequestBuilder::from(messages)
    .with_shell_skill(
        "my-skill",
        "Local task-specific skill.",
        "skills/my-skill",
    )
    .with_max_tool_rounds(6);

let resp = model.send_chat_request(req).await?;
println!("{}", resp.choices[0].message.content.as_ref().unwrap());

Full example

</TabItem> </Tabs>

Storage and lifecycle

Uploaded skills are stored under --skills-dir, which defaults to the system temp directory. Each upload receives a skill_... id and version metadata. The server stores the uploaded version once, then copies only the skills referenced by a request into that request's shell session working directory.

The shell working directory is still controlled by --shell-workdir; without it, each session uses a per-session temp directory. Session state, tool records, and generated files follow the same lifecycle described in persist sessions.

See also