Skip to main content
The sandbox system isolates tool execution from your host, giving you a safe environment for file operations and code execution. You pick a backend depending on where you’re running: LocalSandbox for development, E2BSandbox for production.

Backends

BackendUse when
LocalSandboxDevelopment and testing — runs commands directly on your local system
E2BSandboxProduction — runs commands in a cloud-isolated container via e2b.dev

Configuration

Add a sandbox_config block to your agent’s YAML file.
sandbox_config:
  type: local
  work_dir: /path/to/working/directory  # optional, defaults to current directory
  persist_sandbox: true                  # optional, default true

E2B configuration options

OptionDefaultDescription
template"base"E2B template (Docker image) to use
timeout300Sandbox timeout in seconds
api_keyE2B API key. Can reference ${env.E2B_API_KEY}
persist_sandboxtrueIf false, the sandbox is destroyed after each agent.run call
envsEnvironment variables to set inside the sandbox
metadataCustom metadata dictionary attached to the sandbox
keepalive_interval60Seconds between keepalive pings. Set to 0 to disable
max_retries5Max retries per SDK operation on transient network errors
force_httpfalseUse HTTP instead of HTTPS — useful for self-hosted E2B

Bash output truncation

When a bash command produces large output, the sandbox automatically truncates it to avoid filling your LLM’s context window. The full output is always preserved in a temp file so your agent can read it if needed.

How it works

  1. Every execute_bash call writes stdout and stderr to /tmp/nexau_bash_tool_results/{uuid}/.
  2. After execution, if the combined output exceeds output_char_threshold characters, each stream is independently truncated — keeping the first N and last M characters.
  3. The truncated output includes a hint pointing to the full file.
[first 5,000 chars of stdout]

... [15,000 characters omitted] ...
(Full output: /tmp/nexau_bash_tool_results/a1b2c3d4/stdout.txt)

[last 5,000 chars of stdout]

Configuring thresholds

sandbox_config:
  type: local  # or e2b
  output_char_threshold: 10000  # total chars before truncation kicks in (default: 10,000)
  truncate_head_chars: 5000     # chars to keep from the start (default: 5,000)
  truncate_tail_chars: 5000     # chars to keep from the end (default: 5,000)
Add execute_bash to the bypass_tool_names list in LongToolOutputMiddleware to avoid double-truncating its output. See Middleware for details.

Accessing the sandbox in tools

Tools can access the active sandbox through agent_state.get_sandbox():
from nexau.archs.sandbox import BaseSandbox, SandboxStatus
from nexau.archs.main_sub.agent_state import AgentState

def file_analyzer(file_path: str, agent_state: AgentState) -> dict:
    sandbox: BaseSandbox | None = agent_state.get_sandbox()

    if not sandbox.file_exists(file_path):
        return {"error": f"File not found: {file_path}"}

    result = sandbox.read_file(file_path)
    if result.status != SandboxStatus.SUCCESS:
        return {"error": result.error}

    info = sandbox.get_file_info(file_path)
    return {
        "path": file_path,
        "size": info.size,
        "lines": len(result.content.split("\n")) if result.content else 0,
    }
For code execution:
from nexau.archs.sandbox import BaseSandbox, CodeLanguage
from nexau.archs.main_sub.agent_state import AgentState

def run_analysis(data: dict, agent_state: AgentState) -> dict:
    sandbox: BaseSandbox | None = agent_state.get_sandbox()

    code = f"""
import json
data = {data}
print(json.dumps({{'count': len(data), 'keys': list(data.keys())}}))
"""
    result = sandbox.execute_code(
        code=code,
        language=CodeLanguage.PYTHON,
        timeout=30000,  # milliseconds
    )

    if result.status == SandboxStatus.SUCCESS:
        import json
        output = result.outputs[0]["text"] if result.outputs else "{}"
        return json.loads(output)
    return {"error": result.error_value}

State persistence

Sandbox state is automatically persisted to the session so it survives agent restarts. When agent.run completes, the sandbox manager saves its state. On the next start() call with the same session, it reconnects to the existing sandbox instance rather than creating a new one. Pass session_manager=None to disable persistence and always create a fresh sandbox.
For E2B sandboxes, you can also reconnect to an existing sandbox directly by setting sandbox_id in your config. The manager will call Sandbox.connect(sandbox_id=...) instead of creating a new container.