Skip to main content
Sessions are independent conversation contexts in ACP. Each session maintains its own history, state, and configuration, allowing multiple parallel conversations with an agent.

What are Sessions?

A session represents a distinct conversation between a user and an agent. Sessions provide:
  • Independent Context - Each session has its own conversation history
  • Isolated State - Configuration and mode changes don’t affect other sessions
  • Persistent Identity - Sessions can be saved, loaded, and resumed
  • MCP Connections - Each session connects to its own set of MCP servers
Think of sessions like browser tabs - each is independent but part of the same application.

Session Lifecycle

Sessions progress through several states:

Creating Sessions

New Sessions

Create a new session with session/new:
src/acp.ts
const session = await agent.newSession({
  cwd: "/path/to/project",
  mcpServers: [
    {
      type: "stdio",
      command: "npx",
      args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
    }
  ]
});

console.log(session.sessionId); // "session-abc123"
console.log(session.availableModes); // [{ id: "code", name: "Code" }, ...]
The agent returns a unique sessionId that must be included in all subsequent requests for this session.

Session ID Format

src/schema/types.gen.ts
export type SessionId = string;
Session IDs are opaque strings generated by the agent. Clients should treat them as opaque identifiers.

Loading Sessions

Load an existing session to restore conversation history:
src/acp.ts
await agent.loadSession({
  sessionId: "session-abc123",
  mcpServers: [
    // MCP servers to connect
  ]
});

// Agent streams the entire conversation history via session/update notifications
// Client receives each message and tool call in order
Loading sessions requires the agent to advertise loadSession: true in its capabilities.

How Loading Works

  1. Client sends session/load request with existing session ID
  2. Agent restores session state from storage
  3. Agent streams conversation history via session/update notifications
  4. Client rebuilds UI state from the streamed messages
  5. Agent responds when streaming is complete
  6. Session ready for new prompts

Resuming Sessions (Unstable)

Resume a session without replaying history:
src/acp.ts
await agent.unstable_resumeSession({
  sessionId: "session-abc123",
  mcpServers: []
});

// Agent restores context but doesn't stream history
// Useful when client already has the history
This is an unstable feature (unstable_resumeSession) and may change in future versions.

Forking Sessions (Unstable)

Create a new session based on an existing one:
src/acp.ts
const fork = await agent.unstable_forkSession({
  sessionId: "session-abc123",
  mcpServers: []
});

console.log(fork.sessionId); // "session-xyz789" (new ID)

// Fork has same history as original but is now independent
// Changes to fork don't affect original session

Use Cases for Forking

  • Generate Summaries - Fork to create a summary without affecting main conversation
  • Try Alternatives - Fork to explore different approaches in parallel
  • Experimentation - Test agent behavior without modifying original session

Listing Sessions (Unstable)

Query available sessions:
src/acp.ts
const response = await agent.unstable_listSessions({
  cwd: "/path/to/project", // Optional: filter by directory
  cursor: null // Optional: for pagination
});

for (const session of response.sessions) {
  console.log(session.sessionId);
  console.log(session.title);
  console.log(session.lastUpdateTime);
  console.log(session.cwd);
}

// Handle pagination
if (response.cursor) {
  const nextPage = await agent.unstable_listSessions({
    cursor: response.cursor
  });
}

Session State Management

Session Modes

Agents can support different operational modes that affect behavior:
src/acp.ts
// Set the mode for a session
await agent.setSessionMode({
  sessionId: "session-abc123",
  mode: "code" // or "ask", "architect", etc.
});
Modes typically affect:
  • System prompts - Different instructions for the LLM
  • Tool availability - Which tools are accessible
  • Permission behavior - Automatic vs. manual approval
Available modes are returned in NewSessionResponse.availableModes and LoadSessionResponse.availableModes.

Session Configuration

Set configuration options for a session:
src/acp.ts
const response = await agent.setSessionConfigOption({
  sessionId: "session-abc123",
  optionId: "temperature",
  valueId: "high"
});

// Response contains all current configuration
console.log(response.configOptions);

Session Model (Unstable)

Select which LLM to use for a session:
src/acp.ts
await agent.unstable_setSessionModel({
  sessionId: "session-abc123",
  modelId: "claude-opus-4"
});

Processing Prompts

Once a session is created, send prompts to the agent:
src/acp.ts
const response = await agent.prompt({
  sessionId: "session-abc123",
  messages: [
    {
      role: "user",
      content: {
        type: "text",
        text: "Help me fix the bug in utils.ts"
      }
    }
  ]
});

console.log(response.stopReason); // "endTurn", "cancelled", etc.

Prompt Lifecycle

Receiving Updates

Clients receive real-time updates via notifications:
class MyClient implements Client {
  async sessionUpdate(params: SessionNotification) {
    console.log("Session ID:", params.sessionId);
    
    if (params.content) {
      // Message chunk
      console.log("Content:", params.content);
    }
    
    if (params.toolCallUpdate) {
      // Tool call progress
      console.log("Tool call:", params.toolCallUpdate);
    }
    
    if (params.currentModeUpdate) {
      // Mode changed
      console.log("New mode:", params.currentModeUpdate);
    }
  }
}

Cancelling Operations

Cancel an ongoing prompt:
src/acp.ts
await agent.cancel({
  sessionId: "session-abc123"
});

// Agent should:
// 1. Stop all LLM requests
// 2. Abort tool call invocations  
// 3. Send any pending updates
// 4. Respond with stopReason: "cancelled"
The agent may send additional session/update notifications before responding with the cancelled status.

Session Persistence

Agents are responsible for persisting session state:
class MyAgent implements Agent {
  private sessions = new Map<string, SessionState>();
  
  async newSession(params) {
    const sessionId = crypto.randomUUID();
    const state = {
      id: sessionId,
      cwd: params.cwd,
      messages: [],
      mode: "code"
    };
    
    this.sessions.set(sessionId, state);
    await this.saveToDatabase(state);
    
    return { sessionId, availableModes: [...] };
  }
  
  async loadSession(params) {
    const state = await this.loadFromDatabase(params.sessionId);
    this.sessions.set(params.sessionId, state);
    
    // Stream history to client
    for (const message of state.messages) {
      await this.connection.sessionUpdate({
        sessionId: params.sessionId,
        content: message.content
      });
    }
    
    return { availableModes: [...] };
  }
}

Best Practices

Always validate that session IDs exist and are accessible:
async prompt(params: PromptRequest) {
  if (!this.sessions.has(params.sessionId)) {
    throw RequestError.invalidParams(
      { sessionId: params.sessionId },
      "Session not found"
    );
  }
  // Process prompt
}
Every session-related operation requires the session ID:
// ✅ Correct
await agent.prompt({ sessionId, messages: [...] });
await connection.sessionUpdate({ sessionId, content: {...} });

// ❌ Wrong - missing sessionId
await agent.prompt({ messages: [...] });
When loading sessions, batch updates to avoid overwhelming the client:
// Send updates in chunks
const CHUNK_SIZE = 10;
for (let i = 0; i < messages.length; i += CHUNK_SIZE) {
  const chunk = messages.slice(i, i + CHUNK_SIZE);
  for (const msg of chunk) {
    await connection.sessionUpdate({...});
  }
  // Small delay between chunks
  await new Promise(resolve => setTimeout(resolve, 10));
}
Clean up resources when sessions end:
connection.signal.addEventListener('abort', () => {
  // Clean up all active sessions
  for (const [id, session] of this.sessions) {
    session.mcpConnections.forEach(conn => conn.close());
    this.sessions.delete(id);
  }
});

Session Information

Sessions include metadata for organization:
interface SessionInfo {
  sessionId: string;
  title: string | null;
  lastUpdateTime: string; // ISO 8601
  cwd: string;
}

MCP Server Connections

Each session can connect to MCP servers for additional tools:
const session = await agent.newSession({
  cwd: "/project",
  mcpServers: [
    {
      type: "stdio",
      command: "npx",
      args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
    },
    {
      type: "sse",
      url: "https://api.example.com/mcp"
    }
  ]
});
MCP servers are connected at session creation/load and provide tools and resources to the agent.

Learn More

Protocol Overview

Understanding the ACP specification

Connections

Establishing agent-client connections

Session Setup

Full specification for session operations

Prompt Turn

How prompts are processed in sessions

Build docs developers (and LLMs) love