Session Foreground/Background State Management in the Copilot SDK

The Copilot SDK distinguishes between foreground and background sessions to enable TUI+server mode, exposing getForegroundSessionId() and setForegroundSessionId() methods alongside typed lifecycle events for state synchronization.

The github/copilot-sdk repository provides a TypeScript client for managing interactive AI sessions with fine-grained control over foreground and background state. Session foreground/background state management allows developers to display one active session in the terminal UI while keeping other sessions processing in the background. This architecture supports complex workflows where agents continue running compaction tasks or background operations while the user interacts with a specific foreground session.

Understanding Foreground vs. Background Sessions

The SDK implements a strict separation between the session currently visible to the user and those running unattended.

Foreground Session

A foreground session represents the single session currently displayed in the TUI. Only one session can occupy the foreground state at any given time, ensuring the UI presents a coherent view of exactly one conversation or agent context.

Background Session

A background session encompasses any session not currently displayed in the TUI but which may still be actively running agents, background agents, or compaction tasks. These sessions continue processing without blocking the user interface, enabling asynchronous workflows and long-running computations.

TypeScript Types and Lifecycle Events

The SDK models state transitions using discriminated unions defined in nodejs/src/types.ts (lines 59-79). The SessionLifecycleEvent union type uses a type field to determine the concrete shape of the event payload, providing type-safe event handling throughout the application lifecycle.

The SDK emits typed events whenever a session is created, deleted, updated, or changes its foreground/background status. Key event types include:

  • session.foreground – Emitted when a session enters the foreground state
  • session.background – Emitted when a session moves to the background

These events carry full session metadata including creation time and workspace path, allowing handlers to maintain synchronized UI state.

Client API for Foreground Control

The CopilotClient class in nodejs/src/client.ts exposes high-level methods for querying and manipulating the foreground session (implemented in lines 40-78).

Retrieving the Current Foreground Session

The getForegroundSessionId() method sends the RPC session.getForeground to the server and returns the current foreground session ID, or undefined if no session is currently active.

Switching Foreground Sessions

The setForegroundSessionId(sessionId) method sends the RPC session.setForeground to switch the TUI to display the specified session. This operation throws an error if the session does not exist or the server rejects the transition.

Subscribing to State Changes

Developers can react to lifecycle events using the overloaded onLifecycle method (implemented in nodejs/src/client.ts lines 99-115). This method returns an unsubscribe function for cleanup.

When a session moves to the foreground, the SDK emits a SessionForegroundEvent. When sent to the background, it emits a SessionBackgroundEvent. Both events contain the complete session metadata necessary to update UI components or trigger side effects.

RPC Layer and Server Requirements

The underlying communication relies on RPC methods defined in nodejs/src/generated/rpc.ts. The relevant methods are:

  • session.getForeground – Queries the current foreground state
  • session.setForeground – Requests a foreground transition

Both methods require a live connection to a Copilot server that was launched with the --ui-server flag. Attempting to call these methods against a standard server instance will result in connection errors.

Background Compaction and Automatic Transitions

The SDK automatically manages background work such as context-window compaction. When context utilization exceeds the configurable backgroundCompactionThreshold in the client options, the runtime initiates a background compaction task.

During heavy background processing, the runtime may emit session.background events to indicate that the foreground session is being preempted by background activity, allowing applications to update their UI state accordingly.

Complete Implementation Example

The following example demonstrates connecting to a UI server, querying the current foreground session, switching sessions, and subscribing to lifecycle events:

import { CopilotClient } from "@github/copilot-sdk";

// 1️⃣ Connect to a server that was started with `--ui-server`
const client = await CopilotClient.startInProcessFfi({ mode: "ui-server" });

// 2️⃣ Get the current foreground session (if any)
const currentId = await client.getForegroundSessionId();
if (currentId) {
  console.log(`TUI currently shows session ${currentId}`);
}

// 3️⃣ Switch the TUI to a specific session
await client.setForegroundSessionId("session-42");

// 4️⃣ React to foreground/background changes
const unsubscribe = client.onLifecycle("session.foreground", (event) => {
  console.log(`Session ${event.sessionId} entered foreground`);
});

client.onLifecycle("session.background", (event) => {
  console.log(`Session ${event.sessionId} moved to background`);
});

// When you no longer need the notifications
// unsubscribe();

Summary

  • Single foreground constraint: Only one session can be in the foreground at a time, enforced by the setForegroundSessionId() method in nodejs/src/client.ts.
  • Type-safe events: The SessionLifecycleEvent union in nodejs/src/types.ts provides discriminated types for session.foreground and session.background events.
  • RPC dependency: Foreground operations require RPC methods defined in nodejs/src/generated/rpc.ts and a server launched with --ui-server.
  • Automatic background handling: The SDK monitors backgroundCompactionThreshold and emits background events when automatic compaction preempts foreground sessions.
  • Subscription model: The onLifecycle() method (lines 99-115 of nodejs/src/client.ts) enables reactive UI updates with proper cleanup via returned unsubscribe functions.

Frequently Asked Questions

How do I check which session is currently in the foreground?

Call await client.getForegroundSessionId() on your CopilotClient instance. This method queries the RPC layer using session.getForeground and returns the active session ID or undefined if no session is currently displayed. According to the source code in nodejs/src/client.ts (lines 40-78), this operation requires an active connection to a server running in TUI+server mode.

Can multiple sessions be in the foreground simultaneously?

No. The Copilot SDK enforces a strict single-foreground constraint. Only one session can be displayed in the TUI at any given time, as defined by the ForegroundSessionInfo type in nodejs/src/types.ts. Attempting to switch foreground sessions using setForegroundSessionId() will move the previous foreground session to the background state automatically.

What triggers a session to move to the background?

Sessions move to the background when setForegroundSessionId() is called with a different session ID, or when the runtime initiates automatic compaction that exceeds the backgroundCompactionThreshold. The SDK emits SessionBackgroundEvent events via the session.background lifecycle event type, defined in the SessionLifecycleEvent union at lines 59-79 of nodejs/src/types.ts.

How do I listen for foreground/background state changes?

Use the onLifecycle() method available on the CopilotClient instance. Subscribe to "session.foreground" events to detect when sessions enter the foreground, and "session.background" events to detect when they exit. The implementation in nodejs/src/client.ts (lines 99-115) returns an unsubscribe function that you should call during component unmounting or shutdown to prevent memory leaks.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →