Session operations
Retrieve, list, filter, update, interrupt, archive, and delete sessions in Orca Agent Engine, and page through results correctly.
Once a session exists, you manage it through the operations on this page. Sessions covers creating one and what it contains; this page covers everything you do to it afterward.
$SESSION_ID / sessionId below are the id returned when you create a session; $AGENT_ID / agentId is the id of the agent that owns it. Shell and TypeScript examples use the two spellings of the same value.
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.
Retrieve a session
session=$(ork agent sessions get "$SESSION_ID" -o json)
STATUS=$(jq -r '.status' <<< "$session")The response is the full session object, including status, stats, usage, and the resources currently mounted. Retrieve is the way to poll for a status change when you are not streaming events.
List sessions
sessions=$(ork agent sessions list --agent "$AGENT_ID" --limit 20 -o json)
jq -r '.data[] | "\(.id) \(.status)"' <<< "$sessions"Results are ordered by created_at, newest first, and archived sessions are excluded unless you ask for them.
Filters
| Parameter | Values | Description |
|---|---|---|
agent_id | agt_ ID | Only sessions run by this agent. |
agent_version | positive integer | Only sessions pinned to this version. Pair it with agent_id. |
statuses | running, idle, rescheduling, terminated | Repeat the parameter to match several. |
created_at[gt], created_at[gte], created_at[lt], created_at[lte] | RFC 3339 timestamp | Bound the creation time. Combine two for a window. |
memory_store_id | mems_ ID | Only sessions with that memory store currently attached. |
include_archived | true / false | Default false. |
order | asc / desc | Ordering by created_at. Default desc. |
limit | 1 to 100 | Default 100. |
page | cursor token | See Page through results. |
Finding every session an agent started in a given window is one request:
sessions=$(curl -fsS -G "$ORCA_REGISTRY_URL/v1/sessions" \
-H "Authorization: Bearer $ORCA_ACCESS_TOKEN" \
--data-urlencode "agent_id=$AGENT_ID" \
--data-urlencode "created_at[gte]=2026-07-29T00:00:00Z" \
--data-urlencode "created_at[lt]=2026-07-30T00:00:00Z")
jq -r '.data[] | "\(.id) \(.created_at)"' <<< "$sessions"Narrowing that to the ones that failed takes a second step, and not through status: a session's
status is only ever idle or running, and a failed run is left idle and resumable rather than
being marked. There is no status that means "this went wrong". The signal is the session.error
event, which the events endpoint can filter server-side:
for id in $(jq -r '.data[].id' <<< "$sessions"); do
errors=$(curl -fsS -G "$ORCA_REGISTRY_URL/v1/sessions/$id/events" \
-H "Authorization: Bearer $ORCA_ACCESS_TOKEN" \
--data-urlencode "types=session.error" \
--data-urlencode "limit=1")
[ "$(jq -r '.data | length' <<< "$errors")" -gt 0 ] && echo "$id"
doneAnything outside the table is not a filter. Two are worth calling out because they look like ones:
deployment_id is accepted and always matches nothing, so a request that sends it returns an empty data array no matter what exists. There is no metadata filter either: the CLI's list commands take no --metadata flag, and the registry reads no metadata query parameter. To select on metadata, list without it and filter client-side with jq '.data[] | select(.metadata.channel == "web")'.
Page through results
A list response carries opaque cursors rather than page numbers:
{
"data": [],
"next_page": "eyJkIjoibmV4dCIsIm8iOiJkZXNjIiwiaSI6InNlc18wMUg4In0",
"prev_page": null
}Pass next_page back as page to get the following page. Both cursors are null when there is nothing further in that direction, and a cursor encodes the order it was issued under, so changing order mid-walk returns 400 page cursor order does not match order.
In TypeScript you rarely need to do this by hand - for await (const session of orca.sessions.list({ agent_id: agentId })) walks every page. The explicit form below is what that iteration does, and is the shape to copy when you are driving the API directly.
let page = await orca.sessions.list({ agent_id: agentId, limit: 100 });
const all = [...page.data];
while (page.next_page) {
page = await orca.sessions.list({ agent_id: agentId, limit: 100, page: page.next_page });
all.push(...page.data);
}Update a session
Update is a POST to the session path, not a PATCH.
session=$(ork agent sessions update "$SESSION_ID" \
--title "ticket #4821 (resolved)" \
--metadata resolution=fixed \
-o json)
jq -r '.title' <<< "$session"Three things are mutable:
| Field | Semantics |
|---|---|
title | Replaced outright. |
metadata | Patched. Omitted keys are left alone, a key set to null is removed, and "metadata": null clears the whole map. orca_llm_egress accepts direct or gateway for separate-harness model routing. |
agent.tools, agent.mcp_servers | Session-scoped overrides of the pinned agent's configuration. Each array is replaced in full. |
Everything else is fixed once the session exists. The agent identity, environment_id, resources, stats, and usage are read-only, and vault_ids returns 400 vault_ids updates are not yet supported rather than being ignored.
An update that changes nothing is not an error: the registry compares against current values and returns the unchanged session.
Overriding agent.tools or agent.mcp_servers requires the session to be idle. Any other status returns 409 session must be idle to update agent configuration. Archived and terminated sessions reject every update with 409 archived or terminated sessions cannot be updated.
Change one entry in a replaced array
Because tools and mcp_servers are replaced rather than merged, sending only the entry you want to change deletes the rest. Read the effective value off the session, modify it, and send the whole array back:
current=$(curl -fsS "$ORCA_REGISTRY_URL/v1/sessions/$SESSION_ID" \
-H "Authorization: Bearer $ORCA_ACCESS_TOKEN")
servers=$(jq '[.agent.mcp_servers[]
| if .name == "tickets" then .url = "https://mcp.staging.example.com/tickets" else . end]' \
<<< "$current")
curl -fsS -X POST "$ORCA_REGISTRY_URL/v1/sessions/$SESSION_ID" \
-H "Authorization: Bearer $ORCA_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d "$(jq -n --argjson servers "$servers" '{ agent: { mcp_servers: $servers } }')"session.agent on a retrieve is the fully resolved configuration, so it already reflects any override in force. The agent object on update accepts only tools and mcp_servers - SessionAgentUpdate in the SDK types it the same way - so sending the retrieved agent back wholesale returns 400, because the identity fields it carries are not writable here.
The same full-replacement rule applies to an agent's own arrays on update. Two clients doing read-modify-write concurrently will lose one of the two edits: session update has no version check, unlike agent update. Serialize the writes if more than one process manages a session.
Interrupt a running session
There is no interrupt endpoint. Interrupting is an event: send user.interrupt and the default claude_agent_sdk harness aborts the in-flight turn rather than waiting for it to finish.
await orca.sessions.events.send(sessionId, {
events: [{ type: 'user.interrupt' }],
});Interrupt is what you want when the agent is doing the wrong thing but the session is still worth keeping: the turn ends, the session returns to idle, and the next event starts a new turn with the conversation intact. Use archive when the session itself is finished. See Events and streaming for the rest of the event vocabulary.
Interrupt does not work on the claude_code harness. Its in-sandbox protocol accepts no user event other than user.message and user.custom_tool_result, so user.interrupt is rejected: the session emits session.error and is marked idle, while the turn that was already in flight runs to completion. Do not match on the error type to detect this - the registry only passes through a fixed set of error names, and the underlying unapplied_event is not one of them, so a default-dialect client reads unknown_error. orca-beta clients see unapplied_event. There is no way to stop a turn early there - archive the session instead.
Archive a session
ork agent sessions archive "$SESSION_ID"Archiving stops the session's runner, makes the session read-only, and drops it from list results unless you pass include_archived=true. A running session does not need to be interrupted first. The event history stays readable. Individual threads archive the same way, at /sessions/{sessionId}/threads/{threadId}/archive.
Delete a session
ork agent sessions delete "$SESSION_ID"Delete removes the session and its event history permanently. Archive is what you want for anything you may need to audit later.
Permissions
Treat every Workspace API key as full access to its Workspace's resources, and separate access with Workspaces. See Control registry access.