Agent Sandbox Registry

python-sdk

01 - Principles, scope and non-goals

docs/en/archive/server-sdk-v2/01-principles.md

01 - Principles, scope and non-goals

Status: archive. Not the current specification.

Status: target design, not implemented. The shipped server uses endpoint ids and one policy engine; see README section 1 for what exists and section 2 for what does not.

Part of Server SDK v2. Target principles; where they differ from the shipped server, the status list in README wins.

1. What the server SDK is

agent-sandbox-server (import agent_sandbox.server) is the in-sandbox runtime of Agent Sandbox: a stdlib-only HTTP server that runs inside a sandbox image (port 9000, PTY WebSocket on 9001) and gives callers - the Python client SDK, the Node abx CLI, the official openai SDK, plain curl - a typed, policy-controlled surface over the sandbox: files, commands, processes, terminals, system information, browser, developer tools, coding agents, and user-defined operations.

It is not an envd clone. envd (port 49983) stays the platform's data plane that Sandbox.files/commands use. The server is the template author's plane. The two overlap on purpose only where that helps (see 07-client-mirror.md section 6).

2. The seven design rules

These rules are the tie-breakers for every decision in this set. Each is testable.

R1. One identity per operation: a dotted ID, defined once. files.list, commands.run, agents.codex.sessions.create. The ID is the only name used in the server registry, policy rules, the audit log, error bodies, /capabilities, OpenAPI operationId, the generated client attribute path, and the CLI. HTTP method and path are bindings of an operation, never identifiers. There is no second registry (no KEEP = {("GET", "/health"), ...}-style sets of method/path tuples anywhere; a CI test greps for them).

R2. Everything is an operation, and every operation is policy-checked by the same code path. Built-ins, custom commands, legacy table.route(...) extensions and agent calls all go through one pipeline: transport checks (step 0: timeouts, target/Host/Origin/content-type) -> authenticate -> look up -> validate arguments -> policy -> (limits) -> handler -> audit. There is no route that skips the pipeline, including /health (it is op core.health, allowed by every preset).

R3. Absent unless enabled; enabled does not mean unconstrained. An operation is mounted only if at least one allow rule covers it. Unmounted operations answer 404 op.not_enabled and are not listed in /capabilities for that caller. Mounted operations can be narrowed by scopes (paths, commands, limits, principals, hooks). Policy is deny-overrides, fail-closed (any hook or scope error denies; an unset token_env refuses to start; allows over path/command/agent-exec ops without a scope are rejected with policy.scope_required) and restrict-only below the author layer (operators can tighten, never loosen).

R4. Coarse is sugar for fine. Groups (file_ops, process, ...), presets (readonly, download-only, ...) and the legacy CapabilityGroup/enable_builtin API are expansions into rules over operation IDs. Fine-grained rules never need a group to exist, and a group never grants more than its golden list of IDs ("no privilege creep", pinned by a snapshot test).

R5. Server and client are one schema. The registry emits a catalog (operations.json) from which the OpenAPI document, the Python client (ServerClient), the TypeScript client for the Node CLI and the docs tables are generated. A contract test replays every operation from the catalog against the real server. Hand-written client method names that differ from the op ID are a defect.

R6. Batteries included, never installed until used. The server core is stdlib-only and small. Coding-agent CLIs, a browser, Node and similar tools are described by manifests and installed lazily on first use (or at build time by agent-sandbox-server prepare, derived from the enabled operations). Nothing is downloaded at import, at server start, or by an operation that was not enabled and called.

R7. Boring for humans, predictable for AI coding agents. One obvious way to do the common thing (presets.*, Policy().allow(...), @op), strings with typo suggestions instead of silent no-ops, errors that say what to change, and a one-page reference (09-ai-codegen-usability.md) that is sufficient to write correct configurations without reading source.

3. Scope

In scope:

Non-goals:

4. Vocabulary

Term Meaning
operation (op) A named, typed, policy-checked capability, e.g. files.download.
op ID The dotted lowercase name; grammar in 02 section 2.
namespace An ID prefix: files, agents.codex, agents.codex.sessions.
binding An HTTP method + path (or WS/SSE endpoint) that dispatches to an op. POST /ops/{id} always exists.
effect A coarse tag on an op: read, write, delete, exec, net, admin.
group A legacy coarse switch (file_ops, process, ...) = a named list of op IDs.
rule allow(...) or deny(...) over selectors with optional scopes.
selector An op ID, ns.* (one level), ns.** (any depth), group:<name>, effect:<tag>, or *.
scope Constraints attached to an allow rule: paths, commands, limits.
principal The authenticated caller: id, roles, claims.
preset A Policy factory (presets.readonly()); policies compose with +.
hook authorize(ctx) -> Decision: a veto-only extra check.
adapter The per-agent-CLI plugin that builds an invocation and parses its output.
manifest Declarative description of how to obtain a tool (npm lock, tarball + sha256, ...).
LLM endpoint llm: - the model API an agent CLI talks to. (Not "provider": that word means the sandbox backend in the providers design.)

5. Compatibility stance