Note: Claude handled the investigation and prose via back-and-forth. Idea, decisions, and everything else are mine. — @Seluj78
Problem
sendAvailableCommandsUpdate(sessionId) is called in four places in acp-agent.js:
acp-agent.js:338 newSession
acp-agent.js:353 unstable_forkSession
acp-agent.js:361 resumeSession
acp-agent.js:370 loadSession
It is not called when the available command surface changes mid-session. Several common operations mutate the SDK's command list but leave the ACP client's cached availableCommands stale:
/clear — Clears the internal conversation; the next assistant turn runs in a fresh SDK session. Plugins / skills / MCP servers attached to the new internal session may differ from those at original newSession time.
/login / /logout — Changes auth state and (potentially) which commands are exposed (cost, gated capabilities).
- Plugin install (out-of-band, via the SDK's plugin manifest reload).
- Skill load (project-level skills picked up after
newSession).
- MCP server attach (mid-session config reload).
When any of these happen, ACP clients keep showing the stale slash palette until the user manually creates a new session. The user installs a new MCP server, runs /clear to start fresh on a task that needs it, and the slash palette in the client doesn't show the new MCP-exposed commands.
What we'd like
Call sendAvailableCommandsUpdate(sessionId) in every code path that mutates the SDK's command surface for an active session. Specifically:
/clear handler
Wherever the adapter recognises /clear completed (system message subtype, SDK callback, or wherever the clear boundary lands in the message stream): add a setTimeout(() => this.sendAvailableCommandsUpdate(sessionId), 0) matching the pattern at acp-agent.js:338.
/login / /logout
Same shape. After the auth state transition completes, push a fresh command list.
Plugin / skill / MCP reload paths
If the SDK exposes a "command surface changed" event (similar to how it surfaces compact_boundary), the adapter should subscribe and emit sendAvailableCommandsUpdate on each fire. If no such event exists, that's an SDK-side ask: at minimum, an internal callback the adapter can subscribe to.
Why this matters
Today, the only way to refresh the slash palette in an ACP client is to tear down the session and create a new one. That:
- Loses the cached
acp_session_id (so resume-on-restart breaks for that session).
- Forces clients to UX-around "you have to reattach to see new commands."
- Mismatches user mental model: "I just installed a thing, my client should see it."
The fix is a handful of one-line sendAvailableCommandsUpdate calls in existing handlers.
Concrete behavioral asks
- Identify each adapter-side handler that mutates
getAvailableSlashCommands's output set. The two obvious ones are /clear and /login//logout. Plugin / skill / MCP mid-session reload depends on SDK plumbing.
- Call
sendAvailableCommandsUpdate(sessionId) from each one.
- Document the contract in the adapter README: "available commands are refreshed on the following events" with the list.
Open question
Is there an SDK-side signal already exposed (similar to compact_boundary system message) that the adapter could subscribe to for "command surface changed"? If yes, prefer that over manual call-site instrumentation. If no, the per-handler approach is the right v1.
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 clear its cached availableCommands defensively on /clear detection, but the population side is upstream-only: without sendAvailableCommandsUpdate firing, the cleared palette stays empty until a fresh session create.
Adapter source inspected at dist/acp-agent.js:331-372 (the four current sendAvailableCommandsUpdate call sites) and dist/acp-agent.js:1124,1796 (sendAvailableCommandsUpdate and getAvailableSlashCommands definitions).
Note: Claude handled the investigation and prose via back-and-forth. Idea, decisions, and everything else are mine. — @Seluj78
Problem
sendAvailableCommandsUpdate(sessionId)is called in four places inacp-agent.js:It is not called when the available command surface changes mid-session. Several common operations mutate the SDK's command list but leave the ACP client's cached
availableCommandsstale:/clear— Clears the internal conversation; the next assistant turn runs in a fresh SDK session. Plugins / skills / MCP servers attached to the new internal session may differ from those at originalnewSessiontime./login//logout— Changes auth state and (potentially) which commands are exposed (cost, gated capabilities).newSession).When any of these happen, ACP clients keep showing the stale slash palette until the user manually creates a new session. The user installs a new MCP server, runs
/clearto start fresh on a task that needs it, and the slash palette in the client doesn't show the new MCP-exposed commands.What we'd like
Call
sendAvailableCommandsUpdate(sessionId)in every code path that mutates the SDK's command surface for an active session. Specifically:/clearhandlerWherever the adapter recognises
/clearcompleted (system message subtype, SDK callback, or wherever the clear boundary lands in the message stream): add asetTimeout(() => this.sendAvailableCommandsUpdate(sessionId), 0)matching the pattern atacp-agent.js:338./login//logoutSame shape. After the auth state transition completes, push a fresh command list.
Plugin / skill / MCP reload paths
If the SDK exposes a "command surface changed" event (similar to how it surfaces
compact_boundary), the adapter should subscribe and emitsendAvailableCommandsUpdateon each fire. If no such event exists, that's an SDK-side ask: at minimum, an internal callback the adapter can subscribe to.Why this matters
Today, the only way to refresh the slash palette in an ACP client is to tear down the session and create a new one. That:
acp_session_id(so resume-on-restart breaks for that session).The fix is a handful of one-line
sendAvailableCommandsUpdatecalls in existing handlers.Concrete behavioral asks
getAvailableSlashCommands's output set. The two obvious ones are/clearand/login//logout. Plugin / skill / MCP mid-session reload depends on SDK plumbing.sendAvailableCommandsUpdate(sessionId)from each one.Open question
Is there an SDK-side signal already exposed (similar to
compact_boundarysystem message) that the adapter could subscribe to for "command surface changed"? If yes, prefer that over manual call-site instrumentation. If no, the per-handler approach is the right v1.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 clear its cachedavailableCommandsdefensively on/cleardetection, but the population side is upstream-only: withoutsendAvailableCommandsUpdatefiring, the cleared palette stays empty until a fresh session create.Adapter source inspected at
dist/acp-agent.js:331-372(the four currentsendAvailableCommandsUpdatecall sites) anddist/acp-agent.js:1124,1796(sendAvailableCommandsUpdateandgetAvailableSlashCommandsdefinitions).