From 6f8100768e1f2899936bd230a432ae2ff07f41c6 Mon Sep 17 00:00:00 2001 From: Egor Baranov Date: Tue, 24 Mar 2026 21:58:47 +0100 Subject: [PATCH 1/9] feat: implement additional directories --- docs/protocol/draft/schema.mdx | 45 +++++++ docs/protocol/file-system.mdx | 7 +- docs/protocol/initialization.mdx | 5 + docs/protocol/schema.mdx | 39 ++++++ docs/protocol/session-list.mdx | 32 ++++- docs/protocol/session-setup.mdx | 25 +++- docs/rfds/session-info-update.mdx | 2 +- schema/schema.json | 50 ++++++++ schema/schema.unstable.json | 64 ++++++++++ src/agent.rs | 206 ++++++++++++++++++++++++++++++ 10 files changed, 467 insertions(+), 8 deletions(-) diff --git a/docs/protocol/draft/schema.mdx b/docs/protocol/draft/schema.mdx index d9a81347..918310b3 100644 --- a/docs/protocol/draft/schema.mdx +++ b/docs/protocol/draft/schema.mdx @@ -355,6 +355,9 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + +<>"string"[] | null} > + Additional workspace roots to activate for this session. Each path must be absolute. The working directory for this session. @@ -433,6 +436,9 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + +<>"string"[] | null} > + Filter sessions by the exact ordered additional workspace roots. Each path must be absolute. Opaque cursor token from a previous response's nextCursor field for cursor-based pagination @@ -499,6 +505,9 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + +<>"string"[] | null} > + Additional workspace roots to activate for this session. Each path must be absolute. The working directory for this session. @@ -578,6 +587,13 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + +<>"string"[] | null} > + Additional workspace roots for this session. Each path must be absolute. + +These expand the session's filesystem scope without changing `cwd`, which +remains the base for relative paths. + The working directory for this session. Must be an absolute path. @@ -776,6 +792,9 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + +<>"string"[] | null} > + Additional workspace roots to activate for this session. Each path must be absolute. The working directory for this session. @@ -4165,6 +4184,26 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte The ID of the option the user selected. +## SessionAdditionalDirectoriesCapabilities + +Capabilities for additional session directories support. + +By supplying `\{\}` it means that the agent supports the `additionalDirectories` field on +session lifecycle requests and `session/list`. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + + ## SessionCapabilities Session capabilities supported by the agent. @@ -4188,6 +4227,9 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + +SessionAdditionalDirectoriesCapabilities | null} > + Whether the agent supports `additionalDirectories` on session lifecycle requests and `session/list`. SessionCloseCapabilities | null} > **UNSTABLE** @@ -4493,6 +4535,9 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + +<>"string"[] | null} > + Authoritative ordered additional workspace roots for this session. Each path must be absolute. The working directory for this session. Must be an absolute path. diff --git a/docs/protocol/file-system.mdx b/docs/protocol/file-system.mdx index c16b2baf..97888ad0 100644 --- a/docs/protocol/file-system.mdx +++ b/docs/protocol/file-system.mdx @@ -5,6 +5,8 @@ description: "Client filesystem access methods" The filesystem methods allow Agents to read and write text files within the Client's environment. These methods enable Agents to access unsaved editor state and allow Clients to track file modifications made during agent execution. +Filesystem `path` values are always absolute. If a session was created with [`additionalDirectories`](./session-setup#additional-directories), Clients that enforce workspace boundaries **MUST** authorize `fs/*` requests against the full ordered root set `[cwd, ...additionalDirectories]`, not `cwd` alone. + ## Checking Support Before attempting to use filesystem methods, Agents **MUST** verify that the Client supports these capabilities by checking the [Client Capabilities](./initialization#client-capabilities) field in the `initialize` response: @@ -50,7 +52,8 @@ The `fs/read_text_file` method allows Agents to read text file contents from the - Absolute path to the file to read + Absolute path to the file to read. Clients that enforce session workspace + boundaries validate this path against the session's effective root set. @@ -99,6 +102,8 @@ Absolute path to the file to write. The Client **MUST** create the file if it doesn't exist. +Clients that enforce session workspace boundaries validate this path against the session's effective root set. + diff --git a/docs/protocol/initialization.mdx b/docs/protocol/initialization.mdx index a2b55b73..f49f885b 100644 --- a/docs/protocol/initialization.mdx +++ b/docs/protocol/initialization.mdx @@ -71,6 +71,9 @@ The Agent **MUST** respond with the chosen [protocol version](#protocol-version) "mcp": { "http": true, "sse": true + }, + "sessionCapabilities": { + "additionalDirectories": {} } }, "agentInfo": { @@ -197,6 +200,8 @@ Optionally, they **MAY** support other session methods and notifications by spec This will be unified in future versions of the protocol. +Agents that support multi-root session workspaces advertise `sessionCapabilities.additionalDirectories`. Clients **MUST** only send `additionalDirectories` on session lifecycle requests or `session/list` when that capability is present. + ## Implementation Information Both Clients and Agents **SHOULD** provide information about their implementation in the `clientInfo` and `agentInfo` fields respectively. Both take the following three fields: diff --git a/docs/protocol/schema.mdx b/docs/protocol/schema.mdx index 79b6693e..41e378a3 100644 --- a/docs/protocol/schema.mdx +++ b/docs/protocol/schema.mdx @@ -222,6 +222,9 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + +<>"string"[] | null} > + Filter sessions by the exact ordered additional workspace roots. Each path must be absolute. Opaque cursor token from a previous response's nextCursor field for cursor-based pagination @@ -288,6 +291,9 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + +<>"string"[] | null} > + Additional workspace roots to activate for this session. Each path must be absolute. The working directory for this session. @@ -359,6 +365,13 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + +<>"string"[] | null} > + Additional workspace roots for this session. Each path must be absolute. + +These expand the session's filesystem scope without changing `cwd`, which +remains the base for relative paths. + The working directory for this session. Must be an absolute path. @@ -2567,6 +2580,26 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte The ID of the option the user selected. +## SessionAdditionalDirectoriesCapabilities + +Capabilities for additional session directories support. + +By supplying `\{\}` it means that the agent supports the `additionalDirectories` field on +session lifecycle requests and `session/list`. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + + ## SessionCapabilities Session capabilities supported by the agent. @@ -2590,6 +2623,9 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + +SessionAdditionalDirectoriesCapabilities | null} > + Whether the agent supports `additionalDirectories` on session lifecycle requests and `session/list`. SessionListCapabilities | null} > Whether the agent supports `session/list`. @@ -2786,6 +2822,9 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + +<>"string"[] | null} > + Authoritative ordered additional workspace roots for this session. Each path must be absolute. The working directory for this session. Must be an absolute path. diff --git a/docs/protocol/session-list.mdx b/docs/protocol/session-list.mdx index 6592b4e3..bf5b704f 100644 --- a/docs/protocol/session-list.mdx +++ b/docs/protocol/session-list.mdx @@ -3,7 +3,7 @@ title: "Session List" description: "Discovering existing sessions" --- -The `session/list` method allows Clients to discover sessions known to an Agent. Clients can use this to display session history and switch between sessions. +The `session/list` method allows Clients to discover sessions known to an Agent. Clients can use this to display session history, recover authoritative workspace roots, and switch between sessions. Agents can also push session metadata updates to Clients in real-time via the `session_info_update` notification, keeping session titles and metadata in sync without polling. @@ -36,7 +36,7 @@ sequenceDiagram Before attempting to list sessions, Clients **MUST** verify that the Agent supports this capability by checking the `sessionCapabilities.list` field in the `initialize` response: -```json highlight={7-9} +```json highlight={7-10} { "jsonrpc": "2.0", "id": 0, @@ -44,7 +44,8 @@ Before attempting to list sessions, Clients **MUST** verify that the Agent suppo "protocolVersion": 1, "agentCapabilities": { "sessionCapabilities": { - "list": {} + "list": {}, + "additionalDirectories": {} } } } @@ -53,6 +54,8 @@ Before attempting to list sessions, Clients **MUST** verify that the Agent suppo If `sessionCapabilities.list` is not present, the Agent does not support listing sessions and Clients **MUST NOT** attempt to call `session/list`. +If `sessionCapabilities.additionalDirectories` is present, Clients **MAY** use the `additionalDirectories` filter and rely on `SessionInfo.additionalDirectories` in the response. + ## Listing Sessions Clients discover existing sessions by calling the `session/list` method with optional filtering and pagination parameters: @@ -64,6 +67,7 @@ Clients discover existing sessions by calling the `session/list` method with opt "method": "session/list", "params": { "cwd": "/home/user/project", + "additionalDirectories": ["/home/user/shared", "/home/user/.agent/skills"], "cursor": "eyJwYWdlIjogMn0=" } } @@ -76,11 +80,20 @@ All parameters are optional. A request with an empty `params` object returns the with a matching `cwd` are returned. + + Filter sessions by the exact ordered `additionalDirectories` list. Each path + must be absolute. An empty array matches only sessions with no additional + directories. Clients **MUST** only send this field when the Agent advertises + `sessionCapabilities.additionalDirectories`. + + Opaque cursor token from a previous response's `nextCursor` field for cursor-based pagination. See [Pagination](#pagination). +When the Agent advertises `sessionCapabilities.additionalDirectories`, each returned `SessionInfo.additionalDirectories` value is the authoritative ordered additional-root list for that session. + The Agent **MUST** respond with a list of sessions and optional pagination metadata: ```json @@ -92,6 +105,10 @@ The Agent **MUST** respond with a list of sessions and optional pagination metad { "sessionId": "sess_abc123def456", "cwd": "/home/user/project", + "additionalDirectories": [ + "/home/user/shared", + "/home/user/.agent/skills" + ], "title": "Implement session list API", "updatedAt": "2025-10-29T14:22:15Z", "_meta": { @@ -102,12 +119,14 @@ The Agent **MUST** respond with a list of sessions and optional pagination metad { "sessionId": "sess_xyz789ghi012", "cwd": "/home/user/another-project", + "additionalDirectories": [], "title": "Debug authentication flow", "updatedAt": "2025-10-28T16:45:30Z" }, { "sessionId": "sess_uvw345rst678", "cwd": "/home/user/project", + "additionalDirectories": ["/home/user/shared"], "updatedAt": "2025-10-27T15:30:00Z" } ], @@ -126,6 +145,11 @@ The Agent **MUST** respond with a list of sessions and optional pagination metad Working directory for the session. Always an absolute path. + + Authoritative ordered additional workspace roots for the session. When + the Agent advertises `sessionCapabilities.additionalDirectories`, this + field is present and `[]` means the session has no additional roots. + Human-readable title for the session. May be auto-generated from the first prompt. @@ -190,7 +214,7 @@ All fields are optional. Only include fields that have changed — omitted field Agent-specific metadata. See [Extensibility](./extensibility). -The `sessionId` and `cwd` fields are **not** included in the update — `sessionId` is already in the notification's `params`, and `cwd` is immutable (set during [`session/new`](./session-setup#creating-a-session)). Agents typically send this notification after the first meaningful exchange to auto-generate a title. +The `sessionId`, `cwd`, and `additionalDirectories` fields are **not** included in the update — `sessionId` is already in the notification's `params`, `cwd` is immutable, and this method does not define mid-session mutation of additional roots. Agents typically send this notification after the first meaningful exchange to auto-generate a title. ## Interaction with Other Session Methods diff --git a/docs/protocol/session-setup.mdx b/docs/protocol/session-setup.mdx index f323f320..535f169d 100644 --- a/docs/protocol/session-setup.mdx +++ b/docs/protocol/session-setup.mdx @@ -42,6 +42,7 @@ sequenceDiagram Clients create a new session by calling the `session/new` method with: - The [working directory](#working-directory) for the session +- Optional [additional directories](#additional-directories) for the session workspace - A list of [MCP servers](#mcp-servers) the Agent should connect to ```json @@ -51,6 +52,7 @@ Clients create a new session by calling the `session/new` method with: "method": "session/new", "params": { "cwd": "/home/user/project", + "additionalDirectories": ["/home/user/shared", "/home/user/common"], "mcpServers": [ { "name": "filesystem", @@ -63,6 +65,8 @@ Clients create a new session by calling the `session/new` method with: } ``` +Clients **MUST** send `additionalDirectories` only when the Agent advertises `sessionCapabilities.additionalDirectories`. + The Agent **MUST** respond with a unique [Session ID](#session-id) that identifies this conversation: ```json @@ -105,6 +109,7 @@ To load an existing session, Clients **MUST** call the `session/load` method wit - The [Session ID](#session-id) to resume - [MCP servers](#mcp-servers) to connect to - The [working directory](#working-directory) +- The full intended [additional directories](#additional-directories) list when the Agent supports multi-root workspaces ```json { @@ -114,6 +119,7 @@ To load an existing session, Clients **MUST** call the `session/load` method wit "params": { "sessionId": "sess_789xyz", "cwd": "/home/user/project", + "additionalDirectories": ["/home/user/shared", "/home/user/.agent/skills"], "mcpServers": [ { "name": "filesystem", @@ -190,11 +196,26 @@ Clients use this ID to: ## Working Directory -The `cwd` (current working directory) parameter establishes the file system context for the session. This directory: +The `cwd` (current working directory) parameter establishes the primary file system context for the session. This directory: - **MUST** be an absolute path - **MUST** be used for the session regardless of where the Agent subprocess was spawned -- **SHOULD** serve as a boundary for tool operations on the file system +- **MUST** remain the base for relative path resolution +- **SHOULD** be treated as the primary root in the session workspace + +## Additional Directories + +Agents that advertise `sessionCapabilities.additionalDirectories` accept an optional `additionalDirectories` array on `session/new` and `session/load`. + +Each entry in `additionalDirectories`: + +- **MUST** be an absolute path +- Extends the session's filesystem scope without replacing `cwd` +- Becomes part of the session's effective ordered root set: `[cwd, ...additionalDirectories]` + +Relative paths continue to resolve against `cwd` only. + +On `session/load`, Clients **MUST** resend the full intended `additionalDirectories` list. If the field is omitted, the loaded session activates no additional directories. When [`session/list`](./session-list) is available, `SessionInfo.additionalDirectories` provides the authoritative current list for a session. ## MCP Servers diff --git a/docs/rfds/session-info-update.mdx b/docs/rfds/session-info-update.mdx index f25ab60b..49aa7b87 100644 --- a/docs/rfds/session-info-update.mdx +++ b/docs/rfds/session-info-update.mdx @@ -42,7 +42,7 @@ Add a new `session_info_update` variant to the existing `SessionUpdate` discrimi - Contains the same fields as `SessionInfo` from `session/list` - All fields are optional (partial updates) - Enables incremental metadata updates - - **Important**: `SessionInfoUpdate` must stay aligned with `SessionInfo` - when new fields are added to `SessionInfo`, they should also be added to `SessionInfoUpdate` as optional fields + - **Important**: `SessionInfoUpdate` must stay aligned with the mutable metadata fields of `SessionInfo` - immutable fields such as workspace roots do not need corresponding update fields 3. **Support common use cases**: - Agent auto-generates title after first prompt diff --git a/schema/schema.json b/schema/schema.json index 9aca01f4..988edc6b 100644 --- a/schema/schema.json +++ b/schema/schema.json @@ -1476,6 +1476,13 @@ "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", "type": ["object", "null"] }, + "additionalDirectories": { + "description": "Filter sessions by the exact ordered additional workspace roots. Each path must be absolute.", + "items": { + "type": "string" + }, + "type": ["array", "null"] + }, "cursor": { "description": "Opaque cursor token from a previous response's nextCursor field for cursor-based pagination", "type": ["string", "null"] @@ -1522,6 +1529,13 @@ "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", "type": ["object", "null"] }, + "additionalDirectories": { + "description": "Additional workspace roots to activate for this session. Each path must be absolute.", + "items": { + "type": "string" + }, + "type": ["array", "null"] + }, "cwd": { "description": "The working directory for this session.", "type": "string" @@ -1741,6 +1755,13 @@ "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", "type": ["object", "null"] }, + "additionalDirectories": { + "description": "Additional workspace roots for this session. Each path must be absolute.\n\nThese expand the session's filesystem scope without changing `cwd`, which\nremains the base for relative paths.", + "items": { + "type": "string" + }, + "type": ["array", "null"] + }, "cwd": { "description": "The working directory for this session. Must be an absolute path.", "type": "string" @@ -2306,6 +2327,17 @@ "required": ["optionId"], "type": "object" }, + "SessionAdditionalDirectoriesCapabilities": { + "description": "Capabilities for additional session directories support.\n\nBy supplying `{}` it means that the agent supports the `additionalDirectories` field on\nsession lifecycle requests and `session/list`.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + } + }, + "type": "object" + }, "SessionCapabilities": { "description": "Session capabilities supported by the agent.\n\nAs a baseline, all Agents **MUST** support `session/new`, `session/prompt`, `session/cancel`, and `session/update`.\n\nOptionally, they **MAY** support other session methods and notifications by specifying additional capabilities.\n\nNote: `session/load` is still handled by the top-level `load_session` capability. This will be unified in future versions of the protocol.\n\nSee protocol docs: [Session Capabilities](https://agentclientprotocol.com/protocol/initialization#session-capabilities)", "properties": { @@ -2314,6 +2346,17 @@ "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", "type": ["object", "null"] }, + "additionalDirectories": { + "anyOf": [ + { + "$ref": "#/$defs/SessionAdditionalDirectoriesCapabilities" + }, + { + "type": "null" + } + ], + "description": "Whether the agent supports `additionalDirectories` on session lifecycle requests and `session/list`." + }, "list": { "anyOf": [ { @@ -2540,6 +2583,13 @@ "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", "type": ["object", "null"] }, + "additionalDirectories": { + "description": "Authoritative ordered additional workspace roots for this session. Each path must be absolute.", + "items": { + "type": "string" + }, + "type": ["array", "null"] + }, "cwd": { "description": "The working directory for this session. Must be an absolute path.", "type": "string" diff --git a/schema/schema.unstable.json b/schema/schema.unstable.json index 081e1a1f..03fbe86f 100644 --- a/schema/schema.unstable.json +++ b/schema/schema.unstable.json @@ -2126,6 +2126,13 @@ "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", "type": ["object", "null"] }, + "additionalDirectories": { + "description": "Additional workspace roots to activate for this session. Each path must be absolute.", + "items": { + "type": "string" + }, + "type": ["array", "null"] + }, "cwd": { "description": "The working directory for this session.", "type": "string" @@ -2467,6 +2474,13 @@ "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", "type": ["object", "null"] }, + "additionalDirectories": { + "description": "Filter sessions by the exact ordered additional workspace roots. Each path must be absolute.", + "items": { + "type": "string" + }, + "type": ["array", "null"] + }, "cursor": { "description": "Opaque cursor token from a previous response's nextCursor field for cursor-based pagination", "type": ["string", "null"] @@ -2513,6 +2527,13 @@ "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", "type": ["object", "null"] }, + "additionalDirectories": { + "description": "Additional workspace roots to activate for this session. Each path must be absolute.", + "items": { + "type": "string" + }, + "type": ["array", "null"] + }, "cwd": { "description": "The working directory for this session.", "type": "string" @@ -2877,6 +2898,13 @@ "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", "type": ["object", "null"] }, + "additionalDirectories": { + "description": "Additional workspace roots for this session. Each path must be absolute.\n\nThese expand the session's filesystem scope without changing `cwd`, which\nremains the base for relative paths.", + "items": { + "type": "string" + }, + "type": ["array", "null"] + }, "cwd": { "description": "The working directory for this session. Must be an absolute path.", "type": "string" @@ -3484,6 +3512,13 @@ "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", "type": ["object", "null"] }, + "additionalDirectories": { + "description": "Additional workspace roots to activate for this session. Each path must be absolute.", + "items": { + "type": "string" + }, + "type": ["array", "null"] + }, "cwd": { "description": "The working directory for this session.", "type": "string" @@ -3576,6 +3611,17 @@ "required": ["optionId"], "type": "object" }, + "SessionAdditionalDirectoriesCapabilities": { + "description": "Capabilities for additional session directories support.\n\nBy supplying `{}` it means that the agent supports the `additionalDirectories` field on\nsession lifecycle requests and `session/list`.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + } + }, + "type": "object" + }, "SessionCapabilities": { "description": "Session capabilities supported by the agent.\n\nAs a baseline, all Agents **MUST** support `session/new`, `session/prompt`, `session/cancel`, and `session/update`.\n\nOptionally, they **MAY** support other session methods and notifications by specifying additional capabilities.\n\nNote: `session/load` is still handled by the top-level `load_session` capability. This will be unified in future versions of the protocol.\n\nSee protocol docs: [Session Capabilities](https://agentclientprotocol.com/protocol/initialization#session-capabilities)", "properties": { @@ -3584,6 +3630,17 @@ "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", "type": ["object", "null"] }, + "additionalDirectories": { + "anyOf": [ + { + "$ref": "#/$defs/SessionAdditionalDirectoriesCapabilities" + }, + { + "type": "null" + } + ], + "description": "Whether the agent supports `additionalDirectories` on session lifecycle requests and `session/list`." + }, "close": { "anyOf": [ { @@ -3892,6 +3949,13 @@ "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", "type": ["object", "null"] }, + "additionalDirectories": { + "description": "Authoritative ordered additional workspace roots for this session. Each path must be absolute.", + "items": { + "type": "string" + }, + "type": ["array", "null"] + }, "cwd": { "description": "The working directory for this session. Must be an absolute path.", "type": "string" diff --git a/src/agent.rs b/src/agent.rs index b8ce81de..f99a89fc 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -893,6 +893,12 @@ impl AuthMethodTerminal { pub struct NewSessionRequest { /// The working directory for this session. Must be an absolute path. pub cwd: PathBuf, + /// Additional workspace roots for this session. Each path must be absolute. + /// + /// These expand the session's filesystem scope without changing `cwd`, which + /// remains the base for relative paths. + #[serde(skip_serializing_if = "Option::is_none")] + pub additional_directories: Option>, /// List of MCP (Model Context Protocol) servers the agent should connect to. pub mcp_servers: Vec, /// The _meta property is reserved by ACP to allow clients and agents to attach additional @@ -909,11 +915,22 @@ impl NewSessionRequest { pub fn new(cwd: impl Into) -> Self { Self { cwd: cwd.into(), + additional_directories: None, mcp_servers: vec![], meta: None, } } + /// Additional workspace roots for this session. Each path must be absolute. + #[must_use] + pub fn additional_directories( + mut self, + additional_directories: impl IntoOption>, + ) -> Self { + self.additional_directories = additional_directories.into_option(); + self + } + /// List of MCP (Model Context Protocol) servers the agent should connect to. #[must_use] pub fn mcp_servers(mut self, mcp_servers: Vec) -> Self { @@ -1042,6 +1059,9 @@ pub struct LoadSessionRequest { pub mcp_servers: Vec, /// The working directory for this session. pub cwd: PathBuf, + /// Additional workspace roots to activate for this session. Each path must be absolute. + #[serde(skip_serializing_if = "Option::is_none")] + pub additional_directories: Option>, /// The ID of the session to load. pub session_id: SessionId, /// The _meta property is reserved by ACP to allow clients and agents to attach additional @@ -1059,11 +1079,22 @@ impl LoadSessionRequest { Self { mcp_servers: vec![], cwd: cwd.into(), + additional_directories: None, session_id: session_id.into(), meta: None, } } + /// Additional workspace roots to activate for this session. Each path must be absolute. + #[must_use] + pub fn additional_directories( + mut self, + additional_directories: impl IntoOption>, + ) -> Self { + self.additional_directories = additional_directories.into_option(); + self + } + /// List of MCP servers to connect to for this session. #[must_use] pub fn mcp_servers(mut self, mcp_servers: Vec) -> Self { @@ -1185,6 +1216,9 @@ pub struct ForkSessionRequest { pub session_id: SessionId, /// The working directory for this session. pub cwd: PathBuf, + /// Additional workspace roots to activate for this session. Each path must be absolute. + #[serde(skip_serializing_if = "Option::is_none")] + pub additional_directories: Option>, /// List of MCP servers to connect to for this session. #[serde(default, skip_serializing_if = "Vec::is_empty")] pub mcp_servers: Vec, @@ -1204,11 +1238,22 @@ impl ForkSessionRequest { Self { session_id: session_id.into(), cwd: cwd.into(), + additional_directories: None, mcp_servers: vec![], meta: None, } } + /// Additional workspace roots to activate for this session. Each path must be absolute. + #[must_use] + pub fn additional_directories( + mut self, + additional_directories: impl IntoOption>, + ) -> Self { + self.additional_directories = additional_directories.into_option(); + self + } + /// List of MCP servers to connect to for this session. #[must_use] pub fn mcp_servers(mut self, mcp_servers: Vec) -> Self { @@ -1345,6 +1390,9 @@ pub struct ResumeSessionRequest { pub session_id: SessionId, /// The working directory for this session. pub cwd: PathBuf, + /// Additional workspace roots to activate for this session. Each path must be absolute. + #[serde(skip_serializing_if = "Option::is_none")] + pub additional_directories: Option>, /// List of MCP servers to connect to for this session. #[serde(default, skip_serializing_if = "Vec::is_empty")] pub mcp_servers: Vec, @@ -1364,11 +1412,22 @@ impl ResumeSessionRequest { Self { session_id: session_id.into(), cwd: cwd.into(), + additional_directories: None, mcp_servers: vec![], meta: None, } } + /// Additional workspace roots to activate for this session. Each path must be absolute. + #[must_use] + pub fn additional_directories( + mut self, + additional_directories: impl IntoOption>, + ) -> Self { + self.additional_directories = additional_directories.into_option(); + self + } + /// List of MCP servers to connect to for this session. #[must_use] pub fn mcp_servers(mut self, mcp_servers: Vec) -> Self { @@ -1578,6 +1637,9 @@ pub struct ListSessionsRequest { /// Filter sessions by working directory. Must be an absolute path. #[serde(skip_serializing_if = "Option::is_none")] pub cwd: Option, + /// Filter sessions by the exact ordered additional workspace roots. Each path must be absolute. + #[serde(skip_serializing_if = "Option::is_none")] + pub additional_directories: Option>, /// Opaque cursor token from a previous response's nextCursor field for cursor-based pagination #[serde(skip_serializing_if = "Option::is_none")] pub cursor: Option, @@ -1603,6 +1665,16 @@ impl ListSessionsRequest { self } + /// Filter sessions by the exact ordered additional workspace roots. Each path must be absolute. + #[must_use] + pub fn additional_directories( + mut self, + additional_directories: impl IntoOption>, + ) -> Self { + self.additional_directories = additional_directories.into_option(); + self + } + /// Opaque cursor token from a previous response's nextCursor field for cursor-based pagination #[must_use] pub fn cursor(mut self, cursor: impl IntoOption) -> Self { @@ -1680,6 +1752,9 @@ pub struct SessionInfo { pub session_id: SessionId, /// The working directory for this session. Must be an absolute path. pub cwd: PathBuf, + /// Authoritative ordered additional workspace roots for this session. Each path must be absolute. + #[serde(skip_serializing_if = "Option::is_none")] + pub additional_directories: Option>, /// Human-readable title for the session #[serde(skip_serializing_if = "Option::is_none")] pub title: Option, @@ -1701,12 +1776,23 @@ impl SessionInfo { Self { session_id: session_id.into(), cwd: cwd.into(), + additional_directories: None, title: None, updated_at: None, meta: None, } } + /// Authoritative ordered additional workspace roots for this session. Each path must be absolute. + #[must_use] + pub fn additional_directories( + mut self, + additional_directories: impl IntoOption>, + ) -> Self { + self.additional_directories = additional_directories.into_option(); + self + } + /// Human-readable title for the session #[must_use] pub fn title(mut self, title: impl IntoOption) -> Self { @@ -3320,11 +3406,15 @@ impl AgentCapabilities { /// /// See protocol docs: [Session Capabilities](https://agentclientprotocol.com/protocol/initialization#session-capabilities) #[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] #[non_exhaustive] pub struct SessionCapabilities { /// Whether the agent supports `session/list`. #[serde(skip_serializing_if = "Option::is_none")] pub list: Option, + /// Whether the agent supports `additionalDirectories` on session lifecycle requests and `session/list`. + #[serde(skip_serializing_if = "Option::is_none")] + pub additional_directories: Option, /// **UNSTABLE** /// /// This capability is not part of the spec yet, and may be removed or changed at any point. @@ -3371,6 +3461,16 @@ impl SessionCapabilities { self } + /// Whether the agent supports `additionalDirectories` on session lifecycle requests and `session/list`. + #[must_use] + pub fn additional_directories( + mut self, + additional_directories: impl IntoOption, + ) -> Self { + self.additional_directories = additional_directories.into_option(); + self + } + #[cfg(feature = "unstable_session_fork")] /// Whether the agent supports `session/fork`. #[must_use] @@ -3427,6 +3527,41 @@ impl SessionListCapabilities { pub fn new() -> Self { Self::default() } + + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[must_use] + pub fn meta(mut self, meta: impl IntoOption) -> Self { + self.meta = meta.into_option(); + self + } +} + +/// Capabilities for additional session directories support. +/// +/// By supplying `{}` it means that the agent supports the `additionalDirectories` field on +/// session lifecycle requests and `session/list`. +#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +#[non_exhaustive] +pub struct SessionAdditionalDirectoriesCapabilities { + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")] + pub meta: Option, +} + +impl SessionAdditionalDirectoriesCapabilities { + #[must_use] + pub fn new() -> Self { + Self::default() + } + /// The _meta property is reserved by ACP to allow clients and agents to attach additional /// metadata to their interactions. Implementations MUST NOT make assumptions about values at /// these keys. @@ -4333,6 +4468,77 @@ mod test_serialization { assert!(matches!(deserialized, AuthMethod::Agent(_))); } + #[test] + fn test_session_additional_directories_serialization() { + assert_eq!( + serde_json::to_value(NewSessionRequest::new("/workspace/app")).unwrap(), + json!({ + "cwd": "/workspace/app", + "mcpServers": [] + }) + ); + assert_eq!( + serde_json::to_value( + NewSessionRequest::new("/workspace/app").additional_directories(vec![ + PathBuf::from("/workspace/libs/shared"), + PathBuf::from("/workspace/skills"), + ]) + ) + .unwrap(), + json!({ + "cwd": "/workspace/app", + "additionalDirectories": [ + "/workspace/libs/shared", + "/workspace/skills" + ], + "mcpServers": [] + }) + ); + assert_eq!( + serde_json::to_value( + ListSessionsRequest::new().additional_directories(Vec::::new()) + ) + .unwrap(), + json!({ + "additionalDirectories": [] + }) + ); + assert_eq!( + serde_json::to_value( + SessionInfo::new("sess_abc123", "/workspace/app") + .additional_directories(Vec::::new()) + ) + .unwrap(), + json!({ + "sessionId": "sess_abc123", + "cwd": "/workspace/app", + "additionalDirectories": [] + }) + ); + assert_eq!( + serde_json::from_value::(json!({ + "additionalDirectories": [] + })) + .unwrap() + .additional_directories, + Some(vec![]) + ); + } + + #[test] + fn test_session_additional_directories_capabilities_serialization() { + assert_eq!( + serde_json::to_value( + SessionCapabilities::new() + .additional_directories(SessionAdditionalDirectoriesCapabilities::new()) + ) + .unwrap(), + json!({ + "additionalDirectories": {} + }) + ); + } + #[cfg(feature = "unstable_auth_methods")] #[test] fn test_auth_method_env_var_serialization() { From 259a1aeb4360782a4aa7f4791a7d0dbbbfa03ecd Mon Sep 17 00:00:00 2001 From: Egor Baranov Date: Wed, 25 Mar 2026 12:13:08 +0100 Subject: [PATCH 2/9] fix: gate additional directories behind unstable feature --- Cargo.toml | 2 + docs/protocol/draft/schema.mdx | 52 +++++++++++++++++--- docs/protocol/file-system.mdx | 7 +-- docs/protocol/initialization.mdx | 5 -- docs/protocol/schema.mdx | 39 --------------- docs/protocol/session-list.mdx | 32 ++---------- docs/protocol/session-setup.mdx | 25 +--------- schema/schema.json | 50 ------------------- schema/schema.unstable.json | 16 +++--- src/agent.rs | 83 ++++++++++++++++++++++++++++++++ 10 files changed, 145 insertions(+), 166 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 86160b45..aec1307d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ include = ["/src/**/*.rs", "/README.md", "/LICENSE", "/Cargo.toml"] [features] unstable = [ + "unstable_additional_directories", "unstable_auth_methods", "unstable_cancel_request", "unstable_elicitation", @@ -27,6 +28,7 @@ unstable = [ "unstable_message_id", "unstable_boolean_config", ] +unstable_additional_directories = [] unstable_auth_methods = [] unstable_cancel_request = [] unstable_elicitation = [] diff --git a/docs/protocol/draft/schema.mdx b/docs/protocol/draft/schema.mdx index 918310b3..901183b9 100644 --- a/docs/protocol/draft/schema.mdx +++ b/docs/protocol/draft/schema.mdx @@ -357,7 +357,12 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte <>"string"[] | null} > - Additional workspace roots to activate for this session. Each path must be absolute. + **UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Additional workspace roots to activate for this session. Each path must be absolute. + The working directory for this session. @@ -438,7 +443,12 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte <>"string"[] | null} > - Filter sessions by the exact ordered additional workspace roots. Each path must be absolute. + **UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Filter sessions by the exact ordered additional workspace roots. Each path must be absolute. + Opaque cursor token from a previous response's nextCursor field for cursor-based pagination @@ -507,7 +517,12 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte <>"string"[] | null} > - Additional workspace roots to activate for this session. Each path must be absolute. + **UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Additional workspace roots to activate for this session. Each path must be absolute. + The working directory for this session. @@ -589,7 +604,11 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte <>"string"[] | null} > - Additional workspace roots for this session. Each path must be absolute. + **UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Additional workspace roots for this session. Each path must be absolute. These expand the session's filesystem scope without changing `cwd`, which remains the base for relative paths. @@ -794,7 +813,12 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte <>"string"[] | null} > - Additional workspace roots to activate for this session. Each path must be absolute. + **UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Additional workspace roots to activate for this session. Each path must be absolute. + The working directory for this session. @@ -4186,6 +4210,10 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte ## SessionAdditionalDirectoriesCapabilities +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + Capabilities for additional session directories support. By supplying `\{\}` it means that the agent supports the `additionalDirectories` field on @@ -4229,7 +4257,12 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte SessionAdditionalDirectoriesCapabilities | null} > - Whether the agent supports `additionalDirectories` on session lifecycle requests and `session/list`. + **UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Whether the agent supports `additionalDirectories` on session lifecycle requests and `session/list`. + SessionCloseCapabilities | null} > **UNSTABLE** @@ -4537,7 +4570,12 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte <>"string"[] | null} > - Authoritative ordered additional workspace roots for this session. Each path must be absolute. + **UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Authoritative ordered additional workspace roots for this session. Each path must be absolute. + The working directory for this session. Must be an absolute path. diff --git a/docs/protocol/file-system.mdx b/docs/protocol/file-system.mdx index 97888ad0..c16b2baf 100644 --- a/docs/protocol/file-system.mdx +++ b/docs/protocol/file-system.mdx @@ -5,8 +5,6 @@ description: "Client filesystem access methods" The filesystem methods allow Agents to read and write text files within the Client's environment. These methods enable Agents to access unsaved editor state and allow Clients to track file modifications made during agent execution. -Filesystem `path` values are always absolute. If a session was created with [`additionalDirectories`](./session-setup#additional-directories), Clients that enforce workspace boundaries **MUST** authorize `fs/*` requests against the full ordered root set `[cwd, ...additionalDirectories]`, not `cwd` alone. - ## Checking Support Before attempting to use filesystem methods, Agents **MUST** verify that the Client supports these capabilities by checking the [Client Capabilities](./initialization#client-capabilities) field in the `initialize` response: @@ -52,8 +50,7 @@ The `fs/read_text_file` method allows Agents to read text file contents from the - Absolute path to the file to read. Clients that enforce session workspace - boundaries validate this path against the session's effective root set. + Absolute path to the file to read @@ -102,8 +99,6 @@ Absolute path to the file to write. The Client **MUST** create the file if it doesn't exist. -Clients that enforce session workspace boundaries validate this path against the session's effective root set. - diff --git a/docs/protocol/initialization.mdx b/docs/protocol/initialization.mdx index f49f885b..a2b55b73 100644 --- a/docs/protocol/initialization.mdx +++ b/docs/protocol/initialization.mdx @@ -71,9 +71,6 @@ The Agent **MUST** respond with the chosen [protocol version](#protocol-version) "mcp": { "http": true, "sse": true - }, - "sessionCapabilities": { - "additionalDirectories": {} } }, "agentInfo": { @@ -200,8 +197,6 @@ Optionally, they **MAY** support other session methods and notifications by spec This will be unified in future versions of the protocol. -Agents that support multi-root session workspaces advertise `sessionCapabilities.additionalDirectories`. Clients **MUST** only send `additionalDirectories` on session lifecycle requests or `session/list` when that capability is present. - ## Implementation Information Both Clients and Agents **SHOULD** provide information about their implementation in the `clientInfo` and `agentInfo` fields respectively. Both take the following three fields: diff --git a/docs/protocol/schema.mdx b/docs/protocol/schema.mdx index 41e378a3..79b6693e 100644 --- a/docs/protocol/schema.mdx +++ b/docs/protocol/schema.mdx @@ -222,9 +222,6 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) - -<>"string"[] | null} > - Filter sessions by the exact ordered additional workspace roots. Each path must be absolute. Opaque cursor token from a previous response's nextCursor field for cursor-based pagination @@ -291,9 +288,6 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) - -<>"string"[] | null} > - Additional workspace roots to activate for this session. Each path must be absolute. The working directory for this session. @@ -365,13 +359,6 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) - -<>"string"[] | null} > - Additional workspace roots for this session. Each path must be absolute. - -These expand the session's filesystem scope without changing `cwd`, which -remains the base for relative paths. - The working directory for this session. Must be an absolute path. @@ -2580,26 +2567,6 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte The ID of the option the user selected. -## SessionAdditionalDirectoriesCapabilities - -Capabilities for additional session directories support. - -By supplying `\{\}` it means that the agent supports the `additionalDirectories` field on -session lifecycle requests and `session/list`. - -**Type:** Object - -**Properties:** - - - The _meta property is reserved by ACP to allow clients and agents to attach additional -metadata to their interactions. Implementations MUST NOT make assumptions about values at -these keys. - -See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) - - - ## SessionCapabilities Session capabilities supported by the agent. @@ -2623,9 +2590,6 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) - -SessionAdditionalDirectoriesCapabilities | null} > - Whether the agent supports `additionalDirectories` on session lifecycle requests and `session/list`. SessionListCapabilities | null} > Whether the agent supports `session/list`. @@ -2822,9 +2786,6 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) - -<>"string"[] | null} > - Authoritative ordered additional workspace roots for this session. Each path must be absolute. The working directory for this session. Must be an absolute path. diff --git a/docs/protocol/session-list.mdx b/docs/protocol/session-list.mdx index bf5b704f..6592b4e3 100644 --- a/docs/protocol/session-list.mdx +++ b/docs/protocol/session-list.mdx @@ -3,7 +3,7 @@ title: "Session List" description: "Discovering existing sessions" --- -The `session/list` method allows Clients to discover sessions known to an Agent. Clients can use this to display session history, recover authoritative workspace roots, and switch between sessions. +The `session/list` method allows Clients to discover sessions known to an Agent. Clients can use this to display session history and switch between sessions. Agents can also push session metadata updates to Clients in real-time via the `session_info_update` notification, keeping session titles and metadata in sync without polling. @@ -36,7 +36,7 @@ sequenceDiagram Before attempting to list sessions, Clients **MUST** verify that the Agent supports this capability by checking the `sessionCapabilities.list` field in the `initialize` response: -```json highlight={7-10} +```json highlight={7-9} { "jsonrpc": "2.0", "id": 0, @@ -44,8 +44,7 @@ Before attempting to list sessions, Clients **MUST** verify that the Agent suppo "protocolVersion": 1, "agentCapabilities": { "sessionCapabilities": { - "list": {}, - "additionalDirectories": {} + "list": {} } } } @@ -54,8 +53,6 @@ Before attempting to list sessions, Clients **MUST** verify that the Agent suppo If `sessionCapabilities.list` is not present, the Agent does not support listing sessions and Clients **MUST NOT** attempt to call `session/list`. -If `sessionCapabilities.additionalDirectories` is present, Clients **MAY** use the `additionalDirectories` filter and rely on `SessionInfo.additionalDirectories` in the response. - ## Listing Sessions Clients discover existing sessions by calling the `session/list` method with optional filtering and pagination parameters: @@ -67,7 +64,6 @@ Clients discover existing sessions by calling the `session/list` method with opt "method": "session/list", "params": { "cwd": "/home/user/project", - "additionalDirectories": ["/home/user/shared", "/home/user/.agent/skills"], "cursor": "eyJwYWdlIjogMn0=" } } @@ -80,20 +76,11 @@ All parameters are optional. A request with an empty `params` object returns the with a matching `cwd` are returned. - - Filter sessions by the exact ordered `additionalDirectories` list. Each path - must be absolute. An empty array matches only sessions with no additional - directories. Clients **MUST** only send this field when the Agent advertises - `sessionCapabilities.additionalDirectories`. - - Opaque cursor token from a previous response's `nextCursor` field for cursor-based pagination. See [Pagination](#pagination). -When the Agent advertises `sessionCapabilities.additionalDirectories`, each returned `SessionInfo.additionalDirectories` value is the authoritative ordered additional-root list for that session. - The Agent **MUST** respond with a list of sessions and optional pagination metadata: ```json @@ -105,10 +92,6 @@ The Agent **MUST** respond with a list of sessions and optional pagination metad { "sessionId": "sess_abc123def456", "cwd": "/home/user/project", - "additionalDirectories": [ - "/home/user/shared", - "/home/user/.agent/skills" - ], "title": "Implement session list API", "updatedAt": "2025-10-29T14:22:15Z", "_meta": { @@ -119,14 +102,12 @@ The Agent **MUST** respond with a list of sessions and optional pagination metad { "sessionId": "sess_xyz789ghi012", "cwd": "/home/user/another-project", - "additionalDirectories": [], "title": "Debug authentication flow", "updatedAt": "2025-10-28T16:45:30Z" }, { "sessionId": "sess_uvw345rst678", "cwd": "/home/user/project", - "additionalDirectories": ["/home/user/shared"], "updatedAt": "2025-10-27T15:30:00Z" } ], @@ -145,11 +126,6 @@ The Agent **MUST** respond with a list of sessions and optional pagination metad Working directory for the session. Always an absolute path. - - Authoritative ordered additional workspace roots for the session. When - the Agent advertises `sessionCapabilities.additionalDirectories`, this - field is present and `[]` means the session has no additional roots. - Human-readable title for the session. May be auto-generated from the first prompt. @@ -214,7 +190,7 @@ All fields are optional. Only include fields that have changed — omitted field Agent-specific metadata. See [Extensibility](./extensibility). -The `sessionId`, `cwd`, and `additionalDirectories` fields are **not** included in the update — `sessionId` is already in the notification's `params`, `cwd` is immutable, and this method does not define mid-session mutation of additional roots. Agents typically send this notification after the first meaningful exchange to auto-generate a title. +The `sessionId` and `cwd` fields are **not** included in the update — `sessionId` is already in the notification's `params`, and `cwd` is immutable (set during [`session/new`](./session-setup#creating-a-session)). Agents typically send this notification after the first meaningful exchange to auto-generate a title. ## Interaction with Other Session Methods diff --git a/docs/protocol/session-setup.mdx b/docs/protocol/session-setup.mdx index 535f169d..f323f320 100644 --- a/docs/protocol/session-setup.mdx +++ b/docs/protocol/session-setup.mdx @@ -42,7 +42,6 @@ sequenceDiagram Clients create a new session by calling the `session/new` method with: - The [working directory](#working-directory) for the session -- Optional [additional directories](#additional-directories) for the session workspace - A list of [MCP servers](#mcp-servers) the Agent should connect to ```json @@ -52,7 +51,6 @@ Clients create a new session by calling the `session/new` method with: "method": "session/new", "params": { "cwd": "/home/user/project", - "additionalDirectories": ["/home/user/shared", "/home/user/common"], "mcpServers": [ { "name": "filesystem", @@ -65,8 +63,6 @@ Clients create a new session by calling the `session/new` method with: } ``` -Clients **MUST** send `additionalDirectories` only when the Agent advertises `sessionCapabilities.additionalDirectories`. - The Agent **MUST** respond with a unique [Session ID](#session-id) that identifies this conversation: ```json @@ -109,7 +105,6 @@ To load an existing session, Clients **MUST** call the `session/load` method wit - The [Session ID](#session-id) to resume - [MCP servers](#mcp-servers) to connect to - The [working directory](#working-directory) -- The full intended [additional directories](#additional-directories) list when the Agent supports multi-root workspaces ```json { @@ -119,7 +114,6 @@ To load an existing session, Clients **MUST** call the `session/load` method wit "params": { "sessionId": "sess_789xyz", "cwd": "/home/user/project", - "additionalDirectories": ["/home/user/shared", "/home/user/.agent/skills"], "mcpServers": [ { "name": "filesystem", @@ -196,26 +190,11 @@ Clients use this ID to: ## Working Directory -The `cwd` (current working directory) parameter establishes the primary file system context for the session. This directory: +The `cwd` (current working directory) parameter establishes the file system context for the session. This directory: - **MUST** be an absolute path - **MUST** be used for the session regardless of where the Agent subprocess was spawned -- **MUST** remain the base for relative path resolution -- **SHOULD** be treated as the primary root in the session workspace - -## Additional Directories - -Agents that advertise `sessionCapabilities.additionalDirectories` accept an optional `additionalDirectories` array on `session/new` and `session/load`. - -Each entry in `additionalDirectories`: - -- **MUST** be an absolute path -- Extends the session's filesystem scope without replacing `cwd` -- Becomes part of the session's effective ordered root set: `[cwd, ...additionalDirectories]` - -Relative paths continue to resolve against `cwd` only. - -On `session/load`, Clients **MUST** resend the full intended `additionalDirectories` list. If the field is omitted, the loaded session activates no additional directories. When [`session/list`](./session-list) is available, `SessionInfo.additionalDirectories` provides the authoritative current list for a session. +- **SHOULD** serve as a boundary for tool operations on the file system ## MCP Servers diff --git a/schema/schema.json b/schema/schema.json index 988edc6b..9aca01f4 100644 --- a/schema/schema.json +++ b/schema/schema.json @@ -1476,13 +1476,6 @@ "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", "type": ["object", "null"] }, - "additionalDirectories": { - "description": "Filter sessions by the exact ordered additional workspace roots. Each path must be absolute.", - "items": { - "type": "string" - }, - "type": ["array", "null"] - }, "cursor": { "description": "Opaque cursor token from a previous response's nextCursor field for cursor-based pagination", "type": ["string", "null"] @@ -1529,13 +1522,6 @@ "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", "type": ["object", "null"] }, - "additionalDirectories": { - "description": "Additional workspace roots to activate for this session. Each path must be absolute.", - "items": { - "type": "string" - }, - "type": ["array", "null"] - }, "cwd": { "description": "The working directory for this session.", "type": "string" @@ -1755,13 +1741,6 @@ "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", "type": ["object", "null"] }, - "additionalDirectories": { - "description": "Additional workspace roots for this session. Each path must be absolute.\n\nThese expand the session's filesystem scope without changing `cwd`, which\nremains the base for relative paths.", - "items": { - "type": "string" - }, - "type": ["array", "null"] - }, "cwd": { "description": "The working directory for this session. Must be an absolute path.", "type": "string" @@ -2327,17 +2306,6 @@ "required": ["optionId"], "type": "object" }, - "SessionAdditionalDirectoriesCapabilities": { - "description": "Capabilities for additional session directories support.\n\nBy supplying `{}` it means that the agent supports the `additionalDirectories` field on\nsession lifecycle requests and `session/list`.", - "properties": { - "_meta": { - "additionalProperties": true, - "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", - "type": ["object", "null"] - } - }, - "type": "object" - }, "SessionCapabilities": { "description": "Session capabilities supported by the agent.\n\nAs a baseline, all Agents **MUST** support `session/new`, `session/prompt`, `session/cancel`, and `session/update`.\n\nOptionally, they **MAY** support other session methods and notifications by specifying additional capabilities.\n\nNote: `session/load` is still handled by the top-level `load_session` capability. This will be unified in future versions of the protocol.\n\nSee protocol docs: [Session Capabilities](https://agentclientprotocol.com/protocol/initialization#session-capabilities)", "properties": { @@ -2346,17 +2314,6 @@ "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", "type": ["object", "null"] }, - "additionalDirectories": { - "anyOf": [ - { - "$ref": "#/$defs/SessionAdditionalDirectoriesCapabilities" - }, - { - "type": "null" - } - ], - "description": "Whether the agent supports `additionalDirectories` on session lifecycle requests and `session/list`." - }, "list": { "anyOf": [ { @@ -2583,13 +2540,6 @@ "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", "type": ["object", "null"] }, - "additionalDirectories": { - "description": "Authoritative ordered additional workspace roots for this session. Each path must be absolute.", - "items": { - "type": "string" - }, - "type": ["array", "null"] - }, "cwd": { "description": "The working directory for this session. Must be an absolute path.", "type": "string" diff --git a/schema/schema.unstable.json b/schema/schema.unstable.json index 03fbe86f..c4785e04 100644 --- a/schema/schema.unstable.json +++ b/schema/schema.unstable.json @@ -2127,7 +2127,7 @@ "type": ["object", "null"] }, "additionalDirectories": { - "description": "Additional workspace roots to activate for this session. Each path must be absolute.", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAdditional workspace roots to activate for this session. Each path must be absolute.", "items": { "type": "string" }, @@ -2475,7 +2475,7 @@ "type": ["object", "null"] }, "additionalDirectories": { - "description": "Filter sessions by the exact ordered additional workspace roots. Each path must be absolute.", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nFilter sessions by the exact ordered additional workspace roots. Each path must be absolute.", "items": { "type": "string" }, @@ -2528,7 +2528,7 @@ "type": ["object", "null"] }, "additionalDirectories": { - "description": "Additional workspace roots to activate for this session. Each path must be absolute.", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAdditional workspace roots to activate for this session. Each path must be absolute.", "items": { "type": "string" }, @@ -2899,7 +2899,7 @@ "type": ["object", "null"] }, "additionalDirectories": { - "description": "Additional workspace roots for this session. Each path must be absolute.\n\nThese expand the session's filesystem scope without changing `cwd`, which\nremains the base for relative paths.", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAdditional workspace roots for this session. Each path must be absolute.\n\nThese expand the session's filesystem scope without changing `cwd`, which\nremains the base for relative paths.", "items": { "type": "string" }, @@ -3513,7 +3513,7 @@ "type": ["object", "null"] }, "additionalDirectories": { - "description": "Additional workspace roots to activate for this session. Each path must be absolute.", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAdditional workspace roots to activate for this session. Each path must be absolute.", "items": { "type": "string" }, @@ -3612,7 +3612,7 @@ "type": "object" }, "SessionAdditionalDirectoriesCapabilities": { - "description": "Capabilities for additional session directories support.\n\nBy supplying `{}` it means that the agent supports the `additionalDirectories` field on\nsession lifecycle requests and `session/list`.", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nCapabilities for additional session directories support.\n\nBy supplying `{}` it means that the agent supports the `additionalDirectories` field on\nsession lifecycle requests and `session/list`.", "properties": { "_meta": { "additionalProperties": true, @@ -3639,7 +3639,7 @@ "type": "null" } ], - "description": "Whether the agent supports `additionalDirectories` on session lifecycle requests and `session/list`." + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nWhether the agent supports `additionalDirectories` on session lifecycle requests and `session/list`." }, "close": { "anyOf": [ @@ -3950,7 +3950,7 @@ "type": ["object", "null"] }, "additionalDirectories": { - "description": "Authoritative ordered additional workspace roots for this session. Each path must be absolute.", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAuthoritative ordered additional workspace roots for this session. Each path must be absolute.", "items": { "type": "string" }, diff --git a/src/agent.rs b/src/agent.rs index f99a89fc..d34e42a4 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -893,10 +893,15 @@ impl AuthMethodTerminal { pub struct NewSessionRequest { /// The working directory for this session. Must be an absolute path. pub cwd: PathBuf, + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// /// Additional workspace roots for this session. Each path must be absolute. /// /// These expand the session's filesystem scope without changing `cwd`, which /// remains the base for relative paths. + #[cfg(feature = "unstable_additional_directories")] #[serde(skip_serializing_if = "Option::is_none")] pub additional_directories: Option>, /// List of MCP (Model Context Protocol) servers the agent should connect to. @@ -915,13 +920,19 @@ impl NewSessionRequest { pub fn new(cwd: impl Into) -> Self { Self { cwd: cwd.into(), + #[cfg(feature = "unstable_additional_directories")] additional_directories: None, mcp_servers: vec![], meta: None, } } + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// /// Additional workspace roots for this session. Each path must be absolute. + #[cfg(feature = "unstable_additional_directories")] #[must_use] pub fn additional_directories( mut self, @@ -1059,7 +1070,12 @@ pub struct LoadSessionRequest { pub mcp_servers: Vec, /// The working directory for this session. pub cwd: PathBuf, + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// /// Additional workspace roots to activate for this session. Each path must be absolute. + #[cfg(feature = "unstable_additional_directories")] #[serde(skip_serializing_if = "Option::is_none")] pub additional_directories: Option>, /// The ID of the session to load. @@ -1079,13 +1095,19 @@ impl LoadSessionRequest { Self { mcp_servers: vec![], cwd: cwd.into(), + #[cfg(feature = "unstable_additional_directories")] additional_directories: None, session_id: session_id.into(), meta: None, } } + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// /// Additional workspace roots to activate for this session. Each path must be absolute. + #[cfg(feature = "unstable_additional_directories")] #[must_use] pub fn additional_directories( mut self, @@ -1216,7 +1238,12 @@ pub struct ForkSessionRequest { pub session_id: SessionId, /// The working directory for this session. pub cwd: PathBuf, + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// /// Additional workspace roots to activate for this session. Each path must be absolute. + #[cfg(feature = "unstable_additional_directories")] #[serde(skip_serializing_if = "Option::is_none")] pub additional_directories: Option>, /// List of MCP servers to connect to for this session. @@ -1238,13 +1265,19 @@ impl ForkSessionRequest { Self { session_id: session_id.into(), cwd: cwd.into(), + #[cfg(feature = "unstable_additional_directories")] additional_directories: None, mcp_servers: vec![], meta: None, } } + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// /// Additional workspace roots to activate for this session. Each path must be absolute. + #[cfg(feature = "unstable_additional_directories")] #[must_use] pub fn additional_directories( mut self, @@ -1390,7 +1423,12 @@ pub struct ResumeSessionRequest { pub session_id: SessionId, /// The working directory for this session. pub cwd: PathBuf, + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// /// Additional workspace roots to activate for this session. Each path must be absolute. + #[cfg(feature = "unstable_additional_directories")] #[serde(skip_serializing_if = "Option::is_none")] pub additional_directories: Option>, /// List of MCP servers to connect to for this session. @@ -1412,13 +1450,19 @@ impl ResumeSessionRequest { Self { session_id: session_id.into(), cwd: cwd.into(), + #[cfg(feature = "unstable_additional_directories")] additional_directories: None, mcp_servers: vec![], meta: None, } } + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// /// Additional workspace roots to activate for this session. Each path must be absolute. + #[cfg(feature = "unstable_additional_directories")] #[must_use] pub fn additional_directories( mut self, @@ -1637,7 +1681,12 @@ pub struct ListSessionsRequest { /// Filter sessions by working directory. Must be an absolute path. #[serde(skip_serializing_if = "Option::is_none")] pub cwd: Option, + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// /// Filter sessions by the exact ordered additional workspace roots. Each path must be absolute. + #[cfg(feature = "unstable_additional_directories")] #[serde(skip_serializing_if = "Option::is_none")] pub additional_directories: Option>, /// Opaque cursor token from a previous response's nextCursor field for cursor-based pagination @@ -1665,7 +1714,12 @@ impl ListSessionsRequest { self } + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// /// Filter sessions by the exact ordered additional workspace roots. Each path must be absolute. + #[cfg(feature = "unstable_additional_directories")] #[must_use] pub fn additional_directories( mut self, @@ -1752,7 +1806,12 @@ pub struct SessionInfo { pub session_id: SessionId, /// The working directory for this session. Must be an absolute path. pub cwd: PathBuf, + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// /// Authoritative ordered additional workspace roots for this session. Each path must be absolute. + #[cfg(feature = "unstable_additional_directories")] #[serde(skip_serializing_if = "Option::is_none")] pub additional_directories: Option>, /// Human-readable title for the session @@ -1776,6 +1835,7 @@ impl SessionInfo { Self { session_id: session_id.into(), cwd: cwd.into(), + #[cfg(feature = "unstable_additional_directories")] additional_directories: None, title: None, updated_at: None, @@ -1783,7 +1843,12 @@ impl SessionInfo { } } + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// /// Authoritative ordered additional workspace roots for this session. Each path must be absolute. + #[cfg(feature = "unstable_additional_directories")] #[must_use] pub fn additional_directories( mut self, @@ -3412,7 +3477,12 @@ pub struct SessionCapabilities { /// Whether the agent supports `session/list`. #[serde(skip_serializing_if = "Option::is_none")] pub list: Option, + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// /// Whether the agent supports `additionalDirectories` on session lifecycle requests and `session/list`. + #[cfg(feature = "unstable_additional_directories")] #[serde(skip_serializing_if = "Option::is_none")] pub additional_directories: Option, /// **UNSTABLE** @@ -3461,7 +3531,12 @@ impl SessionCapabilities { self } + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// /// Whether the agent supports `additionalDirectories` on session lifecycle requests and `session/list`. + #[cfg(feature = "unstable_additional_directories")] #[must_use] pub fn additional_directories( mut self, @@ -3540,10 +3615,15 @@ impl SessionListCapabilities { } } +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// /// Capabilities for additional session directories support. /// /// By supplying `{}` it means that the agent supports the `additionalDirectories` field on /// session lifecycle requests and `session/list`. +#[cfg(feature = "unstable_additional_directories")] #[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[non_exhaustive] pub struct SessionAdditionalDirectoriesCapabilities { @@ -3556,6 +3636,7 @@ pub struct SessionAdditionalDirectoriesCapabilities { pub meta: Option, } +#[cfg(feature = "unstable_additional_directories")] impl SessionAdditionalDirectoriesCapabilities { #[must_use] pub fn new() -> Self { @@ -4468,6 +4549,7 @@ mod test_serialization { assert!(matches!(deserialized, AuthMethod::Agent(_))); } + #[cfg(feature = "unstable_additional_directories")] #[test] fn test_session_additional_directories_serialization() { assert_eq!( @@ -4525,6 +4607,7 @@ mod test_serialization { ); } + #[cfg(feature = "unstable_additional_directories")] #[test] fn test_session_additional_directories_capabilities_serialization() { assert_eq!( From 6f0987d700727a5db9497cf596d3a4fff9b023a3 Mon Sep 17 00:00:00 2001 From: Egor Baranov Date: Wed, 25 Mar 2026 12:30:58 +0100 Subject: [PATCH 3/9] Make paths more consistent --- docs/rfds/additional-directories.mdx | 26 +++++++++++++------------- src/agent.rs | 20 ++++++++++---------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/docs/rfds/additional-directories.mdx b/docs/rfds/additional-directories.mdx index 061987e6..a4ea15d9 100644 --- a/docs/rfds/additional-directories.mdx +++ b/docs/rfds/additional-directories.mdx @@ -150,8 +150,8 @@ When an agent supports both `sessionCapabilities.additionalDirectories` and `ses "id": 5, "method": "session/list", "params": { - "cwd": "/workspace/app", - "additionalDirectories": ["/workspace/libs/shared", "/workspace/skills"] + "cwd": "/home/user/project", + "additionalDirectories": ["/home/user/shared-lib", "/home/user/product-docs"] } } ``` @@ -164,10 +164,10 @@ When an agent supports both `sessionCapabilities.additionalDirectories` and `ses "sessions": [ { "sessionId": "sess_abc123", - "cwd": "/workspace/app", + "cwd": "/home/user/project", "additionalDirectories": [ - "/workspace/libs/shared", - "/workspace/skills" + "/home/user/shared-lib", + "/home/user/product-docs" ], "updatedAt": "2026-03-24T12:00:00Z" } @@ -303,8 +303,8 @@ If a client launches an agent with direct filesystem access, `additionalDirector "id": 1, "method": "session/new", "params": { - "cwd": "/workspace/app", - "additionalDirectories": ["/workspace/libs/shared", "/workspace/skills"], + "cwd": "/home/user/project", + "additionalDirectories": ["/home/user/shared-lib", "/home/user/product-docs"], "mcpServers": [] } } @@ -319,8 +319,8 @@ If a client launches an agent with direct filesystem access, `additionalDirector "method": "session/load", "params": { "sessionId": "sess_abc123", - "cwd": "/workspace/app", - "additionalDirectories": ["/workspace/libs/shared", "/workspace/skills"], + "cwd": "/home/user/project", + "additionalDirectories": ["/home/user/shared-lib", "/home/user/product-docs"], "mcpServers": [] } } @@ -335,8 +335,8 @@ If a client launches an agent with direct filesystem access, `additionalDirector "method": "session/resume", "params": { "sessionId": "sess_abc123", - "cwd": "/workspace/app", - "additionalDirectories": ["/workspace/libs/shared", "/workspace/skills"], + "cwd": "/home/user/project", + "additionalDirectories": ["/home/user/shared-lib", "/home/user/product-docs"], "mcpServers": [] } } @@ -351,8 +351,8 @@ If a client launches an agent with direct filesystem access, `additionalDirector "method": "session/fork", "params": { "sessionId": "sess_abc123", - "cwd": "/workspace/app", - "additionalDirectories": ["/workspace/libs/shared", "/workspace/skills"], + "cwd": "/home/user/project", + "additionalDirectories": ["/home/user/shared-lib", "/home/user/product-docs"], "mcpServers": [] } } diff --git a/src/agent.rs b/src/agent.rs index d34e42a4..bec5c4b2 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -4553,25 +4553,25 @@ mod test_serialization { #[test] fn test_session_additional_directories_serialization() { assert_eq!( - serde_json::to_value(NewSessionRequest::new("/workspace/app")).unwrap(), + serde_json::to_value(NewSessionRequest::new("/home/user/project")).unwrap(), json!({ - "cwd": "/workspace/app", + "cwd": "/home/user/project", "mcpServers": [] }) ); assert_eq!( serde_json::to_value( - NewSessionRequest::new("/workspace/app").additional_directories(vec![ - PathBuf::from("/workspace/libs/shared"), - PathBuf::from("/workspace/skills"), + NewSessionRequest::new("/home/user/project").additional_directories(vec![ + PathBuf::from("/home/user/shared-lib"), + PathBuf::from("/home/user/product-docs"), ]) ) .unwrap(), json!({ - "cwd": "/workspace/app", + "cwd": "/home/user/project", "additionalDirectories": [ - "/workspace/libs/shared", - "/workspace/skills" + "/home/user/shared-lib", + "/home/user/product-docs" ], "mcpServers": [] }) @@ -4587,13 +4587,13 @@ mod test_serialization { ); assert_eq!( serde_json::to_value( - SessionInfo::new("sess_abc123", "/workspace/app") + SessionInfo::new("sess_abc123", "/home/user/project") .additional_directories(Vec::::new()) ) .unwrap(), json!({ "sessionId": "sess_abc123", - "cwd": "/workspace/app", + "cwd": "/home/user/project", "additionalDirectories": [] }) ); From 13ef105c157491cd669d4e82ec057a671c38402d Mon Sep 17 00:00:00 2001 From: Egor Baranov Date: Thu, 26 Mar 2026 10:59:21 +0100 Subject: [PATCH 4/9] Run prettier on additional-directories.mdx --- docs/rfds/additional-directories.mdx | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/docs/rfds/additional-directories.mdx b/docs/rfds/additional-directories.mdx index a4ea15d9..1e20380c 100644 --- a/docs/rfds/additional-directories.mdx +++ b/docs/rfds/additional-directories.mdx @@ -151,7 +151,10 @@ When an agent supports both `sessionCapabilities.additionalDirectories` and `ses "method": "session/list", "params": { "cwd": "/home/user/project", - "additionalDirectories": ["/home/user/shared-lib", "/home/user/product-docs"] + "additionalDirectories": [ + "/home/user/shared-lib", + "/home/user/product-docs" + ] } } ``` @@ -304,7 +307,10 @@ If a client launches an agent with direct filesystem access, `additionalDirector "method": "session/new", "params": { "cwd": "/home/user/project", - "additionalDirectories": ["/home/user/shared-lib", "/home/user/product-docs"], + "additionalDirectories": [ + "/home/user/shared-lib", + "/home/user/product-docs" + ], "mcpServers": [] } } @@ -320,7 +326,10 @@ If a client launches an agent with direct filesystem access, `additionalDirector "params": { "sessionId": "sess_abc123", "cwd": "/home/user/project", - "additionalDirectories": ["/home/user/shared-lib", "/home/user/product-docs"], + "additionalDirectories": [ + "/home/user/shared-lib", + "/home/user/product-docs" + ], "mcpServers": [] } } @@ -336,7 +345,10 @@ If a client launches an agent with direct filesystem access, `additionalDirector "params": { "sessionId": "sess_abc123", "cwd": "/home/user/project", - "additionalDirectories": ["/home/user/shared-lib", "/home/user/product-docs"], + "additionalDirectories": [ + "/home/user/shared-lib", + "/home/user/product-docs" + ], "mcpServers": [] } } @@ -352,7 +364,10 @@ If a client launches an agent with direct filesystem access, `additionalDirector "params": { "sessionId": "sess_abc123", "cwd": "/home/user/project", - "additionalDirectories": ["/home/user/shared-lib", "/home/user/product-docs"], + "additionalDirectories": [ + "/home/user/shared-lib", + "/home/user/product-docs" + ], "mcpServers": [] } } From 43f54e72f9880068c80a4d2055aae340c00b03f8 Mon Sep 17 00:00:00 2001 From: Egor Baranov Date: Thu, 26 Mar 2026 15:20:48 +0100 Subject: [PATCH 5/9] Make additionalDirectories nullable --- docs/protocol/file-system.mdx | 19 +++++++++-- docs/protocol/session-list.mdx | 26 ++++++++++++++- docs/protocol/session-setup.mdx | 48 ++++++++++++++++++++++++-- docs/rfds/additional-directories.mdx | 50 ++++++++++++++-------------- 4 files changed, 113 insertions(+), 30 deletions(-) diff --git a/docs/protocol/file-system.mdx b/docs/protocol/file-system.mdx index c16b2baf..7c67319d 100644 --- a/docs/protocol/file-system.mdx +++ b/docs/protocol/file-system.mdx @@ -5,6 +5,19 @@ description: "Client filesystem access methods" The filesystem methods allow Agents to read and write text files within the Client's environment. These methods enable Agents to access unsaved editor state and allow Clients to track file modifications made during agent execution. +## Session Root Scope + +Filesystem methods always operate on absolute paths, but the Client **MUST** +authorize those paths against the session's effective root set. + +- by default, the effective root set is just `cwd` +- if the unstable `sessionCapabilities.additionalDirectories` capability is in use, the effective root set becomes `[cwd, ...additionalDirectories]` +- `cwd` remains the base for relative paths; additional roots only expand filesystem scope +- when a Client discovers a session through `session/list`, it SHOULD treat `cwd` plus `SessionInfo.additionalDirectories` as the authoritative current root set until a later lifecycle request changes it + +Because ACP filesystem methods are client-mediated, the Client remains +responsible for enforcing those root boundaries. + ## Checking Support Before attempting to use filesystem methods, Agents **MUST** verify that the Client supports these capabilities by checking the [Client Capabilities](./initialization#client-capabilities) field in the `initialize` response: @@ -46,7 +59,8 @@ The `fs/read_text_file` method allows Agents to read text file contents from the ``` - The [Session ID](./session-setup#session-id) for this request + The [Session ID](./session-setup#session-id) for this request. The session + determines which filesystem roots are in scope for the path. @@ -91,7 +105,8 @@ The `fs/write_text_file` method allows Agents to write or update text files in t ``` - The [Session ID](./session-setup#session-id) for this request + The [Session ID](./session-setup#session-id) for this request. The session + determines which filesystem roots are in scope for the path. diff --git a/docs/protocol/session-list.mdx b/docs/protocol/session-list.mdx index 6592b4e3..219962b8 100644 --- a/docs/protocol/session-list.mdx +++ b/docs/protocol/session-list.mdx @@ -53,6 +53,13 @@ Before attempting to list sessions, Clients **MUST** verify that the Agent suppo If `sessionCapabilities.list` is not present, the Agent does not support listing sessions and Clients **MUST NOT** attempt to call `session/list`. + + If the Agent also advertises the unstable + `sessionCapabilities.additionalDirectories` capability, `session/list` + supports filtering by `additionalDirectories`, and each returned `SessionInfo` + includes the authoritative additional-root list for that session. + + ## Listing Sessions Clients discover existing sessions by calling the `session/list` method with optional filtering and pagination parameters: @@ -76,6 +83,13 @@ All parameters are optional. A request with an empty `params` object returns the with a matching `cwd` are returned. + + If the Agent advertises `sessionCapabilities.additionalDirectories`, filter + sessions by the exact ordered additional-root list. Omit the field or set it + to `null` to avoid filtering on additional roots. An empty array matches only + sessions whose authoritative additional-root list is empty. + + Opaque cursor token from a previous response's `nextCursor` field for cursor-based pagination. See [Pagination](#pagination). @@ -126,6 +140,12 @@ The Agent **MUST** respond with a list of sessions and optional pagination metad Working directory for the session. Always an absolute path. + + If the Agent advertises `sessionCapabilities.additionalDirectories`, this + is the authoritative ordered additional-root list for the session. `[]` + means there are no additional roots. `null` also means there are no + additional roots, but Agents should prefer `[]`. + Human-readable title for the session. May be auto-generated from the first prompt. @@ -190,7 +210,11 @@ All fields are optional. Only include fields that have changed — omitted field Agent-specific metadata. See [Extensibility](./extensibility). -The `sessionId` and `cwd` fields are **not** included in the update — `sessionId` is already in the notification's `params`, and `cwd` is immutable (set during [`session/new`](./session-setup#creating-a-session)). Agents typically send this notification after the first meaningful exchange to auto-generate a title. +The `sessionId`, `cwd`, and `additionalDirectories` fields are **not** included +in the update. `sessionId` is already in the notification's `params`, `cwd` is +immutable after session setup, and ACP does not currently define mid-session +mutation for `additionalDirectories`. Agents typically send this notification +after the first meaningful exchange to auto-generate a title. ## Interaction with Other Session Methods diff --git a/docs/protocol/session-setup.mdx b/docs/protocol/session-setup.mdx index f323f320..afa20984 100644 --- a/docs/protocol/session-setup.mdx +++ b/docs/protocol/session-setup.mdx @@ -178,6 +178,44 @@ When **all** the conversation entries have been streamed to the Client, the Agen The Client can then continue sending prompts as if the session was never interrupted. +## Additional Workspace Roots + + + This section describes the unstable + `sessionCapabilities.additionalDirectories` capability. Clients MUST gate + usage on that capability being present during initialization. + + +When advertised, Clients MAY include `additionalDirectories` on supported +session lifecycle requests to expand the session's effective filesystem root +set. In the stable lifecycle pages, that means `session/new` and `session/load`. +The same unstable field is also available on `session/resume` and +`session/fork` when those methods are supported. + +```json +{ + "jsonrpc": "2.0", + "id": 2, + "method": "session/load", + "params": { + "sessionId": "sess_789xyz", + "cwd": "/home/user/project", + "additionalDirectories": [ + "/home/user/shared-lib", + "/home/user/product-docs" + ], + "mcpServers": [] + } +} +``` + +When present, `additionalDirectories` has the following behavior: + +- `cwd` remains the primary working directory and the base for relative paths +- each `additionalDirectories` entry **MUST** be an absolute path +- omitting the field or setting it to `null` activates no additional roots for the resulting session +- on `session/load`, Clients must send the full intended additional-root list again because omitted or `null` does not restore stored roots implicitly + ## Session ID The session ID returned by `session/new` is a unique identifier for the conversation context. @@ -190,11 +228,17 @@ Clients use this ID to: ## Working Directory -The `cwd` (current working directory) parameter establishes the file system context for the session. This directory: +The `cwd` (current working directory) parameter establishes the primary file +system context for the session. This directory: - **MUST** be an absolute path - **MUST** be used for the session regardless of where the Agent subprocess was spawned -- **SHOULD** serve as a boundary for tool operations on the file system +- **MUST** remain the base for relative-path resolution +- **MUST** be part of the session's effective root set + +When the unstable `sessionCapabilities.additionalDirectories` capability is in +use, the session's effective root set is `[cwd, ...additionalDirectories]`. +Otherwise, the effective root set is just `cwd`. ## MCP Servers diff --git a/docs/rfds/additional-directories.mdx b/docs/rfds/additional-directories.mdx index 1e20380c..a8ead3f7 100644 --- a/docs/rfds/additional-directories.mdx +++ b/docs/rfds/additional-directories.mdx @@ -14,7 +14,7 @@ ACP currently standardizes `cwd` on session lifecycle requests, but does not def This RFD proposes an optional field: ```ts -additionalDirectories?: string[] +additionalDirectories?: string[] | null ``` on: @@ -44,7 +44,7 @@ Without a standardized field, clients and agents must rely on implementation-spe > What are you proposing to improve the situation? -Add `additionalDirectories?: string[]` to the session lifecycle request schemas listed above and to `session/list`, and define protocol-level validation and semantics for it. +Add `additionalDirectories?: string[] | null` to the session lifecycle request schemas listed above and to `session/list`, and define protocol-level validation and semantics for it. The proposal is scoped to session lifecycle requests, session discovery requests, and session discovery metadata only: @@ -54,7 +54,7 @@ The proposal is scoped to session lifecycle requests, session discovery requests Agents advertise support with `sessionCapabilities.additionalDirectories`. Clients MUST gate usage on that capability. -This proposal also extends `SessionInfo` returned by `session/list` with authoritative `additionalDirectories` state, and allows `session/list` to filter on `cwd` plus `additionalDirectories`, so clients that support session discovery can recover and query the active root set for listed sessions. `session/load` and `session/resume` nevertheless remain explicit-list only: omitted `additionalDirectories` means no additional roots are activated for the resulting session, while a provided `additionalDirectories` value becomes the complete resulting additional-root list for that request. +This proposal also extends `SessionInfo` returned by `session/list` with authoritative `additionalDirectories` state, and allows `session/list` to filter on `cwd` plus `additionalDirectories`, so clients that support session discovery can recover and query the active root set for listed sessions. `session/load` and `session/resume` nevertheless remain explicit-list only: omitted or `null` `additionalDirectories` means no additional roots are activated for the resulting session, while an array-valued `additionalDirectories` becomes the complete resulting additional-root list for that request. ## Shiny future @@ -62,7 +62,7 @@ This proposal also extends `SessionInfo` returned by `session/list` with authori Clients can declare multi-root workspace scope in a standard way while preserving existing `cwd` behavior. -Agents can treat a session as an ordered root set (`[cwd, ...additionalDirectories]`) and apply the same discovery and resource-handling behavior they already apply under `cwd` to the other declared roots. +Agents can treat a session as an ordered root set starting with `cwd` and followed by any array-valued `additionalDirectories` entries, and apply the same discovery and resource-handling behavior they already apply under `cwd` to the other declared roots. Security boundaries remain explicit: declared roots communicate intended scope, while sandboxing, approvals, and OS permissions continue to govern actual access. @@ -94,19 +94,19 @@ Security boundaries remain explicit: declared roots communicate intended scope, The following optional property is added to each request type named above: ```ts -additionalDirectories?: string[] +additionalDirectories?: string[] | null ``` The following optional property is also added to `ListSessionsRequest`: ```ts -additionalDirectories?: string[] +additionalDirectories?: string[] | null ``` The following optional property is also added to `SessionInfo`: ```ts -additionalDirectories?: string[] +additionalDirectories?: string[] | null ``` The following capability is added to `SessionCapabilities`: @@ -117,9 +117,9 @@ additionalDirectories?: {} Clients MUST send `additionalDirectories` only when `sessionCapabilities.additionalDirectories` is present. -If an agent advertises `sessionCapabilities.additionalDirectories` and also supports `session/list`, each `SessionInfo` it returns MUST include `additionalDirectories` as the authoritative ordered additional-root list for that session. When a listed session has no additional roots, the field MUST be present as `[]`. +If an agent advertises `sessionCapabilities.additionalDirectories` and also supports `session/list`, each `SessionInfo` it returns MUST include `additionalDirectories` as the authoritative ordered additional-root list for that session. Agents SHOULD encode "no additional roots" as `[]` rather than `null`. Clients MUST treat `null` the same as `[]`. -If an agent advertises `sessionCapabilities.additionalDirectories` and also supports `session/list`, `ListSessionsRequest.additionalDirectories` filters sessions by exact match on the authoritative ordered additional-root list. When both `cwd` and `additionalDirectories` are present on `session/list`, both filters apply. An empty `additionalDirectories` filter matches only sessions whose authoritative additional-root list is `[]`. +If an agent advertises `sessionCapabilities.additionalDirectories` and also supports `session/list`, `ListSessionsRequest.additionalDirectories` filters sessions by exact match on the authoritative ordered additional-root list. When both `cwd` and `additionalDirectories` are present on `session/list`, both filters apply. An empty `additionalDirectories` filter matches only sessions whose authoritative additional-root list is `[]`. A `null` filter is equivalent to omitting the field. If adopted, the session-setup, session-list, and filesystem documentation will need corresponding updates so they describe the effective root set rather than `cwd` alone as the session filesystem context or boundary. @@ -183,14 +183,15 @@ When an agent supports both `sessionCapabilities.additionalDirectories` and `ses `additionalDirectories` has the following properties: -- The field MUST be an array of strings when present. -- Each entry MUST be an absolute path under the same platform path rules used for `cwd`. +- The field MAY be omitted, set to `null`, or set to an array of strings. +- `null` is equivalent to omitting the field. +- Each array entry MUST be an absolute path under the same platform path rules used for `cwd`. - Empty strings MUST be rejected. -- `null` is not a valid value for the field or for any entry. +- `null` is not a valid array entry. ACP does not define a wire-level lexical normalization algorithm for `cwd` or `additionalDirectories`. -Clients SHOULD remove exact duplicate path strings before sending the request. Clients SHOULD also avoid entries whose path string exactly matches `cwd`. Overlapping or nested roots are not semantically redundant for ACP purposes: because discovery across `[cwd, ...additionalDirectories]` is ordered and implementation-defined, such entries MAY affect behavior even when they do not change the union of accessible paths. Agents MAY remove exact duplicate path strings, including entries identical to `cwd`, provided doing so preserves the first occurrence order of the remaining entries and does not expand scope. +Clients SHOULD remove exact duplicate path strings before sending the request. Clients SHOULD also avoid entries whose path string exactly matches `cwd`. Overlapping or nested roots are not semantically redundant for ACP purposes: because discovery across the effective ordered root list is ordered and implementation-defined, such entries MAY affect behavior even when they do not change the union of accessible paths. Agents MAY remove exact duplicate path strings, including entries identical to `cwd`, provided doing so preserves the first occurrence order of the remaining entries and does not expand scope. For `session/list` filtering, matching is against the session's authoritative ordered additional-root list as surfaced in `SessionInfo.additionalDirectories`. Implementations that normalize or canonicalize path strings for comparison SHOULD apply the same platform-appropriate rule consistently to stored session state, `SessionInfo.additionalDirectories`, and `ListSessionsRequest.additionalDirectories`. @@ -206,9 +207,8 @@ For `session/list` filtering, matching is against the session's authoritative or The effective ordered root list for a session is: -```ts -[cwd, ...additionalDirectories]; -``` +- `[cwd]` when `additionalDirectories` is omitted or `null` +- `[cwd, ...additionalDirectories]` when `additionalDirectories` is an array This ordered root list has the following semantics: @@ -224,20 +224,20 @@ A file path is in scope for the session if, after platform-appropriate path reso For `NewSessionRequest`, the resulting additional root list is: -- `additionalDirectories` when present; +- `additionalDirectories` when present with an array value; - otherwise `[]`. For `LoadSessionRequest` and `ResumeSessionRequest`: -- when `additionalDirectories` is present, it is the complete resulting list of additional roots for the active session, even if that list differs from the session's previously stored additional roots; -- when omitted, the resulting additional root list is `[]`. +- when `additionalDirectories` is present with an array value, it is the complete resulting list of additional roots for the active session, even if that list differs from the session's previously stored additional roots; +- when omitted or set to `null`, the resulting additional root list is `[]`. Agents MUST NOT implicitly reactivate stored additional roots that were not supplied on the `session/load` or `session/resume` request. Supplying `additionalDirectories` on `session/load` or `session/resume` is always allowed when the capability is advertised, and doing so may preserve, replace, reduce, or expand the session's previously stored additional-root list for the resulting active session, subject to validation and policy checks. Clients that need to preserve a session's additional roots across restarts or across client instances MUST obtain, persist, or reconstruct the full list and resend it on load or resume. When `session/list` is available, `SessionInfo.additionalDirectories` provides the authoritative current additional-root list for that purpose. For `ForkSessionRequest`: -- when `additionalDirectories` is present, it is a full replacement list for the forked session; -- when omitted, the resulting additional root list is `[]`. +- when `additionalDirectories` is present with an array value, it is a full replacement list for the forked session; +- when omitted or set to `null`, the resulting additional root list is `[]`. Agents MUST NOT implicitly inherit additional roots from the source session unless the implementation can prove that the active root list is already authoritative to the requesting client on the current connection. Otherwise, the agent MUST fail the request or require the client to provide the full list explicitly. @@ -251,7 +251,7 @@ Agents MUST treat paths under `additionalDirectories` as part of the session's a For any discovery, indexing, or resource-loading behavior an agent applies under `cwd` such as instructions, skills, configuration, or other agent-specific artifacts, the agent SHOULD apply the same behavior to each declared root in `additionalDirectories`, subject to the same capabilities and permissions. -If an implementation resolves conflicts across multiple roots, earlier roots in `[cwd, ...additionalDirectories]` SHOULD take precedence over later roots. Conflict resolution within a single root remains implementation-defined. +If an implementation resolves conflicts across multiple roots, earlier roots in the effective ordered root list SHOULD take precedence over later roots. Conflict resolution within a single root remains implementation-defined. ACP does not define: @@ -268,7 +268,7 @@ An agent receiving a session lifecycle request with `additionalDirectories` MUST The agent MUST reject the request if: -- `additionalDirectories` is not an array; +- `additionalDirectories` is neither `null` nor an array; - any entry is not a string; - any entry is empty; - any entry is not absolute. @@ -387,7 +387,7 @@ Because ACP does not define directory contents, agents SHOULD avoid assuming tha ### Backward compatibility -This proposal is additive at the schema level. Requests that omit `additionalDirectories` behave exactly as they do today. Existing clients that do not need multi-root support require no changes. +This proposal is additive at the schema level. Requests that omit `additionalDirectories` or set it to `null` behave exactly as they do today. Existing clients that do not need multi-root support require no changes. Updated agents MUST continue to accept requests that do not include the field. @@ -430,7 +430,7 @@ Clients MUST gate `additionalDirectories` on `sessionCapabilities.additionalDire ### Why not restore stored roots on `session/load` or `session/resume` when the field is omitted? -Even with `SessionInfo.additionalDirectories` available through `session/list`, implicit restoration would still let an agent reactivate filesystem scope that the current request did not state explicitly. That is undesirable for clients that do not use `session/list`, for clients resuming a session by ID without first listing it, and for clients that want request-time control over the active root set. This proposal therefore keeps load and resume explicit-list only for additional roots: omitting the field activates none, while supplying it is explicitly allowed and sets the complete resulting additional-root list for that request. +Even with `SessionInfo.additionalDirectories` available through `session/list`, implicit restoration would still let an agent reactivate filesystem scope that the current request did not state explicitly. That is undesirable for clients that do not use `session/list`, for clients resuming a session by ID without first listing it, and for clients that want request-time control over the active root set. This proposal therefore keeps load and resume explicit-list only for additional roots: omitting the field or sending `null` activates none, while supplying an array is explicitly allowed and sets the complete resulting additional-root list for that request. ### What alternative approaches did you consider, and why did you settle on this one? From 5f930cbd5607473f9d1a69502b876ccc1337355f Mon Sep 17 00:00:00 2001 From: Ben Brandt Date: Fri, 27 Mar 2026 12:06:36 +0100 Subject: [PATCH 6/9] Rename feature flag --- Cargo.toml | 4 ++-- src/agent.rs | 46 +++++++++++++++++++++++----------------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index aec1307d..1b429a39 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,11 +15,11 @@ include = ["/src/**/*.rs", "/README.md", "/LICENSE", "/Cargo.toml"] [features] unstable = [ - "unstable_additional_directories", "unstable_auth_methods", "unstable_cancel_request", "unstable_elicitation", "unstable_logout", + "unstable_session_additional_directories", "unstable_session_fork", "unstable_session_model", "unstable_session_resume", @@ -28,11 +28,11 @@ unstable = [ "unstable_message_id", "unstable_boolean_config", ] -unstable_additional_directories = [] unstable_auth_methods = [] unstable_cancel_request = [] unstable_elicitation = [] unstable_logout = [] +unstable_session_additional_directories = [] unstable_session_fork = [] unstable_session_model = [] unstable_session_resume = [] diff --git a/src/agent.rs b/src/agent.rs index bec5c4b2..d107b8cf 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -901,7 +901,7 @@ pub struct NewSessionRequest { /// /// These expand the session's filesystem scope without changing `cwd`, which /// remains the base for relative paths. - #[cfg(feature = "unstable_additional_directories")] + #[cfg(feature = "unstable_session_additional_directories")] #[serde(skip_serializing_if = "Option::is_none")] pub additional_directories: Option>, /// List of MCP (Model Context Protocol) servers the agent should connect to. @@ -920,7 +920,7 @@ impl NewSessionRequest { pub fn new(cwd: impl Into) -> Self { Self { cwd: cwd.into(), - #[cfg(feature = "unstable_additional_directories")] + #[cfg(feature = "unstable_session_additional_directories")] additional_directories: None, mcp_servers: vec![], meta: None, @@ -932,7 +932,7 @@ impl NewSessionRequest { /// This capability is not part of the spec yet, and may be removed or changed at any point. /// /// Additional workspace roots for this session. Each path must be absolute. - #[cfg(feature = "unstable_additional_directories")] + #[cfg(feature = "unstable_session_additional_directories")] #[must_use] pub fn additional_directories( mut self, @@ -1075,7 +1075,7 @@ pub struct LoadSessionRequest { /// This capability is not part of the spec yet, and may be removed or changed at any point. /// /// Additional workspace roots to activate for this session. Each path must be absolute. - #[cfg(feature = "unstable_additional_directories")] + #[cfg(feature = "unstable_session_additional_directories")] #[serde(skip_serializing_if = "Option::is_none")] pub additional_directories: Option>, /// The ID of the session to load. @@ -1095,7 +1095,7 @@ impl LoadSessionRequest { Self { mcp_servers: vec![], cwd: cwd.into(), - #[cfg(feature = "unstable_additional_directories")] + #[cfg(feature = "unstable_session_additional_directories")] additional_directories: None, session_id: session_id.into(), meta: None, @@ -1107,7 +1107,7 @@ impl LoadSessionRequest { /// This capability is not part of the spec yet, and may be removed or changed at any point. /// /// Additional workspace roots to activate for this session. Each path must be absolute. - #[cfg(feature = "unstable_additional_directories")] + #[cfg(feature = "unstable_session_additional_directories")] #[must_use] pub fn additional_directories( mut self, @@ -1243,7 +1243,7 @@ pub struct ForkSessionRequest { /// This capability is not part of the spec yet, and may be removed or changed at any point. /// /// Additional workspace roots to activate for this session. Each path must be absolute. - #[cfg(feature = "unstable_additional_directories")] + #[cfg(feature = "unstable_session_additional_directories")] #[serde(skip_serializing_if = "Option::is_none")] pub additional_directories: Option>, /// List of MCP servers to connect to for this session. @@ -1265,7 +1265,7 @@ impl ForkSessionRequest { Self { session_id: session_id.into(), cwd: cwd.into(), - #[cfg(feature = "unstable_additional_directories")] + #[cfg(feature = "unstable_session_additional_directories")] additional_directories: None, mcp_servers: vec![], meta: None, @@ -1277,7 +1277,7 @@ impl ForkSessionRequest { /// This capability is not part of the spec yet, and may be removed or changed at any point. /// /// Additional workspace roots to activate for this session. Each path must be absolute. - #[cfg(feature = "unstable_additional_directories")] + #[cfg(feature = "unstable_session_additional_directories")] #[must_use] pub fn additional_directories( mut self, @@ -1428,7 +1428,7 @@ pub struct ResumeSessionRequest { /// This capability is not part of the spec yet, and may be removed or changed at any point. /// /// Additional workspace roots to activate for this session. Each path must be absolute. - #[cfg(feature = "unstable_additional_directories")] + #[cfg(feature = "unstable_session_additional_directories")] #[serde(skip_serializing_if = "Option::is_none")] pub additional_directories: Option>, /// List of MCP servers to connect to for this session. @@ -1450,7 +1450,7 @@ impl ResumeSessionRequest { Self { session_id: session_id.into(), cwd: cwd.into(), - #[cfg(feature = "unstable_additional_directories")] + #[cfg(feature = "unstable_session_additional_directories")] additional_directories: None, mcp_servers: vec![], meta: None, @@ -1462,7 +1462,7 @@ impl ResumeSessionRequest { /// This capability is not part of the spec yet, and may be removed or changed at any point. /// /// Additional workspace roots to activate for this session. Each path must be absolute. - #[cfg(feature = "unstable_additional_directories")] + #[cfg(feature = "unstable_session_additional_directories")] #[must_use] pub fn additional_directories( mut self, @@ -1686,7 +1686,7 @@ pub struct ListSessionsRequest { /// This capability is not part of the spec yet, and may be removed or changed at any point. /// /// Filter sessions by the exact ordered additional workspace roots. Each path must be absolute. - #[cfg(feature = "unstable_additional_directories")] + #[cfg(feature = "unstable_session_additional_directories")] #[serde(skip_serializing_if = "Option::is_none")] pub additional_directories: Option>, /// Opaque cursor token from a previous response's nextCursor field for cursor-based pagination @@ -1719,7 +1719,7 @@ impl ListSessionsRequest { /// This capability is not part of the spec yet, and may be removed or changed at any point. /// /// Filter sessions by the exact ordered additional workspace roots. Each path must be absolute. - #[cfg(feature = "unstable_additional_directories")] + #[cfg(feature = "unstable_session_additional_directories")] #[must_use] pub fn additional_directories( mut self, @@ -1811,7 +1811,7 @@ pub struct SessionInfo { /// This capability is not part of the spec yet, and may be removed or changed at any point. /// /// Authoritative ordered additional workspace roots for this session. Each path must be absolute. - #[cfg(feature = "unstable_additional_directories")] + #[cfg(feature = "unstable_session_additional_directories")] #[serde(skip_serializing_if = "Option::is_none")] pub additional_directories: Option>, /// Human-readable title for the session @@ -1835,7 +1835,7 @@ impl SessionInfo { Self { session_id: session_id.into(), cwd: cwd.into(), - #[cfg(feature = "unstable_additional_directories")] + #[cfg(feature = "unstable_session_additional_directories")] additional_directories: None, title: None, updated_at: None, @@ -1848,7 +1848,7 @@ impl SessionInfo { /// This capability is not part of the spec yet, and may be removed or changed at any point. /// /// Authoritative ordered additional workspace roots for this session. Each path must be absolute. - #[cfg(feature = "unstable_additional_directories")] + #[cfg(feature = "unstable_session_additional_directories")] #[must_use] pub fn additional_directories( mut self, @@ -3482,7 +3482,7 @@ pub struct SessionCapabilities { /// This capability is not part of the spec yet, and may be removed or changed at any point. /// /// Whether the agent supports `additionalDirectories` on session lifecycle requests and `session/list`. - #[cfg(feature = "unstable_additional_directories")] + #[cfg(feature = "unstable_session_additional_directories")] #[serde(skip_serializing_if = "Option::is_none")] pub additional_directories: Option, /// **UNSTABLE** @@ -3536,7 +3536,7 @@ impl SessionCapabilities { /// This capability is not part of the spec yet, and may be removed or changed at any point. /// /// Whether the agent supports `additionalDirectories` on session lifecycle requests and `session/list`. - #[cfg(feature = "unstable_additional_directories")] + #[cfg(feature = "unstable_session_additional_directories")] #[must_use] pub fn additional_directories( mut self, @@ -3623,7 +3623,7 @@ impl SessionListCapabilities { /// /// By supplying `{}` it means that the agent supports the `additionalDirectories` field on /// session lifecycle requests and `session/list`. -#[cfg(feature = "unstable_additional_directories")] +#[cfg(feature = "unstable_session_additional_directories")] #[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[non_exhaustive] pub struct SessionAdditionalDirectoriesCapabilities { @@ -3636,7 +3636,7 @@ pub struct SessionAdditionalDirectoriesCapabilities { pub meta: Option, } -#[cfg(feature = "unstable_additional_directories")] +#[cfg(feature = "unstable_session_additional_directories")] impl SessionAdditionalDirectoriesCapabilities { #[must_use] pub fn new() -> Self { @@ -4549,7 +4549,7 @@ mod test_serialization { assert!(matches!(deserialized, AuthMethod::Agent(_))); } - #[cfg(feature = "unstable_additional_directories")] + #[cfg(feature = "unstable_session_additional_directories")] #[test] fn test_session_additional_directories_serialization() { assert_eq!( @@ -4607,7 +4607,7 @@ mod test_serialization { ); } - #[cfg(feature = "unstable_additional_directories")] + #[cfg(feature = "unstable_session_additional_directories")] #[test] fn test_session_additional_directories_capabilities_serialization() { assert_eq!( From 53ad1b10bda742fb3fc1517830f3fa2010a4191d Mon Sep 17 00:00:00 2001 From: Ben Brandt Date: Fri, 27 Mar 2026 12:48:56 +0100 Subject: [PATCH 7/9] Clean up --- docs/protocol/draft/file-system.mdx | 131 ++++++++ docs/protocol/draft/schema.mdx | 12 +- docs/protocol/draft/session-list.mdx | 228 ++++++++++++++ docs/protocol/draft/session-setup.mdx | 419 ++++++++++++++++++++++++++ docs/protocol/file-system.mdx | 19 +- docs/protocol/session-list.mdx | 26 +- docs/protocol/session-setup.mdx | 48 +-- docs/rfds/additional-directories.mdx | 33 +- docs/rfds/session-info-update.mdx | 2 +- schema/schema.unstable.json | 12 +- src/agent.rs | 107 +++---- 11 files changed, 868 insertions(+), 169 deletions(-) create mode 100644 docs/protocol/draft/file-system.mdx create mode 100644 docs/protocol/draft/session-list.mdx create mode 100644 docs/protocol/draft/session-setup.mdx diff --git a/docs/protocol/draft/file-system.mdx b/docs/protocol/draft/file-system.mdx new file mode 100644 index 00000000..7c67319d --- /dev/null +++ b/docs/protocol/draft/file-system.mdx @@ -0,0 +1,131 @@ +--- +title: "File System" +description: "Client filesystem access methods" +--- + +The filesystem methods allow Agents to read and write text files within the Client's environment. These methods enable Agents to access unsaved editor state and allow Clients to track file modifications made during agent execution. + +## Session Root Scope + +Filesystem methods always operate on absolute paths, but the Client **MUST** +authorize those paths against the session's effective root set. + +- by default, the effective root set is just `cwd` +- if the unstable `sessionCapabilities.additionalDirectories` capability is in use, the effective root set becomes `[cwd, ...additionalDirectories]` +- `cwd` remains the base for relative paths; additional roots only expand filesystem scope +- when a Client discovers a session through `session/list`, it SHOULD treat `cwd` plus `SessionInfo.additionalDirectories` as the authoritative current root set until a later lifecycle request changes it + +Because ACP filesystem methods are client-mediated, the Client remains +responsible for enforcing those root boundaries. + +## Checking Support + +Before attempting to use filesystem methods, Agents **MUST** verify that the Client supports these capabilities by checking the [Client Capabilities](./initialization#client-capabilities) field in the `initialize` response: + +```json highlight={8,9} +{ + "jsonrpc": "2.0", + "id": 0, + "result": { + "protocolVersion": 1, + "clientCapabilities": { + "fs": { + "readTextFile": true, + "writeTextFile": true + } + } + } +} +``` + +If `readTextFile` or `writeTextFile` is `false` or not present, the Agent **MUST NOT** attempt to call the corresponding filesystem method. + +## Reading Files + +The `fs/read_text_file` method allows Agents to read text file contents from the Client's filesystem, including unsaved changes in the editor. + +```json +{ + "jsonrpc": "2.0", + "id": 3, + "method": "fs/read_text_file", + "params": { + "sessionId": "sess_abc123def456", + "path": "/home/user/project/src/main.py", + "line": 10, + "limit": 50 + } +} +``` + + + The [Session ID](./session-setup#session-id) for this request. The session + determines which filesystem roots are in scope for the path. + + + + Absolute path to the file to read + + + + Optional line number to start reading from (1-based) + + + + Optional maximum number of lines to read + + +The Client responds with the file contents: + +```json +{ + "jsonrpc": "2.0", + "id": 3, + "result": { + "content": "def hello_world():\n print('Hello, world!')\n" + } +} +``` + +## Writing Files + +The `fs/write_text_file` method allows Agents to write or update text files in the Client's filesystem. + +```json +{ + "jsonrpc": "2.0", + "id": 4, + "method": "fs/write_text_file", + "params": { + "sessionId": "sess_abc123def456", + "path": "/home/user/project/config.json", + "content": "{\n \"debug\": true,\n \"version\": \"1.0.0\"\n}" + } +} +``` + + + The [Session ID](./session-setup#session-id) for this request. The session + determines which filesystem roots are in scope for the path. + + + +Absolute path to the file to write. + +The Client **MUST** create the file if it doesn't exist. + + + + + The text content to write to the file + + +The Client responds with an empty result on success: + +```json +{ + "jsonrpc": "2.0", + "id": 4, + "result": null +} +``` diff --git a/docs/protocol/draft/schema.mdx b/docs/protocol/draft/schema.mdx index 901183b9..8de281d7 100644 --- a/docs/protocol/draft/schema.mdx +++ b/docs/protocol/draft/schema.mdx @@ -356,7 +356,7 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) -<>"string"[] | null} > +"string"[]} > **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. @@ -442,7 +442,7 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) -<>"string"[] | null} > +"string"[]} > **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. @@ -516,7 +516,7 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) -<>"string"[] | null} > +"string"[]} > **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. @@ -603,7 +603,7 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) -<>"string"[] | null} > +"string"[]} > **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. @@ -812,7 +812,7 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) -<>"string"[] | null} > +"string"[]} > **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. @@ -4569,7 +4569,7 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) -<>"string"[] | null} > +"string"[]} > **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. diff --git a/docs/protocol/draft/session-list.mdx b/docs/protocol/draft/session-list.mdx new file mode 100644 index 00000000..7137a933 --- /dev/null +++ b/docs/protocol/draft/session-list.mdx @@ -0,0 +1,228 @@ +--- +title: "Session List" +description: "Discovering existing sessions" +--- + +The `session/list` method allows Clients to discover sessions known to an Agent. Clients can use this to display session history and switch between sessions. + +Agents can also push session metadata updates to Clients in real-time via the `session_info_update` notification, keeping session titles and metadata in sync without polling. + +Before listing sessions, Clients **MUST** first complete the [initialization](./initialization) phase to verify the Agent supports this capability. + +
+ +```mermaid +sequenceDiagram + participant Client + participant Agent + + Note over Agent,Client: Initialized + + Client->>Agent: session/list + Agent-->>Client: session/list response (sessions) + + alt User selects a session + Client->>Agent: session/load (sessionId) + Note over Agent,Client: Replay conversation history... + Agent-->>Client: session/load response + end + + Note over Client,Agent: Ready for prompts +``` + +
+ +## Checking Support + +Before attempting to list sessions, Clients **MUST** verify that the Agent supports this capability by checking the `sessionCapabilities.list` field in the `initialize` response: + +```json highlight={7-9} +{ + "jsonrpc": "2.0", + "id": 0, + "result": { + "protocolVersion": 1, + "agentCapabilities": { + "sessionCapabilities": { + "list": {} + } + } + } +} +``` + +If `sessionCapabilities.list` is not present, the Agent does not support listing sessions and Clients **MUST NOT** attempt to call `session/list`. + + + If the Agent also advertises the unstable + `sessionCapabilities.additionalDirectories` capability, `session/list` + supports filtering by `additionalDirectories`, and any returned + `SessionInfo.additionalDirectories` value is the authoritative additional-root + list for that session. + + +## Listing Sessions + +Clients discover existing sessions by calling the `session/list` method with optional filtering and pagination parameters: + +```json +{ + "jsonrpc": "2.0", + "id": 2, + "method": "session/list", + "params": { + "cwd": "/home/user/project", + "cursor": "eyJwYWdlIjogMn0=" + } +} +``` + +All parameters are optional. A request with an empty `params` object returns the first page of sessions. + + + Filter sessions by working directory. Must be an absolute path. Only sessions + with a matching `cwd` are returned. + + + + If the Agent advertises `sessionCapabilities.additionalDirectories`, filter + sessions by the exact ordered additional-root list. Omit the field or set it + to `null` to avoid filtering on additional roots. An empty array matches only + sessions whose authoritative additional-root list is empty. + + + + Opaque cursor token from a previous response's `nextCursor` field for + cursor-based pagination. See [Pagination](#pagination). + + +The Agent **MUST** respond with a list of sessions and optional pagination metadata: + +```json +{ + "jsonrpc": "2.0", + "id": 2, + "result": { + "sessions": [ + { + "sessionId": "sess_abc123def456", + "cwd": "/home/user/project", + "title": "Implement session list API", + "updatedAt": "2025-10-29T14:22:15Z", + "_meta": { + "messageCount": 12, + "hasErrors": false + } + }, + { + "sessionId": "sess_xyz789ghi012", + "cwd": "/home/user/another-project", + "title": "Debug authentication flow", + "updatedAt": "2025-10-28T16:45:30Z" + }, + { + "sessionId": "sess_uvw345rst678", + "cwd": "/home/user/project", + "updatedAt": "2025-10-27T15:30:00Z" + } + ], + "nextCursor": "eyJwYWdlIjogM30=" + } +} +``` + + + Array of session information objects. + + + + Unique identifier for the session. + + + Working directory for the session. Always an absolute path. + + + If the Agent advertises `sessionCapabilities.additionalDirectories`, this + is the authoritative ordered additional-root list for the session when + present. Omitting the field or returning `[]` means there are no + additional roots. + + + + Human-readable title for the session. May be auto-generated from the first prompt. + + + ISO 8601 timestamp of the last activity in the session. + + + Agent-specific metadata. See [Extensibility](./extensibility). + + + + + + + Opaque cursor token. If present, pass this in the next request's `cursor` + parameter to fetch the next page. If absent, there are no more results. + + +When no sessions match the criteria, the Agent **MUST** return an empty `sessions` array. + +## Pagination + +`session/list` uses cursor-based pagination. The request includes an optional `cursor`, and the response includes `nextCursor` when more results are available. + +- Clients **MUST** treat a missing `nextCursor` as the end of results +- Clients **MUST** treat cursors as opaque tokens — do not parse, modify, or persist them +- Agents **SHOULD** return an error if the cursor is invalid +- Agents **SHOULD** enforce reasonable page sizes internally + +## Updating Session Metadata + +Agents can update session metadata in real-time by sending a `session_info_update` notification via `session/update`. This follows the same pattern as other session notifications like [`available_commands_update`](./slash-commands) and [`current_mode_update`](./session-modes). + +```json +{ + "jsonrpc": "2.0", + "method": "session/update", + "params": { + "sessionId": "sess_abc123def456", + "update": { + "sessionUpdate": "session_info_update", + "title": "Implement user authentication", + "_meta": { + "tags": ["feature", "auth"], + "priority": "high" + } + } + } +} +``` + +All fields are optional. Only include fields that have changed — omitted fields are left unchanged. + + + Human-readable title for the session. Set to `null` to clear. + + + + ISO 8601 timestamp of last activity. Set to `null` to clear. + + + + Agent-specific metadata. See [Extensibility](./extensibility). + + +The `sessionId`, `cwd`, and `additionalDirectories` fields are **not** included +in the update. `sessionId` is already in the notification's `params`, `cwd` is +immutable after session setup, and ACP does not currently define mid-session +mutation for `additionalDirectories`. Agents typically send this notification +after the first meaningful exchange to auto-generate a title. + +## Interaction with Other Session Methods + +`session/list` is a discovery mechanism only — it does **not** restore or modify sessions: + +1. Client calls `session/list` to discover available sessions +2. User selects a session from the list +3. Client calls [`session/load`](./session-setup#loading-sessions) with the chosen `sessionId` to resume the conversation diff --git a/docs/protocol/draft/session-setup.mdx b/docs/protocol/draft/session-setup.mdx new file mode 100644 index 00000000..afa20984 --- /dev/null +++ b/docs/protocol/draft/session-setup.mdx @@ -0,0 +1,419 @@ +--- +title: "Session Setup" +description: "Creating and loading sessions" +--- + +Sessions represent a specific conversation or thread between the [Client](./overview#client) and [Agent](./overview#agent). Each session maintains its own context, conversation history, and state, allowing multiple independent interactions with the same Agent. + +Before creating a session, Clients **MUST** first complete the [initialization](./initialization) phase to establish protocol compatibility and capabilities. + +
+ +```mermaid +sequenceDiagram + participant Client + participant Agent + + Note over Agent,Client: Initialized + + alt + Client->>Agent: session/new + Note over Agent: Create session context + Note over Agent: Connect to MCP servers + Agent-->>Client: session/new response (sessionId) + else + Client->>Agent: session/load (sessionId) + Note over Agent: Restore session context + Note over Agent: Connect to MCP servers + Note over Agent,Client: Replay conversation history... + Agent->>Client: session/update + Agent->>Client: session/update + Note over Agent,Client: All content streamed + Agent-->>Client: session/load response + end + + Note over Client,Agent: Ready for prompts +``` + +
+ +## Creating a Session + +Clients create a new session by calling the `session/new` method with: + +- The [working directory](#working-directory) for the session +- A list of [MCP servers](#mcp-servers) the Agent should connect to + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "session/new", + "params": { + "cwd": "/home/user/project", + "mcpServers": [ + { + "name": "filesystem", + "command": "/path/to/mcp-server", + "args": ["--stdio"], + "env": [] + } + ] + } +} +``` + +The Agent **MUST** respond with a unique [Session ID](#session-id) that identifies this conversation: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "result": { + "sessionId": "sess_abc123def456" + } +} +``` + +## Loading Sessions + +Agents that support the `loadSession` capability allow Clients to resume previous conversations. This feature enables persistence across restarts and sharing sessions between different Client instances. + +### Checking Support + +Before attempting to load a session, Clients **MUST** verify that the Agent supports this capability by checking the `loadSession` field in the `initialize` response: + +```json highlight={7} +{ + "jsonrpc": "2.0", + "id": 0, + "result": { + "protocolVersion": 1, + "agentCapabilities": { + "loadSession": true + } + } +} +``` + +If `loadSession` is `false` or not present, the Agent does not support loading sessions and Clients **MUST NOT** attempt to call `session/load`. + +### Loading a Session + +To load an existing session, Clients **MUST** call the `session/load` method with: + +- The [Session ID](#session-id) to resume +- [MCP servers](#mcp-servers) to connect to +- The [working directory](#working-directory) + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "session/load", + "params": { + "sessionId": "sess_789xyz", + "cwd": "/home/user/project", + "mcpServers": [ + { + "name": "filesystem", + "command": "/path/to/mcp-server", + "args": ["--mode", "filesystem"], + "env": [] + } + ] + } +} +``` + +The Agent **MUST** replay the entire conversation to the Client in the form of `session/update` notifications (like `session/prompt`). + +For example, a user message from the conversation history: + +```json +{ + "jsonrpc": "2.0", + "method": "session/update", + "params": { + "sessionId": "sess_789xyz", + "update": { + "sessionUpdate": "user_message_chunk", + "content": { + "type": "text", + "text": "What's the capital of France?" + } + } + } +} +``` + +Followed by the agent's response: + +```json +{ + "jsonrpc": "2.0", + "method": "session/update", + "params": { + "sessionId": "sess_789xyz", + "update": { + "sessionUpdate": "agent_message_chunk", + "content": { + "type": "text", + "text": "The capital of France is Paris." + } + } + } +} +``` + +When **all** the conversation entries have been streamed to the Client, the Agent **MUST** respond to the original `session/load` request. + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "result": null +} +``` + +The Client can then continue sending prompts as if the session was never interrupted. + +## Additional Workspace Roots + + + This section describes the unstable + `sessionCapabilities.additionalDirectories` capability. Clients MUST gate + usage on that capability being present during initialization. + + +When advertised, Clients MAY include `additionalDirectories` on supported +session lifecycle requests to expand the session's effective filesystem root +set. In the stable lifecycle pages, that means `session/new` and `session/load`. +The same unstable field is also available on `session/resume` and +`session/fork` when those methods are supported. + +```json +{ + "jsonrpc": "2.0", + "id": 2, + "method": "session/load", + "params": { + "sessionId": "sess_789xyz", + "cwd": "/home/user/project", + "additionalDirectories": [ + "/home/user/shared-lib", + "/home/user/product-docs" + ], + "mcpServers": [] + } +} +``` + +When present, `additionalDirectories` has the following behavior: + +- `cwd` remains the primary working directory and the base for relative paths +- each `additionalDirectories` entry **MUST** be an absolute path +- omitting the field or setting it to `null` activates no additional roots for the resulting session +- on `session/load`, Clients must send the full intended additional-root list again because omitted or `null` does not restore stored roots implicitly + +## Session ID + +The session ID returned by `session/new` is a unique identifier for the conversation context. + +Clients use this ID to: + +- Send prompt requests via `session/prompt` +- Cancel ongoing operations via `session/cancel` +- Load previous sessions via `session/load` (if the Agent supports the `loadSession` capability) + +## Working Directory + +The `cwd` (current working directory) parameter establishes the primary file +system context for the session. This directory: + +- **MUST** be an absolute path +- **MUST** be used for the session regardless of where the Agent subprocess was spawned +- **MUST** remain the base for relative-path resolution +- **MUST** be part of the session's effective root set + +When the unstable `sessionCapabilities.additionalDirectories` capability is in +use, the session's effective root set is `[cwd, ...additionalDirectories]`. +Otherwise, the effective root set is just `cwd`. + +## MCP Servers + +The [Model Context Protocol (MCP)](https://modelcontextprotocol.io) allows Agents to access external tools and data sources. When creating a session, Clients **MAY** include connection details for MCP servers that the Agent should connect to. + +MCP servers can be connected to using different transports. All Agents **MUST** support the stdio transport, while HTTP and SSE transports are optional capabilities that can be checked during initialization. + +While they are not required to by the spec, new Agents **SHOULD** support the HTTP transport to ensure compatibility with modern MCP servers. + +### Transport Types + +#### Stdio Transport + +All Agents **MUST** support connecting to MCP servers via stdio (standard input/output). This is the default transport mechanism. + + + A human-readable identifier for the server + + + + The absolute path to the MCP server executable + + + + Command-line arguments to pass to the server + + + + Environment variables to set when launching the server + + + + The name of the environment variable. + + + The value of the environment variable. + + + + +Example stdio transport configuration: + +```json +{ + "name": "filesystem", + "command": "/path/to/mcp-server", + "args": ["--stdio"], + "env": [ + { + "name": "API_KEY", + "value": "secret123" + } + ] +} +``` + +#### HTTP Transport + +When the Agent supports `mcpCapabilities.http`, Clients can specify MCP servers configurations using the HTTP transport. + + + Must be `"http"` to indicate HTTP transport + + + + A human-readable identifier for the server + + + + The URL of the MCP server + + + + HTTP headers to include in requests to the server + + + + The name of the HTTP header. + + + The value to set for the HTTP header. + + + + +Example HTTP transport configuration: + +```json +{ + "type": "http", + "name": "api-server", + "url": "https://api.example.com/mcp", + "headers": [ + { + "name": "Authorization", + "value": "Bearer token123" + }, + { + "name": "Content-Type", + "value": "application/json" + } + ] +} +``` + +#### SSE Transport + +When the Agent supports `mcpCapabilities.sse`, Clients can specify MCP servers configurations using the SSE transport. + +This transport was deprecated by the MCP spec. + + + Must be `"sse"` to indicate SSE transport + + + + A human-readable identifier for the server + + + + The URL of the SSE endpoint + + + + HTTP headers to include when establishing the SSE connection + + + + The name of the HTTP header. + + + The value to set for the HTTP header. + + + + +Example SSE transport configuration: + +```json +{ + "type": "sse", + "name": "event-stream", + "url": "https://events.example.com/mcp", + "headers": [ + { + "name": "X-API-Key", + "value": "apikey456" + } + ] +} +``` + +### Checking Transport Support + +Before using HTTP or SSE transports, Clients **MUST** verify the Agent's capabilities during initialization: + +```json highlight={7-10} +{ + "jsonrpc": "2.0", + "id": 0, + "result": { + "protocolVersion": 1, + "agentCapabilities": { + "mcpCapabilities": { + "http": true, + "sse": true + } + } + } +} +``` + +If `mcpCapabilities.http` is `false` or not present, the Agent does not support HTTP transport. +If `mcpCapabilities.sse` is `false` or not present, the Agent does not support SSE transport. + +Agents **SHOULD** connect to all MCP servers specified by the Client. + +Clients **MAY** use this ability to provide tools directly to the underlying language model by including their own MCP server. diff --git a/docs/protocol/file-system.mdx b/docs/protocol/file-system.mdx index 7c67319d..c16b2baf 100644 --- a/docs/protocol/file-system.mdx +++ b/docs/protocol/file-system.mdx @@ -5,19 +5,6 @@ description: "Client filesystem access methods" The filesystem methods allow Agents to read and write text files within the Client's environment. These methods enable Agents to access unsaved editor state and allow Clients to track file modifications made during agent execution. -## Session Root Scope - -Filesystem methods always operate on absolute paths, but the Client **MUST** -authorize those paths against the session's effective root set. - -- by default, the effective root set is just `cwd` -- if the unstable `sessionCapabilities.additionalDirectories` capability is in use, the effective root set becomes `[cwd, ...additionalDirectories]` -- `cwd` remains the base for relative paths; additional roots only expand filesystem scope -- when a Client discovers a session through `session/list`, it SHOULD treat `cwd` plus `SessionInfo.additionalDirectories` as the authoritative current root set until a later lifecycle request changes it - -Because ACP filesystem methods are client-mediated, the Client remains -responsible for enforcing those root boundaries. - ## Checking Support Before attempting to use filesystem methods, Agents **MUST** verify that the Client supports these capabilities by checking the [Client Capabilities](./initialization#client-capabilities) field in the `initialize` response: @@ -59,8 +46,7 @@ The `fs/read_text_file` method allows Agents to read text file contents from the ``` - The [Session ID](./session-setup#session-id) for this request. The session - determines which filesystem roots are in scope for the path. + The [Session ID](./session-setup#session-id) for this request @@ -105,8 +91,7 @@ The `fs/write_text_file` method allows Agents to write or update text files in t ``` - The [Session ID](./session-setup#session-id) for this request. The session - determines which filesystem roots are in scope for the path. + The [Session ID](./session-setup#session-id) for this request diff --git a/docs/protocol/session-list.mdx b/docs/protocol/session-list.mdx index 219962b8..6592b4e3 100644 --- a/docs/protocol/session-list.mdx +++ b/docs/protocol/session-list.mdx @@ -53,13 +53,6 @@ Before attempting to list sessions, Clients **MUST** verify that the Agent suppo If `sessionCapabilities.list` is not present, the Agent does not support listing sessions and Clients **MUST NOT** attempt to call `session/list`. - - If the Agent also advertises the unstable - `sessionCapabilities.additionalDirectories` capability, `session/list` - supports filtering by `additionalDirectories`, and each returned `SessionInfo` - includes the authoritative additional-root list for that session. - - ## Listing Sessions Clients discover existing sessions by calling the `session/list` method with optional filtering and pagination parameters: @@ -83,13 +76,6 @@ All parameters are optional. A request with an empty `params` object returns the with a matching `cwd` are returned. - - If the Agent advertises `sessionCapabilities.additionalDirectories`, filter - sessions by the exact ordered additional-root list. Omit the field or set it - to `null` to avoid filtering on additional roots. An empty array matches only - sessions whose authoritative additional-root list is empty. - - Opaque cursor token from a previous response's `nextCursor` field for cursor-based pagination. See [Pagination](#pagination). @@ -140,12 +126,6 @@ The Agent **MUST** respond with a list of sessions and optional pagination metad Working directory for the session. Always an absolute path. - - If the Agent advertises `sessionCapabilities.additionalDirectories`, this - is the authoritative ordered additional-root list for the session. `[]` - means there are no additional roots. `null` also means there are no - additional roots, but Agents should prefer `[]`. - Human-readable title for the session. May be auto-generated from the first prompt. @@ -210,11 +190,7 @@ All fields are optional. Only include fields that have changed — omitted field Agent-specific metadata. See [Extensibility](./extensibility).
-The `sessionId`, `cwd`, and `additionalDirectories` fields are **not** included -in the update. `sessionId` is already in the notification's `params`, `cwd` is -immutable after session setup, and ACP does not currently define mid-session -mutation for `additionalDirectories`. Agents typically send this notification -after the first meaningful exchange to auto-generate a title. +The `sessionId` and `cwd` fields are **not** included in the update — `sessionId` is already in the notification's `params`, and `cwd` is immutable (set during [`session/new`](./session-setup#creating-a-session)). Agents typically send this notification after the first meaningful exchange to auto-generate a title. ## Interaction with Other Session Methods diff --git a/docs/protocol/session-setup.mdx b/docs/protocol/session-setup.mdx index afa20984..f323f320 100644 --- a/docs/protocol/session-setup.mdx +++ b/docs/protocol/session-setup.mdx @@ -178,44 +178,6 @@ When **all** the conversation entries have been streamed to the Client, the Agen The Client can then continue sending prompts as if the session was never interrupted. -## Additional Workspace Roots - - - This section describes the unstable - `sessionCapabilities.additionalDirectories` capability. Clients MUST gate - usage on that capability being present during initialization. - - -When advertised, Clients MAY include `additionalDirectories` on supported -session lifecycle requests to expand the session's effective filesystem root -set. In the stable lifecycle pages, that means `session/new` and `session/load`. -The same unstable field is also available on `session/resume` and -`session/fork` when those methods are supported. - -```json -{ - "jsonrpc": "2.0", - "id": 2, - "method": "session/load", - "params": { - "sessionId": "sess_789xyz", - "cwd": "/home/user/project", - "additionalDirectories": [ - "/home/user/shared-lib", - "/home/user/product-docs" - ], - "mcpServers": [] - } -} -``` - -When present, `additionalDirectories` has the following behavior: - -- `cwd` remains the primary working directory and the base for relative paths -- each `additionalDirectories` entry **MUST** be an absolute path -- omitting the field or setting it to `null` activates no additional roots for the resulting session -- on `session/load`, Clients must send the full intended additional-root list again because omitted or `null` does not restore stored roots implicitly - ## Session ID The session ID returned by `session/new` is a unique identifier for the conversation context. @@ -228,17 +190,11 @@ Clients use this ID to: ## Working Directory -The `cwd` (current working directory) parameter establishes the primary file -system context for the session. This directory: +The `cwd` (current working directory) parameter establishes the file system context for the session. This directory: - **MUST** be an absolute path - **MUST** be used for the session regardless of where the Agent subprocess was spawned -- **MUST** remain the base for relative-path resolution -- **MUST** be part of the session's effective root set - -When the unstable `sessionCapabilities.additionalDirectories` capability is in -use, the session's effective root set is `[cwd, ...additionalDirectories]`. -Otherwise, the effective root set is just `cwd`. +- **SHOULD** serve as a boundary for tool operations on the file system ## MCP Servers diff --git a/docs/rfds/additional-directories.mdx b/docs/rfds/additional-directories.mdx index a8ead3f7..3ab0f970 100644 --- a/docs/rfds/additional-directories.mdx +++ b/docs/rfds/additional-directories.mdx @@ -14,7 +14,7 @@ ACP currently standardizes `cwd` on session lifecycle requests, but does not def This RFD proposes an optional field: ```ts -additionalDirectories?: string[] | null +additionalDirectories?: string[] ``` on: @@ -44,7 +44,7 @@ Without a standardized field, clients and agents must rely on implementation-spe > What are you proposing to improve the situation? -Add `additionalDirectories?: string[] | null` to the session lifecycle request schemas listed above and to `session/list`, and define protocol-level validation and semantics for it. +Add `additionalDirectories?: string[]` to the session lifecycle request schemas listed above and to `session/list`, and define protocol-level validation and semantics for it. The proposal is scoped to session lifecycle requests, session discovery requests, and session discovery metadata only: @@ -54,7 +54,7 @@ The proposal is scoped to session lifecycle requests, session discovery requests Agents advertise support with `sessionCapabilities.additionalDirectories`. Clients MUST gate usage on that capability. -This proposal also extends `SessionInfo` returned by `session/list` with authoritative `additionalDirectories` state, and allows `session/list` to filter on `cwd` plus `additionalDirectories`, so clients that support session discovery can recover and query the active root set for listed sessions. `session/load` and `session/resume` nevertheless remain explicit-list only: omitted or `null` `additionalDirectories` means no additional roots are activated for the resulting session, while an array-valued `additionalDirectories` becomes the complete resulting additional-root list for that request. +This proposal also extends `SessionInfo` returned by `session/list` with authoritative `additionalDirectories` state, and allows `session/list` to filter on `cwd` plus `additionalDirectories`, so clients that support session discovery can recover and query the active root set for listed sessions. `session/load` and `session/resume` nevertheless remain explicit-list only: omitted `additionalDirectories` means no additional roots are activated for the resulting session, while an array-valued `additionalDirectories` becomes the complete resulting additional-root list for that request. ## Shiny future @@ -94,19 +94,19 @@ Security boundaries remain explicit: declared roots communicate intended scope, The following optional property is added to each request type named above: ```ts -additionalDirectories?: string[] | null +additionalDirectories?: string[] ``` The following optional property is also added to `ListSessionsRequest`: ```ts -additionalDirectories?: string[] | null +additionalDirectories?: string[] ``` The following optional property is also added to `SessionInfo`: ```ts -additionalDirectories?: string[] | null +additionalDirectories?: string[] ``` The following capability is added to `SessionCapabilities`: @@ -117,9 +117,9 @@ additionalDirectories?: {} Clients MUST send `additionalDirectories` only when `sessionCapabilities.additionalDirectories` is present. -If an agent advertises `sessionCapabilities.additionalDirectories` and also supports `session/list`, each `SessionInfo` it returns MUST include `additionalDirectories` as the authoritative ordered additional-root list for that session. Agents SHOULD encode "no additional roots" as `[]` rather than `null`. Clients MUST treat `null` the same as `[]`. +If an agent advertises `sessionCapabilities.additionalDirectories` and also supports `session/list`, any `SessionInfo.additionalDirectories` value it returns is the authoritative ordered additional-root list for that session. Agents MAY omit the field when there are no additional roots, and clients MUST treat an omitted field the same as `[]`. -If an agent advertises `sessionCapabilities.additionalDirectories` and also supports `session/list`, `ListSessionsRequest.additionalDirectories` filters sessions by exact match on the authoritative ordered additional-root list. When both `cwd` and `additionalDirectories` are present on `session/list`, both filters apply. An empty `additionalDirectories` filter matches only sessions whose authoritative additional-root list is `[]`. A `null` filter is equivalent to omitting the field. +If an agent advertises `sessionCapabilities.additionalDirectories` and also supports `session/list`, `ListSessionsRequest.additionalDirectories` filters sessions by exact match on the authoritative ordered additional-root list. When both `cwd` and `additionalDirectories` are present on `session/list`, both filters apply. An empty `additionalDirectories` filter matches only sessions whose authoritative additional-root list is `[]`. If adopted, the session-setup, session-list, and filesystem documentation will need corresponding updates so they describe the effective root set rather than `cwd` alone as the session filesystem context or boundary. @@ -183,11 +183,10 @@ When an agent supports both `sessionCapabilities.additionalDirectories` and `ses `additionalDirectories` has the following properties: -- The field MAY be omitted, set to `null`, or set to an array of strings. -- `null` is equivalent to omitting the field. -- Each array entry MUST be an absolute path under the same platform path rules used for `cwd`. +- The field MUST be an array of strings when present. +- Each entry MUST be an absolute path under the same platform path rules used for `cwd`. - Empty strings MUST be rejected. -- `null` is not a valid array entry. +- `null` is not a valid value for the field or for any entry. ACP does not define a wire-level lexical normalization algorithm for `cwd` or `additionalDirectories`. @@ -230,14 +229,14 @@ For `NewSessionRequest`, the resulting additional root list is: For `LoadSessionRequest` and `ResumeSessionRequest`: - when `additionalDirectories` is present with an array value, it is the complete resulting list of additional roots for the active session, even if that list differs from the session's previously stored additional roots; -- when omitted or set to `null`, the resulting additional root list is `[]`. +- when omitted, the resulting additional root list is `[]`. Agents MUST NOT implicitly reactivate stored additional roots that were not supplied on the `session/load` or `session/resume` request. Supplying `additionalDirectories` on `session/load` or `session/resume` is always allowed when the capability is advertised, and doing so may preserve, replace, reduce, or expand the session's previously stored additional-root list for the resulting active session, subject to validation and policy checks. Clients that need to preserve a session's additional roots across restarts or across client instances MUST obtain, persist, or reconstruct the full list and resend it on load or resume. When `session/list` is available, `SessionInfo.additionalDirectories` provides the authoritative current additional-root list for that purpose. For `ForkSessionRequest`: - when `additionalDirectories` is present with an array value, it is a full replacement list for the forked session; -- when omitted or set to `null`, the resulting additional root list is `[]`. +- when omitted, the resulting additional root list is `[]`. Agents MUST NOT implicitly inherit additional roots from the source session unless the implementation can prove that the active root list is already authoritative to the requesting client on the current connection. Otherwise, the agent MUST fail the request or require the client to provide the full list explicitly. @@ -268,7 +267,7 @@ An agent receiving a session lifecycle request with `additionalDirectories` MUST The agent MUST reject the request if: -- `additionalDirectories` is neither `null` nor an array; +- `additionalDirectories` is not an array; - any entry is not a string; - any entry is empty; - any entry is not absolute. @@ -387,7 +386,7 @@ Because ACP does not define directory contents, agents SHOULD avoid assuming tha ### Backward compatibility -This proposal is additive at the schema level. Requests that omit `additionalDirectories` or set it to `null` behave exactly as they do today. Existing clients that do not need multi-root support require no changes. +This proposal is additive at the schema level. Requests that omit `additionalDirectories` behave exactly as they do today. Existing clients that do not need multi-root support require no changes. Updated agents MUST continue to accept requests that do not include the field. @@ -430,7 +429,7 @@ Clients MUST gate `additionalDirectories` on `sessionCapabilities.additionalDire ### Why not restore stored roots on `session/load` or `session/resume` when the field is omitted? -Even with `SessionInfo.additionalDirectories` available through `session/list`, implicit restoration would still let an agent reactivate filesystem scope that the current request did not state explicitly. That is undesirable for clients that do not use `session/list`, for clients resuming a session by ID without first listing it, and for clients that want request-time control over the active root set. This proposal therefore keeps load and resume explicit-list only for additional roots: omitting the field or sending `null` activates none, while supplying an array is explicitly allowed and sets the complete resulting additional-root list for that request. +Even with `SessionInfo.additionalDirectories` available through `session/list`, implicit restoration would still let an agent reactivate filesystem scope that the current request did not state explicitly. That is undesirable for clients that do not use `session/list`, for clients resuming a session by ID without first listing it, and for clients that want request-time control over the active root set. This proposal therefore keeps load and resume explicit-list only for additional roots: omitting the field activates none, while supplying an array is explicitly allowed and sets the complete resulting additional-root list for that request. ### What alternative approaches did you consider, and why did you settle on this one? diff --git a/docs/rfds/session-info-update.mdx b/docs/rfds/session-info-update.mdx index 49aa7b87..f25ab60b 100644 --- a/docs/rfds/session-info-update.mdx +++ b/docs/rfds/session-info-update.mdx @@ -42,7 +42,7 @@ Add a new `session_info_update` variant to the existing `SessionUpdate` discrimi - Contains the same fields as `SessionInfo` from `session/list` - All fields are optional (partial updates) - Enables incremental metadata updates - - **Important**: `SessionInfoUpdate` must stay aligned with the mutable metadata fields of `SessionInfo` - immutable fields such as workspace roots do not need corresponding update fields + - **Important**: `SessionInfoUpdate` must stay aligned with `SessionInfo` - when new fields are added to `SessionInfo`, they should also be added to `SessionInfoUpdate` as optional fields 3. **Support common use cases**: - Agent auto-generates title after first prompt diff --git a/schema/schema.unstable.json b/schema/schema.unstable.json index c4785e04..6ca090e8 100644 --- a/schema/schema.unstable.json +++ b/schema/schema.unstable.json @@ -2131,7 +2131,7 @@ "items": { "type": "string" }, - "type": ["array", "null"] + "type": "array" }, "cwd": { "description": "The working directory for this session.", @@ -2479,7 +2479,7 @@ "items": { "type": "string" }, - "type": ["array", "null"] + "type": "array" }, "cursor": { "description": "Opaque cursor token from a previous response's nextCursor field for cursor-based pagination", @@ -2532,7 +2532,7 @@ "items": { "type": "string" }, - "type": ["array", "null"] + "type": "array" }, "cwd": { "description": "The working directory for this session.", @@ -2903,7 +2903,7 @@ "items": { "type": "string" }, - "type": ["array", "null"] + "type": "array" }, "cwd": { "description": "The working directory for this session. Must be an absolute path.", @@ -3517,7 +3517,7 @@ "items": { "type": "string" }, - "type": ["array", "null"] + "type": "array" }, "cwd": { "description": "The working directory for this session.", @@ -3954,7 +3954,7 @@ "items": { "type": "string" }, - "type": ["array", "null"] + "type": "array" }, "cwd": { "description": "The working directory for this session. Must be an absolute path.", diff --git a/src/agent.rs b/src/agent.rs index d107b8cf..59df88f2 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -902,8 +902,8 @@ pub struct NewSessionRequest { /// These expand the session's filesystem scope without changing `cwd`, which /// remains the base for relative paths. #[cfg(feature = "unstable_session_additional_directories")] - #[serde(skip_serializing_if = "Option::is_none")] - pub additional_directories: Option>, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub additional_directories: Vec, /// List of MCP (Model Context Protocol) servers the agent should connect to. pub mcp_servers: Vec, /// The _meta property is reserved by ACP to allow clients and agents to attach additional @@ -921,7 +921,7 @@ impl NewSessionRequest { Self { cwd: cwd.into(), #[cfg(feature = "unstable_session_additional_directories")] - additional_directories: None, + additional_directories: vec![], mcp_servers: vec![], meta: None, } @@ -934,11 +934,8 @@ impl NewSessionRequest { /// Additional workspace roots for this session. Each path must be absolute. #[cfg(feature = "unstable_session_additional_directories")] #[must_use] - pub fn additional_directories( - mut self, - additional_directories: impl IntoOption>, - ) -> Self { - self.additional_directories = additional_directories.into_option(); + pub fn additional_directories(mut self, additional_directories: Vec) -> Self { + self.additional_directories = additional_directories; self } @@ -1076,8 +1073,8 @@ pub struct LoadSessionRequest { /// /// Additional workspace roots to activate for this session. Each path must be absolute. #[cfg(feature = "unstable_session_additional_directories")] - #[serde(skip_serializing_if = "Option::is_none")] - pub additional_directories: Option>, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub additional_directories: Vec, /// The ID of the session to load. pub session_id: SessionId, /// The _meta property is reserved by ACP to allow clients and agents to attach additional @@ -1096,7 +1093,7 @@ impl LoadSessionRequest { mcp_servers: vec![], cwd: cwd.into(), #[cfg(feature = "unstable_session_additional_directories")] - additional_directories: None, + additional_directories: vec![], session_id: session_id.into(), meta: None, } @@ -1109,11 +1106,8 @@ impl LoadSessionRequest { /// Additional workspace roots to activate for this session. Each path must be absolute. #[cfg(feature = "unstable_session_additional_directories")] #[must_use] - pub fn additional_directories( - mut self, - additional_directories: impl IntoOption>, - ) -> Self { - self.additional_directories = additional_directories.into_option(); + pub fn additional_directories(mut self, additional_directories: Vec) -> Self { + self.additional_directories = additional_directories; self } @@ -1244,8 +1238,8 @@ pub struct ForkSessionRequest { /// /// Additional workspace roots to activate for this session. Each path must be absolute. #[cfg(feature = "unstable_session_additional_directories")] - #[serde(skip_serializing_if = "Option::is_none")] - pub additional_directories: Option>, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub additional_directories: Vec, /// List of MCP servers to connect to for this session. #[serde(default, skip_serializing_if = "Vec::is_empty")] pub mcp_servers: Vec, @@ -1266,7 +1260,7 @@ impl ForkSessionRequest { session_id: session_id.into(), cwd: cwd.into(), #[cfg(feature = "unstable_session_additional_directories")] - additional_directories: None, + additional_directories: vec![], mcp_servers: vec![], meta: None, } @@ -1279,11 +1273,8 @@ impl ForkSessionRequest { /// Additional workspace roots to activate for this session. Each path must be absolute. #[cfg(feature = "unstable_session_additional_directories")] #[must_use] - pub fn additional_directories( - mut self, - additional_directories: impl IntoOption>, - ) -> Self { - self.additional_directories = additional_directories.into_option(); + pub fn additional_directories(mut self, additional_directories: Vec) -> Self { + self.additional_directories = additional_directories; self } @@ -1429,8 +1420,8 @@ pub struct ResumeSessionRequest { /// /// Additional workspace roots to activate for this session. Each path must be absolute. #[cfg(feature = "unstable_session_additional_directories")] - #[serde(skip_serializing_if = "Option::is_none")] - pub additional_directories: Option>, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub additional_directories: Vec, /// List of MCP servers to connect to for this session. #[serde(default, skip_serializing_if = "Vec::is_empty")] pub mcp_servers: Vec, @@ -1451,7 +1442,7 @@ impl ResumeSessionRequest { session_id: session_id.into(), cwd: cwd.into(), #[cfg(feature = "unstable_session_additional_directories")] - additional_directories: None, + additional_directories: vec![], mcp_servers: vec![], meta: None, } @@ -1464,11 +1455,8 @@ impl ResumeSessionRequest { /// Additional workspace roots to activate for this session. Each path must be absolute. #[cfg(feature = "unstable_session_additional_directories")] #[must_use] - pub fn additional_directories( - mut self, - additional_directories: impl IntoOption>, - ) -> Self { - self.additional_directories = additional_directories.into_option(); + pub fn additional_directories(mut self, additional_directories: Vec) -> Self { + self.additional_directories = additional_directories; self } @@ -1687,8 +1675,8 @@ pub struct ListSessionsRequest { /// /// Filter sessions by the exact ordered additional workspace roots. Each path must be absolute. #[cfg(feature = "unstable_session_additional_directories")] - #[serde(skip_serializing_if = "Option::is_none")] - pub additional_directories: Option>, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub additional_directories: Vec, /// Opaque cursor token from a previous response's nextCursor field for cursor-based pagination #[serde(skip_serializing_if = "Option::is_none")] pub cursor: Option, @@ -1721,11 +1709,8 @@ impl ListSessionsRequest { /// Filter sessions by the exact ordered additional workspace roots. Each path must be absolute. #[cfg(feature = "unstable_session_additional_directories")] #[must_use] - pub fn additional_directories( - mut self, - additional_directories: impl IntoOption>, - ) -> Self { - self.additional_directories = additional_directories.into_option(); + pub fn additional_directories(mut self, additional_directories: Vec) -> Self { + self.additional_directories = additional_directories; self } @@ -1812,8 +1797,9 @@ pub struct SessionInfo { /// /// Authoritative ordered additional workspace roots for this session. Each path must be absolute. #[cfg(feature = "unstable_session_additional_directories")] - #[serde(skip_serializing_if = "Option::is_none")] - pub additional_directories: Option>, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub additional_directories: Vec, + /// Human-readable title for the session #[serde(skip_serializing_if = "Option::is_none")] pub title: Option, @@ -1836,7 +1822,7 @@ impl SessionInfo { session_id: session_id.into(), cwd: cwd.into(), #[cfg(feature = "unstable_session_additional_directories")] - additional_directories: None, + additional_directories: vec![], title: None, updated_at: None, meta: None, @@ -1850,11 +1836,8 @@ impl SessionInfo { /// Authoritative ordered additional workspace roots for this session. Each path must be absolute. #[cfg(feature = "unstable_session_additional_directories")] #[must_use] - pub fn additional_directories( - mut self, - additional_directories: impl IntoOption>, - ) -> Self { - self.additional_directories = additional_directories.into_option(); + pub fn additional_directories(mut self, additional_directories: Vec) -> Self { + self.additional_directories = additional_directories; self } @@ -4585,25 +4568,47 @@ mod test_serialization { "additionalDirectories": [] }) ); + assert_eq!( + serde_json::to_value(SessionInfo::new("sess_abc123", "/home/user/project")).unwrap(), + json!({ + "sessionId": "sess_abc123", + "cwd": "/home/user/project" + }) + ); assert_eq!( serde_json::to_value( - SessionInfo::new("sess_abc123", "/home/user/project") - .additional_directories(Vec::::new()) + SessionInfo::new("sess_abc123", "/home/user/project").additional_directories(vec![ + PathBuf::from("/home/user/shared-lib"), + PathBuf::from("/home/user/product-docs"), + ]) ) .unwrap(), json!({ "sessionId": "sess_abc123", "cwd": "/home/user/project", - "additionalDirectories": [] + "additionalDirectories": [ + "/home/user/shared-lib", + "/home/user/product-docs" + ] }) ); + assert_eq!( + serde_json::from_value::(json!({ + "sessionId": "sess_abc123", + "cwd": "/home/user/project" + })) + .unwrap() + .additional_directories, + Vec::::new() + ); + assert_eq!( serde_json::from_value::(json!({ "additionalDirectories": [] })) .unwrap() .additional_directories, - Some(vec![]) + Vec::::new() ); } From 860e7e66181bff31dd948b4988b5bc9f3609f4cb Mon Sep 17 00:00:00 2001 From: Ben Brandt Date: Fri, 27 Mar 2026 13:23:56 +0100 Subject: [PATCH 8/9] More clean up --- docs/protocol/draft/session-list.mdx | 10 +++++----- docs/protocol/draft/session-setup.mdx | 4 ++-- docs/rfds/additional-directories.mdx | 20 ++++++++++---------- src/agent.rs | 11 ++++++++--- 4 files changed, 25 insertions(+), 20 deletions(-) diff --git a/docs/protocol/draft/session-list.mdx b/docs/protocol/draft/session-list.mdx index 7137a933..dee0040a 100644 --- a/docs/protocol/draft/session-list.mdx +++ b/docs/protocol/draft/session-list.mdx @@ -84,11 +84,11 @@ All parameters are optional. A request with an empty `params` object returns the with a matching `cwd` are returned.
- + If the Agent advertises `sessionCapabilities.additionalDirectories`, filter - sessions by the exact ordered additional-root list. Omit the field or set it - to `null` to avoid filtering on additional roots. An empty array matches only - sessions whose authoritative additional-root list is empty. + sessions by the exact ordered additional-root list when this field is present + and non-empty. Omitting the field or providing an empty array means no + additional-root filter is applied. @@ -144,7 +144,7 @@ The Agent **MUST** respond with a list of sessions and optional pagination metad If the Agent advertises `sessionCapabilities.additionalDirectories`, this is the authoritative ordered additional-root list for the session when - present. Omitting the field or returning `[]` means there are no + present. Omitting the field or returning an empty array means there are no additional roots. diff --git a/docs/protocol/draft/session-setup.mdx b/docs/protocol/draft/session-setup.mdx index afa20984..79ccca9b 100644 --- a/docs/protocol/draft/session-setup.mdx +++ b/docs/protocol/draft/session-setup.mdx @@ -213,8 +213,8 @@ When present, `additionalDirectories` has the following behavior: - `cwd` remains the primary working directory and the base for relative paths - each `additionalDirectories` entry **MUST** be an absolute path -- omitting the field or setting it to `null` activates no additional roots for the resulting session -- on `session/load`, Clients must send the full intended additional-root list again because omitted or `null` does not restore stored roots implicitly +- omitting the field or providing an empty array activates no additional roots for the resulting session +- on `session/load`, Clients must send the full intended additional-root list again because omitting the field or providing an empty array does not restore stored roots implicitly ## Session ID diff --git a/docs/rfds/additional-directories.mdx b/docs/rfds/additional-directories.mdx index 3ab0f970..fb2f512c 100644 --- a/docs/rfds/additional-directories.mdx +++ b/docs/rfds/additional-directories.mdx @@ -54,7 +54,7 @@ The proposal is scoped to session lifecycle requests, session discovery requests Agents advertise support with `sessionCapabilities.additionalDirectories`. Clients MUST gate usage on that capability. -This proposal also extends `SessionInfo` returned by `session/list` with authoritative `additionalDirectories` state, and allows `session/list` to filter on `cwd` plus `additionalDirectories`, so clients that support session discovery can recover and query the active root set for listed sessions. `session/load` and `session/resume` nevertheless remain explicit-list only: omitted `additionalDirectories` means no additional roots are activated for the resulting session, while an array-valued `additionalDirectories` becomes the complete resulting additional-root list for that request. +This proposal also extends `SessionInfo` returned by `session/list` with authoritative `additionalDirectories` state, and allows `session/list` to filter on `cwd` plus `additionalDirectories`, so clients that support session discovery can recover and query the active root set for listed sessions. `session/load` and `session/resume` nevertheless remain explicit-list only: omitting `additionalDirectories` or supplying an empty array means no additional roots are activated for the resulting session, while a non-empty array-valued `additionalDirectories` becomes the complete resulting additional-root list for that request. ## Shiny future @@ -119,7 +119,7 @@ Clients MUST send `additionalDirectories` only when `sessionCapabilities.additio If an agent advertises `sessionCapabilities.additionalDirectories` and also supports `session/list`, any `SessionInfo.additionalDirectories` value it returns is the authoritative ordered additional-root list for that session. Agents MAY omit the field when there are no additional roots, and clients MUST treat an omitted field the same as `[]`. -If an agent advertises `sessionCapabilities.additionalDirectories` and also supports `session/list`, `ListSessionsRequest.additionalDirectories` filters sessions by exact match on the authoritative ordered additional-root list. When both `cwd` and `additionalDirectories` are present on `session/list`, both filters apply. An empty `additionalDirectories` filter matches only sessions whose authoritative additional-root list is `[]`. +If an agent advertises `sessionCapabilities.additionalDirectories` and also supports `session/list`, `ListSessionsRequest.additionalDirectories` filters sessions by exact match on the authoritative ordered additional-root list when the field is present and non-empty. When both `cwd` and a non-empty `additionalDirectories` are present on `session/list`, both filters apply. Omitting the field or supplying an empty array means no additional-root filter is applied. If adopted, the session-setup, session-list, and filesystem documentation will need corresponding updates so they describe the effective root set rather than `cwd` alone as the session filesystem context or boundary. @@ -206,8 +206,8 @@ For `session/list` filtering, matching is against the session's authoritative or The effective ordered root list for a session is: -- `[cwd]` when `additionalDirectories` is omitted or `null` -- `[cwd, ...additionalDirectories]` when `additionalDirectories` is an array +- `[cwd]` when `additionalDirectories` is omitted or is an empty array +- `[cwd, ...additionalDirectories]` when `additionalDirectories` is a non-empty array This ordered root list has the following semantics: @@ -223,20 +223,20 @@ A file path is in scope for the session if, after platform-appropriate path reso For `NewSessionRequest`, the resulting additional root list is: -- `additionalDirectories` when present with an array value; +- `additionalDirectories` when present with a non-empty array value; - otherwise `[]`. For `LoadSessionRequest` and `ResumeSessionRequest`: -- when `additionalDirectories` is present with an array value, it is the complete resulting list of additional roots for the active session, even if that list differs from the session's previously stored additional roots; -- when omitted, the resulting additional root list is `[]`. +- when `additionalDirectories` is present with a non-empty array value, it is the complete resulting list of additional roots for the active session, even if that list differs from the session's previously stored additional roots; +- when omitted or present as an empty array, the resulting additional root list is `[]`. Agents MUST NOT implicitly reactivate stored additional roots that were not supplied on the `session/load` or `session/resume` request. Supplying `additionalDirectories` on `session/load` or `session/resume` is always allowed when the capability is advertised, and doing so may preserve, replace, reduce, or expand the session's previously stored additional-root list for the resulting active session, subject to validation and policy checks. Clients that need to preserve a session's additional roots across restarts or across client instances MUST obtain, persist, or reconstruct the full list and resend it on load or resume. When `session/list` is available, `SessionInfo.additionalDirectories` provides the authoritative current additional-root list for that purpose. For `ForkSessionRequest`: -- when `additionalDirectories` is present with an array value, it is a full replacement list for the forked session; -- when omitted, the resulting additional root list is `[]`. +- when `additionalDirectories` is present with a non-empty array value, it is a full replacement list for the forked session; +- when omitted or present as an empty array, the resulting additional root list is `[]`. Agents MUST NOT implicitly inherit additional roots from the source session unless the implementation can prove that the active root list is already authoritative to the requesting client on the current connection. Otherwise, the agent MUST fail the request or require the client to provide the full list explicitly. @@ -429,7 +429,7 @@ Clients MUST gate `additionalDirectories` on `sessionCapabilities.additionalDire ### Why not restore stored roots on `session/load` or `session/resume` when the field is omitted? -Even with `SessionInfo.additionalDirectories` available through `session/list`, implicit restoration would still let an agent reactivate filesystem scope that the current request did not state explicitly. That is undesirable for clients that do not use `session/list`, for clients resuming a session by ID without first listing it, and for clients that want request-time control over the active root set. This proposal therefore keeps load and resume explicit-list only for additional roots: omitting the field activates none, while supplying an array is explicitly allowed and sets the complete resulting additional-root list for that request. +Even with `SessionInfo.additionalDirectories` available through `session/list`, implicit restoration would still let an agent reactivate filesystem scope that the current request did not state explicitly. That is undesirable for clients that do not use `session/list`, for clients resuming a session by ID without first listing it, and for clients that want request-time control over the active root set. This proposal therefore keeps load and resume explicit-list only for additional roots: omitting the field or supplying an empty array activates none, while supplying a non-empty array is explicitly allowed and sets the complete resulting additional-root list for that request. ### What alternative approaches did you consider, and why did you settle on this one? diff --git a/src/agent.rs b/src/agent.rs index 59df88f2..c4bd1a1a 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -4564,9 +4564,7 @@ mod test_serialization { ListSessionsRequest::new().additional_directories(Vec::::new()) ) .unwrap(), - json!({ - "additionalDirectories": [] - }) + json!({}) ); assert_eq!( serde_json::to_value(SessionInfo::new("sess_abc123", "/home/user/project")).unwrap(), @@ -4602,6 +4600,13 @@ mod test_serialization { Vec::::new() ); + assert_eq!( + serde_json::from_value::(json!({})) + .unwrap() + .additional_directories, + Vec::::new() + ); + assert_eq!( serde_json::from_value::(json!({ "additionalDirectories": [] From 2412717e4cb28c8ef091a9b454f3c95e02bdcc9a Mon Sep 17 00:00:00 2001 From: Ben Brandt Date: Fri, 27 Mar 2026 16:10:56 +0100 Subject: [PATCH 9/9] Final cleanups --- docs/docs.json | 3 +++ docs/protocol/draft/file-system.mdx | 10 +++++----- docs/protocol/draft/schema.mdx | 24 +++++++++++++++++++++--- docs/protocol/draft/session-list.mdx | 10 +++++----- docs/protocol/draft/session-setup.mdx | 4 ++-- schema/schema.unstable.json | 16 ++++++++-------- src/agent.rs | 26 ++++++++++++++++++++++---- 7 files changed, 66 insertions(+), 27 deletions(-) diff --git a/docs/docs.json b/docs/docs.json index a8e43fd1..e5156612 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -82,6 +82,9 @@ "group": "Draft: In Progress and May Change", "hidden": true, "pages": [ + "protocol/draft/session-setup", + "protocol/draft/session-list", + "protocol/draft/file-system", "protocol/draft/cancellation", "protocol/draft/schema" ] diff --git a/docs/protocol/draft/file-system.mdx b/docs/protocol/draft/file-system.mdx index 7c67319d..98c6e312 100644 --- a/docs/protocol/draft/file-system.mdx +++ b/docs/protocol/draft/file-system.mdx @@ -20,7 +20,7 @@ responsible for enforcing those root boundaries. ## Checking Support -Before attempting to use filesystem methods, Agents **MUST** verify that the Client supports these capabilities by checking the [Client Capabilities](./initialization#client-capabilities) field in the `initialize` response: +Before attempting to use filesystem methods, Agents **MUST** verify that the Client supports these capabilities by checking the [Client Capabilities](/protocol/initialization#client-capabilities) field in the `initialize` response: ```json highlight={8,9} { @@ -59,8 +59,8 @@ The `fs/read_text_file` method allows Agents to read text file contents from the ``` - The [Session ID](./session-setup#session-id) for this request. The session - determines which filesystem roots are in scope for the path. + The [Session ID](/protocol/session-setup#session-id) for this request. The + session determines which filesystem roots are in scope for the path. @@ -105,8 +105,8 @@ The `fs/write_text_file` method allows Agents to write or update text files in t ``` - The [Session ID](./session-setup#session-id) for this request. The session - determines which filesystem roots are in scope for the path. + The [Session ID](/protocol/session-setup#session-id) for this request. The + session determines which filesystem roots are in scope for the path. diff --git a/docs/protocol/draft/schema.mdx b/docs/protocol/draft/schema.mdx index 8de281d7..92466bcf 100644 --- a/docs/protocol/draft/schema.mdx +++ b/docs/protocol/draft/schema.mdx @@ -363,6 +363,10 @@ This capability is not part of the spec yet, and may be removed or changed at an Additional workspace roots to activate for this session. Each path must be absolute. +When omitted or empty, no additional roots are activated. When non-empty, +this is the complete resulting additional-root list for the forked +session. + The working directory for this session. @@ -449,6 +453,9 @@ This capability is not part of the spec yet, and may be removed or changed at an Filter sessions by the exact ordered additional workspace roots. Each path must be absolute. +This filter applies only when the field is present and non-empty. When +omitted or empty, no additional-root filter is applied. + Opaque cursor token from a previous response's nextCursor field for cursor-based pagination @@ -523,6 +530,10 @@ This capability is not part of the spec yet, and may be removed or changed at an Additional workspace roots to activate for this session. Each path must be absolute. +When omitted or empty, no additional roots are activated. When non-empty, +this is the complete resulting additional-root list for the loaded +session. + The working directory for this session. @@ -611,7 +622,8 @@ This capability is not part of the spec yet, and may be removed or changed at an Additional workspace roots for this session. Each path must be absolute. These expand the session's filesystem scope without changing `cwd`, which -remains the base for relative paths. +remains the base for relative paths. When omitted or empty, no +additional roots are activated for the new session. @@ -819,6 +831,10 @@ This capability is not part of the spec yet, and may be removed or changed at an Additional workspace roots to activate for this session. Each path must be absolute. +When omitted or empty, no additional roots are activated. When non-empty, +this is the complete resulting additional-root list for the resumed +session. + The working directory for this session. @@ -4217,7 +4233,7 @@ This capability is not part of the spec yet, and may be removed or changed at an Capabilities for additional session directories support. By supplying `\{\}` it means that the agent supports the `additionalDirectories` field on -session lifecycle requests and `session/list`. +supported session lifecycle requests and `session/list`. **Type:** Object @@ -4261,7 +4277,7 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte This capability is not part of the spec yet, and may be removed or changed at any point. -Whether the agent supports `additionalDirectories` on session lifecycle requests and `session/list`. +Whether the agent supports `additionalDirectories` on supported session lifecycle requests and `session/list`. SessionCloseCapabilities | null} > @@ -4576,6 +4592,8 @@ This capability is not part of the spec yet, and may be removed or changed at an Authoritative ordered additional workspace roots for this session. Each path must be absolute. +When omitted or empty, there are no additional roots for the session. + The working directory for this session. Must be an absolute path. diff --git a/docs/protocol/draft/session-list.mdx b/docs/protocol/draft/session-list.mdx index dee0040a..8e1be790 100644 --- a/docs/protocol/draft/session-list.mdx +++ b/docs/protocol/draft/session-list.mdx @@ -7,7 +7,7 @@ The `session/list` method allows Clients to discover sessions known to an Agent. Agents can also push session metadata updates to Clients in real-time via the `session_info_update` notification, keeping session titles and metadata in sync without polling. -Before listing sessions, Clients **MUST** first complete the [initialization](./initialization) phase to verify the Agent supports this capability. +Before listing sessions, Clients **MUST** first complete the [initialization](/protocol/initialization) phase to verify the Agent supports this capability.
@@ -155,7 +155,7 @@ The Agent **MUST** respond with a list of sessions and optional pagination metad ISO 8601 timestamp of the last activity in the session.
- Agent-specific metadata. See [Extensibility](./extensibility). + Agent-specific metadata. See [Extensibility](/protocol/extensibility). @@ -179,7 +179,7 @@ When no sessions match the criteria, the Agent **MUST** return an empty `session ## Updating Session Metadata -Agents can update session metadata in real-time by sending a `session_info_update` notification via `session/update`. This follows the same pattern as other session notifications like [`available_commands_update`](./slash-commands) and [`current_mode_update`](./session-modes). +Agents can update session metadata in real-time by sending a `session_info_update` notification via `session/update`. This follows the same pattern as other session notifications like [`available_commands_update`](/protocol/slash-commands) and [`current_mode_update`](/protocol/session-modes). ```json { @@ -210,7 +210,7 @@ All fields are optional. Only include fields that have changed — omitted field - Agent-specific metadata. See [Extensibility](./extensibility). + Agent-specific metadata. See [Extensibility](/protocol/extensibility). The `sessionId`, `cwd`, and `additionalDirectories` fields are **not** included @@ -225,4 +225,4 @@ after the first meaningful exchange to auto-generate a title. 1. Client calls `session/list` to discover available sessions 2. User selects a session from the list -3. Client calls [`session/load`](./session-setup#loading-sessions) with the chosen `sessionId` to resume the conversation +3. Client calls [`session/load`](/protocol/session-setup#loading-sessions) with the chosen `sessionId` to resume the conversation diff --git a/docs/protocol/draft/session-setup.mdx b/docs/protocol/draft/session-setup.mdx index 79ccca9b..0e19536a 100644 --- a/docs/protocol/draft/session-setup.mdx +++ b/docs/protocol/draft/session-setup.mdx @@ -3,9 +3,9 @@ title: "Session Setup" description: "Creating and loading sessions" --- -Sessions represent a specific conversation or thread between the [Client](./overview#client) and [Agent](./overview#agent). Each session maintains its own context, conversation history, and state, allowing multiple independent interactions with the same Agent. +Sessions represent a specific conversation or thread between the [Client](/protocol/overview#client) and [Agent](/protocol/overview#agent). Each session maintains its own context, conversation history, and state, allowing multiple independent interactions with the same Agent. -Before creating a session, Clients **MUST** first complete the [initialization](./initialization) phase to establish protocol compatibility and capabilities. +Before creating a session, Clients **MUST** first complete the [initialization](/protocol/initialization) phase to establish protocol compatibility and capabilities.
diff --git a/schema/schema.unstable.json b/schema/schema.unstable.json index 6ca090e8..b93adf5f 100644 --- a/schema/schema.unstable.json +++ b/schema/schema.unstable.json @@ -2127,7 +2127,7 @@ "type": ["object", "null"] }, "additionalDirectories": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAdditional workspace roots to activate for this session. Each path must be absolute.", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAdditional workspace roots to activate for this session. Each path must be absolute.\n\nWhen omitted or empty, no additional roots are activated. When non-empty,\nthis is the complete resulting additional-root list for the forked\nsession.", "items": { "type": "string" }, @@ -2475,7 +2475,7 @@ "type": ["object", "null"] }, "additionalDirectories": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nFilter sessions by the exact ordered additional workspace roots. Each path must be absolute.", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nFilter sessions by the exact ordered additional workspace roots. Each path must be absolute.\n\nThis filter applies only when the field is present and non-empty. When\nomitted or empty, no additional-root filter is applied.", "items": { "type": "string" }, @@ -2528,7 +2528,7 @@ "type": ["object", "null"] }, "additionalDirectories": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAdditional workspace roots to activate for this session. Each path must be absolute.", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAdditional workspace roots to activate for this session. Each path must be absolute.\n\nWhen omitted or empty, no additional roots are activated. When non-empty,\nthis is the complete resulting additional-root list for the loaded\nsession.", "items": { "type": "string" }, @@ -2899,7 +2899,7 @@ "type": ["object", "null"] }, "additionalDirectories": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAdditional workspace roots for this session. Each path must be absolute.\n\nThese expand the session's filesystem scope without changing `cwd`, which\nremains the base for relative paths.", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAdditional workspace roots for this session. Each path must be absolute.\n\nThese expand the session's filesystem scope without changing `cwd`, which\nremains the base for relative paths. When omitted or empty, no\nadditional roots are activated for the new session.", "items": { "type": "string" }, @@ -3513,7 +3513,7 @@ "type": ["object", "null"] }, "additionalDirectories": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAdditional workspace roots to activate for this session. Each path must be absolute.", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAdditional workspace roots to activate for this session. Each path must be absolute.\n\nWhen omitted or empty, no additional roots are activated. When non-empty,\nthis is the complete resulting additional-root list for the resumed\nsession.", "items": { "type": "string" }, @@ -3612,7 +3612,7 @@ "type": "object" }, "SessionAdditionalDirectoriesCapabilities": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nCapabilities for additional session directories support.\n\nBy supplying `{}` it means that the agent supports the `additionalDirectories` field on\nsession lifecycle requests and `session/list`.", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nCapabilities for additional session directories support.\n\nBy supplying `{}` it means that the agent supports the `additionalDirectories` field on\nsupported session lifecycle requests and `session/list`.", "properties": { "_meta": { "additionalProperties": true, @@ -3639,7 +3639,7 @@ "type": "null" } ], - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nWhether the agent supports `additionalDirectories` on session lifecycle requests and `session/list`." + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nWhether the agent supports `additionalDirectories` on supported session lifecycle requests and `session/list`." }, "close": { "anyOf": [ @@ -3950,7 +3950,7 @@ "type": ["object", "null"] }, "additionalDirectories": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAuthoritative ordered additional workspace roots for this session. Each path must be absolute.", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAuthoritative ordered additional workspace roots for this session. Each path must be absolute.\n\nWhen omitted or empty, there are no additional roots for the session.", "items": { "type": "string" }, diff --git a/src/agent.rs b/src/agent.rs index c4bd1a1a..d67a6698 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -900,7 +900,8 @@ pub struct NewSessionRequest { /// Additional workspace roots for this session. Each path must be absolute. /// /// These expand the session's filesystem scope without changing `cwd`, which - /// remains the base for relative paths. + /// remains the base for relative paths. When omitted or empty, no + /// additional roots are activated for the new session. #[cfg(feature = "unstable_session_additional_directories")] #[serde(default, skip_serializing_if = "Vec::is_empty")] pub additional_directories: Vec, @@ -1072,6 +1073,10 @@ pub struct LoadSessionRequest { /// This capability is not part of the spec yet, and may be removed or changed at any point. /// /// Additional workspace roots to activate for this session. Each path must be absolute. + /// + /// When omitted or empty, no additional roots are activated. When non-empty, + /// this is the complete resulting additional-root list for the loaded + /// session. #[cfg(feature = "unstable_session_additional_directories")] #[serde(default, skip_serializing_if = "Vec::is_empty")] pub additional_directories: Vec, @@ -1237,6 +1242,10 @@ pub struct ForkSessionRequest { /// This capability is not part of the spec yet, and may be removed or changed at any point. /// /// Additional workspace roots to activate for this session. Each path must be absolute. + /// + /// When omitted or empty, no additional roots are activated. When non-empty, + /// this is the complete resulting additional-root list for the forked + /// session. #[cfg(feature = "unstable_session_additional_directories")] #[serde(default, skip_serializing_if = "Vec::is_empty")] pub additional_directories: Vec, @@ -1419,6 +1428,10 @@ pub struct ResumeSessionRequest { /// This capability is not part of the spec yet, and may be removed or changed at any point. /// /// Additional workspace roots to activate for this session. Each path must be absolute. + /// + /// When omitted or empty, no additional roots are activated. When non-empty, + /// this is the complete resulting additional-root list for the resumed + /// session. #[cfg(feature = "unstable_session_additional_directories")] #[serde(default, skip_serializing_if = "Vec::is_empty")] pub additional_directories: Vec, @@ -1674,6 +1687,9 @@ pub struct ListSessionsRequest { /// This capability is not part of the spec yet, and may be removed or changed at any point. /// /// Filter sessions by the exact ordered additional workspace roots. Each path must be absolute. + /// + /// This filter applies only when the field is present and non-empty. When + /// omitted or empty, no additional-root filter is applied. #[cfg(feature = "unstable_session_additional_directories")] #[serde(default, skip_serializing_if = "Vec::is_empty")] pub additional_directories: Vec, @@ -1796,6 +1812,8 @@ pub struct SessionInfo { /// This capability is not part of the spec yet, and may be removed or changed at any point. /// /// Authoritative ordered additional workspace roots for this session. Each path must be absolute. + /// + /// When omitted or empty, there are no additional roots for the session. #[cfg(feature = "unstable_session_additional_directories")] #[serde(default, skip_serializing_if = "Vec::is_empty")] pub additional_directories: Vec, @@ -3464,7 +3482,7 @@ pub struct SessionCapabilities { /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// - /// Whether the agent supports `additionalDirectories` on session lifecycle requests and `session/list`. + /// Whether the agent supports `additionalDirectories` on supported session lifecycle requests and `session/list`. #[cfg(feature = "unstable_session_additional_directories")] #[serde(skip_serializing_if = "Option::is_none")] pub additional_directories: Option, @@ -3518,7 +3536,7 @@ impl SessionCapabilities { /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// - /// Whether the agent supports `additionalDirectories` on session lifecycle requests and `session/list`. + /// Whether the agent supports `additionalDirectories` on supported session lifecycle requests and `session/list`. #[cfg(feature = "unstable_session_additional_directories")] #[must_use] pub fn additional_directories( @@ -3605,7 +3623,7 @@ impl SessionListCapabilities { /// Capabilities for additional session directories support. /// /// By supplying `{}` it means that the agent supports the `additionalDirectories` field on -/// session lifecycle requests and `session/list`. +/// supported session lifecycle requests and `session/list`. #[cfg(feature = "unstable_session_additional_directories")] #[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[non_exhaustive]