Skip to content

Sandbox API

Package: elsai-agents  v0.3.0+

Sandbox execution APIs live in elsai.execution and elsai.agent. Remote backends (AgentCore, Daytona) ship in elsai-agents-tools.

Concept guides: Sandbox overview · Shared workspace · Backends


Sandbox

python
from elsai.execution import Sandbox

Shared sandbox workspace for one or more agents in a single process. The application creates and owns the Sandbox; agents attach via AgentConfig(sandbox=...).

python
async with Sandbox(
    workspace_id="graph-run-1",
    backend=backend_template,
    ttl_seconds=7200,
    seed_from="/path/to/project",
) as sandbox:
    ...

Sandbox.__init__

ParameterRequiredDefaultDescription
workspace_idYesRegistry key for this workspace in the current process. All agents on the same Sandbox instance share one backend. Not a cross-process sharing key.
backendYesBackend instance or template (LocalSandboxBackend, AgentCoreSandboxTemplate, DaytonaSandboxTemplate, …).
ttl_secondsYesWorkspace idle TTL (seconds). Required — choose explicitly (for example 7200). Idle time is measured from the last sandbox activity. Enforced when SandboxManager.cleanup_expired() runs; primary teardown is stop() or async with Sandbox. See Timeouts and TTL.
managerNoauto SandboxManager(ttl_seconds=...)Session manager instance. Override for tests or multi-sandbox applications.
seed_fromNoNoneHost project directory copied into the workspace on start().
seed_excludeNoNoneExtra glob patterns merged with DEFAULT_SANDBOX_SEED_EXCLUDES.
sync_policyNodefault_sandbox_sync_policy()Include/exclude globs for flush().
sync_destNoseed_fromHost path for artifact sync when flush() dest is omitted.

Properties

PropertyTypeDescription
is_startedboolTrue after a successful start().
owner_idstr | NoneIn-process ownership token for the current start cycle.

Sandbox.start

python
await sandbox.start()  # -> WorkspaceSeedResult | None

Create the backend, claim the workspace, and seed when seed_from is set. Idempotent.

Raises: SandboxStartError when another Sandbox instance already owns this workspace_id in-process.

Sandbox.stop

python
await sandbox.stop(sync=True)

Detach all attached agents, optionally flush() artifacts, then close the backend session.

ParameterRequiredDefaultDescription
syncNoTrueWhen True, run flush() before closing.

Sandbox.add_files

python
await sandbox.add_files(files, overwrite=True)  # -> list[str]

Write or upload files into the workspace without an agent turn (orchestrator API).

ParameterRequiredDefaultDescription
filesYesMapping of workspace-relative path → str, bytes, or host Path.
overwriteNoTrueWhen False, skip paths that already exist in the workspace.

Returns: List of workspace paths written.

Sandbox.download_files

python
await sandbox.download_files(files, overwrite=True)  # -> list[str]

Download sandbox files to host paths.

ParameterRequiredDefaultDescription
filesYesMapping of sandbox-relative path → host destination path.
overwriteNoTrueWhen False, skip when the host destination already exists.

Returns: Sandbox paths downloaded successfully.

Raises: OSError when a sandbox file cannot be read or written on the host.

Sandbox.delete_files

python
await sandbox.delete_files(paths)

Delete workspace-relative paths. Host-side API — not restricted by agent attach mode.

ParameterRequiredDescription
pathsYesList of workspace-relative file paths.

Sandbox.move_file

python
await sandbox.move_file(src, dest)

Move or rename a file within the workspace (read → write → delete).

ParameterRequiredDescription
srcYesSource workspace-relative path.
destYesDestination workspace-relative path.

Sandbox.read_file

python
await sandbox.read_file(path)  # -> str

Convenience read for applications and tests.

ParameterRequiredDescription
pathYesWorkspace-relative path.

Sandbox.flush

python
await sandbox.flush(dest=None)  # -> WorkspaceSyncResult | None

Sync sandbox artifacts to the host per sync_policy.

ParameterRequiredDefaultDescription
destNosync_dest or seed_fromHost directory for synced files. Returns None when no destination is configured.

Sandbox.attach

python
sandbox.attach(agent, mode=SandboxAttachMode.READ_WRITE)

Wire an agent to this sandbox. Normally invoked automatically from AgentConfig(sandbox=...) — callers rarely call this directly.

ParameterRequiredDefaultDescription
agentYesAgent instance to attach.
modeNoREAD_WRITESandboxAttachMode — tool access level.

Raises: SandboxAttachError when the sandbox is not started, the agent is already attached elsewhere, or attach cannot complete.

Sandbox.detach

python
sandbox.detach(agent)

Remove an agent's binding without stopping the sandbox VM. Idempotent when the agent is not attached.

See Shared workspace — Attach and detach.

Sandbox.ref

python
sandbox.ref()  # -> SandboxRef

Return a forward-compatible handle stub (v1 — not used for cross-process sharing).

Context manager

python
async with Sandbox(...) as sandbox:
    ...

Calls start() on enter and stop(sync=True) on exit.


SandboxManager

python
from elsai.execution import SandboxManager

Get-or-create sandbox sessions keyed by workspace_id, with optional TTL expiry.

python
SandboxManager(ttl_seconds=3600.0)
ParameterRequiredDefaultDescription
ttl_secondsNo3600.0Idle seconds before a session is eligible for cleanup_expired(). Set to None to disable idle expiry checks. Does not run automatically — call cleanup_expired() on a schedule in long-running apps.

Methods

MethodDescription
resolve_workspace_id(agent)Workspace key: _sandbox_workspace_idSessionManager.session_idagent_id.
resolve_session_id(agent)Legacy alias for resolve_workspace_id.
get_session(session_id)Return ManagedSandboxSession or None.
get_or_create(session_id, factory)Return or create a managed session (per-agent path).
claim_session(session_id, factory, owner_id=...)Atomically claim a workspace for a Sandbox start cycle.
mark_prepared(session_id, seed_result=...)Mark session as seeded.
close_session(session_id, sync_artifacts=True, agent=None)Destroy session and close backend.
cleanup_expired()Close all idle sessions past ttl_seconds. Returns closed session IDs. Call periodically if you rely on TTL as a backstop when stop() is missed.
backend_factory_for_session(template, session_id)Build a factory; uses build_for_session when the template supports it.

LocalSandboxBackend

python
from elsai.execution import LocalSandboxBackend

Host-mounted workspace for local development only — no process isolation.

Not isolated

Commands run as subprocesses on the host. Use AgentCore or Daytona for production workloads.

python
LocalSandboxBackend(
    workspace_root="/tmp/sandbox-ws",
    timeout=120,
    max_output_bytes=100_000,
)
ParameterRequiredDefaultDescription
workspace_rootYesHost directory used as the workspace root.
timeoutNo120Default command timeout in seconds. Timeout → exit code 124.
max_output_bytesNo100000Max combined stdout/stderr captured; longer output is truncated.
inherit_envNoTrueWhether subprocesses inherit the parent process environment.
envNoNoneExtra environment variables (merged when inherit_env=True).

Remote backend templates and their environment variables are documented in Sandbox backends.


SandboxPlugin

python
from elsai.plugins.sandbox import SandboxPlugin

Registers sandbox workspace tools when a backend is active. When AgentConfig(sandbox=...) is set, the plugin is auto-registered on attach if not already present.

See Plugins — SandboxPlugin.

Tools

execute

ParameterTypeRequiredDescription
commandstrYesShell command to run in the workspace.
cwdstrNoWorking directory override inside the workspace.

Omitted when the backend does not implement SandboxBackend (no shell execution support).

read_file

ParameterTypeRequiredDefaultDescription
pathstrYesWorkspace-relative file path.
offsetintNo0Line offset for partial reads.
limitintNoNoneMaximum number of lines to read.

write_file

ParameterTypeRequiredDescription
pathstrYesWorkspace-relative file path.
contentstrYesText content to write.

list_dir

ParameterTypeRequiredDescription
pathstrYesWorkspace-relative directory path.

Custom tool helpers

python
from elsai.plugins.sandbox import (
    run_command,
    read_workspace_file,
    write_workspace_file,
    list_workspace_dir,
    format_execute_result,
)
HelperDescription
run_command(agent, command, cwd=None)Run a shell command; returns formatted exit code and output.
read_workspace_file(agent, path, offset=0, limit=None)Read a workspace file from a custom @tool.
write_workspace_file(agent, path, content)Write a workspace file from a custom @tool.
list_workspace_dir(agent, path)List a directory from a custom @tool.
format_execute_result(result)Format an ExecuteResult like the execute tool.

Mutating helpers call ensure_sandbox_mutation_allowed — raises on read-only or detached agents.

For custom timeouts on run_command, wrap with async with asyncio.timeout(seconds):.


AgentConfig sandbox fields

python
from elsai.agent import AgentConfig, SandboxMode, SandboxAttachMode, WorkspaceSyncPolicy, SandboxOutputOffloadPolicy
FieldTypeDefaultDescription
sandboxSandbox | NoneNoneShared workspace. Triggers attach at agent init. Do not combine with execution_backend, workspace_root, or sandbox_manager.
sandbox_attach_modeSandboxAttachModeREAD_WRITEAccess mode when attaching to sandbox.
sandbox_modeSandboxModeOFFSandbox execution mode. See SandboxMode.
sandbox_output_offloadSandboxOutputOffloadPolicy | NoneNoneAuto-register ContextOffloader for large sandbox tool outputs.
execution_backendAnyNoneAdvanced: per-agent backend template or instance (single-agent path).
workspace_rootstr | NoneNoneAdvanced: host directory seeded into the sandbox (per-agent path).
workspace_sync_policyWorkspaceSyncPolicydefaultsInclude/exclude globs for seed and artifact sync.
sandbox_managerSandboxManager | NoneNoneAdvanced: session manager for per-agent path. Auto-created when sandbox mode is enabled without sandbox=.

Validation errors at Agent.__init__:

Invalid combinationError
sandbox= + execution_backendDual config — use Sandbox only
sandbox= + workspace_rootUse Sandbox(seed_from=...)
sandbox= + sandbox_managerManager is owned by Sandbox
sandbox_mode=SANDBOX without backend or sandbox=Missing backend

SandboxMode

python
from elsai.agent import SandboxMode
ValueDescription
offNo sandbox backend active. Host prebuilt tools run normally.
sandboxProduction mode. Host execution tools (shell, file_read, file_write, python_repl, environment) are blocked — use sandbox plugin tools instead.
local_devSandbox tools active and host prebuilt tools remain available. Development only.

SandboxAttachMode

python
from elsai.agent import SandboxAttachMode
# also: from elsai.execution import SandboxAttachMode
ValueAgent tools
read_writeexecute, read_file, write_file, list_dir
read_onlyread_file, list_dir only

Read-only enforcement uses tool unregistration plus runtime hooks. Custom mutating helpers raise SandboxMutationDeniedError.


WorkspaceSyncPolicy

python
from elsai.agent import WorkspaceSyncPolicy
FieldDefaultDescription
exclude_patterns.git, node_modules, __pycache__, .venvGlob patterns skipped when seeding into the sandbox.
sync_include_patternsNoneGlobs copied back on flush. When omitted, backends use default sync behavior.

SandboxOutputOffloadPolicy

python
from elsai.agent import SandboxOutputOffloadPolicy
FieldRequiredDefaultDescription
storageYesOffload backend (InMemoryStorage, FileStorage, S3Storage, …).
max_result_tokensNo2500Offload results above this token count.
preview_tokensNo1000Preview tokens kept in active context.
include_retrieval_toolNoTrueRegister retrieve_offloaded_content.
tool_namesNoexecute, read_file, write_file, list_dirTools whose outputs are eligible.

Workspace helpers

python
from elsai.execution import (
    prepare_workspace,
    sync_workspace_artifacts,
    close_sandbox_workspace,
    sync_workspace_for_sandbox,
    sandbox_is_active,
    workspace_is_prepared,
    WorkspaceOrchestrator,
)
SymbolDescription
prepare_workspace(agent)Create backend and seed if needed. Usually automatic via WorkspaceOrchestrator on first invocation.
sync_workspace_artifacts(agent)Sync artifacts from sandbox to host per agent workspace_sync_policy.
close_sandbox_workspace(agent, sync_artifacts=True)Optional sync, then close per-agent sandbox session.
sync_workspace_for_sandbox(sandbox, dest=None)Alias for sandbox.flush(dest).
sandbox_is_active(agent)True when sandbox_mode != off and backend is configured.
workspace_is_prepared(agent)True after prepare completed for this agent.
WorkspaceOrchestratorHook provider — calls prepare_workspace before each agent invocation.

Workspace ID helpers

python
from elsai.execution import workspace_id_for_run, workspace_id_for_context
FunctionReturnsUse case
workspace_id_for_run(run_id)graph-{run_id}Graph or workflow runs
workspace_id_for_context(context_id, shared=False)context_id or {context_id}:shared-wsA2A isolated vs team workspace

Default constants

python
from elsai.execution import (
    DEFAULT_SANDBOX_SEED_EXCLUDES,
    DEFAULT_SANDBOX_SYNC_INCLUDE,
    default_sandbox_sync_policy,
    HOST_EXECUTION_TOOL_NAMES,
    SANDBOX_OFFLOAD_TOOL_NAMES,
)

DEFAULT_SANDBOX_SEED_EXCLUDES

.git, node_modules, __pycache__, .venv, .env, *.pem, credentials.json, secrets/

DEFAULT_SANDBOX_SYNC_INCLUDE

src/**, tests/**, *.md, *.py, *.json, *.yaml, *.yml, dist/**, build/**

HOST_EXECUTION_TOOL_NAMES

Host tools blocked when sandbox_mode=sandbox: shell, python_repl, file_read, file_write, environment.

Other prebuilt tools (for example editor, http_request, retrieve) are not in this set.


Result types

ExecuteResult

FieldTypeDescription
outputstrCombined stdout (and primary output text).
exit_codeintProcess exit code.
truncatedboolWhether output was truncated.
stderrstrStderr text when captured separately.
successbool (property)True when exit_code == 0.

FileInfo

FieldTypeDescription
pathstrWorkspace-relative path.
is_dirboolWhether the entry is a directory.
sizeint | NoneFile size in bytes when available.

FileTransferResult

FieldTypeDescription
pathstrFile path.
contentbytes | NoneTransferred content.
errorstr | NoneError message when transfer failed.
successbool (property)True when error is None.

WorkspaceSeedResult

FieldTypeDescription
files_seededintNumber of files copied.
bytes_seededintTotal bytes copied.
skipped_pathslist[str]Paths skipped by exclude patterns.
errorslist[str]Errors encountered during seeding.
successbool (property)True when errors is empty.

WorkspaceSyncResult

FieldTypeDescription
files_syncedintNumber of files synced to host.
bytes_syncedintTotal bytes synced.
errorslist[str]Errors during sync.
successbool (property)True when errors is empty.

SandboxRef

FieldTypeDescription
workspace_idstrWorkspace identifier.
backend_typestrBackend class name.
manager_idstr | NoneOptional manager hint (forward-compatible).

ManagedSandboxSession

FieldTypeDescription
session_idstrWorkspace / session key.
backendAnyLive backend instance.
preparedboolWhether seeding completed.
seed_resultWorkspaceSeedResult | NoneSeed summary.
owner_idstr | NoneOwning Sandbox instance for this cycle.
created_atfloatMonotonic creation time.
last_used_atfloatLast activity time (for TTL).

Protocols

ExecutionBackend

Minimal backend for filesystem and workspace operations: id, create, close, read_file, write_file, list_dir, remove_file, seed_workspace, sync_artifacts, upload_files, download_files.

SandboxBackend

Extends ExecutionBackend with execute(command, timeout=None, cwd=None, **kwargs).

python
from elsai.execution import supports_execution
supports_execution(backend)  # True when execute tools should register

Exceptions

ExceptionWhen raised
SandboxStartErrorSecond Sandbox instance claims the same workspace_id in-process.
SandboxAttachErrorAttach before start(), wrong Sandbox instance, agent already attached elsewhere, or partial attach failure.
AgentSandboxDetachedErrorDetached agent calls a mutating sandbox helper.
SandboxMutationDeniedErrorRead-only attached agent attempts execute or write_file.
WorkspacePrepareErrorSeeding or sync reports errors.

Observability

Structured audit events are emitted to the logger elsai.sandbox.audit at INFO level for lifecycle and mutation events (sandbox.start, sandbox.add_files, sandbox.execute, sandbox.flush, sandbox.stop, attach, detach, …).

Shell command audit records command length and SHA-256 prefix — not full command text. Optional inferred_op labels (for example shell_delete) are best-effort.


Copyright © 2026 elsai foundry.