Note: Claude handled the investigation and prose via back-and-forth. Idea, decisions, and everything else are mine. — @Seluj78
Problem
When the user runs /clear, the Claude Code SDK ends its current internal conversation and starts a fresh one. The agent has no memory of prior turns after this point. From the ACP client's perspective, there is no structured signal that this happened: the adapter forwards /clear as a regular user prompt, the SDK handles it internally, and the next assistant turn just looks like a normal response with empty context.
Compare against compact_boundary, which the adapter explicitly handles in acp-agent.js:478-507:
case "compact_boundary": {
// Send used:0 ... post-compaction context size dropped dramatically
await this.client.sessionUpdate({
sessionId: message.session_id,
update: { sessionUpdate: "usage_update", used: 0, size: session.contextWindowSize },
});
await this.client.sessionUpdate({
sessionId: message.session_id,
update: {
sessionUpdate: "agent_message_chunk",
content: { type: "text", text: "\n\nCompacting completed." },
},
});
break;
}
compact_boundary lets ACP clients render a visible divider, reset transcript expectations, and update the context-window indicator. /clear produces the same kind of state transition (context wiped, transcript misleading from the model's perspective) but the adapter emits nothing comparable.
Why this matters for ACP clients
Without a structured signal, clients have to detect /clear heuristically (substring match on the user prompt text). That fragile pattern:
- Breaks on locale variants if
/clear ever gets localised.
- Breaks on user-defined custom clear commands.
- Can't tell "user pasted the word /clear" from "user invoked the /clear command."
Most importantly, the transcript divergence after /clear is severe: the agent has no continuity at all (vs /compact which retains a summary). Without a boundary signal, the client either renders the full pre-clear transcript as if continuity exists (misleading) or has to text-match heuristically. Neither is robust.
What we'd like
Mirror compact_boundary. When /clear completes inside the SDK, emit either:
Option 1: _meta flag on the next agent message chunk
Same convention used for parentToolUseId. On the first chunk emitted after the clear:
update: {
sessionUpdate: "agent_message_chunk",
content: { type: "text", text: ... },
_meta: { claudeCode: { clearBoundary: true } },
}
Minimal protocol surface. ACP clients that understand the flag render a clear boundary; clients that ignore it see a normal chunk. Same shape as compact_boundary's _meta would be if it were ever extended.
Option 2: dedicated sessionUpdate variant
A new top-level sessionUpdate: "session_cleared" variant the adapter emits when the SDK reports the clear boundary. Cleaner long-term protocol but needs ACP spec coordination.
Option 1 is the practical v1; Option 2 the right shape if the spec is being extended.
Concrete behavioral asks
When /clear lands inside the SDK and the adapter sees the corresponding boundary system message:
- Reset the cached
lastAssistantTotalUsage / lastAssistantUsage to zero (matches compact_boundary behavior).
- Emit a
usage_update with used: 0, size: session.contextWindowSize. Clients keep their context-window indicator from showing stale pre-clear numbers.
- Emit the clear-boundary signal (Option 1 or 2) so clients can render a divider and update transcript-presentation logic.
- Trigger
sendAvailableCommandsUpdate(sessionId) so the client refreshes its slash palette (separate issue tracking this; mentioned here because the two land naturally together).
Out of scope
- Surfacing the SDK's internal "what was cleared" payload. Clients only need to know the boundary happened; the prior transcript is on the client side already.
- Locale handling of
/clear itself. Boundary signal is independent of which surface command triggered it.
Context
Filed from the agent-of-empires side as the upstream half of njbrake/agent-of-empires#1101 (cockpit /clear UX gap). The aoe-side fix can ship with text-match detection as v1 (mirroring how /compact was handled in aoe), but a structured signal would eliminate that fragility and let any ACP client implement the same UX without per-client heuristics.
Tested against @agentclientprotocol/claude-agent-acp package at the version currently installed via npx claude-agent-acp. Adapter source inspected at dist/acp-agent.js lines 460-520 (system message switch) and 1796+ (getAvailableSlashCommands).
Note: Claude handled the investigation and prose via back-and-forth. Idea, decisions, and everything else are mine. — @Seluj78
Problem
When the user runs
/clear, the Claude Code SDK ends its current internal conversation and starts a fresh one. The agent has no memory of prior turns after this point. From the ACP client's perspective, there is no structured signal that this happened: the adapter forwards/clearas a regular user prompt, the SDK handles it internally, and the next assistant turn just looks like a normal response with empty context.Compare against
compact_boundary, which the adapter explicitly handles inacp-agent.js:478-507:compact_boundarylets ACP clients render a visible divider, reset transcript expectations, and update the context-window indicator./clearproduces the same kind of state transition (context wiped, transcript misleading from the model's perspective) but the adapter emits nothing comparable.Why this matters for ACP clients
Without a structured signal, clients have to detect
/clearheuristically (substring match on the user prompt text). That fragile pattern:/clearever gets localised.Most importantly, the transcript divergence after
/clearis severe: the agent has no continuity at all (vs/compactwhich retains a summary). Without a boundary signal, the client either renders the full pre-clear transcript as if continuity exists (misleading) or has to text-match heuristically. Neither is robust.What we'd like
Mirror
compact_boundary. When/clearcompletes inside the SDK, emit either:Option 1:
_metaflag on the next agent message chunkSame convention used for
parentToolUseId. On the first chunk emitted after the clear:Minimal protocol surface. ACP clients that understand the flag render a clear boundary; clients that ignore it see a normal chunk. Same shape as
compact_boundary's_metawould be if it were ever extended.Option 2: dedicated
sessionUpdatevariantA new top-level
sessionUpdate: "session_cleared"variant the adapter emits when the SDK reports the clear boundary. Cleaner long-term protocol but needs ACP spec coordination.Option 1 is the practical v1; Option 2 the right shape if the spec is being extended.
Concrete behavioral asks
When
/clearlands inside the SDK and the adapter sees the corresponding boundary system message:lastAssistantTotalUsage/lastAssistantUsageto zero (matchescompact_boundarybehavior).usage_updatewithused: 0,size: session.contextWindowSize. Clients keep their context-window indicator from showing stale pre-clear numbers.sendAvailableCommandsUpdate(sessionId)so the client refreshes its slash palette (separate issue tracking this; mentioned here because the two land naturally together).Out of scope
/clearitself. Boundary signal is independent of which surface command triggered it.Context
Filed from the
agent-of-empiresside as the upstream half of njbrake/agent-of-empires#1101 (cockpit/clearUX gap). The aoe-side fix can ship with text-match detection as v1 (mirroring how/compactwas handled in aoe), but a structured signal would eliminate that fragility and let any ACP client implement the same UX without per-client heuristics.Tested against
@agentclientprotocol/claude-agent-acppackage at the version currently installed vianpx claude-agent-acp. Adapter source inspected atdist/acp-agent.jslines 460-520 (system message switch) and 1796+ (getAvailableSlashCommands).