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).
mistralrs serve --enable-shell -m <model>--agent also enables shell alongside search and Python code execution:
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.
Configuration
Section titled “Configuration”| Flag | Default | Purpose |
|---|---|---|
--enable-shell | off | Register the shell tool. |
--shell-path <path> | /bin/sh on Unix, cmd on Windows | Shell executable. |
--shell-timeout <secs> | 30 | Per-call timeout in seconds. |
--shell-workdir <path> | per-session temp dir | Working directory for shell commands. |
--skills-dir <path> | system temp dir | Server-side storage for OpenAI-compatible Skills. |
--agent-permission <mode> | auto | auto, ask, or deny; see permissions and approvals. |
--sandbox <mode> | auto | OS-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.
Examples
Section titled “Examples”mistralrs serve --enable-shell -m Qwen/Qwen3-4BUse --agent when you want search, code execution, and shell together:
mistralrs serve --agent -m Qwen/Qwen3-4Bfrom openai import OpenAI
client = OpenAI(base_url="http://localhost:1234/v1", api_key="not-used")
response = client.responses.create( model="default", input="Use the shell to count the files in the current directory.", tools=[{"type": "shell", "environment": {"type": "container_auto"}}], max_tool_rounds=4,)
print(response.output_text)from mistralrs import ChatCompletionRequest, Runner, ShellConfig, 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 the shell to list this directory."}], enable_shell=True, max_tool_rounds=4, ))print(resp.choices[0].message.content)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 the shell to list this directory.");let req = RequestBuilder::from(messages) .with_shell_execution() .with_max_tool_rounds(4);
let resp = model.send_chat_request(req).await?;println!("{}", resp.choices[0].message.content.as_ref().unwrap());Working directory
Section titled “Working directory”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.
File outputs
Section titled “File outputs”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
outputsargument to the same shell call that creates the file. - Call the built-in
mistralrs_surface_outputstool 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.
Streaming output
Section titled “Streaming output”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.
Isolation
Section titled “Isolation”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.
See also
Section titled “See also”- OpenAI-compatible Skills: upload and reference Skills from Responses requests.
- Permissions and approvals: gate execution behind app or user approval.
- Agentic runtime for apps: streaming events, files, and media.
- Examples: Python, Rust.