1---
2date: 2025-08-28 15:34:28 PDT
3researcher: Mikayla Maki
4git_commit: 425291f0aed2abe148e1a8ea4eda74569e25c2b7
5branch: claude-experiments
6repository: zed
7topic: "Custom Slash Commands for Agent Client Protocol"
8tags: [research, codebase, acp, slash-commands, claude-code, protocol-extension]
9status: complete
10last_updated: 2025-08-28
11last_updated_by: Nathan
12last_updated_note: "Added detailed findings from agent-client-protocol and claude-code-acp repositories"
13---
14
15# Research: Custom Slash Commands for Agent Client Protocol
16
17**Date**: 2025-08-28 15:34:28 PDT
18**Researcher**: Mikayla Maki
19**Git Commit**: 565782a1c769c90e58e012a80ea1c2d0cfcdb837
20**Branch**: claude-experiments
21**Repository**: zed
22
23## Research Question
24
25We're adding support for custom slash commands to Agent Client Protocol for the **agent panel** (not assistant 1/text threads). The client should be able to:
26
27- List available commands
28- Run a command with arguments (check Claude Code behavior)
29
30In the Claude Code ACP adapter, we want implement the _agent_ side of the protocol:
31
32- List commands by reading out of the `.claude/commands` directory
33- Run commands via the SDK
34
35We need to update the protocol to support the new RPCs for listing and running commands.
36We need to understand how to run commands via the SDK.
37
38**Important Note**: This is for the agent panel UX, NOT the existing assistant/text thread slash commands. The existing slash command infrastructure is for assistant 1/text threads and is not relevant to this implementation.
39
40## Summary
41
42The research reveals the architecture needed for implementing custom slash commands in the **agent panel** via ACP:
43
44**Agent Panel Architecture**: Separate UI system from assistant/text threads with dedicated components (`AgentPanel`, `AcpThreadView`) and message handling through ACP protocol integration.
45
46**ACP Protocol**: JSON-RPC based with clear patterns for adding new RPC methods through request/response enums, method dispatch, and capability negotiation. Handles session management, tool calls, and real-time message streaming.
47
48**Claude Commands Structure**: Markdown-based command definitions in `.claude/commands/` with consistent format, metadata, and programmatic parsing potential.
49
50**SDK Integration**: Claude Code ACP adapter bridges ACP protocol with Claude SDK, providing tool execution and session management through MCP servers.
51
52**Note**: The existing Claude Code slash command system (`SlashCommand` trait, `assistant_slash_command` crate) is **not relevant** - that's for assistant 1/text threads. The agent panel needs its own custom command implementation.
53
54## Detailed Findings
55
56### Agent Panel Architecture
57
58**Core Infrastructure** (`crates/agent_ui/`):
59
60- `agent_panel.rs:24` - Main `AgentPanel` struct and UI component
61- `acp/thread_view.rs:315` - `AcpThreadView` component for individual agent conversations
62- `acp/message_editor.rs` - Message input component with slash command integration for agent panel
63- `acp.rs` - ACP module entry point connecting to external ACP agents
64
65**Agent Panel vs Assistant Distinction**:
66
67The agent panel is **completely separate** from the assistant/text thread system:
68- Agent panel uses ACP (Agent Client Protocol) for external agent communication
69- Assistant uses internal Zed slash commands and text thread editors
70- Different UI components, different input handling, different protocol integration
71
72**ACP Integration Flow**:
73
741. External ACP agent process spawned via `agent_servers/src/acp.rs:63-76`
752. JSON-RPC connection established over stdin/stdout at line 84
763. Protocol initialization with capability negotiation at line 131
774. Sessions created via `new_session()` request for isolated conversations
785. User input converted to `PromptRequest` and sent to ACP agent
796. Agent responses stream back as `SessionUpdate` notifications
807. UI updates processed in `AcpThread::handle_session_update()`
81
82**Current Input Handling**:
83
84- Message composition through `MessageEditor` and specialized ACP message editor
85- Standard chat input without custom command support currently
86- Integration with model selector, context strip, and profile management
87
88### Agent Client Protocol RPC Patterns
89
90**Core Structure** (`agent-client-protocol/rust/`):
91
92- JSON-RPC based bidirectional communication via symmetric `Agent`/`Client` traits
93- Type-safe request/response enums with `#[serde(untagged)]` routing
94- Capability negotiation via `AgentCapabilities` and `ClientCapabilities`
95- Auto-generated JSON Schema from Rust types via `JsonSchema` derives
96
97**Agent Trait Methods** (`agent.rs:18-108`):
98- `initialize()` - Connection establishment and capability negotiation
99- `authenticate()` - Authentication using advertised methods
100- `new_session()` - Creates conversation contexts
101- `load_session()` - Loads existing sessions (capability-gated)
102- `prompt()` - Processes user prompts with full lifecycle
103- `cancel()` - Cancels ongoing operations
104
105**Client Trait Methods** (`client.rs:19-114`):
106- `request_permission()` - Requests user permission for tool calls
107- `write_text_file()` / `read_text_file()` - File operations (capability-gated)
108- `session_notification()` - Handles session updates from agent
109
110**RPC Infrastructure Pattern**:
111
1121. **Method Constants** - Define at lines `agent.rs:395-415` / `client.rs:451-485`
1132. **Request/Response Structs** - With `#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]`
1143. **Schema Annotations** - `#[schemars(extend("x-side" = "agent", "x-method" = "method_name"))]`
1154. **Untagged Enums** - Add to `ClientRequest`/`AgentResponse` enums for message routing
1165. **Trait Methods** - Add to `Agent`/`Client` traits with `impl Future` signatures
1176. **Connection Methods** - Implement in `ClientSideConnection`/`AgentSideConnection`
1187. **Message Handling** - Update `MessageHandler` implementations for dispatch
119
120**Protocol Versioning** (`version.rs:4-20`):
121- Current: V1 with backward compatibility
122- Breaking changes require version bump
123- Non-breaking additions use capability flags
124
125### .claude/commands Directory Structure
126
127**Format**: Markdown files with consistent structure:
128
129```markdown
130# Command Name
131
132[Description]
133
134## Initial Response
135
136[Standardized first response]
137
138## Process Steps
139
140### Step 1: [Phase Name]
141
142[Instructions]
143
144### Claude Code ACP Adapter Implementation
145
146**Architecture** (`claude-code-acp/src/`):
147
148- `acp-agent.ts:51` - `ClaudeAcpAgent` class implementing complete ACP `Agent` interface
149- `mcp-server.ts:9` - Internal MCP proxy server for file operations and permissions
150- `tools.ts:22` - Tool format conversion between Claude SDK and ACP representations
151- Session management with UUID tracking and Claude SDK `Query` objects
152
153**Agent Interface Implementation** (`acp-agent.ts:51-218`):
154- `initialize()` at line 63: Declares capabilities (image, embedded_context) and auth methods
155- `newSession()` at line 84: Creates UUID sessions with MCP server integration
156- `prompt()` at line 140: Main query execution using Claude SDK with real-time streaming
157- `cancel()` at line 211: Properly handles session cancellation and cleanup
158
159**Session Lifecycle** (`acp-agent.ts:84-134`):
1601. Generate UUID session ID and create pushable input stream
1612. Configure MCP servers from ACP request parameters
1623. Start internal HTTP-based MCP proxy server on dynamic port
1634. Initialize Claude SDK query with working directory, MCP servers, tool permissions
1645. Enable `mcp__acp__read` while disabling direct file tools for security
165
166**Query Execution Flow** (`acp-agent.ts:140-209`):
1671. Convert ACP prompt to Claude format via `promptToClaude()` at line 237
1682. Push user message to Claude SDK input stream
1693. Iterate through Claude SDK responses with real-time streaming
1704. Handle system, result, user, and assistant message types
1715. Convert Claude messages to ACP format via `toAcpNotifications()` at line 312
1726. Stream session updates back to ACP client
173
174**MCP Proxy Architecture** (`mcp-server.ts:9-449`):
175- **Internal HTTP Server**: Creates MCP server for Claude SDK integration
176- **Tool Implementations**:
177 - `read` (lines 19-94): Proxies to ACP client's `readTextFile()`
178 - `write` (lines 96-149): Proxies to ACP client's `writeTextFile()`
179 - `edit` (lines 152-239): Text replacement with line tracking
180 - `multi-edit` (lines 241-318): Sequential edit operations
181- **Permission Integration**: Routes tool permission requests through ACP client
182
183**Current Command Support**:
184- **No existing slash command infrastructure** - all interactions use standard prompt interface
185- **No `.claude/commands` directory integration** currently implemented
186- **Command detection would require preprocessing** before Claude SDK integration
187
188## Code References
189
190### Zed Integration Layer
191- `crates/agent_ui/src/agent_panel.rs:24` - Main AgentPanel component
192- `crates/agent_ui/src/acp/thread_view.rs:315` - AcpThreadView UI component
193- `crates/agent_ui/src/acp/message_editor.rs` - Agent panel message input
194- `crates/agent_servers/src/acp.rs:63-162` - ACP connection establishment
195- `crates/acp_thread/src/acp_thread.rs:826` - ACP thread creation
196
197### Agent Client Protocol
198- `agent-client-protocol/rust/agent.rs:18-108` - Agent trait with 6 core methods
199- `agent-client-protocol/rust/client.rs:19-114` - Client trait for bidirectional communication
200- `agent-client-protocol/rust/acp.rs:120` - ClientSideConnection implementation
201- `agent-client-protocol/rust/acp.rs:341` - AgentSideConnection implementation
202- `agent-client-protocol/rust/rpc.rs:30-367` - RPC connection infrastructure
203- `agent-client-protocol/rust/agent.rs:333-371` - AgentCapabilities and PromptCapabilities
204- `agent-client-protocol/rust/agent.rs:423-432` - ClientRequest/AgentResponse enum routing
205- `agent-client-protocol/rust/generate.rs:24-77` - JSON schema generation
206
207### Claude Code ACP Adapter
208- `claude-code-acp/src/acp-agent.ts:51-218` - ClaudeAcpAgent implementing Agent interface
209- `claude-code-acp/src/mcp-server.ts:9-449` - Internal MCP proxy server
210- `claude-code-acp/src/tools.ts:22-395` - Tool format conversion
211- `claude-code-acp/src/utils.ts:7-75` - Stream processing utilities
212
213### Command Infrastructure
214- `.claude/commands/*.md` - Command definition files (markdown format)
215- No existing slash command infrastructure in claude-code-acp currently
216
217## Architecture Insights
218
219**Agent Panel System**: Completely separate from assistant/text threads, uses ACP protocol for external agent communication with JSON-RPC over stdin/stdout, manages sessions with unique IDs, and provides real-time message streaming with UI updates.
220
221**ACP Protocol**: Designed for extensibility with capability negotiation, type safety through Rust enums, symmetric bidirectional design, and JSON-RPC foundation. Handles tool calls, permissions, and session management.
222
223**Command Definitions**: Human-readable markdown with programmatically parseable structure, consistent metadata patterns, and workflow automation framework stored in `.claude/commands/`.
224
225**Integration Patterns**: Claude Code ACP adapter provides proven pattern for bridging protocols, MCP servers enable tool execution proxying, session management handles concurrent interactions. Agent panel needs new command integration separate from existing slash commands.
226
227## Implementation Recommendations
228
229### 1. Protocol Extension for Custom Commands
230
231Add new RPC methods following exact ACP patterns in `agent-client-protocol/rust/`:
232
233**Method Constants** (`agent.rs:395-415`):
234```rust
235pub const SESSION_LIST_COMMANDS: &str = "session/list_commands";
236pub const SESSION_RUN_COMMAND: &str = "session/run_command";
237```
238
239**Request/Response Types** (after `agent.rs:371`):
240```rust
241#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
242#[schemars(extend("x-side" = "agent", "x-method" = "session/list_commands"))]
243#[serde(rename_all = "camelCase")]
244pub struct ListCommandsRequest {
245 pub session_id: SessionId,
246}
247
248#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
249#[schemars(extend("x-side" = "agent", "x-method" = "session/list_commands"))]
250#[serde(rename_all = "camelCase")]
251pub struct ListCommandsResponse {
252 pub commands: Vec<CommandInfo>,
253}
254
255#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
256#[serde(rename_all = "camelCase")]
257pub struct CommandInfo {
258 pub name: String,
259 pub description: String,
260 pub requires_argument: bool,
261}
262
263#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
264#[schemars(extend("x-side" = "agent", "x-method" = "session/run_command"))]
265#[serde(rename_all = "camelCase")]
266pub struct RunCommandRequest {
267 pub session_id: SessionId,
268 pub command: String,
269 pub args: Option<String>,
270}
271```
272
273**Trait Extension** (add to `Agent` trait after `cancel()` at line 107):
274```rust
275fn list_commands(
276 &self,
277 arguments: ListCommandsRequest,
278) -> impl Future<Output = Result<ListCommandsResponse, Error>>;
279
280fn run_command(
281 &self,
282 arguments: RunCommandRequest,
283) -> impl Future<Output = Result<(), Error>>;
284```
285
286**Enum Routing** (add to `ClientRequest` at line 423 and `AgentResponse`):
287```rust
288ListCommandsRequest(ListCommandsRequest),
289RunCommandRequest(RunCommandRequest),
290```
291
292**Capability Extension** (add to `PromptCapabilities` at line 358):
293```rust
294/// Agent supports custom slash commands via `list_commands` and `run_command`.
295#[serde(default)]
296pub supports_custom_commands: bool,
297```
298
299### 2. Agent Panel UI Integration
300
301**Option A**: Extend ACP Message Editor
302- Modify `crates/agent_ui/src/acp/message_editor.rs` to detect custom commands
303- Add command completion/suggestion UI similar to existing patterns
304- Trigger custom command execution through ACP protocol
305
306**Option B**: New Command Interface
307- Create dedicated command input component in agent panel
308- Separate from regular message input to provide distinct UX
309- Integrate with `AcpThreadView` for command results display
310
311### 3. ACP Agent Implementation
312
313In Claude Code ACP adapter, extend `ClaudeAcpAgent` class at `claude-code-acp/src/acp-agent.ts:51`:
314
315**Add Command Parser** (new module at `src/command-parser.ts`):
316```typescript
317export interface CommandInfo {
318 name: string;
319 description: string;
320 requires_argument: boolean;
321 content?: string;
322}
323
324export class CommandParser {
325 private commandsDir: string;
326 private cachedCommands?: CommandInfo[];
327
328 constructor(cwd: string) {
329 this.commandsDir = path.join(cwd, '.claude', 'commands');
330 }
331
332 async listCommands(): Promise<CommandInfo[]> {
333 // Parse *.md files, extract H1 titles and descriptions
334 }
335
336 async getCommand(name: string): Promise<CommandInfo | null> {
337 // Return specific command with full content for execution
338 }
339}
340```
341
342**Extend ClaudeAcpAgent** (add after line 218):
343```typescript
344private commandParser?: CommandParser;
345
346// In constructor around line 60:
347if (options.cwd && fs.existsSync(path.join(options.cwd, '.claude', 'commands'))) {
348 this.commandParser = new CommandParser(options.cwd);
349}
350
351// Update initialize() around line 68 to advertise capability:
352agent_capabilities: {
353 prompt_capabilities: {
354 image: true,
355 audio: false,
356 embedded_context: true,
357 supports_custom_commands: !!this.commandParser,
358 },
359}
360
361async listCommands(request: ListCommandsRequest): Promise<ListCommandsResponse> {
362 if (!this.commandParser) return { commands: [] };
363
364 const commands = await this.commandParser.listCommands();
365 return {
366 commands: commands.map(cmd => ({
367 name: cmd.name,
368 description: cmd.description,
369 requires_argument: cmd.requires_argument,
370 }))
371 };
372}
373
374async runCommand(request: RunCommandRequest): Promise<void> {
375 if (!this.commandParser) throw new Error('Commands not supported');
376
377 const command = await this.commandParser.getCommand(request.command);
378 if (!command) throw new Error(`Command not found: ${request.command}`);
379
380 // Execute command via existing session mechanism
381 const session = this.sessions.get(request.session_id);
382 if (!session) throw new Error('Session not found');
383
384 // Create system prompt from command content
385 let prompt = command.content;
386 if (command.requires_argument && request.args) {
387 prompt += `\n\nArguments: ${request.args}`;
388 }
389
390 // Inject as system message and process via existing prompt flow
391 session.input.push({ role: 'user', content: prompt });
392
393 // Stream results back via existing session update mechanism
394 // (handled automatically by query execution loop at line 150)
395}
396```
397
398### 4. Command Parsing and Execution
399
400Implement markdown parser for `.claude/commands/*.md`:
401
402```typescript
403function parseCommandFile(content: string): CommandInfo {
404 // Extract H1 title for name/description
405 // Find "Initial Response" section
406 // Parse metadata and requirements
407 // Return structured command info
408}
409```
410
411Execute commands by sending command content as system prompt to Claude SDK, similar to existing ACP query patterns.
412
413## Open Questions
414
4151. **Agent Panel UX**: Should custom commands be integrated into the existing message input or as a separate command interface?
416
4172. **Command Arguments**: How should complex command arguments be structured and validated in the agent panel context?
418
4193. **Command Context**: Should commands have access to current ACP session state, file context, or conversation history?
420
4214. **Command Discovery**: Should commands be cached or re-read on each listing request? How does this integrate with ACP session lifecycle?
422
4235. **Command Execution**: Should commands run in isolated contexts or share ACP session state?
424
4256. **Error Handling**: What's the appropriate error handling strategy for command parsing and execution failures in the agent panel?
426
4277. **UI Integration**: How should command execution progress and results be displayed within the `AcpThreadView` component?
428
429## Follow-up Research 2025-08-28 20:29:47 MDT
430
431After gaining access to the actual `agent-client-protocol` and `claude-code-acp` repositories, I updated this research document with concrete implementation details:
432
433### Key New Findings
434
435**Agent Client Protocol Structure**: The protocol uses a symmetric `Agent`/`Client` trait design with `#[serde(untagged)]` enum routing, JSON schema generation, and explicit capability negotiation. Adding new RPC methods requires specific patterns for method constants, request/response structs, trait extensions, and enum routing.
436
437**Claude Code ACP Adapter**: Implements the full Agent interface using Claude SDK integration via MCP proxy servers. Currently has no slash command infrastructure - all interactions use the standard prompt interface. Command detection would require preprocessing before Claude SDK integration.
438
439**Implementation Requirements**: More complex than initially understood - requires protocol extension, trait implementations, enum routing updates, capability advertisement, and coordination between three repositories (zed, agent-client-protocol, claude-code-acp).
440
441### Updated Implementation Approach
442
4431. **Protocol Extension**: Add `session/list_commands` and `session/run_command` methods following exact ACP patterns
4442. **Capability System**: Extend `PromptCapabilities` with `supports_custom_commands` flag
4453. **Agent Implementation**: Create command parser module in claude-code-acp to read `.claude/commands/*.md` files
4464. **UI Integration**: Use existing completion provider patterns in Zed's agent panel message editor
447
448The research now includes specific file:line references and concrete code examples for all three layers of the implementation.
449
450###### ORIGINAL CLAUDE PROMPT (2025-08-28 15:34:28 PDT):
451
452⏺ I've completed comprehensive research on adding custom
453slash commands to the Agent Client Protocol for the
454**agent panel** (NOT assistant/text threads). Here's what
455I found:
456
457Key Findings
458
459Agent Panel Architecture: The agent panel is completely
460separate from assistant/text threads, using ACP protocol
461for external agent communication via JSON-RPC over
462stdin/stdout. It has dedicated UI components like
463AgentPanel and AcpThreadView.
464
465ACP Protocol Patterns: The protocol uses JSON-RPC with
466type-safe request/response enums. Adding new RPC methods
467follows a clear pattern: define structs, add to enums,
468update dispatch logic. Handles sessions, tool calls, and
469real-time streaming.
470
471.claude/commands Structure: Commands are defined as
472structured Markdown files with consistent format -
473perfect for programmatic parsing. Each contains metadata,
474process steps, and execution guidelines.
475
476SDK Integration: The Claude Code ACP adapter already
477bridges ACP with the Claude SDK through MCP servers,
478providing a proven pattern for command execution.
479
480**IMPORTANT**: The existing Claude Code slash command
481system (SlashCommand trait, assistant_slash_command crate)
482is NOT relevant - that's for assistant 1/text threads.
483The agent panel needs its own custom command
484implementation.
485
486Implementation Approach
487
488You'll need to:
489
4901. Extend ACP Protocol: Add ListCommandsRequest/Response
491 and RunCommandRequest/Response to the schema
4922. Agent Panel UI: Integrate custom commands into agent
493 panel message input or create separate command interface
4943. Parse Command Definitions: Read .claude/commands/\*.md
495 files and extract metadata (name, description,
496 requirements)
4974. Execute Commands: Run commands via Claude SDK queries
498 through existing ACP session mechanism
4995. Handle Streaming: Use ACP's session notification
500 system to stream command progress to AcpThreadView
501
502The research document is saved at thoughts/shared/researc
503h/2025-08-28_15-34-28_custom-slash-commands-acp.md with
504detailed implementation recommendations, code references,
505and open questions for your consideration.
506
507###### STATS ON PROMPT TO GENERATE THIS DOCUMENT:
508
509Total cost: $2.87
510Total duration (API): 12m 59.0s
511Total duration (wall): 6m 52.2s
512Total code changes: 242 lines added, 0 lines removed
513Usage by model:
514claude-3-5-haiku: 4.3k input, 175 output, 0 cache read, 0 cache write
515claude-sonnet: 2.9k input, 31.3k output, 4.8m cache read, 256.1k cache write