From 126172a1da52dd769c5b50ee2725e937dde30782 Mon Sep 17 00:00:00 2001 From: Charles Covey-Brandt Date: Wed, 15 Apr 2026 09:35:17 -0400 Subject: [PATCH 1/3] =?UTF-8?q?docs(rfd):=20session/status=20=E2=80=94=20s?= =?UTF-8?q?ession=20liveness=20check?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/rfds/session-status.mdx | 123 +++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 docs/rfds/session-status.mdx diff --git a/docs/rfds/session-status.mdx b/docs/rfds/session-status.mdx new file mode 100644 index 00000000..6cf40aa0 --- /dev/null +++ b/docs/rfds/session-status.mdx @@ -0,0 +1,123 @@ +--- +title: "Session liveness check" +--- + +Author(s): [@chazcb](https://github.com/chazcb) + +## Elevator pitch + +> What are you proposing to change? + +Add a `session/status` method that checks whether an agent is currently handling a specific session. Unlike `session/load`, which forces the agent to start handling a session, `session/status` is a read-only query: "do you have this session loaded right now?" + +## Status quo + +> How do things work today and what problems does this cause? Why would we change things? + +ACP has no way to check if an agent is currently handling a session without side effects. + +The existing methods that operate on sessions all change state: + +- `session/load` forces the agent to load and start handling the session. +- `session/prompt` sends work to the session. +- `session/cancel` cancels work in the session. + +There is no read-only query. If a client wants to know whether a session is live before interacting with it, it has no option — it must commit to a `session/load` (which may be expensive: loading from storage, replaying history, allocating resources) or send a `session/prompt` and hope for the best. + +This is a problem when: + +- **A client reconnects** after a page reload or network drop. It has a `sessionId` but doesn't know if the agent still has the session loaded. Calling `session/load` forces a reload even if the session is already live. +- **A routing layer needs to probe an agent.** In multi-pod deployments, the routing layer needs to ask "is this session on your pod?" before forwarding requests. Without a lightweight probe, it must send `session/load` — which forces the session onto that pod even if it shouldn't be there. +- **The agent crashed and restarted.** The session is gone from memory but the client doesn't know. It sends requests to a dead session and gets timeouts or errors instead of a clear "not found." + +## What we propose to do about it + +> What are you proposing to improve the situation? + +Add `session/status` — a read-only method with no side effects. The agent checks its in-memory state and responds immediately. + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "session/status", + "params": { + "sessionId": "sess_abc123" + } +} +``` + +Response when the session is currently loaded: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "result": { + "status": "live" + } +} +``` + +Response when the session is not loaded: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "result": { + "status": "not_found" + } +} +``` + +- `"live"` — The agent has this session loaded in memory. Requests sent to it will be processed. +- `"not_found"` — The agent does not currently have this session. It was never created, has been closed, or was lost to a crash. The client should use `session/load` to bring it back. + +No response (timeout) means the agent itself is unresponsive. + +### Contract + +- `session/status` must be side-effect-free. It must not load, create, or modify the session. +- It must be cheap. The agent checks its in-memory session map and responds. No storage lookups. +- It may be called frequently (e.g., as a health probe by a routing layer). + +## Shiny future + +> How will things will play out once this feature exists? + +- Clients check `session/status` before deciding whether to call `session/load` (expensive) or go straight to `session/prompt` (cheap). +- Routing layers use `session/status` as a lightweight probe to locate which pod is handling a session, without forcing a load on the wrong pod. +- UIs can show session availability immediately on reconnect instead of waiting for a timeout. + +## Implementation details and plan + +> Tell me more about your implementation. What is your detailed implementation plan? + +Agents declare support via capabilities: + +```json +{ + "sessionCapabilities": { + "status": {} + } +} +``` + +## Frequently asked questions + +### Why not just call session/load? + +`session/load` forces the agent to handle the session. If the session is already loaded on another pod, calling `session/load` on the wrong pod creates a duplicate. `session/status` is the read-only probe that tells you where the session actually is. + +### Why not use session/attach or session/resume? + +Both `session/attach` ([RFD](https://github.com/agentclientprotocol/agent-client-protocol/pull/533)) and `session/resume` mutate state — they cause the agent to start handling the session. They are not suitable for probing. A routing layer that calls `session/attach` to check if a session exists will accidentally attach to it. `session/status` is the read-only primitive that these methods are missing. + +### What alternative approaches did you consider, and why did you settle on this one? + +Transport-level heartbeats and side-channel ping/pong protocols. These operate outside ACP — the agent can't participate, leading to false positives (transport says "alive" but the session is gone). `session/status` puts the agent in control of reporting its own session state. + +## Revision history + +2026-04-15: Initial draft From 8efac39303e44192855ad255528dd53a655a2118 Mon Sep 17 00:00:00 2001 From: Charles Covey-Brandt Date: Wed, 15 Apr 2026 09:42:32 -0400 Subject: [PATCH 2/3] docs(rfd): clarify session/status is about handling, not memory --- .claude/settings.local.json | 41 ++++++++++++++++++++++++++++++++++++ docs/rfds/session-status.mdx | 21 +++++++++--------- 2 files changed, 52 insertions(+), 10 deletions(-) create mode 100644 .claude/settings.local.json diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 00000000..24bf01a9 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,41 @@ +{ + "permissions": { + "allow": [ + "Bash(git -C /Users/charles_coveybrandt/development/agent-client-protocol remote -v)", + "Bash(wc:*)", + "Bash(gh repo view:*)", + "Bash(gh api:*)", + "WebFetch(domain:spec.modelcontextprotocol.io)", + "mcp__airbnb-core__fetch", + "WebFetch(domain:a2a-protocol.org)", + "Bash(git checkout:*)", + "Bash(git push:*)", + "Bash(git pull:*)", + "Bash(gh pr view:*)", + "WebFetch(domain:github.com)", + "Bash(grep:*)", + "Bash(git log:*)", + "Bash(find:*)", + "Bash(for hash in 473ceae 2c79061 33687a0 7075952 e7b1611)", + "Bash(do echo \"=== $hash ===\")", + "Bash(git show:*)", + "Bash(done)", + "Bash(git fetch:*)", + "Bash(git rebase:*)", + "Bash(gh pr list:*)", + "WebFetch(domain:drnick.d.musta.ch)", + "WebFetch(domain:npm.d.musta.ch)", + "WebFetch(domain:git.musta.ch)", + "Bash(cd /Users/charles_coveybrandt/development/ergo/projects/airchat-sdk/typescript && pnpm vitest run integration-tests/__tests__/elicitation.test.ts 2>&1)", + "Bash(pnpm vitest:*)", + "Bash(cd /Users/charles_coveybrandt/development/ergo/projects/airchat-sdk/typescript && pnpm tsc --noEmit 2>&1 && pnpm vitest run packages/airchat-sdk-claude-code/__tests__/elicitation.integration.test.ts integration-tests/__tests__/elicitation.test.ts 2>&1 | tail -8)", + "mcp__airbnb-core__sourcegraph_grep", + "mcp__airbnb-core__extract", + "WebFetch(domain:docs.claude.com)", + "WebFetch(domain:telescope-otlp.obs.musta.ch)" + ], + "additionalDirectories": [ + "/Users/charles_coveybrandt/development/ergo" + ] + } +} diff --git a/docs/rfds/session-status.mdx b/docs/rfds/session-status.mdx index 6cf40aa0..decbe559 100644 --- a/docs/rfds/session-status.mdx +++ b/docs/rfds/session-status.mdx @@ -8,7 +8,7 @@ Author(s): [@chazcb](https://github.com/chazcb) > What are you proposing to change? -Add a `session/status` method that checks whether an agent is currently handling a specific session. Unlike `session/load`, which forces the agent to start handling a session, `session/status` is a read-only query: "do you have this session loaded right now?" +Add a `session/status` method that checks whether an agent is currently handling a specific session. Unlike `session/load`, which forces the agent to start handling a session, `session/status` is a read-only query: "are you currently handling this session?" ## Status quo @@ -26,15 +26,15 @@ There is no read-only query. If a client wants to know whether a session is live This is a problem when: -- **A client reconnects** after a page reload or network drop. It has a `sessionId` but doesn't know if the agent still has the session loaded. Calling `session/load` forces a reload even if the session is already live. -- **A routing layer needs to probe an agent.** In multi-pod deployments, the routing layer needs to ask "is this session on your pod?" before forwarding requests. Without a lightweight probe, it must send `session/load` — which forces the session onto that pod even if it shouldn't be there. -- **The agent crashed and restarted.** The session is gone from memory but the client doesn't know. It sends requests to a dead session and gets timeouts or errors instead of a clear "not found." +- **A client reconnects** after a page reload or network drop. It has a `sessionId` but doesn't know if the agent is still handling that session. Calling `session/load` forces a reload even if the session is already live. +- **A routing layer needs to probe an agent.** In multi-pod deployments, the routing layer needs to ask "are you handling this session?" before forwarding requests. Without a lightweight probe, it must send `session/load` — which forces the session onto that pod even if it shouldn't be there. +- **The agent crashed and restarted.** The session is no longer being handled but the client doesn't know. It sends requests to a dead session and gets timeouts or errors instead of a clear "not found." ## What we propose to do about it > What are you proposing to improve the situation? -Add `session/status` — a read-only method with no side effects. The agent checks its in-memory state and responds immediately. +Add `session/status` — a read-only method with no side effects. The agent checks whether it is currently handling the requested session and responds immediately. ```json { @@ -71,24 +71,25 @@ Response when the session is not loaded: } ``` -- `"live"` — The agent has this session loaded in memory. Requests sent to it will be processed. -- `"not_found"` — The agent does not currently have this session. It was never created, has been closed, or was lost to a crash. The client should use `session/load` to bring it back. +- `"live"` — The agent is currently handling this session. Other session methods (`session/prompt`, `session/cancel`, etc.) will work as expected. +- `"not_found"` — The agent is not handling this session. It was never created here, has been closed, or was lost to a crash/restart. The client should use `session/load` to start handling it. No response (timeout) means the agent itself is unresponsive. ### Contract - `session/status` must be side-effect-free. It must not load, create, or modify the session. -- It must be cheap. The agent checks its in-memory session map and responds. No storage lookups. +- It must be cheap. The agent should be able to answer immediately without expensive lookups. - It may be called frequently (e.g., as a health probe by a routing layer). ## Shiny future > How will things will play out once this feature exists? -- Clients check `session/status` before deciding whether to call `session/load` (expensive) or go straight to `session/prompt` (cheap). +- Clients check `session/status` before deciding whether to call `session/load` (expensive) or go straight to `session/prompt` (the session is already live). - Routing layers use `session/status` as a lightweight probe to locate which pod is handling a session, without forcing a load on the wrong pod. - UIs can show session availability immediately on reconnect instead of waiting for a timeout. +- If an agent responds `"live"`, the client can trust that `session/prompt`, `session/cancel`, and other session methods will work. ## Implementation details and plan @@ -108,7 +109,7 @@ Agents declare support via capabilities: ### Why not just call session/load? -`session/load` forces the agent to handle the session. If the session is already loaded on another pod, calling `session/load` on the wrong pod creates a duplicate. `session/status` is the read-only probe that tells you where the session actually is. +`session/load` forces the agent to start handling the session. If the session is already being handled on another pod, calling `session/load` on the wrong pod creates a duplicate. `session/status` is the read-only probe that tells you where the session actually is. ### Why not use session/attach or session/resume? From 2cec7fd6c9f59c373d64ebe0a31375a130343f76 Mon Sep 17 00:00:00 2001 From: Charles Covey-Brandt Date: Wed, 15 Apr 2026 09:44:24 -0400 Subject: [PATCH 3/3] remove accidentally committed settings file --- .claude/settings.local.json | 41 ------------------------------------- 1 file changed, 41 deletions(-) delete mode 100644 .claude/settings.local.json diff --git a/.claude/settings.local.json b/.claude/settings.local.json deleted file mode 100644 index 24bf01a9..00000000 --- a/.claude/settings.local.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "permissions": { - "allow": [ - "Bash(git -C /Users/charles_coveybrandt/development/agent-client-protocol remote -v)", - "Bash(wc:*)", - "Bash(gh repo view:*)", - "Bash(gh api:*)", - "WebFetch(domain:spec.modelcontextprotocol.io)", - "mcp__airbnb-core__fetch", - "WebFetch(domain:a2a-protocol.org)", - "Bash(git checkout:*)", - "Bash(git push:*)", - "Bash(git pull:*)", - "Bash(gh pr view:*)", - "WebFetch(domain:github.com)", - "Bash(grep:*)", - "Bash(git log:*)", - "Bash(find:*)", - "Bash(for hash in 473ceae 2c79061 33687a0 7075952 e7b1611)", - "Bash(do echo \"=== $hash ===\")", - "Bash(git show:*)", - "Bash(done)", - "Bash(git fetch:*)", - "Bash(git rebase:*)", - "Bash(gh pr list:*)", - "WebFetch(domain:drnick.d.musta.ch)", - "WebFetch(domain:npm.d.musta.ch)", - "WebFetch(domain:git.musta.ch)", - "Bash(cd /Users/charles_coveybrandt/development/ergo/projects/airchat-sdk/typescript && pnpm vitest run integration-tests/__tests__/elicitation.test.ts 2>&1)", - "Bash(pnpm vitest:*)", - "Bash(cd /Users/charles_coveybrandt/development/ergo/projects/airchat-sdk/typescript && pnpm tsc --noEmit 2>&1 && pnpm vitest run packages/airchat-sdk-claude-code/__tests__/elicitation.integration.test.ts integration-tests/__tests__/elicitation.test.ts 2>&1 | tail -8)", - "mcp__airbnb-core__sourcegraph_grep", - "mcp__airbnb-core__extract", - "WebFetch(domain:docs.claude.com)", - "WebFetch(domain:telescope-otlp.obs.musta.ch)" - ], - "additionalDirectories": [ - "/Users/charles_coveybrandt/development/ergo" - ] - } -}