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

Sessions

Create, manage, and observe sessions in Orca Agent Engine - the running instances of an agent inside an environment.

A Session is a running instance of an agent. Sessions are created in two steps: first you create the session itself, which records the agent, the environment, and the resources to mount; then you send events that drive the agent to act. Creating a session provisions nothing - it starts idle with no container and no start time. The sandbox is acquired when the first event is dispatched, so until you send one, the session exists only as a row.

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 a session

Create a session by POSTing a CreateSessionRequest to /v1/sessions. Sessions are a top-level resource: the agent is named in the request body, not in the path.

Two fields are required:

  • agent - the agent that runs the session. Pass an agt_ ID as a bare string, or an object for more control (see Pinning an agent version).
  • environment_id - the environment the session's container runs in. Omitting it returns 400 with environment_id is required; there is no default.

Everything else - title, metadata, vault_ids, resources, and initial_events - is optional.

$AGENT_ID / agentId below is the id of an agent, and $ENVIRONMENT_ID / environmentId the id of an environment. Each example then captures the new session's id as $SESSION_ID / sessionId.

session=$(ork agent sessions create \
  --agent "$AGENT_ID" \
  --environment-id "$ENVIRONMENT_ID" \
  --title "ticket #4821" \
  --metadata channel=web \
  -o json)

SESSION_ID=$(jq -r '.id' <<< "$session")

A successful create returns 200 OK with the new session:

{
  "id": "ses_01H8...",
  "type": "session",
  "agent": { "id": "agt_01H8...", "type": "agent", "version": 1, "name": "support-triage" },
  "environment_id": "env_01H8...",
  "vault_ids": [],
  "status": "idle",
  "title": "ticket #4821",
  "stats": { "active_seconds": 0.0, "duration_seconds": 0.0 },
  "usage": { "input_tokens": 0, "output_tokens": 0 },
  "resources": [],
  "metadata": { "channel": "web" },
  "created_at": "2026-05-11T17:24:08Z",
  "updated_at": "2026-05-11T17:24:08Z"
}

Choose model egress for this session

For a harness in separate mode, set metadata.orca_llm_egress to gateway or direct to override the deployment's LLM_EGRESS_DEFAULT setting. The default is direct unless the operator changes it. Gateway egress requires the registry and LLM_GATEWAY_URL to be configured in the harness. A colocated Cloud harness always uses gateway egress, regardless of this metadata. Other values return 400. See Use the gateway with Agent Engine.

Pinning an agent version

The agent field accepts three shapes:

ShapeBehavior
"agt_01H8..."Bare ID. The session uses the agent's latest version at the moment of creation.
{ "type": "agent", "id": "agt_01H8...", "version": 2 }Pins the session to one version. Omit version to take the latest.
{ "type": "agent_with_overrides", "id": "agt_01H8...", ... }Pins a version and overrides parts of the agent for this session only.
session=$(curl -fsS "$ORCA_REGISTRY_URL/v1/sessions" \
  -H "Authorization: Bearer $ORCA_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg agent "$AGENT_ID" --arg env "$ENVIRONMENT_ID" '{
    agent: { type: "agent", id: $agent, version: 2 },
    environment_id: $env
  }')")

SESSION_ID=$(jq -r '.id' <<< "$session")

The session retains that version for its entire lifetime even if the underlying agent is updated.

Overriding an agent for one session

agent_with_overrides lets one session diverge from the published agent without creating a new agent version. It accepts model, system, tools, mcp_servers, and skills, each replacing the pinned version's value in full. The same limits apply as on the agent: at most 128 tools and 20 MCP servers. It also accepts guardrail_ids, which adds guardrails to the agent's own rather than replacing them.

session=$(curl -fsS "$ORCA_REGISTRY_URL/v1/sessions" \
  -H "Authorization: Bearer $ORCA_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg agent "$AGENT_ID" --arg env "$ENVIRONMENT_ID" '{
    agent: {
      type: "agent_with_overrides",
      id: $agent,
      version: 2,
      system: "You triage support tickets for the EU region only."
    },
    environment_id: $env
  }')")

SESSION_ID=$(jq -r '.id' <<< "$session")

MCP authentication via vaults

If the agent calls MCP servers that require per-user credentials, reference one or more vaults when creating the session. The runtime injects the vault's credentials into MCP requests on the agent's behalf.

Create a session with a vault
session=$(curl -fsS "$ORCA_REGISTRY_URL/v1/sessions" \
  -H "Authorization: Bearer $ORCA_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg agent "$AGENT_ID" --arg env "$ENVIRONMENT_ID" --arg vault "$VAULT_ID" '{
    agent: $agent,
    environment_id: $env,
    vault_ids: [$vault]
  }')")

SESSION_ID=$(jq -r '.id' <<< "$session")

$VAULT_ID is the id of a vault you created earlier.

A vault has to belong to the same Workspace and not be archived - that is the whole check - and vault_ids is fixed at creation, so it cannot be changed later. See Vaults for how to create vaults and add credentials.

Start the session

A session does not start the agent until you send it an event. Send a user.message event to drive the agent's first turn. content is an array of content blocks, not a string.

Send the first event
curl -fsS "$ORCA_REGISTRY_URL/v1/sessions/$SESSION_ID/events" \
  -H "Authorization: Bearer $ORCA_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [
      {
        "type": "user.message",
        "content": [{ "type": "text", "text": "Triage this ticket: customer cannot log in." }]
      }
    ]
  }'

To create the session and start it in the same call, pass the events as initial_events instead. It takes up to 50 events, each a user.message or a user.define_outcome. No other event type is accepted at creation time:

session=$(curl -fsS "$ORCA_REGISTRY_URL/v1/sessions" \
  -H "Authorization: Bearer $ORCA_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg agent "$AGENT_ID" --arg env "$ENVIRONMENT_ID" '{
    agent: $agent,
    environment_id: $env,
    initial_events: [
      {
        type: "user.message",
        content: [{ type: "text", text: "Triage this ticket: customer cannot log in." }]
      }
    ]
  }')")

SESSION_ID=$(jq -r '.id' <<< "$session")

The session comes back already running. The CLI takes the same events through --initial-event-json, which is repeatable:

Create and start in one call, from the CLI
session=$(ork agent sessions create \
  --agent "$AGENT_ID" \
  --environment-id "$ENVIRONMENT_ID" \
  --initial-event-json '{"type":"user.message","content":[{"type":"text","text":"Triage this ticket: customer cannot log in."}]}' \
  -o json)

SESSION_ID=$(jq -r '.id' <<< "$session")

Open the event stream to receive the agent's response as it runs.

Session statuses

The registry exposes the session status field returned by the agent provider. The status reflects the runtime state of the session and updates as events flow through.

StatusDescription
idleWaiting for input. New sessions start here, and return here when a turn ends.
runningThe agent is executing a turn.
reschedulingDeclared for Anthropic compatibility, but no session record enters this state. The default harness emits a separate session.status_rescheduled event while it retries a transient provider failure.
terminatedA thread that was explicitly archived. Threads only, and not an error state. The session.thread_status_terminated event retains stop_reason: "archived" only with orca-beta; the default response omits it.

Inspect the session at GET /v1/sessions/{sessionId} to check the current value.

A session's own status is only ever idle or running. Those are the only two values the runtime writes to a session, and a failed run is left idle and resumable rather than marked - so no status means "this failed". Look for a session.error event instead. terminated describes a thread that was archived, read from GET /v1/sessions/{sessionId}/threads; rescheduling is a compatibility value for the session record, distinct from the retry event of the same name. The statuses query parameter on the list endpoint accepts all four names, so filtering sessions by terminated returns 200 with an empty data array rather than an error. Archiving a session does not change its status either; it sets archived_at.

Session resources

A session's resources array holds everything mounted into its container. Pass resources at creation time, or manage them afterward through the session's resources sub-resource. Three types are supported:

typeRequired fieldsDescription
filefile_idMounts an uploaded file.
memory_storememory_store_idMounts a memory store as a directory.
github_repositoryurl, authorization_tokenClones a GitHub repository. checkout is accepted but not reliably applied - see the caveat on Repositories.

All three also accept an optional access mode of read_only or read_write and instructions (up to 4096 characters). instructions is stored and returned but never reaches the agent - nothing in the harness reads it - so put anything the agent needs to know about a resource in the system prompt or a user.message instead. Only file and github_repository take a mount_path. A memory store's mount path is server-derived: it comes back on the resource but is rejected on the way in, and an update that sets it returns 400 memory_store mount_path is output-only and cannot be updated.

$MEMORY_STORE_ID / memoryStoreId below is the id of a store you created earlier.

ork agent sessions resources list --session "$SESSION_ID"

ork agent sessions resources add \
  --session "$SESSION_ID" \
  --type memory-store \
  --memory-store-id "$MEMORY_STORE_ID" \
  --access read_write

Updating a resource accepts authorization_token, mount_path, access, instructions, and mount_strategy. The token is rotated; the other four are written to the resource. Not every field applies to every type - a memory_store's mount_path is output-only and returns 400 memory_store mount_path is output-only and cannot be updated. To change anything not in that list, remove the resource and add it again.

The published OpenAPI specification is behind the running route here: it declares authorization_token as the only accepted property. A client generated from that spec will not expose the other four fields even though the endpoint accepts them.

Session threads

A session has one primary thread plus zero or more child threads. On the default Claude Managed Agents wire format, threads are produced by the coordinator as the session runs - there is no endpoint that creates one, and clients cannot spawn them. A multiagent coordinator delegating work to a sub-agent is what causes a child thread to appear.

orca-beta exposes legacy thread controls. A client event with a nonempty subpath creates or targets a child thread, and session_thread_id targets a control event at an existing thread. Those fields and the full transcript envelope are Orca extensions, not part of the default Claude Managed Agents event contract.

Each thread carries its own status, stats, usage, and the agent configuration it ran with:

FieldDescription
idThread identifier, prefixed sth_.
session_idThe session the thread belongs to.
parent_thread_idThe thread that spawned this one, or null for the primary thread.
agentThe agent configuration the thread ran with.
statusrunning, idle, rescheduling, or terminated.
stats, usagePer-thread timing and token accounting. May be null.

Threads are read-only apart from archive. You can list them, retrieve one, archive one, and read or stream its events. $THREAD_ID / threadId is an sth_ ID taken from the thread list:

threads=$(ork agent sessions threads list --session "$SESSION_ID" -o json)
THREAD_ID=$(jq -r '.data[0].id' <<< "$threads")

ork agent sessions threads events list \
  --session "$SESSION_ID" \
  --thread "$THREAD_ID"

Manage a session

Retrieving, listing and filtering, updating, interrupting, archiving, and deleting a session are covered on their own page:

Session operations

Every operation on an existing session, plus cursor pagination and the read-modify-write rule for replaced arrays.

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