The second of three stacked PRs that replace #1257. It's based on #1320, so its diff shows only the resume part. Merge #1320 first; this PR then retargets to `main`. 1. #1320: the RFD form for a v1 client that declares `subagents` and isn't AIR. 2. **This PR:** a child keeps its session across SendMessage resumes. 3. #1322: `requires_action` while a child's permission or question request is open. **AIR is unchanged:** it keeps a new session per generation, as in its draft. ## What changes The [subagents RFD](https://github.com/agentclientprotocol/agent-client-protocol/blob/main/docs/rfds/subagents.mdx) gives a child one session id across every delegation to it. With #1320 alone, a resumed child stays `idle`. | RFD | With #1320 | Now | | --- | --- | --- | | One session id per child, across delegations | a resumed child stays `idle`, and its resumed work isn't shown | the child runs again in the same session, under the SDK agent id. The CLI runs a resumed agent under the SendMessage call's tool id, so that call becomes the child's current delegation: the resumed run's output and end reach the child | | The parent's message to the child is an incoming `session_message` | only the launch prompt | each SendMessage that resumes the child is a `session_message` with the SendMessage tool use's id. Its sender is the session that made that call, or left out when unknown. A repeated resume signal doesn't repeat it | Out-of-order events, from the reviews of #1257: - **Late end:** the end of an earlier delegation ends nothing (`isStaleEnd`). It also no longer settles the resumed run's live task at the agent level. - **Late result:** a SendMessage result that arrives after its run ended resumes nothing (`isEndedDelegation`). - **Early output:** a resume's output that arrives before its `task_started` is buffered, then delivered to the child. - **Reused id:** a run under an id the child used before ends the run, since the SDK falls back to it. - **Running patch:** a `task_updated` running patch reports `running` without its guessed prompt or call. ## Live run Against real Claude Code (Sonnet), a SendMessage to a finished child ran it again in the same session. Its message arrived with the SendMessage's id and the root as sender, and the turn waited for the resumed run. No schema violations. ## Tests - **End to end:** - a SendMessage resume under the SendMessage's tool id: one session, two prompts, the resumed output in the child, a stale end ignored - the resumed run's live task kept when an earlier delegation's end arrives late - a late SendMessage result - **Runtime:** - reuse and resume - a resume's output buffered before its `task_started` - the sender of a resume's prompt: the root, a child, or unknown - a run under a reused id - a running patch - a result without a text - **Mutation checks during #1257's reviews:** removing any of these rules fails tests. - **Checks:** `npm run check`, build and all 2873 tests pass on this branch. CI runs only on PRs to `main`, so I ran `ci.yml` on this branch by hand.
ACP adapter for the Claude Agent SDK
Use Claude Agent SDK from ACP-compatible clients!
This tool implements an ACP agent by using the official Claude Agent SDK, supporting:
- Context @-mentions
- Images
- Tool calls (with permission requests)
- Compact file changes through the negotiated AIR diff patch extension
- Following
- Edit review
- TODO lists
- Nested subagent transcripts
- Interactive (and background) terminals
- Custom Slash commands
- Client MCP servers
/mcpin the chat: the MCP server status as a list. The adapter runs/mcp reconnect,/mcp enable, and/mcp disablethrough the SDK control API, because Claude Code refuses them in SDK mode. A reconnect of an ACP server that needs authentication starts MCP OAuth through URL elicitation- Session-scoped long-running goals for AIR through the goal extension under
_meta.jetbrains.air.goal - Structured errors, recovery, and warnings through the opt-in session failure extension
- Concrete model and effort defaults through the opt-in recommended config value extension
- Tool permission presentation, editable choices, and durable effects through the permission extension
- One fact per field in every tool call report, as the ACP tool call contract defines
- All AIR extensions, capabilities, and
_metakeys: AIR extensions
Learn more about the Agent Client Protocol.
To try changes that have landed on main but are not released yet, install from the
preview channel — every push to main publishes one. See
docs/RELEASES.md.
npm install @agentclientprotocol/claude-agent-acp@preview
Subagent sessions
A client that declares clientCapabilities.subagents, other than JetBrains AIR, gets each Agent or
Task subagent as its own child session, following the subagents RFD:
subagent_updateon the parent announces the child before any of its traffic, with the parent'stitleanddescriptionfor it, and reports its work state:running, andidlewhen its work ends, withend_turnorcancelledwhen the SDK gives the reason. A failure isidlewith theerrorstop reason and the SDK's error text as itserror. The child keeps its session for every delegation to it.- The prompt of the Agent or Task call that launches the child, and the message of each
SendMessage call that resumes it, is a
session_messagein the child's transcript. The tool call stays a tool call of the session that made it. session/cancelon the parent interrupts Claude Code, which stops the foreground children that the turn waits on and, currently, background children too. Each stopped child reportsidlewithcancelledfrom Claude Code's own events, and the open requests of the foreground ones are withdrawn. The adapter ends no child at a cancel itself, so a child that keeps running keeps its open requests. A child that still runs when Claude Code exits isidlewith no stop reason.- A child whose parent is not yet known when it ends is not exposed, since the RFD forbids guessing its parent.
- A client cannot prompt, cancel, or otherwise change a child yet, and a replay does not restore children yet.
JetBrains AIR keeps the earlier draft of the RFD (subagent_spawned, subagent_state_update),
which it enables with nativeSubagentSessions in _meta.jetbrains.air.capabilities. See
AIR extensions.
Without either signal, Agent and Task stay ordinary tool calls and child interactions stay on the
root session. Clients that use the historical _meta["subagent-transcript"] capability or the
forwardSubagentText session option retain the flattened child transcript.
Contribution Policy
This project does not require a Contributor License Agreement (CLA). Instead, contributions are accepted under the following terms:
By contributing to this project, you agree that your contributions will be licensed under the Apache License, Version 2.0. You affirm that you have the legal right to submit your work, that you are not including code you do not have rights to, and that you understand contributions are made without requiring a Contributor License Agreement (CLA).