Sandboxes
Where the agent's commands and files run, and the network policy of a sandbox.
Guides: Sandbox, Mistral sandbox, Local sandboxes and Network.
| Name | What it is |
|---|---|
Sandbox | The options every sandbox takes: network, secrets, hooks and the tools the model gets. |
NoSandbox | Run without a sandbox. |
BashkitSandbox | A sandbox that runs the model's shell commands in the agent's process, through the Bashkit bash interpreter, with no container and no Python. |
DangerousLocalSandbox | Runs commands directly in the process that runs the agent, with no isolation. |
LocalDockerSandbox | A sandbox in a Docker container on your machine, for development. |
MistralSandbox | A sandbox Mistral runs for each session, on Mistral Cloud. |
SandboxExecutionResult | Output of a command run in the current session sandbox. |
SandboxHook | Code that runs when the sandbox is created and when the session closes. |
pattern.sandbox_hook.GitIdentity | Set the sandbox's global git user.name and user.email when it is created. |
EgressPolicy | The IP addresses a MistralSandbox can open connections to, on top of its network. |
Network | Outbound network of a sandbox. |
HeaderBinding | Add a secret to the HTTPS requests that a sandbox sends to one host. |
GitHubBinding | Give a sandbox Git and GitHub API access as the session user. |
MistralApiBinding | Give a sandbox Mistral API access as the session user. |
WorkspaceHeaderBindings | Route a Mistral sandbox through Sandbox Proxy, and apply the rules a workspace admin stored there. |
SandboxSandbox
class Sandbox(
*,
network: Network | None = None,
header_bindings: Sequence[HeaderBinding | GitHubBinding | MistralApiBinding | WorkspaceHeaderBindings] = (),
hooks: Sequence[SandboxHook] = (),
access: Literal['none', 'files', 'full'] | None = None,
)The options every sandbox takes: network, secrets, hooks and the tools the model gets.
access sets the sandbox tools the model gets: "files" gives the file tools,
"full" adds bash, and "none" gives neither while tools, hooks and skills
still use the sandbox. None gives every level the sandbox supports. A sandbox type declares
in supported_access the widest level it serves, and its constructor refuses a wider one.
network sets the outbound connections the sandbox can open, and defaults to
Network.none(). header_bindings lists the secrets the sandbox gets on those connections. A
sandbox type declares in supported_network and supported_header_bindings what it can
enforce, and its constructor refuses the rest.
| Parameter | Type | Default | Description |
|---|---|---|---|
network | Network | None | None | The outbound connections the sandbox can open. Defaults to Network.none(). |
header_bindings | Sequence[HeaderBinding | GitHubBinding | MistralApiBinding | WorkspaceHeaderBindings] | () | The secrets the sandbox gets on those connections. |
hooks | Sequence[SandboxHook] | () | Sandbox hooks, which run when the sandbox is created and when the session closes. |
access | Literal['none', 'files', 'full'] | None | None | The sandbox tools the model gets: "full", "files" or "none". None gives every level the sandbox supports. |
| Attribute | Type | Description |
|---|---|---|
supported_network | tuple[Literal['none', 'all', 'allow'], ...] | The network modes that the sandbox type can enforce, such as ("none", "all"). |
supported_header_bindings | tuple[type[BaseModel], ...] | The header_bindings types that the sandbox type serves. |
supported_access | Literal['none', 'files', 'full'] | The widest access level that the sandbox type serves. |
delete_on_cleanup | bool | Whether the sandbox is deleted when the session closes. |
supports_background_processes | bool | Whether the model can keep commands running in the background, through the built-in process tools. |
NoSandboxNoSandbox
class NoSandbox(*, hooks: Sequence[SandboxHook] = ())Run without a sandbox.
Based on Sandbox.
| Attribute | Type | Description |
|---|---|---|
supported_network | tuple[Literal['none', 'all', 'allow'], ...] | The network modes that the sandbox type can enforce: "none". |
delete_on_cleanup | bool | Whether the sandbox is deleted when the session closes. |
BashkitSandboxBashkitSandbox
class BashkitSandbox(
*,
instance_id: str | None = None,
network: Network | None = None,
block_private_ips: bool = True,
hooks: Sequence[SandboxHook] = (),
access: Literal['none', 'files', 'full'] | None = None,
)A sandbox that runs the model's shell commands in the agent's process, through the Bashkit bash interpreter, with no container and no Python. Its network is none by default.
A command without timeout_seconds gets 300 seconds.
Private and loopback addresses stay refused even when network allows them. Set
block_private_ips=False to reach a service on your machine, for example in local tests.
instance_id names the sandbox's folders on your machine, under the system's temporary
folder, together with each session's ID. A session reopened with the same instance_id, by
this process or a new one, finds its folders again. Without instance_id, the folders are
named after the session alone.
Based on Sandbox.
| Parameter | Type | Default | Description |
|---|---|---|---|
instance_id | str | None | None | A name for the sandbox's folders, together with each session's ID. |
network | Network | None | None | Network.none(), the default, Network.all() or Network.allow(hosts=...). |
block_private_ips | bool | True | Whether private and loopback addresses stay refused whatever network allows. |
hooks | Sequence[SandboxHook] | () | Sandbox hooks, which run when the sandbox is created and when the session closes. |
access | Literal['none', 'files', 'full'] | None | None | The sandbox tools the model gets: "full", "files" or "none". None gives every level the sandbox supports. |
| Attribute | Type | Description |
|---|---|---|
supported_network | tuple[Literal['none', 'all', 'allow'], ...] | The network modes that the sandbox type can enforce: "none", "all" and "allow". |
DangerousLocalSandboxDangerousLocalSandbox
class DangerousLocalSandbox(
*,
shell: Literal['bash', 'sh'] | None = None,
default_exec_timeout_seconds: int | None = None,
workspace: str | None = None,
delete_on_cleanup: bool | None = None,
hooks: Sequence[SandboxHook] = (),
access: Literal['none', 'files', 'full'] | None = None,
)Runs commands directly in the process that runs the agent, with no isolation.
There is no container: the model's commands run on your machine as the user of that process. Use it only for local development and CI, never in production.
Commands reach every network your machine reaches, so the sandbox's network is always
Network.all().
workspace is the host folder where commands run and the agent reads and writes files.
Without it, the sandbox creates a new folder under
~/.cache/mistral-vibe-harness-local-host/. A relative workspace is resolved
against the working folder of the process that runs the agent.
delete_on_cleanup deletes the workspace when the session closes. It defaults to
True without workspace and to False with one, so the sandbox never deletes
your folder unless you ask. A workspace to delete must be absolute and must not contain
your home folder or the process's working folder; the session fails at start otherwise.
Based on Sandbox.
| Attribute | Type | Description |
|---|---|---|
supported_network | tuple[Literal['none', 'all', 'allow'], ...] | The network modes that the sandbox type can enforce: "all". |
supports_background_processes | bool | Whether the model can keep commands running in the background, through the built-in process tools. |
LocalDockerSandboxLocalDockerSandbox
class LocalDockerSandbox(
*,
image: str | None = None,
supports_background_processes: bool | None = None,
shell: Literal['bash', 'sh'] | None = None,
default_exec_timeout_seconds: int | None = None,
setup_script: str | None = None,
setup_script_timeout_seconds: int | None = None,
network: Network | None = None,
hooks: Sequence[SandboxHook] = (),
access: Literal['none', 'files', 'full'] | None = None,
)A sandbox in a Docker container on your machine, for development.
network defaults to Network.none(): the container has no network but loopback, and
neither has the setup script. Network.all() gives it Docker's default network.
default_exec_timeout_seconds (600 by default) stops a command sent without a timeout of
its own, such as a sandbox hook's ctx.sandbox.execute(...): the command and its children
get SIGTERM, then SIGKILL 5 seconds later, and it ends with exit code 124. The image needs a
setsid command (util-linux or BusyBox).
Based on Sandbox.
| Parameter | Type | Default | Description |
|---|---|---|---|
image | str | None | None | The container image to run, which must provide shell. Defaults to python:3.12-bookworm. |
supports_background_processes | bool | None | None | Whether the model can keep commands running in the background. Defaults to True when you leave out image and to False when you pass it. |
shell | Literal['bash', 'sh'] | None | None | The shell that runs the agent's commands: "bash", the default, or "sh". |
default_exec_timeout_seconds | int | None | None | The time limit of a command that does not set its own. Defaults to 600. |
setup_script | str | None | None | A shell command run once after the container starts. |
setup_script_timeout_seconds | int | None | None | The time limit of setup_script. Defaults to 300. |
network | Network | None | None | Network.none(), the default, or Network.all(). |
hooks | Sequence[SandboxHook] | () | Sandbox hooks, which run when the sandbox is created and when the session closes. |
access | Literal['none', 'files', 'full'] | None | None | The sandbox tools the model gets: "full", "files" or "none". None gives every level the sandbox supports. |
| Attribute | Type | Description |
|---|---|---|
supported_network | tuple[Literal['none', 'all', 'allow'], ...] | The network modes that the sandbox type can enforce: "none" and "all". |
MistralSandboxMistralSandbox
class MistralSandbox(
*,
image: str | None = None,
supports_background_processes: bool | None = None,
instance_type: str | None = None,
region: str | None = None,
name_prefix: str | None = None,
ttl_seconds: int | None = None,
idle_timeout_seconds: int | None = None,
default_exec_timeout_seconds: int | None = None,
privileged: bool | None = None,
docker_daemon_enabled: bool | None = None,
docker_daemon_network_mode: str | None = None,
enable_light_sleep: bool | None = None,
setup_script: str | None = None,
setup_script_timeout_seconds: int | None = None,
readiness_max_retries: int | None = None,
readiness_interval_seconds: float | None = None,
readiness_probe_timeout_seconds: int | None = None,
wait_ready_timeout_seconds: int | None = None,
enable_mesh: bool | None = None,
network: Network | None = None,
egress: EgressPolicy | None = None,
header_bindings: Sequence[HeaderBinding | GitHubBinding | MistralApiBinding | WorkspaceHeaderBindings] = (),
pre_provisioned_sandbox_id: str | None = None,
hooks: Sequence[SandboxHook] = (),
access: Literal['none', 'files', 'full'] | None = None,
)A sandbox Mistral runs for each session, on Mistral Cloud.
The API key's user needs the cloud_user role (Mistral Cloud User). Mistral Cloud filters
outbound traffic by IP address, so network takes Network.none() or
Network.all(). egress=EgressPolicy.custom(allow_cidrs=...) opens the listed addresses
on top of Network.none(). Sandbox Proxy serves header_bindings.
An option you leave out, except supports_background_processes, network, egress,
header_bindings, hooks and access, reads its default from the environment variable
AGENTS_SDK_KOYEB_SANDBOX_<OPTION>, such as AGENTS_SDK_KOYEB_SANDBOX_INSTANCE_TYPE.
Based on Sandbox.
| Parameter | Type | Default | Description |
|---|---|---|---|
image | str | None | None | The container image to run. Defaults to Mistral's public sandbox image. |
supports_background_processes | bool | None | None | Whether the model can keep commands running in the background. Defaults to True when you leave out image and to False when you pass it. |
instance_type | str | None | None | The instance size, such as "small", "medium", "large" or "2xlarge". Defaults to "medium". |
region | str | None | None | The region the sandbox runs in. Defaults to "nl-north-1", the only region that can block traffic. |
name_prefix | str | None | None | The start of the sandbox's name. Defaults to "unknown". |
ttl_seconds | int | None | None | How long after its creation Mistral Cloud deletes the sandbox, whatever happens. Defaults to 24 hours, the default session lifetime. |
idle_timeout_seconds | int | None | None | The seconds idle before the sandbox sleeps. Defaults to 0, which never sleeps. |
default_exec_timeout_seconds | int | None | None | The time limit of a command that does not set its own. Defaults to 30. |
privileged | bool | None | None | Whether the container runs privileged. Defaults to False. |
docker_daemon_enabled | bool | None | None | Whether to start a Docker daemon in the sandbox, which also makes it privileged. Defaults to False. |
docker_daemon_network_mode | str | None | None | The network mode passed to that Docker daemon. Defaults to "auto". |
enable_light_sleep | bool | None | None | Whether the sandbox uses light sleep, which wakes faster than deep sleep. Defaults to True. |
setup_script | str | None | None | A shell command run once after the sandbox starts. |
setup_script_timeout_seconds | int | None | None | The time limit of setup_script. Defaults to 300. |
readiness_max_retries | int | None | None | How many times the SDK probes the started sandbox before it gives up. Defaults to 10. |
readiness_interval_seconds | float | None | None | The seconds between two readiness probes. Defaults to 2.0. |
readiness_probe_timeout_seconds | int | None | None | The time limit of one readiness probe. Defaults to 5. |
wait_ready_timeout_seconds | int | None | None | How long the SDK waits for the sandbox to be ready. Defaults to 300. |
enable_mesh | bool | None | None | Whether the Mistral Cloud service mesh is on for the sandbox. Defaults to False. |
network | Network | None | None | Network.none(), the default, or Network.all(). |
egress | EgressPolicy | None | None | EgressPolicy.custom(allow_cidrs=...), the IP addresses to open on top of Network.none(). |
header_bindings | Sequence[HeaderBinding | GitHubBinding | MistralApiBinding | WorkspaceHeaderBindings] | () | GitHubBinding, MistralApiBinding and WorkspaceHeaderBindings, which Sandbox Proxy serves. |
pre_provisioned_sandbox_id | str | None | None | The ID of a running Mistral Cloud sandbox to use instead of creating one. |
hooks | Sequence[SandboxHook] | () | Sandbox hooks, which run when the sandbox is created and when the session closes. |
access | Literal['none', 'files', 'full'] | None | None | The sandbox tools the model gets: "full", "files" or "none". None gives every level the sandbox supports. |
| Attribute | Type | Description |
|---|---|---|
supported_network | tuple[Literal['none', 'all', 'allow'], ...] | The network modes that the sandbox type can enforce: "none" and "all". |
supported_header_bindings | tuple[type[BaseModel], ...] | The header_bindings types that the sandbox type serves. |
authored_settings | Mapping[str, Any] | The options you passed, before this process's environment fills in the rest. |
egress_policy | EgressPolicy | The IP-level policy that enforces network and egress on Mistral Cloud. |
SandboxExecutionResultSandboxExecutionResult
class SandboxExecutionResult(exit_code: int, stdout: str, stderr: str)Output of a command run in the current session sandbox.
Sandbox hooks
SandboxHookSandboxHook
class SandboxHookCode that runs when the sandbox is created and when the session closes.
on_create and on_destroy may declare session inputs with
Annotated[T, agents.Depends()] parameters, like tools and hooks.
On a deployed agent, on_create and on_destroy run in the agent loop: use ctx.sandbox
for commands and files, and agents.now() and agents.sleep() for time.
The arguments a subclass is constructed with are recorded, so a deployed agent rebuilds the
sandbox hook with the same arguments. They must be JSON values. A subclass that writes its own
to_unified_state and from_unified_state replaces this contract.
SandboxHook.to_unified_stateSandboxHook.to_unified_state
def to_unified_state() -> dict[str, JsonValue]Return the arguments the sandbox hook was constructed with, which a deployed agent rebuilds it from.
SandboxHook.from_unified_stateSandboxHook.from_unified_state
@classmethod
def from_unified_state(state: dict[str, JsonValue]) -> SelfRebuild the sandbox hook by calling its constructor with the recorded arguments.
SandboxHook.on_createSandboxHook.on_create
async def on_create(ctx: SandboxCallbackContext) -> NoneRuns once when the sandbox is ready, before the agent starts. The default does nothing.
| Parameter | Type | Default | Description |
|---|---|---|---|
ctx | SandboxCallbackContext | required | An agents.SandboxCallbackContext on the sandbox that was created. |
SandboxHook.on_destroySandboxHook.on_destroy
async def on_destroy(ctx: SandboxCallbackContext) -> NoneRuns once when the session closes. The default does nothing.
| Parameter | Type | Default | Description |
|---|---|---|---|
ctx | SandboxCallbackContext | required | An agents.SandboxCallbackContext on the session's sandbox, as the session closes. |
pattern.sandbox_hook.GitIdentitypattern.sandbox_hook.GitIdentity
class GitIdentity(*, name: str, email: str)Set the sandbox's global git user.name and user.email when it is created:
agents.pattern.sandbox_hook.GitIdentity(name="Acme Bot", email="bot@acme.com")DangerousLocalSandbox refuses it: on your machine, it would overwrite your ~/.gitconfig.
Based on SandboxHook.
Network
EgressPolicyEgressPolicy
class EgressPolicy(
*,
mode: Literal['block_all', 'allow_all', 'custom'] = 'block_all',
allow_cidrs: tuple[str, ...] = (),
)The IP addresses a MistralSandbox can open connections to, on top of its network.
Pass EgressPolicy.custom(allow_cidrs=...) as MistralSandbox(egress=...), which takes only custom().
block_all() and allow_all() describe MistralSandbox.egress_policy for Network.none() and
Network.all().
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | Literal['block_all', 'allow_all', 'custom'] | 'block_all' | "custom" opens allow_cidrs; "block_all" and "allow_all" stand for Network.none() and Network.all(). |
allow_cidrs | tuple[str, ...] | () | The IP addresses or CIDR ranges to open, such as "203.0.113.0/24". |
EgressPolicy.block_allEgressPolicy.block_all
@classmethod
def block_all() -> EgressPolicyBlock every outbound connection: the egress_policy of a MistralSandbox with Network.none().
EgressPolicy.allow_allEgressPolicy.allow_all
@classmethod
def allow_all() -> EgressPolicyAllow every outbound connection: the egress_policy of a MistralSandbox with Network.all().
EgressPolicy.customEgressPolicy.custom
@classmethod
def custom(*, allow_cidrs: Sequence[str]) -> EgressPolicyOpen the listed addresses on top of Network.none().
NetworkNetwork
class Network(*, mode: Literal['none', 'all', 'allow'] = 'none', hosts: tuple[str, ...] = ())Outbound network of a sandbox. Build it with none(), all() or allow(hosts=...).
Network.noneNetwork.none
@classmethod
def none() -> SelfNo outbound connection.
Network.allNetwork.all
@classmethod
def all() -> SelfEvery outbound connection.
Network.allowNetwork.allow
@classmethod
def allow(*, hosts: Sequence[str]) -> SelfOnly HTTPS connections to the listed host or host:port entries. Wildcards are not accepted.
Network.reachesNetwork.reaches
def reaches(host: str) -> boolWhether this network opens connections to host, a host[:port] entry.
HeaderBindingHeaderBinding
class HeaderBinding(
*,
host: str,
header: str,
secret_name: str,
path_prefix: str = '/',
prefix: str = '',
suffix: str = '',
)Add a secret to the HTTPS requests that a sandbox sends to one host.
secret_name picks a secret that Agent(secrets=...) declares. An experimental.CustomSandbox that lists
HeaderBinding in supported_header_bindings takes it, and adds prefix + value + suffix as
the header of each matching request. For a MistralSandbox, a workspace admin stores such
rules in Sandbox Proxy: pass WorkspaceHeaderBindings.
| Parameter | Type | Default | Description |
|---|---|---|---|
host | str | required | The host or host:port whose requests get the header. |
header | str | required | The name of the header, such as "Authorization". |
secret_name | str | required | The name of a secret that Agent(secrets=...) declares. |
path_prefix | str | '/' | Only requests whose path starts with it get the header. |
prefix | str | '' | The text before the secret's value, such as "Bearer ". |
suffix | str | '' | The text after the secret's value. |
| Attribute | Type | Description |
|---|---|---|
kind | Literal['header_binding'] | Always "header_binding". |
GitHubBindingGitHubBinding
class GitHubBinding(
*,
repos: tuple[str, ...] | Literal['all'],
ttl_seconds: int = 3600,
host: str = 'github.com',
)Give a sandbox Git and GitHub API access as the session user.
Sandbox Proxy gets a short-lived token for the user's GitHub access, and the sandbox's git
and gh use it without seeing it. It does more than a header binding: it also sets up git
and gh, and checks each request against repos. It takes no secret_name because the
token never comes from Agent(secrets=...). repos lists the owner/repository names the
sandbox can reach, or is "all" for every repository the user can reach. The token is renewed
before ttl_seconds elapse.
| Attribute | Type | Description |
|---|---|---|
kind | Literal['github'] | Always "github". |
MistralApiBindingMistralApiBinding
class MistralApiBinding(*, ttl_seconds: int = 3600)Give a sandbox Mistral API access as the session user.
Sandbox Proxy gives the sandbox a MISTRAL_API_KEY that only the proxy accepts, and the
proxy URL as MISTRAL_API_HTTP_PROXY. Clients that send their Mistral API requests through
that proxy, such as the agents CLI, act as the session user without seeing a real
credential. The credential is renewed before ttl_seconds elapse.
run_as names that identity. "auto", the only value, is the session's user, or, in a
local run, the user of MISTRAL_API_KEY.
| Attribute | Type | Description |
|---|---|---|
kind | Literal['mistral_api'] | Always "mistral_api". |
run_as | Literal['auto'] | "auto", the only value: the session's user, or, in a local run, the user of MISTRAL_API_KEY. |
WorkspaceHeaderBindingsWorkspaceHeaderBindings
class WorkspaceHeaderBindings()Route a Mistral sandbox through Sandbox Proxy, and apply the rules a workspace admin stored there.
Each rule adds a workspace secret to the HTTPS requests that match it. The rules and their secrets are not in the agent code, and the sandbox never sees the secrets.
| Attribute | Type | Description |
|---|---|---|
kind | Literal['workspace_header_bindings'] | Always "workspace_header_bindings". |