> ## Documentation Index > Fetch the complete documentation index at: https://openrouter.ai/docs/llms.txt > Use this file to discover all available pages before exploring further. # Bash > Give any model a sandboxed shell to run commands server-side export const API_KEY_REF = ''; Beta **Beta** Server tools are currently in beta. The API and behavior may change. Sandboxed execution (`engine: "openrouter"`) is available on the global endpoint (`openrouter.ai`) only. Requests through the [in-region endpoints](/docs/guides/privacy/provider-logging#enterprise-in-region-routing) (`eu.openrouter.ai`, `us.openrouter.ai`) are rejected. The `openrouter:bash` server tool gives a model the ability to run shell commands. It mirrors Anthropic's native bash tool and is available on the **Anthropic Messages API only** (`/api/v1/messages`). When the model needs to run a command, it calls the tool; with server-side execution enabled, OpenRouter runs the command inside an isolated, sandboxed Linux container and returns the combined output and exit code. **Messages API only** `openrouter:bash` is only available on the Anthropic Messages API. Requesting it on the Chat Completions or Responses API returns a `400` error. For **sandboxed** commands on those APIs, use [Shell](/docs/guides/features/server-tools/shell), which runs server-side in the same container infrastructure and is available on the Responses API. For **client-side** execution, send a normal function tool and run the command yourself. ## How It Works 1. You include `{ "type": "openrouter:bash" }` in your `tools` array on a Messages API request. 2. Based on the user's prompt, the model decides whether it needs to run a command and emits the call with one or more shell commands. 3. With `engine: "openrouter"`, OpenRouter executes the commands sequentially in a sandboxed container. 4. The combined `stdout`, `stderr`, and `exitCode` are returned to the model. 5. The model incorporates the result into its response. It may run multiple command batches in a single request if needed. Server-side execution is opt-in: set `engine: "openrouter"` on the tool (see [Execution engine](#execution-engine)). With the default `engine` (`auto`), the tool is a local, human-in-the-loop tool instead: the call is returned to your application to run client-side, and nothing executes on OpenRouter's servers. ## Quick Start Send the tool on a Messages API request. Set `engine: "openrouter"` to run commands server-side in the OpenRouter sandbox. ## Configuration The bash tool accepts optional `parameters` to choose its execution environment: ```json lines theme={null} { "type": "openrouter:bash", "parameters": { "environment": { "type": "container_auto" } } } ``` | Parameter | Type | Default | Description | | ------------- | ------ | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `environment` | object | `container_auto` | Execution environment. Use `{ "type": "container_auto" }` for an OpenRouter-managed container, or `{ "type": "container_reference", "container_id": "..." }` to reuse an existing container. See [Containers](/docs/guides/features/containers) | | `engine` | string | `auto` | Where commands run: `openrouter` runs them server-side in the OpenRouter sandbox; `auto`/`native` (the default) return the tool call to your application to run client-side. See [Execution engine](#execution-engine) | Defaults and caps are server-enforced and may change while the tool is in beta: | Limit | Default | Maximum | | ----------------------------------------- | ------------------- | ------------------- | | `timeout_ms` per batch | 120,000 (2 minutes) | 300,000 (5 minutes) | | `max_output_length` per stream, per batch | 16,384 characters | 65,536 characters | | `commands` per call | — | 100 | When commands run in the OpenRouter sandbox, a `timeout_ms` or `max_output_length` above the maximum is clamped to it. A call with more than 100 commands is rejected. ### Network Policy When commands run in the OpenRouter sandbox (`engine: "openrouter"`), containers have **no outbound internet access by default**. The container configuration objects accept a `network_policy` field: ```json lines theme={null} { "type": "openrouter:bash", "parameters": { "engine": "openrouter", "environment": { "type": "container_auto", "network_policy": { "type": "allowlist", "allowed_domains": ["pypi.org", "files.pythonhosted.org"] } } } } ``` | Policy | Behavior | | --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | | `{ "type": "disabled" }` | No outbound internet access | | `{ "type": "allowlist", "allowed_domains": [...] }` | Outbound access restricted to hosts matching the listed hostnames or glob patterns (max 50) | | omitted | Defaults to `disabled` — no outbound internet access. For unrestricted egress, use an allowlist of `["*"]` | The policy is **fixed when a container starts**: sending a different `network_policy` to a warm container fails the request with a `409`. Do not try to change a running container's policy — send the same policy for the container's lifetime. Platform constraints for allowlisted traffic: * Only ports 80 and 443 are reachable. * DNS resolution is provided by the platform and cannot be overridden by container configuration. * Entries are lowercase hostnames or glob patterns — no schemes, paths, or ports. `*` matches any run of characters (`*.example.com`, `google.*.com`). An exact hostname does not cover its subdomains: `example.com` does not allow `api.example.com`; use `*.example.com` or list each hostname. * `pip install` needs both `pypi.org` and `files.pythonhosted.org` (or `*.pythonhosted.org`) in the allowlist. Requests to hosts outside the policy fail inside the container with a connection error (HTTP traffic sees a `520` status), which the model can read on `stderr` and react to. ### Call Arguments The model generates the call arguments. They mirror Anthropic's native bash tool action: | Field | Type | Description | | ------------------- | --------- | -------------------------------------------------------------------------------------- | | `command` | string | A single shell command to run | | `commands` | string\[] | Shell commands to run sequentially | | `restart` | boolean | Reset the shell session (see [Restart](#restart)) | | `timeout_ms` | integer | Maximum execution time for the batch | | `max_output_length` | integer | Maximum characters returned per stream (`stdout` and `stderr` are each capped to this) | ## Anthropic Messages API native bash tool On the Messages API you can also use Anthropic's native bash tool shape (`{ "type": "bash_20250124", "name": "bash" }`) instead of `openrouter:bash`. ```json lines theme={null} { "tools": [ { "type": "bash_20250124", "name": "bash" } ] } ``` The native `bash_20250124` tool runs **client-side** by default: OpenRouter returns the `tool_use` to your application to execute locally, exactly as a direct call to the provider would. To run commands server-side in OpenRouter's sandbox instead, send the OpenRouter tool shape with `engine: "openrouter"`: ```json lines theme={null} { "tools": [ { "type": "openrouter:bash", "parameters": { "engine": "openrouter" } } ] } ``` ### Restart Anthropic's bash tool supports a `restart` action that resets the shell session. When the model emits `{ "restart": true }`, OpenRouter provisions a fresh sandbox container, so commands run after a restart start from a clean state. The reset applies for the remainder of the current agentic turn. To keep a container alive across separate API requests in a conversation, send a stable `session_id` on each request; the sandbox is keyed by it. ## Execution engine The `engine` parameter controls where commands run: * `openrouter`: run commands server-side in the OpenRouter sandbox. * `auto` (default) / `native`: local, human-in-the-loop execution. The tool call is returned to your application, which runs the commands itself and sends the results back on the next request — no commands are executed on any server. The native `bash_20250124` tool always uses this behavior, since it has no `engine` field. This lets you opt into OpenRouter's sandboxed execution with `openrouter`, while the default leaves command execution entirely to your own application. `engine` selects where commands run, not which APIs accept the tool: every engine, `openrouter` included, is Messages-API-only. For sandboxed commands on the Responses API, use [Shell](/docs/guides/features/server-tools/shell). ## Response Format When the model calls the bash tool, it receives a response like: ```json lines theme={null} { "command": "ls -la", "stdout": "total 0\ndrwxr-xr-x 2 root root 40 Jun 1 12:00 .\n", "stderr": "", "exitCode": 0 } ``` A non-zero `exitCode` indicates the command itself failed; the error output is returned on `stderr` so the model can read and react to it. ## Pricing Sandbox time (commands run with `engine: "openrouter"`) is billed at **\$0.0001 per second**. The clock starts when a request first runs a sandbox command and stops when the response completes. A container that is idle between requests is not billed. A request that starts a new or sleeping container is billed a minimum of 30 seconds. Later requests that reuse the same warm container pay only their metered time. ## Security Running shell commands is powerful and is sandboxed by design: * Commands execute in an isolated container, not on OpenRouter infrastructure or your machine. With `container_auto` the container is ephemeral; with `container_reference` it persists across requests. * Containers are scoped per account, so they are never shared across tenants. * Network access is intended to be disabled by default at the container level. * Execution time is bounded by `timeout_ms`, clamped to 5 minutes. * `stdout` and `stderr` are each truncated to `max_output_length`, a per-stream cap clamped to 65,536 characters. See [Configuration](#configuration) for the defaults. ## Next Steps * [Server Tools Overview](/docs/guides/features/server-tools). Learn about server tools * [Containers](/docs/guides/features/containers). How sandbox containers work * [Web Fetch](/docs/guides/features/server-tools/web-fetch). Fetch content from URLs * [Tool Calling](/docs/guides/features/tool-calling). Learn about user-defined tool calling