> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orcapods.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Sessions

> Live instances of an agent profile, scoped to a single runner and equipped with their own MCP endpoint.

## What is a Session?

A **Session** is a live, stateful instance of an [Agent Profile](/concepts/profiles). When you submit a run, Orca creates (or reuses) a session on a runner that supports the profile's runtime.

Sessions are:

* **Stateful** — owned by a specific runner
* **Profile-scoped** — inherit tool access from their profile at creation time
* **MCP-enabled** — each session gets its own MCP HTTP endpoint
* **Persistent across runs** — a session can process multiple tasks sequentially

***

## Session Lifecycle

```mermaid theme={null}
stateDiagram-v2
  [*] --> idle: POST /api/runs
  idle --> running: run submitted
  running --> idle: run complete
  running --> errored: run failed
  idle --> shutdown: DELETE /api/sessions/{id}
  errored --> shutdown: DELETE /api/sessions/{id}
  shutdown --> [*]
```

***

## Session ID Format

Session IDs encode which runner owns them:

```mermaid theme={null}
flowchart LR
  session["sess-&lt;runnerHash&gt;-&lt;8hex&gt;"]
  hash["runnerHash<br/>first 8 hex chars<br/>of SHA256(RUNNER_BASE_URL)"]
  suffix["8hex<br/>random suffix"]

  session --> hash
  session --> suffix
```

**Example:** `sess-a1b2c3d4-e5f6g7h8`

Any conductor can extract `a1b2c3d4`, look up the runner in `remote.Pool`, and route to it — **without a shared registry**.

***

## Session State

```go theme={null}
type SessionState struct {
  ID               string
  Profile          string
  Runtime          string
  Status           SessionStatus  // idle | running | errored | shutdown
  CreatedAt        time.Time
  LastUsedAt       time.Time
  RuntimeSessionID string         // Claude session_id or Codex thread_id
  StateRev         int64          // persisted state-bundle revision
}
```

***

## Session-Scoped MCP Endpoint

Every active session exposes a **Model Context Protocol** streamable HTTP endpoint:

```
POST /runner/sessions/{sessionId}/mcp
```

This endpoint serves:

1. **Platform tools** allowed by the session's profile (toolkit registry, scoped at creation time)
2. Session context injected into tool calls (`sessionId`, `profileName`, `runId`, delegation depth)

The runner sends `sessionMcpUrl` in the run envelope to the sidecar. The sidecar connects its MCP client to this URL to discover and invoke platform tools. External MCP servers from the profile are opened by the sidecar alongside the runner MCP client.

<Note>
  The MCP endpoint is only available while the session is `idle` or `running`. It is torn down on `shutdown`.
</Note>

***

## Managing Sessions

### List Sessions

```bash theme={null}
curl https://api.orcapods.ai/api/sessions
```

```json theme={null}
[
  {
    "id": "sess-a1b2c3d4-e5f6a7b8",
    "profile": "researcher",
    "runtime": "general",
    "status": "idle",
    "createdAt": "2026-04-25T10:00:00Z",
    "lastUsedAt": "2026-04-25T10:05:32Z",
    "lastPrompt": "Summarize...",
    "lastRunStatus": "ok",
    "runCount": 3
  }
]
```

### Get a Specific Session

```bash theme={null}
curl https://api.orcapods.ai/api/sessions/sess-a1b2c3d4-e5f6g7h8
```

### Session Health (Runner-Direct)

```bash theme={null}
curl http://runner:7070/runner/sessions/sess-a1b2c3d4-e5f6g7h8/health
```

### Terminate a Session

```bash theme={null}
curl -X DELETE https://api.orcapods.ai/api/sessions/sess-a1b2c3d4-e5f6g7h8
```

***

## Session Reuse

Orca reuses a session when a new run explicitly supplies `sessionId` and:

1. The session was created with the same profile
2. The session is not already running
3. The runner that owns the session is healthy

When `sessionId` is omitted, `POST /api/runs` creates a fresh session for that run. You can see session placement and counts with the topology endpoint whenever the conductor has a runner pool, including a single-runner deployment:

```bash theme={null}
curl https://api.orcapods.ai/api/topology
```

***

## Session Persistence

<Warning>
  Runner-resident resources are still live state. A runner restart tears down the MCP endpoint, toolkit snapshot, and attached sandbox/VFS handles for that process until the conductor hydrates the session on a runner again.
</Warning>

When Postgres is configured, the conductor persists tenant-scoped session rows. The `status` lives in a flat column; flexible session metadata is stored in `metadata` JSONB:

| Metadata field     | Purpose                                                                                                         |
| ------------------ | --------------------------------------------------------------------------------------------------------------- |
| `runtime`          | Runtime selected by the profile, such as `general`, `claude`, or `codex`                                        |
| `lastUsedAt`       | Last activity timestamp used for listing and ordering                                                           |
| `runtimeSessionId` | Runtime-native conversation handle: Claude SDK `session_id` or Codex `thread_id`; empty for the general runtime |
| `stateRev`         | Count of persisted state-bundle uploads; zero means no bundle has been persisted yet                            |

For resumable runtimes, the conductor can export the sidecar's opaque state bundle and later hydrate a runner session with the same Orca session id, runtime-native session id, and bundle content. Hydration is best-effort: if no bundle exists or a sidecar cannot restore it, the runner still recreates the session record so the next run can proceed.

In production, callers should still be prepared for state recovery to degrade. The default behavior is:

* Conductor creates a new session automatically when a run is submitted without `sessionId`
* Runs should contain enough context in their task prompt to tolerate a missing or stale runtime-local state bundle

***

## Toolkit Scoping

When a session is created, the runner takes a **snapshot** of the profile's `tools` list and intersects it with the runner's registry. This view is immutable for the session's lifetime:

```
Profile tools: ["web_search", "web_extract", "time_now"]
Runner registry: [all platform tools]

Session toolkit: {"web_search": ToolSpec, "web_extract": ToolSpec, "time_now": ToolSpec}
```

If the profile is edited after session creation, existing sessions are **not affected**.

Calling a tool outside the session toolkit returns `HTTP 403`.

***

## Multi-Session Topology

The **Runtime** page in the dashboard (and `GET /api/topology`) shows:

* Which runner each session is assigned to
* Current session status across all runners
* Runner capabilities, health, and membership state (`live`, `draining`, or `unreachable`)
* Runner process footprint and session counts by runtime
* Sidecar slot state and the worker instances observed behind each slot

The worker list is a lower bound rather than a replica count, and null process
or worker statistics mean that the process has not been probed yet. The page
also treats a `cold` sidecar as configured-but-quiet rather than unhealthy.

This is useful for load-balancing debugging and capacity planning.

***

## Public Chat Sessions

When a profile is published through the [Chat Gateway](/concepts/publishing), public callers never see a session id. Each `conv_...` row in `conversations` pins one stable `conversation_id` to a runtime `session_id`, so threading `conversation_id` across requests reuses the same backing session. See [Publishing](/concepts/publishing#conversations-and-public-runs) for the conversation-to-session mapping.
