Cloud and BYOC for Orca Agent Engine are in Private Preview — request an invite
Docs

Environments

Reusable container templates that define what a session's sandbox is built from in Orca Agent Engine.

An Environment is a reusable template for a session's sandbox. It says where the sandbox runs and what network it can reach, and every session must reference one: environment_id is required at create time and there is no default.

Environments describe the sandbox. What the sandbox guarantees once it is running - the filesystem layout, the one writable path, the per-session caps - is on Sandboxes.

Get your registry endpoint

Registry endpoint

Examples on this page target your registry endpoint - the deployment host root, with no path suffix. For CLI, set ORCA_REGISTRY_URL and exactly one of ORCA_ACCESS_TOKEN (Bearer) or ORCA_API_KEY (x-api-key). For TypeScript SDK, set ORCA_BASE_URL / ORCA_API_KEY (Bearer). To find the endpoint, see Connect to the registry.

Create an environment

name is the only required field. Omitting config gives you a cloud environment with unrestricted networking.

environment=$(ork agent environments create \
  --name "data-science" \
  --description "Python environment for analysis sessions" \
  --config-json '{"type":"cloud","networking":{"type":"limited","allowed_hosts":["api.example.com"]}}' \
  -o json)

ENVIRONMENT_ID=$(jq -r '.id' <<< "$environment")

A successful create returns 200 OK. The response normalizes config: every package manager is present, and networking is filled in even when you did not send it.

{
  "id": "env_01H8...",
  "type": "environment",
  "name": "data-science",
  "description": "Python environment for analysis sessions",
  "config": {
    "type": "cloud",
    "networking": { "type": "limited", "allowed_hosts": ["api.example.com"] },
    "packages": {
      "type": "packages",
      "apt": [],
      "cargo": [],
      "gem": [],
      "go": [],
      "npm": [],
      "pip": []
    }
  },
  "metadata": { "team": "data" },
  "archived_at": null,
  "created_at": "2026-05-11T17:24:08Z",
  "updated_at": "2026-05-11T17:24:08Z"
}

$ENVIRONMENT_ID, or environmentId in the TypeScript examples below, is what you pass to a session as environment_id.

Configure the sandbox

config is a discriminated union on type:

typeAcceptsMeaning
cloudpackages, networkingThe platform provisions the sandbox. The default.
self_hostednothing elseThe sandbox runs in infrastructure you operate. Sending packages or networking alongside it returns 400.

Packages

config.packages declares packages by manager. The registry accepts and stores the field - it recognizes apt, cargo, gem, go, npm, and pip, each taking an array of package names - but no managed sandbox acts on it.

Declaring a package makes the session fail to start. Sandbox setup rejects a non-empty packages list in every managed sandbox mode, before any install could run, and the session ends in setup_failed rather than starting without the packages. An environment that names even one package cannot run a session at all.

Install hooks would execute before resource and Skill roots are sealed, so they are held back until the runtime can seal the filesystem first. Until then, build what a session needs into the environment's image.

Any other key is rejected: the schema is strict, so a typo like "python" fails rather than being ignored - though since a populated list stops the session from starting at all, a rejected typo is the better outcome. See Installing packages.

Networking

config.networking applies only to cloud configs and takes one of two shapes:

Networking
{
  "config": {
    "type": "cloud",
    "networking": {
      "type": "limited",
      "allowed_hosts": ["api.internal.example.com"],
      "allow_package_managers": true,
      "allow_mcp_servers": true
    }
  }
}
FieldTypeDefaultDescription
typeunrestricted / limitedunrestrictedWhether egress is filtered at all.
allowed_hostsstring array[]Hosts reachable under limited.
allow_package_managersbooleanfalseWhether package-manager registries stay reachable under limited.
allow_mcp_serversbooleanfalseWhether declared MCP servers stay reachable under limited.

On update, a limited block merges field by field against the stored one: omitted fields keep their current value, and a field set to null resets it to the default. An unrestricted block replaces whatever was there.

Networking is stored but not enforced in this build. The sandbox layer receives the value and no runtime reads it, so limited restricts nothing and allowed_hosts blocks nothing. Do not use it as a security boundary. Keep secrets out of the sandbox with vaults, which resolve credentials at the gateway, and control reach by choosing which MCP servers an agent declares.

Flat legacy fields

The registry also accepts four flat legacy fields alongside config: packages (a bare string array, treated as apt), networking, image, and target. The flat packages reaches the same place as config.packages, so a non-empty value stops sessions from starting in exactly the same way.

target and config.type write the same stored value, so send whichever your client supports - config.type is the current spelling. Either way the value is read at run time: an environment whose target is self_hosted enables client-executed built-in tools for sessions that also use the claude_agent_sdk harness in separate mode.

image never takes effect. Under the default separate mode it is not read at all. Under an in-sandbox harness it is read, but sandbox setup rejects a user-supplied image before that point, so every session on the environment fails to start - the same check that rejects config.packages. The image that runs is the operator-owned catalog image. Prefer config for everything else: the flat fields exist for compatibility with older clients.

Manage environments

List environments

environments=$(ork agent environments list --limit 20 -o json)
jq -r '.data[] | "\(.id) \(.name)"' <<< "$environments"

List takes only limit (1 to 100, default 100), page, and include_archived. There is no name or metadata filter; select client-side with jq. Paging works the same way as session pagination.

Retrieve an environment

environment=$(ork agent environments get "$ENVIRONMENT_ID" -o json)
jq -r '.config.networking.allowed_hosts[]' <<< "$environment"

Update an environment

Update is a POST to the environment path, not a PATCH.

environment=$(ork agent environments update "$ENVIRONMENT_ID" \
  --config-json '{"type":"cloud","networking":{"type":"limited","allowed_hosts":["api.example.com","cdn.example.com"]}}' \
  -o json)

jq -r '.updated_at' <<< "$environment"

Sending config does not replace every stored child field wholesale. On a cloud environment, omitting config.networking preserves the existing networking block; a supplied limited block merges its fields as described above. Omitting config.packages also preserves the stored package lists, while supplying it replaces those lists. metadata patches instead: omitted keys survive and a key set to null is removed.

Archive an environment

ork agent environments archive "$ENVIRONMENT_ID"

Archiving hides the environment from list results unless you pass include_archived=true. Sessions already using it keep running.

Delete an environment

ork agent environments delete "$ENVIRONMENT_ID"

Delete refuses if any session references the environment, returning 409 environment is referenced by one or more sessions. That check does not exclude archived or terminated sessions, so an environment used even once is effectively permanent until those sessions are deleted. Archive is the operation you want for retiring an environment.

What a change affects

A session does not snapshot its environment. The registry re-reads the environment row on every turn, and the result is part of the runtime configuration key the harness compares before dispatching; when the key changes, the runner is stopped and respawned against the new configuration. An environment edit therefore reaches an existing session on its next turn, not only new sessions. Edit an environment that live sessions depend on with that in mind.

That makes environments safe to edit but easy to misread: if a session is missing a package you just added, check when the session was created before checking the environment.

Permissions

Treat every Workspace API key as full access to its Workspace's resources, and separate access with Workspaces. See Control registry access.

What's next

On this page