Quickstart

Coming soon
1. Write the agent

1. Write the agent

# hello_agent.py
import asyncio
from pydantic import BaseModel

from mistralai.agents import agents


class GetWeatherInput(BaseModel):
    city: str


@agents.tool(
    name="get_weather",
    description="Weather for a city.",
    input_schema=GetWeatherInput,
)
async def get_weather(args: GetWeatherInput) -> dict[str, str]:
    return {"weather": f"sunny in {args.city}"}


agent = agents.Agent(
    model="mistral-medium-3-5",
    name="hello-agent",
    instructions="You are a friendly agent. Tell us the weather in a city.",
    harness=agents.Harness(tools=[get_weather]),
)


async def main() -> None:
    result = await agent.run("Tell me about the weather in Paris")
    print(result.text)

asyncio.run(main())

That's the whole agent.

2. Run it in-process

2. Run it in-process

The agent executes inside your process, offering fast feedback and ability to iterate

export MISTRAL_API_KEY="<your-key>"
uv run python hello_agent.py        # -> The weather in Paris is currently **sunny**. 

This is the fastest loop while you are writing the agent: nothing to register, nothing to containerize, nothing to open. See Run modes for how this relates to the two worker modes below.

:::info No streaming here agent.run(...) returns the finished answer in one block. To read a reply as it is written, use a session. :::

3. Run a temporal worker orchestrated by Workflows API

3. Run a temporal worker orchestrated by Workflows API

agents serve loads the agent object you already wrote. It looks for agent in main.py, so rename the file from step 1, or keep its name and declare it as the project's entrypoint. Nothing about the agent changes: the tool stays in the same file, passed to the Harness.

Alongside it, a pyproject.toml carrying the agent's dependencies:

# pyproject.toml
[project]
name = "hello_agent"
version = "0.0.0"
requires-python = ">=3.12"
# The package was renamed: `mistralai-agents-sdk` (Gemfury) -> `mistralai-agents` (PyPI).
dependencies = ["mistralai-agents[bashkit,sessions-client]==1.1.0rc4"]

[tool.uv]
# A release candidate is a prerelease, so it is opt-in. Setting it here rather than passing
# --prerelease=allow keeps `uv run` from re-resolving the lockfile on every command.
prerelease = "allow"
# Only needed if you have an `exclude-newer` policy (UV_EXCLUDE_NEWER or ~/.config/uv/uv.toml).
# 1.1.0rc4 was published 2026-09-21 and pins mistralai-vibe-harness 0.1.4, so a cutoff older than
# that filters both out. Drop these two lines once your cutoff has moved past 2026-09-22.
exclude-newer-package = { mistralai-agents = false, mistralai-vibe-harness = false }

[[tool.uv.index]]
name = "pypi"
url = "https://pypi.org/simple"
default = true

serve starts a durable local worker and prints a link to chat with your agent:

export MISTRAL_API_KEY="<your-key>"    # API Key allowed to register workers on Workflows API
uv run agents serve
✓ Agent hello-agent is serving on agents-sdk-hello-agent

  Try the agent:
  • easily in Vibe's UI:      https://chat.mistral.ai/code?agent=hello-agent
  • or programmatically, using the Session API: https://docs.mistral.ai/studio/agents/core/sessions

  Debug:  https://console.mistral.ai/build/workflows?workflowSearch=hello-agent

Press Ctrl+C to stop.

Two ways to start a session and consume events:

To use the Session API. With the worker running, attach to it from another process: Agent.load_from(agent_name=) resolves the served agent by name.

# talk_to_worker.py - run this while `agents serve` is up
import asyncio

from mistralai.agents import agents
from mistralai.vibe.harness.app_server.session import (
    HistoryEntryCompletedEvent,
    HistoryEntryPatchedEvent,
    MessageHistoryEntry,
    TextContentBlock,
)


async def main() -> None:
    agent = agents.Agent.load_from(agent_name="hello-agent")
    async with await agent.create_session() as session:
        async for event in session.run_turn([TextContentBlock(text="What is 21 + 21?")]):
            if isinstance(event.payload, HistoryEntryPatchedEvent):
                print(".", end="", flush=True)          # the reply, as it is written
            elif isinstance(event.payload, HistoryEntryCompletedEvent):
                entry = event.payload.entry
                # Narrowing matters: once the agent has a tool, this stream also carries tool
                # call and tool result entries, and neither of those has a `role`.
                if isinstance(entry, MessageHistoryEntry) and entry.role == "assistant":
                    print("\n" + "".join(b.text for b in entry.content))


asyncio.run(main())

The stream is Session v1. Pass session_protocol=SessionProtocol.LEGACY_TASK_PROTOCOL to create_session if you need the legacy task protocol instead. See Session v1 is the default.

This is the difference from step 2: there you got the finished answer in one block, here you see the turn as it happens. Sessions lists the events a turn emits, and how to steer or interrupt one that is still running.

Tip

agents serve is a way to test what a deployed agent would do, or to host and operate this worker in production in your own cluster.

See Run modes for more details.

4. Deploy it as a Mistral's managed Workflow

4. Deploy it as a Mistral's managed Workflow

When you're ready to share it, deploy the same project as a durable and long-lived agent. Mistral runs the worker, so there is nothing to keep alive.

You need to provide a Dockerfile, and a pyproject.toml with the agent's dependencies. The project must be committed to a repository under the Mistral GitHub organization. And you must enable the GitHub Connector on your Mistral account in Studio.

A deploy builds your project's Dockerfile, so add one at the project root and commit it:

# Dockerfile
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim

ENV UV_LINK_MODE=copy UV_PYTHON_DOWNLOADS=never
WORKDIR /app

# Pinned: a deploy rebuilds this image, so an unpinned version changes the runtime under you.
RUN --mount=type=cache,target=/root/.cache/uv \
    uv pip install --system --prerelease=allow mistralai-agents==1.1.0rc4

COPY . /app

CMD ["agents", "serve"]

Add a .dockerignore beside it as well, so that COPY . /app does not carry your .env or .git/ into the image — Run modes has the list to start from.

Then deploy. The project is built from your git checkout, so commit and push first:

agents deploy --name hello-agent

--dockerfile points at another path. If neither that nor ./Dockerfile exists, the deploy stops before creating anything.

--name overrides the name= on your Agent and is what the deployment is keyed on - see The agent must be named for how that scopes across workspaces.

You can interact with a managed worker the same way you did with a self-hosted one:

Next steps

Next steps

Going further