• English
  • Quick Start

    aiod runs as a daemon and serves the sandbox tools API over HTTP.

    The design keeps dependencies minimal:

    • static musl builds
    • one binary for containers, VMs, bare metal, and Windows
    • graceful degradation when a capability is missing

    Examples use {base_url} for the daemon address: http://127.0.0.1:18091 by default, or the gateway port on a prebuilt image. WebSocket URLs use the same host and port with ws:// or wss://.

    TIP

    Coming from a 1.x AIO image? See Migration from 1.x.

    Start the daemon

    Linux: install with the script, then start.

    curl -fsSL https://aio-static.tos-cn-beijing.volces.com/install.sh | sh
    aiod start

    Windows: download aiod.exe for your architecture from the releases page and run it. See Windows.

    aiod start binds 0.0.0.0:18091 (--host, --port, or AIO_HOST, AIO_PORT) and runs in the foreground. Keep it running with systemd, supervisord, a Windows SCM service, or as the image's CMD: see Deployment.

    First calls

    Check that the daemon is up:

    BASE_URL=http://127.0.0.1:18091
    
    curl "$BASE_URL/health"

    Ask what the environment can do: identity, directories, ports, and the probed capabilities.

    curl "$BASE_URL/v2/sandbox"
    curl "$BASE_URL/v1/capabilities"

    Run a command. It runs as a fresh process:

    curl -X POST "$BASE_URL/v2/commands" \
      -H "Content-Type: application/json" \
      -d '{"command": "uname -a"}'
    curl -X POST "$BASE_URL/v1/bash/exec" \
      -H "Content-Type: application/json" \
      -d '{"command": "uname -a"}'

    Add "mode": "async" to run it in the background, then re-read its output later using the returned command_id.

    Read and write a file:

    curl -X POST "$BASE_URL/v2/fs/write" \
      -H "Content-Type: application/json" \
      -d '{"path": "/tmp/hello.txt", "content": "hi from aiod"}'
    curl "$BASE_URL/v2/fs/read?path=/tmp/hello.txt"
    curl -X POST "$BASE_URL/v1/file/write" \
      -H "Content-Type: application/json" \
      -d '{"file": "/tmp/hello.txt", "content": "hi from aiod"}'
    curl -X POST "$BASE_URL/v1/file/read" \
      -H "Content-Type: application/json" \
      -d '{"file": "/tmp/hello.txt"}'

    Execute Python:

    curl -X POST "$BASE_URL/v2/code/execute" \
      -H "Content-Type: application/json" \
      -d '{"language": "python", "code": "1 + 1"}'
    curl -X POST "$BASE_URL/v1/code/execute" \
      -H "Content-Type: application/json" \
      -d '{"language": "python", "code": "1 + 1"}'

    Without a Python interpreter on the host, this answers 503 and names what it looked for (python3).

    The switch above the sidebar picks the plane the examples show; both are served by default. The routes that behave differently between them are in Migration from 1.x.

    From a prebuilt image

    Two images ship with the daemon already inside:

    • aio-daemon — Chromium, VNC, Python and Node toolchains, behind an nginx gateway
    • aio-computer — AIO plus an XFCE desktop and the computer-use worker

    On the AIO image the API is ready well under a second after docker run, where the 1.x image took about two and a half. Chromium keeps starting in the background and is usable a second and a half later:

    Chromium needs two settings on the host side: a seccomp profile that permits its sandbox (--security-opt seccomp=unconfined when nothing stricter is at hand) and a larger /dev/shm (--shm-size 4g). The run commands below set both:

    # AIO image
    docker run --rm -it --security-opt seccomp=unconfined --shm-size 4g \
      -p 127.0.0.1:8091:8091 enterprise-public-cn-beijing.cr.volces.com/vefaas-public/aio-daemon:1.0.0
    # Computer image — adds an XFCE desktop and the computer-use worker
    docker run --rm -it --security-opt seccomp=unconfined --shm-size 4g \
      -p 127.0.0.1:8091:8091 enterprise-public-cn-beijing.cr.volces.com/vefaas-public/aio-computer:1.0.0

    Inside either image, nginx listens on 8091, the only port the run command publishes. It fronts:

    • aiod on loopback port 18091
    • computer-use on 18100
    • Chromium's CDP on 9222

    None of the three is reachable directly from outside the sandbox. Through the gateway you reach:

    • the whole API
    • the docs UI at /docs
    • noVNC at /vnc
    • the CDP endpoints at /cdp/json/* and /cdp/devtools/*

    Image-only environment variables and their defaults are in Migration from 1.x.

    Dashboard

    Use the Dashboard to debug a daemon quickly in your browser.

    SDKs

    Both SDKs use the v1 routes (/v1/*). For v2, call the HTTP API directly; see the API Reference.

    The helper the v2 examples use is defined in the Conventions section of the examples index.

    Install the SDK:

    • Python: pip install agent-sandbox
    • TypeScript: npm i @agent-infra/sandbox

    Point the SDK at the daemon address. When a key is set, put it in headers; omit headers otherwise.

    Python
    TypeScript
    from aio import Aio  # the helper on the examples index
    
    sb = Aio("http://127.0.0.1:18091")
    sb.post("/v2/fs/write", path="/tmp/hello.txt", content="hi from aiod")
    print(sb.get("/v2/fs/read", path="/tmp/hello.txt")["content"])
    # hi from aiod
    
    print(sb.post("/v2/commands", command="printf hello")["stdout"])
    # hello
    Python
    TypeScript
    from agent_sandbox import Sandbox
    
    sandbox = Sandbox(
        base_url="http://127.0.0.1:18091",
        headers={"x-api-key": "<key>"},
    )

    Read and write a file, then run a command:

    Python
    TypeScript
    sandbox.file.write_file(file="/tmp/hello.txt", content="hi from the SDK")
    print(sandbox.file.read_file(file="/tmp/hello.txt").data.content)
    # hi from the SDK
    
    result = sandbox.bash.exec(command="printf hello")
    print(result.data.stdout)
    # hello

    The Python SDK also provides AsyncSandbox, the same interface as Sandbox with asyncio methods.

    SDK compatibility notes are in the migration guide under 1.x SDK compatibility.