Agent Sandbox Registry

python-sdk

Fine-grained capabilities

docs/en/guide/fine-grained-capabilities.md

Fine-grained capabilities

Every route has one endpoint id, and one rule per endpoint decides whether it can be called and which path, command, size, and rate limits apply. There is no second gate in front of the rules. agents-cli exposes only the session routes and leaves POST /shell and POST /v1/agents closed. That is this layer.

The design note is Fine-grained capabilities. Path and command enforcement is in File and command controls. Agents request and response shapes are in Agents API. The full route table is in the Agents API reference.

One switch: the endpoint

An endpoint id (upload, files_list, agents_sessions_create) is the unit everything uses: the policy, the audit log, GET /capabilities, and the client. A group is only a name for a set of endpoint ids. Writing groups: [file_ops], group:file_ops, table.enable_group(CapabilityGroup.FILE_OPS), or ABX_SERVER_ENABLED_GROUPS=file_ops expands to the ids declared in that group, and the result is the same per-endpoint rule set.

Defaults: core is always on. agents, dev_tools, and browser are opt-in and start off. file_ops, process, terminal, system, and commands start on. health, capabilities, and capabilities_check cannot be turned off.

Rules come from five layers and are merged per endpoint:

Layer Source Can turn on Can turn off
default the built-in opt-in groups no yes (opt-in groups)
code default_table().enable_group() / disable_group() in the template's commands.py yes yes
preset preset: yes yes
policy groups, defaults, endpoints of the policy document yes yes
environment ABX_SERVER_ENABLED_GROUPS yes no

The more specific selector wins: an exact id beats a glob, a glob beats group:<name>. At equal specificity the later layer wins, and inside one layer a single enabled: false turns the endpoint off. So endpoints.code_run.enabled: false in the policy stays off even when the environment enables dev_tools.

A denial names the rule that denied it. The 404 body carries code: endpoint_disabled and rule, for example policy:endpoints.shell, policy:groups.process, preset:read-only, code:enable_group:file_ops, or default:opt-in:browser. GET /capabilities reports the same rule per endpoint. Its groups and group_summary fields are derived from the endpoint state ({"file_ops": {"enabled": 11, "total": 12}}), never stored.

ABX_SERVER_ENABLED_GROUPS is the only group environment variable. A comma list of group names, such as agents,dev_tools. An unknown name stops the process with a did-you-mean message. There is no variable to disable groups. Write groups: {process: false} or endpoints rules.

How to turn it on

Three inputs, one document. An invalid document stops the process. It does not fall open.

The server: block in template.yaml. Tooling compiles it to /etc/agent-sandbox/server-policy.json. Accepted keys: version, preset, base_dir, groups, defaults, auth, endpoints, description. groups is either a list of groups to turn on or a map of group to true/false.

server:
  endpoints:
    "*":
      enabled: false
    agents_sessions_create:
      enabled: true
    agents_sessions_events_create:
      enabled: true
    agents_sessions_items_list:
      enabled: true
    agents_runtimes_list:
      enabled: true

Group shorthand, list or map:

server:
  groups: [agents, dev_tools]     # same as {agents: true, dev_tools: true}
server:
  groups:
    process: false
    terminal: false

Inline JSON:

export ABX_SERVER_POLICY='{"groups":["agents"],"endpoints":{"*":{"enabled":false},"agents_sessions_create":{"enabled":true}}}'

Or a file:

export ABX_SERVER_POLICY_FILE=/etc/agent-sandbox/server-policy.json
agent-sandbox-server check-config --policy /etc/agent-sandbox/server-policy.json

Lookup order: ABX_SERVER_POLICY, then ABX_SERVER_POLICY_FILE, then the well-known policy file. With none of them the built-in defaults apply: opt-in groups off, everything else on, no per-endpoint limits.

Python:

from agent_sandbox.server import SandboxServer, ServerPolicy

policy = ServerPolicy.only(
    "agents_sessions_create",
    "agents_sessions_events_create",
    "agents_sessions_items_list",
    "agents_runtimes_list",
)
SandboxServer(policy=policy).serve(port=9000)

ServerPolicy.only turns "*" off, turns the listed ids on, and leaves the core endpoints on. agents-cli's commands.py is this call. only also accepts "transfer" (the four upload and download ids) and "group:<name>".

To open a whole group from commands.py without a policy document:

from agent_sandbox.server import CapabilityGroup, default_table

default_table().enable_group(CapabilityGroup.DEV_TOOLS)

enable_group and disable_group are the only code-level switches. disable_group(CORE) raises.

Selectors

Form Matches
agents_sessions_create That endpoint id
files_* Endpoint ids matching the glob
group:file_ops Endpoints in that group
* Every endpoint
@defaults The defaults block, applied before each endpoint

If several matching rules of the same specificity and layer disagree, enabled: false wins. A more specific selector can turn the endpoint back on.

What a rule may contain

Key Effect
enabled true or false
scopes The caller must hold every listed scope. * is everything. files:* is that namespace
paths.allow Absolute paths. When set, they replace base_dir as that endpoint's boundary
paths.deny Directory prefixes or globs. A pattern without / matches a path component, such as *.pem. Deny wins
paths.read_only true rejects writes and deletes on that endpoint
paths.symlinks within (the target must stay inside the boundary) or never
limits See below. Sizes accept 5MB and 1MiB
params See below. Deny-lists are unioned across layers
audit off, deny, or all

Limits every endpoint accepts: max_request_bytes, rate_per_minute, max_concurrency.

Agents endpoints are in the built-in catalogue. The default scope is agents:use. Enable one endpoint id with enabled: true, the same way as upload. They have no paths and no specialised params, so the only other keys are enabled, scopes, audit, and the three limits above. A paths or specialised params block on them fails policy load.

Presets apply before your endpoint rules:

Preset Effect
default No extra restriction (opt-in groups stay off)
transfer-only Only upload, download, files_upload_stream, files_download_stream
read-only Turns off process, terminal, dev_tools, and browser, and turns off write endpoints and env_set
hardened Turns off those groups and denies /proc, /sys, /dev, .ssh, .env, *.pem, and private-key names on file routes
locked Only list_commands and run_command

Group names: core, commands, file_ops, process, terminal, system, dev_tools, browser, agents. core cannot be disabled.

The checker warns (L1) when one identity can both read scoped files and run shell, process_start, code_run, or a PTY. A process can bypass path rules. An Agents session starts the CLI inside the server. It does not need the process group for that.

Endpoint catalogue

This is the endpoint declaration table (agent_sandbox.server.endpoints.ENDPOINTS). The route table, the policy, and GET /capabilities are all derived from it. pty_connect is the WebSocket upgrade, served on the PTY port. Agents rows use the scope agents:use. They have fewer knobs than file routes that take a path, because these routes do not accept paths or specialised parameters.

Group Method Path Endpoint id Scope Knobs
agents GET /v1/agents/sessions/{id}/artifacts/{artifact_id}/content agents_artifacts_content agents:use enabled, scopes, audit; common limits only
agents DELETE /v1/agents/sessions/{id}/artifacts/{artifact_id} agents_artifacts_delete agents:use enabled, scopes, audit; common limits only
agents GET /v1/agents/sessions/{id}/artifacts/{artifact_id} agents_artifacts_get agents:use enabled, scopes, audit; common limits only
agents GET /v1/agents/sessions/{id}/artifacts agents_artifacts_list agents:use enabled, scopes, audit; common limits only
agents GET /v1/agents/environments/{environment_id}/connect agents_cannot_executor_channel agents:use enabled, scopes, audit; common limits only
agents POST /v1/agents/environments/{environment_id}/register agents_cannot_executor_registration agents:use enabled, scopes, audit; common limits only
agents DELETE /v1/models/{model} agents_cannot_models_delete agents:use enabled, scopes, audit; common limits only
agents POST /v1/responses/input_tokens agents_cannot_responses_input_tokens agents:use enabled, scopes, audit; common limits only
agents POST /v1/agents agents_definitions_create agents:use enabled, scopes, audit; common limits only
agents DELETE /v1/agents/{agent_id} agents_definitions_delete agents:use enabled, scopes, audit; common limits only
agents GET /v1/agents/{agent_id} agents_definitions_get agents:use enabled, scopes, audit; common limits only
agents GET /v1/agents agents_definitions_list agents:use enabled, scopes, audit; common limits only
agents POST /v1/agents/{agent_id} agents_definitions_update agents:use enabled, scopes, audit; common limits only
agents POST /v1/agents/environments/{environment_id}/files agents_environment_files_create agents:use enabled, scopes, audit; common limits only
agents GET /v1/agents/environments/{environment_id}/files agents_environment_files_list agents:use enabled, scopes, audit; common limits only
agents POST /v1/agents/environments/templates agents_environment_templates_create agents:use enabled, scopes, audit; common limits only
agents DELETE /v1/agents/environments/templates/{environment_template_id} agents_environment_templates_delete agents:use enabled, scopes, audit; common limits only
agents GET /v1/agents/environments/templates/{environment_template_id} agents_environment_templates_get agents:use enabled, scopes, audit; common limits only
agents GET /v1/agents/environments/templates agents_environment_templates_list agents:use enabled, scopes, audit; common limits only
agents POST /v1/agents/environments/templates/{environment_template_id} agents_environment_templates_update agents:use enabled, scopes, audit; common limits only
agents POST /v1/agents/environments agents_environments_create agents:use enabled, scopes, audit; common limits only
agents GET /v1/agents/environments/{environment_id} agents_environments_get agents:use enabled, scopes, audit; common limits only
agents GET /v1/agents/environments agents_environments_list agents:use enabled, scopes, audit; common limits only
agents POST /v1/files agents_files_create agents:use enabled, scopes, audit; common limits only
agents GET /v1/models/{model} agents_models_get agents:use enabled, scopes, audit; common limits only
agents GET /v1/models agents_models_list agents:use enabled, scopes, audit; common limits only
agents POST /v1/responses/{response_id}/cancel agents_responses_cancel agents:use enabled, scopes, audit; common limits only
agents POST /v1/responses/compact agents_responses_compact agents:use enabled, scopes, audit; common limits only
agents GET /v1/responses agents_responses_connect agents:use enabled, scopes, audit; common limits only
agents POST /v1/responses agents_responses_create agents:use enabled, scopes, audit; common limits only
agents DELETE /v1/responses/{response_id} agents_responses_delete agents:use enabled, scopes, audit; common limits only
agents GET /v1/responses/{response_id} agents_responses_get agents:use enabled, scopes, audit; common limits only
agents GET /v1/responses/{response_id}/input_items agents_responses_input_items agents:use enabled, scopes, audit; common limits only
agents GET /v1/agents/runtimes agents_runtimes_list agents:use enabled, scopes, audit; common limits only
agents POST /v1/agents/sessions agents_sessions_create agents:use enabled, scopes, audit; common limits only
agents DELETE /v1/agents/sessions/{id} agents_sessions_delete agents:use enabled, scopes, audit; common limits only
agents POST /v1/agents/sessions/{id}/events agents_sessions_events_create agents:use enabled, scopes, audit; common limits only
agents GET /v1/agents/sessions/{id}/events agents_sessions_events_stream agents:use enabled, scopes, audit; common limits only
agents GET /v1/agents/sessions/{id} agents_sessions_get agents:use enabled, scopes, audit; common limits only
agents GET /v1/agents/sessions/{id}/items agents_sessions_items_list agents:use enabled, scopes, audit; common limits only
agents GET /v1/agents/sessions agents_sessions_list agents:use enabled, scopes, audit; common limits only
agents GET /v1/agents/sessions/{id}/turns/{turn_id} agents_sessions_turns_get agents:use enabled, scopes, audit; common limits only
agents GET /v1/agents/sessions/{id}/turns/{turn_id}/items agents_sessions_turns_items_list agents:use enabled, scopes, audit; common limits only
agents GET /v1/agents/sessions/{id}/turns agents_sessions_turns_list agents:use enabled, scopes, audit; common limits only
agents POST /v1/agents/sessions/{id} agents_sessions_update agents:use enabled, scopes, audit; common limits only
agents GET /v1/agents/sessions/{id}/subagents/{subagent_id} agents_subagents_get agents:use enabled, scopes, audit; common limits only
agents GET /v1/agents/sessions/{id}/subagents/{subagent_id}/items agents_subagents_items_list agents:use enabled, scopes, audit; common limits only
agents GET /v1/agents/sessions/{id}/subagents agents_subagents_list agents:use enabled, scopes, audit; common limits only
agents GET /v1/agents/sessions/{id}/subagents/{subagent_id}/turns/{turn_id} agents_subagents_turns_get agents:use enabled, scopes, audit; common limits only
agents GET /v1/agents/sessions/{id}/subagents/{subagent_id}/turns/{turn_id}/items agents_subagents_turns_items_list agents:use enabled, scopes, audit; common limits only
agents GET /v1/agents/sessions/{id}/subagents/{subagent_id}/turns agents_subagents_turns_list agents:use enabled, scopes, audit; common limits only
agents GET /v1/agents/sessions/{id}/traces agents_traces_list agents:use enabled, scopes, audit; common limits only
agents POST /v1/vaults/{vault_id}/credentials agents_vault_credentials_create agents:use enabled, scopes, audit; common limits only
agents DELETE /v1/vaults/{vault_id}/credentials/{credential_id} agents_vault_credentials_delete agents:use enabled, scopes, audit; common limits only
agents GET /v1/vaults/{vault_id}/credentials/{credential_id} agents_vault_credentials_get agents:use enabled, scopes, audit; common limits only
agents GET /v1/vaults/{vault_id}/credentials agents_vault_credentials_list agents:use enabled, scopes, audit; common limits only
agents POST /v1/vaults/{vault_id}/credentials/{credential_id} agents_vault_credentials_update agents:use enabled, scopes, audit; common limits only
agents POST /v1/vaults agents_vaults_create agents:use enabled, scopes, audit; common limits only
agents DELETE /v1/vaults/{vault_id} agents_vaults_delete agents:use enabled, scopes, audit; common limits only
agents GET /v1/vaults/{vault_id} agents_vaults_get agents:use enabled, scopes, audit; common limits only
agents GET /v1/vaults agents_vaults_list agents:use enabled, scopes, audit; common limits only
agents POST /v1/vaults/{vault_id} agents_vaults_update agents:use enabled, scopes, audit; common limits only
agents GET /v1/webhook_event_types agents_webhook_event_types agents:use enabled, scopes, audit; common limits only
agents POST /v1/webhook_endpoints agents_webhooks_create agents:use enabled, scopes, audit; common limits only
agents DELETE /v1/webhook_endpoints/{webhook_endpoint_id} agents_webhooks_delete agents:use enabled, scopes, audit; common limits only
agents GET /v1/webhook_endpoints/{webhook_endpoint_id} agents_webhooks_get agents:use enabled, scopes, audit; common limits only
agents GET /v1/webhook_endpoints agents_webhooks_list agents:use enabled, scopes, audit; common limits only
agents POST /v1/webhook_endpoints/{webhook_endpoint_id}/rotate_secret agents_webhooks_rotate_secret agents:use enabled, scopes, audit; common limits only
agents POST /v1/webhook_endpoints/{webhook_endpoint_id}/test agents_webhooks_test agents:use enabled, scopes, audit; common limits only
agents POST /v1/webhook_endpoints/{webhook_endpoint_id} agents_webhooks_update agents:use enabled, scopes, audit; common limits only
browser POST /browser/click browser_click browser:use common limits only
browser GET /browser/console browser_console browser:use common limits only
browser GET /browser/content browser_content browser:use common limits only
browser POST /browser/evaluate browser_evaluate browser:evaluate executes a program
browser POST /browser/navigate browser_navigate browser:use params: block_private_networks, url_allow, url_deny; executes a program
browser POST /browser/pdf browser_pdf browser:use common limits only
browser POST /browser/screenshot browser_screenshot browser:use common limits only
browser POST /browser/type browser_type browser:use common limits only
commands GET /commands list_commands commands:list common limits only
commands POST /commands/{name} run_command commands:run common limits only
core GET /capabilities capabilities core:read cannot disable
core POST /capabilities/check capabilities_check core:read cannot disable
core GET /health health — cannot disable
dev_tools POST /code/run code_run devtools:run params: languages; limits: max_output_bytes, timeout_seconds; executes a program
dev_tools GET /git/diff git_diff devtools:read paths
dev_tools GET /git/status git_status devtools:read paths
file_ops GET /download download files:read paths; limits: max_bytes
file_ops POST /files/archive files_archive files:read paths; limits: max_bytes, max_files
file_ops DELETE /files files_delete files:delete paths
file_ops GET /files/download-stream files_download_stream files:read paths; limits: max_bytes
file_ops GET /files/list files_list files:read paths; limits: max_depth, max_entries
file_ops POST /files/mkdir files_mkdir files:write paths
file_ops POST /files/move files_move files:write, files:delete paths
file_ops POST /files/search files_search files:read paths; limits: max_depth, max_results, timeout_seconds
file_ops GET /files/stat files_stat files:read paths
file_ops POST /files/upload-stream files_upload_stream files:write paths; params: allow_extensions, deny_extensions, overwrite; limits: max_bytes
file_ops GET /files/watch files_watch files:read paths; limits: max_duration_seconds
file_ops POST /upload upload files:write paths; params: allow_extensions, deny_extensions, overwrite; limits: max_bytes
process GET /process/{pid} process_detail process:read common limits only
process GET /process/list process_list process:read common limits only
process GET /process/{pid}/output process_output process:read common limits only
process POST /process/{pid}/signal process_signal process:manage params: allowed_signals
process POST /process/start process_start process:run paths; params: allow_commands, deny_commands; limits: max_output_bytes, max_processes, timeout_seconds; executes a program
process POST /process/{pid}/stdin process_stdin process:manage common limits only
process POST /shell shell process:run paths; params: allow_commands, deny_commands; limits: max_output_bytes, max_processes, timeout_seconds; executes a program
process POST /shell/stream shell_stream process:run paths; params: allow_commands, deny_commands; limits: max_output_bytes, max_processes, timeout_seconds; executes a program
system GET /env env_get system:read params: allow_vars, deny_vars
system POST /env env_set system:write params: allow_vars, deny_vars
system GET /packages packages system:read common limits only
system GET /ports ports system:read common limits only
system GET /system/info system_info system:read common limits only
system GET /system/metrics system_metrics system:read common limits only
terminal WS /pty pty_connect terminal:use common limits only
terminal POST /pty/sessions pty_create_session terminal:use params: env_deny, shells; limits: max_sessions
terminal DELETE /pty/sessions/{id} pty_delete_session terminal:use common limits only
terminal GET /pty/sessions/{id} pty_detail terminal:use common limits only
terminal GET /pty/sessions pty_list_sessions terminal:use common limits only
terminal POST /pty/sessions/{id}/resize pty_resize terminal:use common limits only

How this meets the Agents API case

agents-cli enables only:

Endpoint id Route
agents_sessions_create POST /v1/agents/sessions
agents_sessions_get GET /v1/agents/sessions/{id}
agents_sessions_list GET /v1/agents/sessions
agents_sessions_events_create POST /v1/agents/sessions/{id}/events
agents_sessions_items_list GET /v1/agents/sessions/{id}/items
agents_runtimes_list GET /v1/agents/runtimes

The local e2e recorded POST /shell as 404, POST /v1/agents (definitions) as 404, and the Codex and Qwen Code session, event, and item calls as 200 / 202. To open another route, add its endpoint id to ServerPolicy.only and to endpoints in template.yaml.