`permission_denied` forwarded an SDK frame as a `tool_call_update` without checking that the referenced `tool_call` was ever announced, leaving it the last emitter without that check after #916. The id is the executing call's own, and the frame is enqueued from inside canUseTool, so it lands between the call's `tool_use` and the `tool_result` carrying the rejection — verified against the bundled CLI, where the deny short-circuit only emits for pre-ask decisions (rules, mode, classifier, asyncAgent) and fires exactly once per denial. In that flow the call is announced and in flight, so the guard changes nothing. It changes the denials that arrive outside that window. The cancelled-turn guard drops the assistant message carrying the tool_use, so no `tool_call` is emitted, and a denial for it can still land afterwards — the same premise the `tool_result` fallback in `toAcpNotifications` gates on `wasEmitted` for. Ids leave `emittedToolCalls` at `tool_result`, so the check also stops a denial trailing its own result from flipping a call the client has seen finish back to failed. While here: a denial raised inside a subagent identifies it by `agent_id`, never by the Agent/Task call that spawned it, so the update went out unattributed while the `tool_call` it resolves sits in the subagent's transcript. Resolve the parent through `liveBackgroundTasks`, as the canUseTool path already does, and leave the update unattributed rather than dropped when `task_started` was never seen for that agent id. `permission_denied` had no test coverage. Add cases for the in-flight resolve, the reason fallback, the never-announced and already-resolved drops, and subagent attribution with and without a recorded parent. Fixes #918 Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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)
- Following
- Edit review
- TODO lists
- Nested subagent transcripts
- Interactive (and background) terminals
- Custom Slash commands
- Client MCP servers
Learn more about the Agent Client Protocol.
Nested subagent transcripts
ACP 1.2 has no standard subagent tool kind or nested-message relationship. Clients that can render
nested transcripts can opt in with clientCapabilities._meta["subagent-transcript"] = true.
The agent then forwards subagent text, thinking, and tool calls, relating nested updates to the
launching Agent/Task call through _meta.claudeCode.parentToolUseId. Agent/Task calls are marked
with _meta.claudeCode.subagent = true.
Clients that do not advertise the capability retain the legacy flattened behavior. In both modes, the normal Agent/Task tool result is preserved as the protocol-compatible fallback.
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).