Summary
When Copilot CLI runs as an ACP agent (copilot --acp --stdio), it does not
implement the ACP session/close request, and its initialize response does
not advertise the sessionCapabilities.close capability. As a result an ACP
client has no protocol-level way to tell Copilot that a session it created
via session/new is finished and can be torn down.
For a client that multiplexes many sessions over a single long-lived
copilot --acp process (Zed, Windows Terminal, other IDE integrations), every
session ever created stays resident for the lifetime of the Copilot process.
session/cancel only aborts the in-flight turn — it does not release the
session — so there is no clean way to reclaim per-session resources short of
killing the whole agent process.
This is the same class of gap as #3256 (ACP mode does not advertise
session.fork capability — slash /fork exists, ACP method missing): the ACP
schema defines the method and a capability bit, but the Copilot ACP server
neither implements it nor advertises it.
Environment
GitHub Copilot CLI 1.0.71-0
- Transport:
copilot --acp --stdio
- ACP schema reference:
agent-client-protocol / agent-client-protocol-schema
— SessionCapabilities.close: Option<SessionCloseCapabilities> gates
session/close; the doc states "only available if the agent advertises the
sessionCapabilities.close capability."
Current behavior (reproduced)
Driving copilot --acp --stdio with a minimal newline-delimited JSON-RPC client:
1. initialize — sessionCapabilities advertises only list, no close:
{
"loadSession": true,
"mcpCapabilities": { "http": true, "sse": true },
"promptCapabilities": { "image": true, "audio": false, "embeddedContext": true },
"sessionCapabilities": { "list": {} }
}
2. session/new succeeds, returns e.g. sessionId: a95110c0-8f81-4933-94e6-75127090eb45.
3. session/close on that id is rejected as Method not found:
// --> {"jsonrpc":"2.0","id":5,"method":"session/close","params":{"sessionId":"a95110c0-..."}}
// <-- error:
{
"code": -32601,
"message": "\"Method not found\": session/close",
"data": { "method": "session/close" }
}
(Side note observed during the repro: session/list returns on-disk history —
50 rows — and does not contain the just-created live sessionId, so
session/list cannot be used as a substitute to discover/close live in-memory
sessions.)
Expected behavior
initialize advertises agentCapabilities.sessionCapabilities.close (e.g.
{}) when the build supports it.
session/close with { "sessionId": "<id>" } releases the live session
(frees its in-memory state / handles) and returns a CloseSessionResponse
({} result).
- After a successful
session/close, using that sessionId again (e.g. a
second session/close, session/prompt, session/set_mode) is rejected with
a "session not found"–style error, so clients can confirm the release.
Why this matters
ACP was designed for a client to own the process lifetime while opening and
closing many sessions against it. Without session/close:
Reproduction
Minimal repro with any ndjson JSON-RPC driver over copilot --acp --stdio:
- Send
initialize { "protocolVersion": 1, "clientCapabilities": {} } →
note sessionCapabilities has no close.
- Send
session/new { "cwd": "<abs path>", "mcpServers": [] } → capture
sessionId.
- Send
session/close { "sessionId": "<id>" } → observe
-32601 "Method not found": session/close.
References
Summary
When Copilot CLI runs as an ACP agent (
copilot --acp --stdio), it does notimplement the ACP
session/closerequest, and itsinitializeresponse doesnot advertise the
sessionCapabilities.closecapability. As a result an ACPclient has no protocol-level way to tell Copilot that a session it created
via
session/newis finished and can be torn down.For a client that multiplexes many sessions over a single long-lived
copilot --acpprocess (Zed, Windows Terminal, other IDE integrations), everysession ever created stays resident for the lifetime of the Copilot process.
session/cancelonly aborts the in-flight turn — it does not release thesession — so there is no clean way to reclaim per-session resources short of
killing the whole agent process.
This is the same class of gap as #3256 (ACP mode does not advertise
session.forkcapability — slash/forkexists, ACP method missing): the ACPschema defines the method and a capability bit, but the Copilot ACP server
neither implements it nor advertises it.
Environment
GitHub Copilot CLI 1.0.71-0copilot --acp --stdioagent-client-protocol/agent-client-protocol-schema—
SessionCapabilities.close: Option<SessionCloseCapabilities>gatessession/close; the doc states "only available if the agent advertises thesessionCapabilities.closecapability."Current behavior (reproduced)
Driving
copilot --acp --stdiowith a minimal newline-delimited JSON-RPC client:1.
initialize—sessionCapabilitiesadvertises onlylist, noclose:{ "loadSession": true, "mcpCapabilities": { "http": true, "sse": true }, "promptCapabilities": { "image": true, "audio": false, "embeddedContext": true }, "sessionCapabilities": { "list": {} } }2.
session/newsucceeds, returns e.g.sessionId: a95110c0-8f81-4933-94e6-75127090eb45.3.
session/closeon that id is rejected as Method not found:(Side note observed during the repro:
session/listreturns on-disk history —50 rows — and does not contain the just-created live
sessionId, sosession/listcannot be used as a substitute to discover/close live in-memorysessions.)
Expected behavior
initializeadvertisesagentCapabilities.sessionCapabilities.close(e.g.{}) when the build supports it.session/closewith{ "sessionId": "<id>" }releases the live session(frees its in-memory state / handles) and returns a
CloseSessionResponse(
{}result).session/close, using thatsessionIdagain (e.g. asecond
session/close,session/prompt,session/set_mode) is rejected witha "session not found"–style error, so clients can confirm the release.
Why this matters
ACP was designed for a client to own the process lifetime while opening and
closing many sessions against it. Without
session/close:session/newfor the whole process lifetime; there is no bounded-lifetimepath. (Related, though not ACP-specific: CLI headless mode: internal state accumulation causes progressive latency degradation across sessions #2755 internal-state accumulation,
Copilot CLI never prunes ~/.copilot/session-state, causing EMFILE / file-descriptor exhaustion (crashes VS Code Copilot Chat) #3892 session-state never pruned.)
session/cancel(turnabort) or kill the process. A UI that opens a session per tab/pane and closes
it when the tab closes has no way to tell Copilot the session is done.
Reproduction
Minimal repro with any ndjson JSON-RPC driver over
copilot --acp --stdio:initialize{ "protocolVersion": 1, "clientCapabilities": {} }→note
sessionCapabilitieshas noclose.session/new{ "cwd": "<abs path>", "mcpServers": [] }→ capturesessionId.session/close{ "sessionId": "<id>" }→ observe-32601 "Method not found": session/close.References
session/fork(ACP method + capability missing whilethe slash command exists).
session/closemethod andsessionCapabilities.closecapability:https://agentclientprotocol.com