Skip to content

Enable shell execution

--enable-shell registers a shell execution tool with the model. Commands run in a persistent per-session working directory; on Linux and macOS the CLI wraps the subprocess in the OS-level sandbox by default (--sandbox auto).

Terminal window
mistralrs serve --enable-shell -m <model>

--agent also enables shell alongside search and Python code execution:

Terminal window
mistralrs serve --agent -m <model>

Server startup makes the executor available. OpenAI-compatible clients opt into shell per request with the Responses API shell tool. Chat Completions does not have an OpenAI shell hosted-tool type, so use Responses for OpenAI-compatible shell calls.

{
"model": "default",
"input": "Use the shell to print the current directory and list its files.",
"tools": [{"type": "shell", "environment": {"type": "container_auto"}}],
"tool_choice": "required"
}

Native SDK users enable shell on the runner or model builder, then opt in on each request. The Python SDK uses Runner(..., shell_config=ShellConfig()) plus ChatCompletionRequest.enable_shell=True; the Rust SDK uses .with_shell_execution(...) on the model builder and request builder.

FlagDefaultPurpose
--enable-shelloffRegister the shell tool.
--shell-path <path>/bin/sh on Unix, cmd on WindowsShell executable.
--shell-timeout <secs>30Per-call timeout in seconds.
--shell-workdir <path>per-session temp dirWorking directory for shell commands.
--skills-dir <path>system temp dirServer-side storage for OpenAI-compatible Skills.
--agent-permission <mode>autoauto, ask, or deny; see permissions and approvals.
--sandbox <mode>autoOS-level sandbox: auto, on, off; see the sandbox reference.

Permissioning is separate from sandboxing. The permission mode decides whether a model-requested command may run at all. The sandbox decides what the command can access after it starts.

Terminal window
mistralrs serve --enable-shell -m Qwen/Qwen3-4B

Use --agent when you want search, code execution, and shell together:

Terminal window
mistralrs serve --agent -m Qwen/Qwen3-4B

Without --shell-workdir, each session gets a unique mistralrs-shell-<random> temp directory. Files written there remain available to later shell calls in the same session and are deleted when the session ends. With --shell-workdir /path, all sessions share that directory, so outputs persist and are visible across sessions.

The shell runtime surfaces only files that the model explicitly marks as outputs. The model can do this in two ways:

  • Add a top-level outputs argument to the same shell call that creates the file.
  • Call the built-in mistralrs_surface_outputs tool after a previous shell call created the file.

Entries are paths relative to the shell working directory. outputs is JSON tool metadata, not shell syntax:

{
"commands": ["python build_report.py --output report.html"],
"outputs": [{"name": "report.html", "format": "html"}]
}

Use mistralrs_surface_outputs when the model only knows the final filenames after inspecting command output:

{
"outputs": [{"name": "mistralrs_artifacts_demo.pptx", "format": "pptx"}]
}

Files named in request files are merged into shell outputs automatically. Files written but not listed in outputs, mistralrs_surface_outputs, or request files remain internal to the shell session.

When using /v1/responses, shell activity is represented as OpenAI Responses output items:

  • shell_call: command, status, and call id.
  • shell_call_output: stdout/stderr output records, exit code, timeout flag, and status.

Chat Completions streaming emits the same work as mistral.rs agentic_tool_call_progress SSE events. The agentic runtime guide covers the event stream and files contract in depth.

The CLI sandboxes by default; the SDKs do not. The CLI and TOML entry points default to --sandbox auto, which enables the OS-level sandbox on Linux and macOS. Programmatic ShellConfig in the Python and Rust SDKs ships with no sandbox by default; attach a SandboxPolicy when embedding the runtime in an app that needs isolation.

For deployments where shell commands must leave the mistralrs host entirely, use --tool-dispatch-url and expose a custom executor instead of enabling built-in shell.