• English
  • Sandbox Info & Capabilities

    The sandbox routes report aiod's environment and its current capabilities. Capabilities come from probing each subsystem, so the report tracks the live runtime rather than a fixed manifest.

    A missing subsystem degrades a capability. The request still succeeds. Results are cached; repeated polling is cheap.

    The v1 and v2 routes side by side are in Migration from 1.x.

    Read the environment

    A client's first request asks where it is, which runtimes are installed, and which planes have a backend:

    curl "$BASE_URL/v2/sandbox"

    The response contains all three. capabilities is the snapshot described in Capability snapshot and branching, with no extra request.

    curl "$BASE_URL/v1/sandbox"

    data is a text summary, and detail, version, and workspace sit at the top level.

    The response also includes home_dir, another name for workspace_dir that is repeated under detail.system. Only the v1 endpoint returns this field.

    There is no capabilities field here, so read it with a second call to GET /v1/capabilities.

    When you want identity, workspace, and capabilities from one request, switch to v2:

    Both responses contain the same environment fields:

    • workspace_dir, workspace — two names for one value: the daemon account's home, where a command that names no working directory runs
    • version — the daemon version
    • detail.systemos, os_version, arch, user, timezone, occupied_ports, and the same two workspace fields
    • detail.runtimepython and nodejs, each an array of {ver, bin, alias}
    • detail.utils — the tools found on PATH, grouped into categories such as editors, network, and search

    detail.system.sandbox_user appears only where the image bakes an unprivileged account; it reports the {name, uid, gid, home} that account actually resolved to.

    occupied_ports is read from /proc/net/tcp, so it lists listening ports on Linux and is empty on every other platform.

    The workspace is not configurable, and there is no --workspace flag. workspace_dir is the account's home.

    Capability snapshot and branching

    These docs call a family of related interfaces a plane: commands, files, terminals, code, browser, and desktop. Read the snapshot once and branch on its capability fields before calling a plane.

    curl "$BASE_URL/v1/capabilities"

    Each fact a client needs at startup is one field:

    FactField
    The working directory of a commandworkspace_dir
    The browser plane's statuscapabilities.browser.status
    The Python interpreter that runs codecapabilities.code_interpreter.default_python
    The desktop plane's statuscapabilities.computer.status
    Why a plane is not readythat plane's missing

    The snapshot is organized in groups:

    GroupFields
    filesTwelve flags, one per file operation
    execshell, bash, pty
    binsResolved binaries: bash, sh, ps, and on Windows powershell and cmd
    code_interpreterstatus, backend, javascript_backend, jupyter_backend, kinds, default_python, default_node, python_kernels, endpoint
    browserstatus, executable, executable_source, process, cdp, cdp_endpoint
    computerstatus, provider, display, screenshot, actions, clipboard, recording, accessibility, resolution

    Three entries carry a probed status: browser (the browser plane), computer (the desktop plane), and code_interpreter (the code plane). Each has status, missing, and warnings. missing names what keeps the plane from ready; warnings explains a partial answer. status is:

    • ready — the plane responds normally
    • degraded — the dependencies are present, but the plane does not respond, as with a browser executable whose CDP port is silent
    • absent — nothing to work with; code_interpreter uses this and ready only

    On a host without a browser, the browser plane looks like this:

    "browser": {
      "cdp": false,
      "cdp_endpoint": "http://127.0.0.1:9222",
      "executable": null,
      "executable_source": null,
      "missing": [
        "browser executable",
        "cdp"
      ],
      "process": true,
      "status": "absent",
      "warnings": [
        "browser process detected but CDP is unreachable"
      ]
    }

    Read the snapshot and branch on it:

    Aio is the envelope-aware helper from Examples:

    Python
    TypeScript
    sb = Aio(BASE_URL)
    
    info = sb.get("/v2/sandbox")
    caps = info["capabilities"]
    
    print(info["workspace_dir"], info["version"])
    # /Users/USER 0.9.1
    statuses = {name: caps[name]["status"]
                for name in ("browser", "code_interpreter", "computer")}
    print(statuses)
    
    if caps["browser"]["status"] != "ready":
        print("browser unusable:", caps["browser"]["missing"])
    Python
    TypeScript
    import httpx
    
    info = httpx.get(f"{BASE_URL}/v1/sandbox").json()
    caps = httpx.get(f"{BASE_URL}/v1/capabilities").json()["data"]
    
    print(info["workspace_dir"], info["version"])
    # /Users/USER 0.9.1
    statuses = {name: caps[name]["status"]
                for name in ("browser", "code_interpreter", "computer")}
    print(statuses)
    
    if caps["browser"]["status"] != "ready":
        print("browser unusable:", caps["browser"]["missing"])

    The Python SDK reads /v1/sandbox over HTTP here; which SDK calls need that is listed in 1.x SDK compatibility.

    A plane whose backend is absent keeps its routes and answers 503, with a hint for the fix:

    {
      "data": null,
      "hint": "Ensure the browser capability is ready (GET /v1/capabilities).",
      "message": "Browser screenshot unavailable: list targets: error sending request for url (http://127.0.0.1:9222/json/list)",
      "success": false
    }

    Branch on the snapshot rather than on a 404: an absent plane still routes, so the status code alone cannot tell a missing backend from a wrong path.

    Results are cached for 5 s, and the daemon probes once at startup, so the first read has a snapshot. A stale snapshot returns immediately and a new probe runs in the background. GET /v1/capabilities?refresh=true waits for the new probe; GET /v2/sandbox never re-probes on demand, so a forced re-probe goes through /v1/capabilities. The browser probe is a single GET /json/version with a 300 ms budget.

    Installed packages

    The daemon lists the globally installed Python and Node.js packages.

    RoutePurposeNotes
    GET /v2/sandbox/packages?lang=pythonThe Python listinglang is required
    GET /v2/sandbox/packages?lang=nodejsThe Node.js listingOne route for both runtimes

    A request with no lang is a 422 naming the field: errors[0].location is ["query", "lang"]. An unrecognised value is a 400 in the envelope — unknown lang "ruby": expected python or nodejs.

    RoutePurposeNotes
    GET /v1/sandbox/packages/pythonThe Python listingOne route per runtime
    GET /v1/sandbox/packages/nodejsThe Node.js listingsandbox.get_nodejs_packages() in the SDK

    data is a text listing, not a structured one. Python comes from pip list on the interpreter the code plane resolved, one - name==version line each. Node.js comes from npm list -g --depth=0, under a header line:

    Node.js Packages:
      - agent-browser@0.34.0
      - npm@10.5.0
      - pnpm@7.33.7

    The same listing is the MCP tool sandbox_get_packages, whose language argument is python or nodejs and defaults to python. See MCP.