4.9 KiB
Claude ACP Raw SDK Message Support Design
- Date: 2026-04-14
- Status: Approved (implementation pending)
- Scope: Protocol support only (backend receives and forwards, frontend event layer receives)
1. Background
Upstream PR agentclientprotocol/claude-agent-acp#527 was merged on 2026-04-13.
It introduces opt-in emission of Claude Code SDK raw stream messages via ACP extension notification:
- Method:
"_claude/sdkMessage" - Params shape:
sessionId: stringmessage: object(raw SDK message)
Opt-in is configured via session _meta:
{
"claudeCode": {
"emitRawSDKMessages": true
}
}
User decision for this project:
- Keep npm/registry at current version (
0.27.0) - Implement protocol support only
- Enable raw SDK messages for Claude by default with
true
2. Goals and Non-Goals
Goals
- For
AgentType::ClaudeCode, send_meta.claudeCode.emitRawSDKMessages = truein session setup. - Receive
"_claude/sdkMessage"notifications in backend connection loop. - Convert and forward notifications to frontend via existing
acp://eventevent bridge. - Extend frontend
AcpEventtyping to accept this event without changing UI behavior.
Non-Goals
- No UI visualization for raw SDK messages in this change.
- No DB persistence for raw SDK messages.
- No behavior changes for non-Claude agents.
- No protocol generalization for all extension notifications in this iteration.
3. Selected Approach
Selected approach: Claude-specific minimal integration.
Why:
- Minimal risk and smallest change surface.
- Matches explicit scope: protocol plumbing only.
- Preserves current runtime and rendering behavior.
Rejected for now:
- Global extension-notification bus (larger scope, more noise, higher maintenance).
- Persistence/debug history (extra storage and lifecycle complexity).
4. Architecture Changes
4.1 Backend session meta injection
File: src-tauri/src/acp/connection.rs
When constructing NewSessionRequest and LoadSessionRequest:
- If
agent_type == AgentType::ClaudeCode, set requestmetawith:claudeCode.emitRawSDKMessages = true
This preserves opt-in semantics upstream while default-enabling for Claude in Codeg.
4.2 Backend extension notification handling
File: src-tauri/src/acp/connection.rs
Current code mainly consumes typed SessionNotification updates. This change adds a path for untyped notifications:
- Match dispatch notification method.
- If method is
"_claude/sdkMessage", parse params:sessionIdmessage
- Emit new app event through
acp://event. - Ignore parse failures and continue session loop.
4.3 Backend event model extension
File: src-tauri/src/acp/types.rs
Add a new AcpEvent variant:
ClaudeSdkMessageconnection_id: Stringsession_id: Stringmessage: serde_json::Value
This keeps payload raw and unopinionated.
4.4 Frontend type and event switch support
Files:
src/lib/types.tssrc/contexts/acp-connections-context.tsx
Changes:
- Extend TS
AcpEventunion with:type: "claude_sdk_message"connection_id: stringsession_id: stringmessage: unknown
- Add a no-op
case "claude_sdk_message"in event handling.
No UI state mutation is required in this iteration.
5. Data Flow
- Codeg starts Claude ACP session.
- Codeg sends
session/neworsession/loadwith_meta.claudeCode.emitRawSDKMessages=true. claude-agent-acpemits extension notifications"_claude/sdkMessage".- Codeg backend parses and maps to
AcpEvent::claude_sdk_message. - Event is pushed via existing
acp://eventchannel. - Frontend receives typed event and safely ignores it (for now).
6. Error Handling and Compatibility
- If upstream ignores meta, session still works; feature simply produces no raw SDK events.
- If
"_claude/sdkMessage"payload is malformed, log and ignore that notification. - Do not fail prompt/session loops due to extension-message parse errors.
- Keep all existing typed
SessionUpdateflows unchanged. - Restrict meta injection to Claude only.
7. Validation Plan
Manual/protocol validation:
- Confirm session setup request includes
_meta.claudeCode.emitRawSDKMessages=truefor Claude. - Confirm
"_claude/sdkMessage"notifications are received and forwarded asclaude_sdk_messageevents. - Confirm malformed ext payloads do not break turns.
- Confirm non-Claude agents have unchanged behavior.
Project checks:
pnpm eslint .pnpm buildcd src-tauri && cargo checkcd src-tauri && cargo check --bin codeg-server --no-default-features
8. Acceptance Criteria
- Claude connections default-enable raw SDK emission via session meta.
- Backend forwards raw SDK notifications into frontend event layer.
- Frontend compiles and receives new event type without UI regressions.
- No persistence and no visual rendering changes.
- No regressions on existing ACP message paths.