Skip to main content

maf-sandbox

PyPI Python License

Experimental. Releases before 1.0 may change or remove APIs. Importing this package emits MafSandboxExperimentalWarning.

Run agent tools through a shared sandbox protocol. The host chooses the isolation and cleanup policy. A backend creates the sandbox; a workload package, called a kind, uses it.

The protocol uses only the Python standard library. Microsoft Agent Framework integration lives in maf_sandbox.maf; the distribution includes the framework dependency. This is an independent package, not a Microsoft product.

Install and wire a backend

pip install maf-sandbox

Install a backend for the environment where code will run. The router defaults to microVM isolation and disposal after each sandboxed tool call.

from maf_sandbox import Capability, SandboxKey, SandboxRouter, SandboxSpec

router = SandboxRouter([backend])
key = SandboxKey(scope="tenant-1", thread_id="thread-1", agent_id="analyst")
spec = SandboxSpec(
    kind="python",
    image="python-3.13",
    work_dir=None,
    requires=frozenset({Capability.EXEC}),
)

router.ensure_can_serve(spec)
try:
    sandbox = await router.acquire(key, spec)
    result = await sandbox.exec(["python3", "-c", "print(6 * 7)"], working_directory=".", timeout=30)
    print(result.stdout_text)
finally:
    await router.dispose(key)

backend is supplied by the host. The image name above selects ACAS's prebuilt Python image; use an image supported by your backend. Docker and WSLC require explicit min_isolation=Isolation.CONTAINER on the router.

Direct acquire does not wrap a tool call or schedule its cleanup. The finally above owns disposal. Packaged kinds use sandboxed_tool, which handles call admission, labels and cleanup.

For complete application wiring, start with the ACAS Bicep sample or Docker CodeAct sample.

Main types

Type Purpose
SandboxKey Names the host scope, conversation, agent and optional tool call.
SandboxSpec States a kind's image, commands, file limits, network policy and other requirements.
SandboxBackend Acquires sandboxes and disposes them by key or conversation.
BackendDeclarations States the backend's capabilities and limits.
Sandbox Runs commands or code and provides the declared file operations.
SandboxRouter Matches requirements to a backend and enforces host policy.
CallerContext Reads the caller's scope, conversation and allowed file listing at call time.

The host supplies key values. They must not become model arguments. CallerContext uses callables so one tool can serve different requests without capturing the wrong conversation.

Kinds use the protocol and never import backends. See the architecture guide for package responsibilities.

Policy checks

ensure_can_serve(spec) checks configuration before a tool is attached. acquire repeats the same policy checks before reaching the backend.

Check Rule
Isolation Meet the stronger of the host and kind minimums.
Capabilities Supply every required operation, including requirements derived from other settings.
Network Enforce the exact requested mode and allowed destinations.
Guest platform Match requires_os_family when the kind names one.
Transfers Accept the requested per-file bytes, total bytes and file count.
Lifetime Meet the host and kind isolation-scope requirements.
Attached authority Respect explicit opt-in, sharing, destination and retention bounds.

The isolation order is none < runtime < os_process < container < hardened_container < microvm < vm. These are backend declarations. Core does not create or independently verify the underlying boundary.

Network access defaults to Egress.CLOSED. An allowlist requires Egress.ALLOWLIST and egress_allow. Method rules such as EgressRule("api.example.com", ("GET",)) additionally require EGRESS_METHODS. No shipped backend declares that capability. GET requests can still carry data.

The default transfer limits in each direction are 8 MiB per file, 32 MiB total and 64 files. They bound accepted transfers; they do not promise an SDK memory ceiling.

By default, Selection.FIXED uses selected= or the first registered backend. Selection.PER_SPEC uses the first backend whose declarations meet the spec. Registration order sets preference. A runtime failure does not trigger fallback to another backend.

See policy and capabilities for the complete rules.

Attached authority

BackendDeclarations.attached_identity describes authority supplied through the core contract. A workload must request ATTACHED_IDENTITY, bound its sharing and lifetime, and name authorized destinations. The host separately sets max_identity_scope; its default permits none.

No real backend advertises this core contract. ACAS sandbox-group identity is separate, deployment-owned configuration. Core does not discover or bound those Azure assignments. See host identity.

Files in and out

work_dir=None lets the backend choose the guest storage base. An explicit path requests that exact base. The spec's default is /maf-sandbox/work. Acquisition prepares the base for workloads using commands or files; it does not grant the guest extra permissions.

Use working_directory="." for the base and relative child paths beneath it. Commands and their arguments are passed through unchanged. SandboxToolSession.guest_call_path() supplies a relative call directory; do not prepend a guessed guest path.

File operations check paths against their working directory. The strength of that check depends on the backend. In particular, ACAS and WSLC document concurrent path changes that can escape a checked directory.

For outputs, declare literal filenames and provide a host-owned destination:

from pathlib import Path

from maf_sandbox import Capability, DeclaredOutput, SandboxSpec, collect_outputs, make_file_system_sink

spec = SandboxSpec(
    kind="diagram",
    requires=frozenset({Capability.EXEC, Capability.FILES_IN, Capability.FILES_OUT}),
    declared_outputs=(DeclaredOutput("diagram.png", media_type="image/png"),),
)
sink = make_file_system_sink(Path("out"))

# After the workload has written its declared output:
landed = await collect_outputs(sandbox, spec, sink=sink)

Collection validates names, checks every declared file and reads all files destined for the sink before delivering any. Transfer failure therefore prevents delivery. A sink failure can still leave earlier artifacts delivered; delivery has no transaction or rollback.

OutputDisposition.CONSUME reserves an output for the kind to parse instead of landing it. It still counts against transfer limits. Call-time declarations require outputs_named_at_call_time=True on the spec.

Sink Behavior
make_file_system_sink(root) Writes beneath the root and refuses existing files by default. existing="replace" permits replacement.
make_file_store_sink(store, provenance=...) Writes UTF-8 text beneath a call-ID folder, refuses replacement and records untrusted origin before writing.
Custom OutputSink Owns destination checks, storage policy and the model-facing display reference.

The filesystem sink checks resolved paths but does not hold them against concurrent host-side replacement. Protect its destination from other writers. A store used for sandbox outputs should be readable by the agent and separate from its writable input store.

For binary content use ExecResult.stdout_bytes and stderr_bytes. Text views, including stdout and stderr, use UTF-8 replacement decoding. Keep byte fields out of JSON serialization unless you encode them explicitly. See execution output.

Labels and model-visible results

Source tools declare what they produce. Returned content items carry integrity and confidentiality labels. The host's information-flow middleware decides what the model can read and which later tools may receive it.

Source tools declare result labels. Returned content items have their own effective integrity and confidentiality. The framework shows content or a hidden reference to the model. Before a later destination tool runs, policy checks the conversation and argument labels against that tool's accepted integrity and confidentiality.

With automatic hiding enabled, untrusted content is hidden while the conversation remains trusted. Hidden content still affects confidentiality. Passing its reference to another tool remains subject to that destination's policy.

sandboxed_tool accepts a string or unlabelled Content items. A kind can commit fixed standing_guidance and return it last on every normal path. Core verifies that text and stamps it trusted/public, while the framework preserves stricter call confidentiality. Counts, exit statuses and advice chosen from guest output do not qualify as fixed guidance.

For these mixed results, the framework-facing source declaration is trusted. The kind's output claim remains in maf_sandbox_derived_integrity, and core labels each derived item separately. Every shipped kind claims untrusted output.

FileStoreProvenance records the integrity of stored text. Session reads can weaken a call's derived result; trusted reads never promote an untrusted kind. requires_file_integrity can refuse weak or unknown inputs before execution. The host must wire the shared provenance record into both writes and reads.

See information flow for label rules and the decided result contract. Its status table identifies the contract work that is not yet implemented.

Calling host tools from guest code

HostToolRegistry exposes only functions the host registers. Registered functions run in the host process with its privileges. These nested calls bypass ordinary agent tool middleware, so the registry must enforce their policy.

Use @sandbox_tool(source=..., sink=..., identity=...) to declare each function's role. Set require_declared=True to refuse undeclared functions. The registry reads declarations at registration and seals when their combined policy is read.

Application authority is allowed by default. User authority requires explicit allowed_identities, a host mint_user_identity callback and approval of the enclosing tool. Identity labels describe authority; they do not reduce the function's permissions.

Call-count and response-size limits apply per run. The router can forbid the entire channel with denied_capabilities={Capability.HOST_TOOLS}. Docker and ACAS support the exec-based transport; WSLC and Hyperlight do not.

See host-tool controls and CodeAct for wiring.

Call cleanup and concurrency

sandboxed_tool disposes sandboxes after each call by default. Hosts can explicitly choose Cleanup.RESET for snapshot restore, or Cleanup.RECLAIM for removal of call files on a supporting backend. Reclaim can leave other files and processes behind. A confinement declaration alone does not permit reuse.

Ordinary calls can overlap through one router. Whole-sandbox cleanup stops new admission and waits for active siblings. Kinds requesting exclusive admission run one call at a time, including cleanup.

This coordination belongs to one router. It does not separate siblings' data or coordinate unrelated processes. Use IsolationScope.CALL when calls must never share a sandbox; it always requires disposal.

Failed call cleanup normally refuses the key until removal succeeds. dispose_unclean retries recorded targets. FailedReclaimPolicy.KEEP is an explicit host choice to accept reuse after failure.

At conversation deletion, stop new work across replicas and call router.dispose_scope(scope, thread_id). Check the returned ScopePurge.undisposed; a count alone does not establish completion. router.scope(...) provides this cleanup as an async context manager.

dispose_kind(key, kind, timeout=...) narrows cleanup to one kind. Adding instance_id= targets one physical instance and protects replacements. Direct admission users must await release_call(...), which may perform queued cleanup.

See call cleanup and host disposal for timeouts, retries and ownership.

Observability and extension points

Register a SandboxObserver on the router and host-tool registry. Kinds also pass it to output collection. Events describe acquisitions, calls, transfers, processes, network decisions and cleanup. Use maf-sandbox-otel for OpenTelemetry export.

Callbacks run synchronously and may arrive on different threads. Keep them short and send records to a thread-safe queue. Ordinary observer failures are logged without changing the tool result. Event delivery is not a durable audit guarantee.

effective_state_middleware() can persist the served configuration in AgentSession.state. It records configuration rather than payloads. See observability.

For new implementations, use writing a kind or writing a backend. Backend declarations belong in BackendDeclarations, not standalone capability attributes.

Run the shared conformance suites against real backends. A kind claiming call-directory confinement must run assert_nothing_left_behind with an engine-backed fingerprint subject. A skipped probe or in-process fake does not prove confinement.

BoundedExec, shell file-transfer helpers and SyncRunner are optional building blocks. Their contracts and failure handling are covered by the guest guide and backend authoring guide.

Maintained by SOKOLAI BV.

Release files for maf-sandbox 0.42.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for maf-sandbox 0.42.0
File Size Uploaded
maf_sandbox-0.42.0.tar.gz 298.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for maf-sandbox 0.42.0
File Interpreter ABI Platform
maf_sandbox-0.42.0-py3-none-any.whl Python 3 none any Details

Total release size: 614.9 kB

Release files / maf_sandbox-0.42.0.tar.gz

Download URL maf_sandbox-0.42.0.tar.gz
Size 298.6 kB
Tags Source
SHA-256 checksum
How to use checksums
b36c67dda73d83991083781bbeec0c25c7fa62b0a47365209d5b0d3540a41a9e
BLAKE2b-256 checksum
How to use checksums
8eab51d24be6228014b60ba3ad13cf3997a050b16cf1f424779f9f3e363a85fd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.

Transparency log

Release files / maf_sandbox-0.42.0-py3-none-any.whl

Download URL maf_sandbox-0.42.0-py3-none-any.whl
Size 316.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4295b549782d0aa86e2f7c86f4af601efc401adaf64ec45620ac4fda1e2f62e5
BLAKE2b-256 checksum
How to use checksums
01789cf59e849ce88ce70ea5ad2145e513e20495e00b2c01bbb711b9a67dedca
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.

Transparency log

Release history Release notifications | RSS feed

0.43.0

2 release files

This release

0.42.0 This release

2 release files

0.41.0

2 release files

0.40.1

2 release files

0.40.0

2 release files

0.39.0

2 release files

0.38.0

2 release files

0.37.0

2 release files

0.27.0

2 release files

0.25.0

2 release files

0.24.0

2 release files

0.23.1

2 release files

0.22.0

2 release files

0.21.0

2 release files

0.20.0

2 release files

0.19.0

2 release files

0.18.1

2 release files

0.18.0

2 release files

0.17.0

2 release files

0.16.0

2 release files

0.15.0

2 release files

0.14.0

2 release files

0.13.0

2 release files

0.12.0

2 release files

0.11.0

2 release files

0.10.0

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page