diff --git a/rust/README.md b/rust/README.md
index 0b5bec1cd..10e922f92 100644
--- a/rust/README.md
+++ b/rust/README.md
@@ -78,6 +78,72 @@ client.stop().await?;
With the default `CliProgram::Resolve`, `Client::start()` resolves the CLI in this order: an explicit `CliProgram::Path(path)`, the `COPILOT_CLI_PATH` env var, then the bundled CLI that was embedded at build time. There is no PATH scanning — if you've opted out of bundling (`default-features = false`) you must supply either `CliProgram::Path` or `COPILOT_CLI_PATH`.
+### Session capabilities
+
+The `SessionCapability` enum lets callers enable or disable named runtime features on a **per-session** basis. Capabilities are sent to the runtime as part of the `session.create` / `session.resume` JSON-RPC calls via two wire fields:
+
+- `enabledCapabilities` -- capabilities to opt the session into (extends the `SDK_CAPABILITIES` baseline)
+- `disabledCapabilities` -- capabilities to opt the session out of (disable wins on overlap)
+
+This approach works for every transport -- including `Transport::External` -- because it does not rely on CLI spawn arguments.
+
+> **Experimental.** Per-session capability controls are an experimental
+> wire-protocol surface and may change or be removed in future SDK or CLI
+> releases. The Rust SDK marks the relevant fields and builders with a
+> `
**Experimental.**
` rustdoc block (the
+> repository convention used in `rust/src/generated/`); there is no
+> `#[experimental]` attribute, so the marker is documentation-only.
+
+> **Runtime dependency.** Per-session capability controls require a runtime
+> version that supports `enabledCapabilities` and `disabledCapabilities`.
+> On older runtimes the fields are silently ignored.
+
+Use `SessionConfig::with_enable_capability` / `with_disable_capability` (and their plural counterparts):
+
+```rust,ignore
+use github_copilot_sdk::{SessionCapability, SessionConfig};
+
+let session = client.create_session(
+ SessionConfig::default()
+ .with_enable_capability(SessionCapability::Memory),
+).await?;
+```
+
+On resume, use the same builders on `ResumeSessionConfig`:
+
+```rust,ignore
+use github_copilot_sdk::{ResumeSessionConfig, SessionCapability};
+
+let session = client.resume_session(
+ ResumeSessionConfig::new(session_id)
+ .with_enable_capability(SessionCapability::Memory),
+).await?;
+```
+
+**Variants:**
+
+| Variant | Wire name | Description |
+| -------------------- | ----------------------- | ----------------------------------------------------- |
+| `TuiHints` | `tui-hints` | TUI keyboard shortcuts |
+| `PlanMode` | `plan-mode` | `[[PLAN]]` handling and plan-mode instructions |
+| `Memory` | `memory` | `store_memory` tool and `` system-prompt section |
+| `CliDocumentation` | `cli-documentation` | `fetch_copilot_cli_documentation` tool and `` section |
+| `AskUser` | `ask-user` | `ask_user` tool for interactive clarification |
+| `InteractiveMode` | `interactive-mode` | Interactive-CLI identity (vs headless) |
+| `SystemNotifications`| `system-notifications` | Automatic batched system notifications to the agent |
+| `Elicitation` | `elicitation` | Elicitation prompts (confirm / select / input) |
+| `SessionStore` | `session-store` | Cross-session history tools and session-store metadata |
+| `McpApps` | `mcp-apps` | MCP-Apps `ui://` resource passthrough (SEP-1865) |
+| `CanvasRenderer` | `canvas-renderer` | Host-rendered extension canvases |
+| `Unknown` | *(none)* | Deserialization fallback; rejected for outbound config |
+
+**Disable-wins semantics.** If the same capability appears in both
+`enabled_capabilities` and `disabled_capabilities`, disable wins. The runtime
+starts from an `SDK_CAPABILITIES` baseline; enabled capabilities extend it and
+disabled capabilities remove from it, in that order. `SessionCapability::Unknown`
+exists only as a generated deserialization fallback and is rejected if supplied
+to the create/resume capability builders.
+
### Session
Created via `Client::create_session` or `Client::resume_session`. Owns an internal event loop that dispatches CLI callbacks to the focused handler traits you install on `SessionConfig`, and broadcasts session events through `subscribe()`.
@@ -714,6 +780,13 @@ gets to be Rust here — cross-SDK parity for these is a post-release
conversation, not a release blocker. None of these are deprecated and
none of them are scheduled for removal.
+- **`SessionCapability` enum** -- generated typed enum for per-session
+ capability opt-in / opt-out. Sent via `enabledCapabilities` /
+ `disabledCapabilities` on the `session.create` and `session.resume` wire
+ calls -- works for all transports including `Transport::External`. See
+ [Session capabilities](#session-capabilities) above. Marked
+ **experimental** via the repository's `
` rustdoc
+ convention. Node/Python/Go/.NET accept stringly-typed flags.
- **Typed newtypes** — `SessionId` and `RequestId` are `#[serde(transparent)]`
newtypes around `String`, so the type system distinguishes a session
identifier from an arbitrary `String` at compile time. Node/Python/Go
diff --git a/rust/src/types.rs b/rust/src/types.rs
index 8b9b5960a..d2ffba027 100644
--- a/rust/src/types.rs
+++ b/rust/src/types.rs
@@ -830,7 +830,7 @@ impl CloudSessionOptions {
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ExtensionInfo {
- /// Extension namespace/source, e.g. `"github-app"`.
+ /// Extension namespace/source, e.g. `"example-host"`.
pub source: String,
/// Stable provider name within the source namespace.
pub name: String,
@@ -1369,6 +1369,33 @@ pub struct SessionConfig {
/// `session.options.update` after create/resume. Defaults to `false` in
/// [`crate::ClientMode::Empty`] when unset.
pub manage_schedule_enabled: Option,
+ /// Capabilities to opt this session into via `enabledCapabilities` on
+ /// the `session.create` wire call. The runtime starts from a
+ /// `SDK_CAPABILITIES` baseline; this list extends it.
+ ///
+ ///
+ ///
+ /// **Experimental.** This is part of an experimental wire-protocol
+ /// surface and may change or be removed in future SDK or CLI releases.
+ ///
+ ///
+ ///
+ /// Requires runtime support for per-session capability controls. On older
+ /// runtimes the field is silently ignored.
+ pub enabled_capabilities: Vec,
+ /// Capabilities to opt this session out of via `disabledCapabilities`
+ /// on the `session.create` wire call. Disable wins over enable on
+ /// overlap. See [`SessionCapability`].
+ ///
+ ///
+ ///
+ /// **Experimental.** This is part of an experimental wire-protocol
+ /// surface and may change or be removed in future SDK or CLI releases.
+ ///
+ ///
+ ///
+ /// Requires runtime support for per-session capability controls.
+ pub disabled_capabilities: Vec,
}
impl std::fmt::Debug for SessionConfig {
@@ -1476,6 +1503,8 @@ impl std::fmt::Debug for SessionConfig {
"system_message_transform",
&self.system_message_transform.as_ref().map(|_| ""),
)
+ .field("enabled_capabilities", &self.enabled_capabilities)
+ .field("disabled_capabilities", &self.disabled_capabilities)
.finish()
}
}
@@ -1550,11 +1579,11 @@ impl Default for SessionConfig {
custom_agents_local_only: None,
coauthor_enabled: None,
manage_schedule_enabled: None,
+ enabled_capabilities: Vec::new(),
+ disabled_capabilities: Vec::new(),
}
}
}
-
-/// Runtime-only bundle drained out of a [`SessionConfig`] or
/// [`ResumeSessionConfig`] by [`SessionConfig::into_wire`] /
/// [`ResumeSessionConfig::into_wire`]. Holds the trait-object handlers,
/// session-fs provider, and slash commands so the wire payload struct
@@ -1574,6 +1603,27 @@ pub(crate) struct SessionConfigRuntime {
pub commands: Option>,
}
+fn capability_list_to_wire(
+ field_name: &str,
+ capabilities: Vec,
+) -> Result