> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/pingdotgg/t3code/llms.txt
> Use this file to discover all available pages before exploring further.

# Sessions

> Understanding provider sessions, lifecycle, and state management

A **session** represents an active connection between T3 Code and a provider (currently Codex). Sessions manage conversation threads, turn execution, and maintain stateful connections to the underlying agent infrastructure.

## Session Lifecycle

Sessions progress through distinct states during their lifetime:

<Steps>
  <Step title="Connecting">
    The server spawns a `codex app-server` process and establishes JSON-RPC communication over stdio.
  </Step>

  <Step title="Ready">
    The session is idle and ready to accept new turns. No active agent execution is in progress.
  </Step>

  <Step title="Running">
    A turn is actively executing. The agent is processing user input, running tools, or generating responses.
  </Step>

  <Step title="Error">
    A recoverable error occurred. The session may be able to continue with intervention.
  </Step>

  <Step title="Closed">
    The session has been terminated and can no longer accept commands.
  </Step>
</Steps>

## Session Schema

Sessions are represented by the `ProviderSession` type:

```typescript packages/contracts/src/provider.ts theme={null}
export const ProviderSession = Schema.Struct({
  provider: ProviderKind,              // "codex"
  status: ProviderSessionStatus,        // Current state
  runtimeMode: RuntimeMode,             // "full-access" | "approval-required"
  cwd: Schema.optional(TrimmedNonEmptyStringSchema),
  model: Schema.optional(TrimmedNonEmptyStringSchema),
  threadId: ThreadId,
  resumeCursor: Schema.optional(Schema.Unknown),
  activeTurnId: Schema.optional(TurnId),
  createdAt: IsoDateTime,
  updatedAt: IsoDateTime,
  lastError: Schema.optional(TrimmedNonEmptyStringSchema),
});
```

<Note>
  The `resumeCursor` field stores provider-specific state needed to resume a thread after restart. For Codex, this contains the provider's internal thread ID.
</Note>

## Starting a Session

Sessions are started via the `ProviderService.startSession` method:

```typescript theme={null}
interface ProviderSessionStartInput {
  threadId: ThreadId;
  provider?: "codex";
  cwd?: string;                    // Working directory
  model?: string;                  // Model identifier
  resumeCursor?: unknown;          // Resume existing thread
  runtimeMode: RuntimeMode;        // Approval policy
  providerOptions?: {              // Provider-specific config
    codex?: {
      binaryPath?: string;
      homePath?: string;
    };
  };
}
```

<CodeGroup>
  ```typescript Starting a New Session theme={null}
  const session = await providerService.startSession(threadId, {
    threadId,
    provider: "codex",
    cwd: "/path/to/workspace",
    model: "gpt-5.4",
    runtimeMode: "full-access",
  });
  ```

  ```typescript Resuming an Existing Session theme={null}
  const session = await providerService.startSession(threadId, {
    threadId,
    provider: "codex",
    runtimeMode: "full-access",
    resumeCursor: { threadId: "previous-thread-id" },
  });
  ```
</CodeGroup>

## Session Resume Behavior

When a `resumeCursor` is provided, T3 Code attempts to resume the existing Codex thread:

<Steps>
  <Step title="Resume Attempt">
    Send `thread/resume` JSON-RPC request to Codex app-server with the provider thread ID
  </Step>

  <Step title="Success Path">
    If resume succeeds, the session reconnects to the existing thread state
  </Step>

  <Step title="Fallback Path">
    If resume fails with a recoverable error (thread not found, missing thread), automatically fall back to starting a fresh thread
  </Step>

  <Step title="Error Path">
    If resume fails with an unrecoverable error, the session transitions to error state
  </Step>
</Steps>

```typescript apps/server/src/codexAppServerManager.ts theme={null}
if (resumeThreadId) {
  try {
    threadOpenMethod = "thread/resume";
    threadOpenResponse = await this.sendRequest(context, "thread/resume", {
      ...sessionOverrides,
      threadId: resumeThreadId,
    });
  } catch (error) {
    if (!isRecoverableThreadResumeError(error)) {
      throw error; // Unrecoverable
    }
    
    // Fallback to fresh start
    threadOpenMethod = "thread/start";
    threadOpenResponse = await this.sendRequest(
      context,
      "thread/start",
      threadStartParams
    );
  }
}
```

<Warning>
  **Recoverable Resume Errors**: Errors containing snippets like "not found", "missing thread", "no such thread", "unknown thread", or "does not exist" trigger automatic fallback to a fresh thread start.
</Warning>

## Session Events

Sessions emit lifecycle events through the provider event stream:

<Accordion title="session/connecting">
  Emitted when the session begins connecting to the provider.

  ```typescript theme={null}
  {
    kind: "session",
    method: "session/connecting",
    message: "Starting codex app-server"
  }
  ```
</Accordion>

<Accordion title="session/threadOpenRequested">
  Emitted when attempting to open or resume a thread.

  ```typescript theme={null}
  {
    kind: "session",
    method: "session/threadOpenRequested",
    message: "Attempting to resume thread abc123."
  }
  ```
</Accordion>

<Accordion title="session/threadResumeFallback">
  Emitted when resume fails and falls back to fresh start.

  ```typescript theme={null}
  {
    kind: "session",
    method: "session/threadResumeFallback",
    message: "Could not resume thread abc123; started a new thread instead."
  }
  ```
</Accordion>

<Accordion title="session/ready">
  Emitted when the session is ready to accept turns.

  ```typescript theme={null}
  {
    kind: "session",
    method: "session/ready",
    message: "Connected to thread abc123"
  }
  ```
</Accordion>

<Accordion title="session/closed">
  Emitted when the session has been closed.

  ```typescript theme={null}
  {
    kind: "session",
    method: "session/closed",
    message: "Session stopped"
  }
  ```
</Accordion>

## Sending Turns

Once a session is ready, you can send turns to the agent:

```typescript theme={null}
interface ProviderSendTurnInput {
  threadId: ThreadId;
  input?: string;                        // User message text
  attachments?: ChatAttachment[];        // Images, etc.
  model?: string;                        // Override model
  interactionMode?: "default" | "plan";  // Interaction mode
}

const result = await providerService.sendTurn({
  threadId,
  input: "Add error handling to the API routes",
  interactionMode: "default",
});

// result.turnId - Identifier for this turn
// result.resumeCursor - Updated resume state
```

<Note>
  When a turn starts, the session transitions from `ready` to `running` state and sets `activeTurnId` to the new turn's ID.
</Note>

## Turn Lifecycle

Turns represent discrete agent execution cycles:

```typescript theme={null}
type TurnState =
  | "running"      // Turn is executing
  | "interrupted"  // User interrupted
  | "completed"    // Turn finished successfully
  | "error";       // Turn failed
```

### Turn Events

Turns emit various events during execution:

<CardGroup cols={2}>
  <Card title="turn/started" icon="play">
    Turn execution has begun
  </Card>

  <Card title="turn/completed" icon="check">
    Turn finished (success or error)
  </Card>

  <Card title="item/agentMessage/delta" icon="message">
    Streaming text from agent response
  </Card>

  <Card title="item/tool/started" icon="wrench">
    Tool execution started
  </Card>
</CardGroup>

## Interrupting Turns

Active turns can be interrupted:

```typescript theme={null}
await providerService.interruptTurn({
  threadId,
  turnId, // Optional: defaults to active turn
});
```

When interrupted:

1. Session status changes to "ready"
2. `activeTurnId` is cleared
3. Partial work may be retained depending on provider behavior

## Stopping Sessions

Sessions can be explicitly stopped:

```typescript theme={null}
await providerService.stopSession({ threadId });
```

Stopping a session:

1. Cancels any active turns
2. Rejects pending approval requests
3. Kills the `codex app-server` process
4. Removes the session from the active session directory
5. Emits `session/closed` event

<Warning>
  Stopped sessions cannot be restarted. You must create a new session, optionally with a `resumeCursor` to continue the conversation.
</Warning>

## Session Directory

The `ProviderSessionDirectory` tracks active sessions:

```typescript theme={null}
interface ProviderSessionDirectory {
  // Register a new session
  register(session: ProviderSession): Effect;
  
  // Update session state
  update(threadId: ThreadId, updates: Partial<ProviderSession>): Effect;
  
  // Get session by thread ID
  get(threadId: ThreadId): Effect<ProviderSession | undefined>;
  
  // Remove session
  remove(threadId: ThreadId): Effect;
  
  // List all active sessions
  list(): Effect<ReadonlyArray<ProviderSession>>;
}
```

## Provider-Specific Session Features

### Codex Sessions

Codex sessions support additional capabilities:

<Accordion title="Thread Snapshots">
  Read the full conversation history:

  ```typescript theme={null}
  const snapshot = await codexAdapter.readThread(threadId);
  // snapshot.turns - Array of turns with items
  ```
</Accordion>

<Accordion title="Thread Rollback">
  Rewind conversation state by N turns:

  ```typescript theme={null}
  await codexAdapter.rollbackThread(threadId, numTurns);
  ```
</Accordion>

<Accordion title="Account Detection">
  Codex sessions detect account type and plan:

  ```typescript theme={null}
  type CodexAccountType = "apiKey" | "chatgpt" | "unknown";

  // Affects model availability (e.g., Spark model restrictions)
  ```
</Accordion>

## Best Practices

<CardGroup cols={2}>
  <Card title="Always Store Resume Cursor" icon="bookmark">
    Save `resumeCursor` after each successful operation to enable seamless restarts
  </Card>

  <Card title="Handle Resume Failures" icon="rotate">
    Be prepared for resume to fall back to fresh thread start
  </Card>

  <Card title="Monitor Session Status" icon="heart-pulse">
    Watch for status transitions to handle errors and completion
  </Card>

  <Card title="Clean Up Sessions" icon="trash">
    Explicitly stop sessions when done to free resources
  </Card>
</CardGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Runtime Modes" icon="shield" href="/concepts/runtime-modes">
    Configure approval policies and sandbox modes
  </Card>

  <Card title="Providers" icon="robot" href="/concepts/providers">
    Learn about provider adapter architecture
  </Card>

  <Card title="Architecture" icon="diagram-project" href="/concepts/architecture">
    Understand the overall system design
  </Card>
</CardGroup>
