Skip to main content

maf-sandbox-hyperlight

PyPI Python License

Experimental. This package warns on import with MafSandboxHyperlightExperimentalWarning. Releases before 1.0 may change or remove APIs without notice.

Run Python statements in Hyperlight microVMs through the maf-sandbox protocol. This backend supports RUN_CODE and SNAPSHOT, including CodeAct without file channels. It is experimental and has not yet been released.

Requirements

Windows x86-64 with Windows Hypervisor Platform, or Linux x86-64 with glibc 2.28 or newer, KVM and a delegated cgroup v2 subtree. Host CPython versions 3.12 through 3.14 are supported by the pinned wheels. The measured configurations are Windows 11 / WHP / host CPython 3.13, Ubuntu 24.04 under WSL2 / KVM / host CPython 3.12, and native Ubuntu 24.04 / KVM / host CPython 3.13, using the exact matched hyperlight-sandbox, hyperlight-sandbox-backend-wasm and hyperlight-sandbox-python-guest 0.7.0 wheels. The guest is CPython 3.14 compiled to WebAssembly. Other operating systems, architectures, hypervisors, custom guests, images and guest working directories are refused. Linux hosts exposing /dev/mshv are refused until that family is validated.

Each sandbox has a dedicated worker process. The adapter sets HYPERLIGHT_MAX_SURROGATES=0 inside that process, initializes the platform, warms the packaged guest and takes its initial snapshot during acquire. Windows retains the WHP library handle and uses a job to bound committed memory and terminate the worker tree. Linux verifies KVM VM creation and uses cgroup memory enforcement with an independent lifetime watcher. Linux forwards only the exact environment names PATH, HOME, XDG_CACHE_HOME, TMPDIR, LANG and LC_ALL; Windows matches its system/runtime environment names case-insensitively. The SDK materializes the packaged guest in its ordinary local application cache; no host directory is exposed to guest code.

One host process owns this backend within its ownership namespace. Windows uses a machine-wide named event; Linux holds /run/lock/maf-sandbox-hyperlight.lock open with an exclusive lock. New lock files are empty, readable by every host user and have no write permissions, regardless of the creating process's umask. The final path is published atomically only after those permissions are ready, without replacing an existing lock. Ordinary Python fork children release their inherited owner descriptor; ownership remains with the original host and its lifetime watchers. Route acquire, execution and purge requests to that process. A second process refuses acquire and returns an unclean disposal result. Ownership lasts until the host exits, including after aclose(); Linux watchers retain the lock until old worker trees are gone. Backend objects within the owner share the same key/kind registry. Do not unlink the lock file or use separate mount/PID/cgroup namespaces to route one logical backend across owners. Replicated containers and cross-machine routing require additional deployment work.

Linux and WSL2 setup

The host user needs read/write access to /dev/kvm. WSL2 needs hardware virtualization exposed by Windows, KVM support enabled in its Linux kernel, and nested virtualization enabled on a supported Windows host; see the WSL configuration reference. Check the device and follow the Hyperlight KVM prerequisites. Acquire attempts actual VM creation, so a device node alone does not satisfy admission.

The operator supplies a writable cgroup v2 root with the memory controller enabled for children, memory.swap.max, memory.oom.group, cgroup.kill and pidfd support. The default root is /sys/fs/cgroup/maf-sandbox-hyperlight; set HyperlightSandboxConfig(linux_cgroup_root="/sys/fs/cgroup/your-delegated-subtree") when a service manager delegates another path. Keep the application in a leaf beneath that subtree so the root has no processes. The application needs permission to create worker groups and migrate its workers at their common ancestor. The library never mounts cgroups, enables ancestor controllers or elevates privileges.

For local development, on a host whose root cgroup already offers the memory controller, an operator can prepare the subtree and launch a host as the calling user. The calling user must already have KVM device access; replace the interpreter and application arguments with their absolute paths:

sudo sh -c '
  set -eu
  root=/sys/fs/cgroup/maf-sandbox-hyperlight
  mkdir -p "$root/host"
  printf +memory > "$root/cgroup.subtree_control"
  chown "$SUDO_UID:$SUDO_GID" "$root" "$root/cgroup.procs"
  printf "%s" "$$" > "$root/host/cgroup.procs"
  exec setpriv --reuid "$SUDO_UID" --regid "$SUDO_GID" --init-groups -- "$@"
' sh /absolute/path/to/.venv/bin/python /absolute/path/to/app.py

A supervisor starts in a separate process session and inherits the ownership lock before creating the worker cgroup or process. It configures memory.max, zero swap allowance and group OOM enforcement; a trusted bootstrap joins that cgroup before executing the worker command. The supervisor holds pidfds for the host and worker and remains outside the worker's memory group. Host exit, worker exit or an explicit close triggers worker termination and cgroup.kill, including descendants that change process session. Cleanup also covers startup before the bootstrap joins the group, waits for the kernel's empty-group indication and removes only that worker's cgroup. The supervisor is trusted host infrastructure and must remain running until cleanup completes. A cleanup timeout or unexpected supervisor exit reports an unclean result; ownership remains held while the supervisor retries cleanup. Service managers should own the delegated subtree's lifetime as well. Missing delegation or enforcement controls refuses acquisition; there is no fallback to an unbounded worker.

Direct execution

Install this package when its first release is available; the dependency pins select the compatible SDK and guest automatically. Repository development uses uv sync.

import asyncio

from maf_sandbox import Capability, SandboxKey, SandboxSpec
from maf_sandbox_hyperlight import HyperlightSandboxBackend


async def main() -> None:
    backend = HyperlightSandboxBackend()
    key = SandboxKey(scope="user-1", thread_id="thread-1", agent_id="analyst")
    spec = SandboxSpec(
        kind="python",
        work_dir=None,
        requires=frozenset({Capability.RUN_CODE}),
    )
    try:
        sandbox = await backend.acquire(key, spec)
        result = await sandbox.run_code("answer = 6 * 7\nprint(answer)", timeout=5)
        print(result.stdout)  # 42
        await sandbox.reset(timeout=5)
    finally:
        await backend.aclose()


asyncio.run(main())

acquire reuses a live sandbox for the complete SandboxKey and kind. A different network policy, execution contract or resource configuration requires disposal first. reset restores the initial runtime state and rotates instance_id; disposal with an older ID cannot remove its replacement. Ordinary Python exceptions return a nonzero ExecResult and leave the runtime usable. Explicit reset is what removes accumulated Python state.

CodeAct

Install maf-sandbox-codeact alongside this backend and explicitly select CodeactRuntime(RUNTIME_INSTRUCTIONS). Its default exec variant requires capabilities this backend does not provide.

from maf_sandbox import CallerContext, Cleanup, SandboxRouter
from maf_sandbox_codeact import CodeactRuntime, make_codeact_tools
from maf_sandbox_hyperlight import RUNTIME_INSTRUCTIONS, HyperlightSandboxBackend


def tools_for(context: CallerContext):
    backend = HyperlightSandboxBackend()
    router = SandboxRouter([backend], min_cleanup=Cleanup.RESET)
    tools = make_codeact_tools(
        router,
        "analyst",
        context,
        runtime=CodeactRuntime(RUNTIME_INSTRUCTIONS),
    )
    return tools, backend

The host supplies CallerContext from trusted request state and calls backend.aclose() at shutdown. Cleanup.RESET permits warm reuse while removing state after each tool call; the router's stronger default disposal policy also works. CodeAct uses exclusive admission so the next call waits for the previous call's cleanup.

The guest has a reduced standard library: json, math and re are available; datetime, statistics, pickle and __future__ are absent. Future imports fail. Programs execute statements and must print results; a final expression is not echoed. RUNTIME_INSTRUCTIONS describes this profile for the model. There is no shell, package installation, writable host filesystem, file-transfer channel or host-tool registration.

Network policy

CLOSED is the default. For HTTP access, request egress=Egress.ALLOWLIST and supply exact hosts in egress_allow. Each host permits HTTP on port 80 and HTTPS on port 443 at all paths through the guest's http_get(url) and http_post(url, body=..., content_type=...) helpers. Raw sockets are unavailable. The pinned SDK always refuses CONNECT and TRACE. Wildcards, unrestricted egress, method-scoped rules and attached-identity rules are refused rather than weakened. Named hosts remain allowed after reset.

HTTP originates in the worker on the host's network. The host must choose destinations accordingly: allowing loopback or an internal service makes it reachable, and an allowlisted hostname is not an IP-address or DNS-rebinding filter. The worker receives only platform runtime/cache/locale variables, not application credentials or proxy configuration, and the guest does not inherit the worker environment. No platform identity is attached by the adapter.

Budgets and failure behavior

HyperlightSandboxConfig provides these limits:

Field Default Meaning
startup_timeout 30 seconds Acquisition queue and cold guest preparation
cleanup_timeout 3 seconds Additional allowance to terminate, reap and close a worker
max_code_bytes 1 MiB UTF-8 source bytes, at most 10 MiB
max_output_bytes 1 MiB Combined UTF-8 stdout/stderr, at most 16 MiB
max_worker_memory_bytes Windows: 1.5 GiB; Linux: 3 GiB Per-worker-tree Windows committed-memory or Linux cgroup-accounted memory ceiling, at most 16 GiB; Linux rounds down to a whole page and disables swap
linux_cgroup_root None Linux uses /sys/fs/cgroup/maf-sandbox-hyperlight unless an absolute delegated path is supplied; unused on Windows

The fixed guest heap and stack are 400 MiB and 200 MiB. run_code(timeout=...) and reset(timeout=...) include their queue time. SandboxQueuedTimeout means no operation was submitted and the current guest remains usable. A started operation exceeding its deadline raises TimeoutError; cancellation propagates after terminating the worker. Cleanup may add cleanup_timeout to the operation budget. Oversized native results raise HyperlightOutputLimitExceeded. Protocol errors and worker crashes raise HyperlightWorkerError. These failures retire the sandbox; a later acquire prepares a new worker and identity.

Native output is buffered before its byte limit can be checked. The worker's kernel memory ceiling bounds that allocation; the deadline bounds endless output. Linux cgroups account charged memory, not virtual-address reservations, and may terminate the group on OOM. The parent separately bounds retained worker diagnostics to 64 KiB while draining the pipe. Lowering the memory limit too far can make cold preparation fail; the measured KVM startup exceeded 1.5 GiB, so Linux has a larger default.

Disposal is idempotent and returns DisposalFailure when cleanup cannot be confirmed. Failed targets stay registered for retry. Cancellation propagates after the active worker's bounded cleanup attempt finishes, without starting another target; unreported targets remain registered for retry. dispose_scope sweeps all agents, kinds and call IDs in the owner's matching scope/conversation. aclose() raises on incomplete cleanup and only disposes targets created by that backend object.

Validation and follow-ups

The ordinary tests use deterministic workers and real subprocess pipes. Windows tests exercise job memory limits and abrupt owner death without requiring WHP. Linux kernel tests exercise cgroup OOM, process-tree termination and owner-lock retention without requiring KVM. In a repository checkout, run those Linux tests using sudo python3 scripts/check_hyperlight_linux.py --python "$PWD/.venv/bin/python"; the helper creates only a temporary test subtree and drops privileges before running pytest.

Run the real guest suite separately and serially. On Windows:

$env:MAF_HYPERLIGHT_LIVE = "1"
uv run pytest -q packages/maf-sandbox-hyperlight/tests/test_hyperlight_live.py

On Linux, sudo python3 scripts/check_hyperlight_linux.py --live --python "$PWD/.venv/bin/python" provisions a temporary test subtree and runs the real guest suite as the calling user. Alternatively, use an already delegated host as described above, set MAF_HYPERLIGHT_LIVE=1 and MAF_HYPERLIGHT_CGROUP_ROOT to the delegated root, and run the same pytest file. The HTTP-policy test needs permission to bind the available loopback port 80. The local WSL2 record ran the other nine guest scenarios unprivileged and the HTTP test with that binding permission.

The live suite validates results, errors and reuse, reset, absent host environment and writable file channels, queued/program timeouts, cancellation, output limits, HTTP enforcement, selective disposal, scope purge and CodeAct under both router selection modes. CI runs portable tests and dedicated Linux/Windows worker enforcement jobs. The Linux job also runs the real KVM guest suite as an unprivileged host with KVM access and delegated cgroups, recording its environment and exact dependency versions; unavailable KVM or a failed guest scenario fails the job. The local WSL2 guest measurement used Ubuntu 24.04, kernel 6.18.40.1-microsoft-standard-WSL2, CPython 3.12.3. Native Linux CI passed all ten guest scenarios on Ubuntu 24.04.5 LTS, kernel 6.17.0-1022-azure, x86-64 and CPython 3.13.15 with the exact 0.7.0 trio. MSHV, ARM64, ACA and AKS were not measured. MSHV, ARM64 and custom guests remain refused.

Release files for maf-sandbox-hyperlight 0.1.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-hyperlight 0.1.0
File Size Uploaded
maf_sandbox_hyperlight-0.1.0.tar.gz 22.2 kB Details

Built distribution (wheel)

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

Total release size: 50.2 kB

Release files / maf_sandbox_hyperlight-0.1.0.tar.gz

Download URL maf_sandbox_hyperlight-0.1.0.tar.gz
Size 22.2 kB
Tags Source
SHA-256 checksum
How to use checksums
59e2b697fd77193eb1ea1ba87880c1f6fb345fd5f19f19c0d717c696f0ce77d6
BLAKE2b-256 checksum
How to use checksums
47dc50feedca5c74c2412e98eebc567288148cc4fe4ad3c9191e64ad57c41c4f
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 14, 2026.

Transparency log

Release files / maf_sandbox_hyperlight-0.1.0-py3-none-any.whl

Download URL maf_sandbox_hyperlight-0.1.0-py3-none-any.whl
Size 28.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
19573043502314c1090c93bb759a7c06a49f480c1cb2835c28e0e57a40d95dff
BLAKE2b-256 checksum
How to use checksums
70b5954d32630c12428af29a935f632d2289b6b6ed268cc0a419ea82124f4e98
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 14, 2026.

Transparency log

Release history Release notifications | RSS feed

0.5.1

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

This release

0.1.0 This release

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