Update agent panel slash command implementation plan with multi-repo coordination

Nathan Sobo and Claude created

- Add critical architecture note about TypeScript code generation from Rust
- Add repository dependency chain and PR coordination strategy
- Update Phase 3 to reflect auto-generated ACP types
- Add migration notes for multi-repository rollout
- Include local development workflow with path dependencies

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

Change summary

thoughts/shared/plans/2025-08-28_20-04-42_agent-panel-slash-command-menu.md | 623 
1 file changed, 458 insertions(+), 165 deletions(-)

Detailed changes

thoughts/shared/plans/2025-08-28_20-04-42_agent-panel-slash-command-menu.md 🔗

@@ -45,6 +45,66 @@ When user types "/" in agent panel message editor:
 
 Follow the existing "@" mention completion pattern but trigger on "/" instead. Use capability negotiation to control menu visibility. Extend ACP integration to call new RPC methods when available.
 
+## Repository Dependencies & PR Strategy
+
+### **Multi-Repository Architecture**
+This feature spans three repositories that must be coordinated:
+
+1. **`agent-client-protocol`**: External crate defining the protocol
+2. **`zed`**: Main editor with ACP client integration  
+3. **`claude-code-acp`**: Reference agent implementation
+
+### **Dependency Chain**
+```
+agent-client-protocol (Phase 1) 
+    ↓ 
+zed (Phase 2) - temporarily depends on local ACP changes
+    ↓
+claude-code-acp (Phase 3) - uses published ACP version
+```
+
+### **Development Workflow**
+
+#### Step 1: Local Development Setup
+```bash
+# Work on ACP protocol extension locally
+cd /Users/nathan/src/agent-client-protocol
+# Make Phase 1 changes...
+
+# Point Zed to local ACP version for testing
+cd /Users/nathan/src/zed
+# Update Cargo.toml to reference local path:
+# agent-client-protocol = { path = "../agent-client-protocol" }
+```
+
+#### Step 2: Testing & Validation
+- Test all phases end-to-end with local dependencies
+- Verify Phase 1+2 integration works correctly
+- Validate Phase 3 against local ACP changes
+
+#### Step 3: PR Sequence
+1. **First PR**: `agent-client-protocol` with new slash command methods
+2. **Second PR**: `zed` referencing published ACP version (after #1 merges)
+3. **Third PR**: `claude-code-acp` using new ACP capabilities
+
+### **Temporary Dependency Management**
+During development, Zed's `Cargo.toml` will need:
+```toml
+[dependencies]
+# Temporary local reference for development/testing
+agent-client-protocol = { path = "../agent-client-protocol" }
+
+# After ACP PR merges, switch to:  
+agent-client-protocol = "0.2.0-alpha.1"  # or appropriate version
+```
+
+### **Cross-Repository Verification**
+Before opening PRs:
+- [ ] ACP protocol extension compiles and tests pass
+- [ ] Zed compiles against local ACP changes
+- [ ] End-to-end slash command flow works locally
+- [ ] Claude ACP adapter works with generated types
+
 ## Phase 1: ACP Protocol Extension
 
 ### Overview
@@ -54,29 +114,18 @@ Add new slash command RPC methods and capabilities to the agent-client-protocol
 
 #### 1. Protocol Types (External Crate)
 **File**: `/Users/nathan/src/agent-client-protocol/rust/agent.rs`
-**Changes**: Add new request/response types and trait methods
+**Changes**: Add new request/response types and trait methods following exact ACP patterns
 
+**Step 1: Add Method Constants** (after line 415):
 ```rust
-// Add around line 108 after the cancel method in the Agent trait
-/// Lists available custom commands for a session.
-///
-/// Returns all commands available in the agent's `.claude/commands` directory
-/// or equivalent command registry. Commands can be executed via `run_command`.
-fn list_commands(
-    &self,
-    arguments: ListCommandsRequest,
-) -> impl Future<Output = Result<ListCommandsResponse, Error>>;
-
-/// Executes a custom command within a session.
-///
-/// Runs the specified command with optional arguments. The agent should
-/// stream results back via session update notifications.
-fn run_command(
-    &self,
-    arguments: RunCommandRequest,
-) -> impl Future<Output = Result<(), Error>>;
+/// Method name for listing custom commands in a session.
+pub const SESSION_LIST_COMMANDS: &str = "session/list_commands";
+/// Method name for running a custom command in a session.  
+pub const SESSION_RUN_COMMAND: &str = "session/run_command";
+```
 
-// Add around line 372 after PromptCapabilities
+**Step 2: Add Request/Response Structs** (after PromptCapabilities at line 371):
+```rust
 /// Request parameters for listing available commands.
 #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
 #[schemars(extend("x-side" = "agent", "x-method" = "session/list_commands"))]
@@ -121,6 +170,47 @@ pub struct RunCommandRequest {
 }
 ```
 
+**Step 3: Add Agent Trait Methods** (after `cancel()` method at line 107):
+```rust
+/// Lists available custom commands for a session.
+///
+/// Returns all commands available in the agent's `.claude/commands` directory
+/// or equivalent command registry. Commands can be executed via `run_command`.
+fn list_commands(
+    &self,
+    arguments: ListCommandsRequest,
+) -> impl Future<Output = Result<ListCommandsResponse, Error>>;
+
+/// Executes a custom command within a session.
+///
+/// Runs the specified command with optional arguments. The agent should
+/// stream results back via session update notifications.
+fn run_command(
+    &self,
+    arguments: RunCommandRequest,
+) -> impl Future<Output = Result<(), Error>>;
+```
+
+**Step 4: Add Enum Routing Variants** (to `ClientRequest` enum around line 423):
+```rust
+#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
+#[serde(untagged)]
+pub enum ClientRequest {
+    InitializeRequest(InitializeRequest),
+    AuthenticateRequest(AuthenticateRequest),
+    NewSessionRequest(NewSessionRequest),
+    LoadSessionRequest(LoadSessionRequest),
+    PromptRequest(PromptRequest),
+    ListCommandsRequest(ListCommandsRequest),  // ADD THIS
+    RunCommandRequest(RunCommandRequest),      // ADD THIS
+}
+```
+
+**Step 5: Add AgentResponse Enum Variant** (find AgentResponse enum):
+```rust
+ListCommandsResponse(ListCommandsResponse),  // ADD THIS
+```
+
 #### 2. Capability Extension
 **File**: `/Users/nathan/src/agent-client-protocol/rust/agent.rs`
 **Changes**: Extend PromptCapabilities with custom command support
@@ -157,10 +247,40 @@ fn run_command(&self, request: acp::RunCommandRequest, cx: &mut App) -> Task<Res
 
 #### 4. ACP Connection Implementation  
 **File**: `crates/agent_servers/src/acp.rs`
-**Changes**: Implement new trait methods in AcpConnection
+**Changes**: Implement new trait methods in AcpConnection following existing patterns
 
+**Step 1: Add ClientSideConnection Methods** (after existing methods around line 340):
+```rust
+impl acp::ClientSideConnection {
+    /// Lists available custom commands for a session.
+    pub async fn list_commands(
+        &self,
+        request: acp::ListCommandsRequest,
+    ) -> Result<acp::ListCommandsResponse, acp::Error> {
+        self.connection
+            .request(acp::ClientRequest::ListCommandsRequest(request))
+            .await
+            .and_then(|response| match response {
+                acp::AgentResponse::ListCommandsResponse(response) => Ok(response),
+                _ => Err(acp::Error::internal_error("Invalid response type")),
+            })
+    }
+
+    /// Executes a custom command in a session.
+    pub async fn run_command(
+        &self,
+        request: acp::RunCommandRequest,
+    ) -> Result<(), acp::Error> {
+        self.connection
+            .request(acp::ClientRequest::RunCommandRequest(request))
+            .await
+            .map(|_| ())
+    }
+}
+```
+
+**Step 2: Implement AgentConnection Trait Methods** (for AcpConnection struct):
 ```rust
-// Add around line 340 after existing method implementations
 fn list_commands(&self, session_id: &acp::SessionId, cx: &mut App) -> Task<Result<acp::ListCommandsResponse>> {
     let conn = self.connection.clone();
     let session_id = session_id.clone();
@@ -177,6 +297,25 @@ fn run_command(&self, request: acp::RunCommandRequest, cx: &mut App) -> Task<Res
 }
 ```
 
+**Step 3: Update Message Dispatch Logic** (in `AgentSide::decode_request()` around line 493):
+```rust
+// Add cases to the match statement:
+acp::SESSION_LIST_COMMANDS => {
+    if let Ok(request) = serde_json::from_value::<acp::ListCommandsRequest>(params) {
+        Ok(acp::ClientRequest::ListCommandsRequest(request))
+    } else {
+        Err(acp::Error::invalid_params("Invalid list_commands parameters"))
+    }
+}
+acp::SESSION_RUN_COMMAND => {
+    if let Ok(request) = serde_json::from_value::<acp::RunCommandRequest>(params) {
+        Ok(acp::ClientRequest::RunCommandRequest(request))
+    } else {
+        Err(acp::Error::invalid_params("Invalid run_command parameters"))
+    }
+}
+```
+
 #### 5. Capability Detection
 **File**: `crates/acp_thread/src/acp_thread.rs`
 **Changes**: Add capability checking helper
@@ -194,14 +333,23 @@ pub fn supports_custom_commands(&self, cx: &App) -> bool {
 - [ ] Protocol crate compiles: `cd /Users/nathan/src/agent-client-protocol && cargo check`
 - [ ] Protocol tests pass: `cd /Users/nathan/src/agent-client-protocol && cargo test`
 - [ ] Schema generation works: `cd /Users/nathan/src/agent-client-protocol && cargo run --bin generate`
+- [ ] Schema includes new methods: `grep -A5 -B5 "session/list_commands\|session/run_command" /Users/nathan/src/agent-client-protocol/schema/schema.json`
 - [ ] Zed compiles successfully: `./script/clippy`
 - [ ] No linting errors: `cargo clippy --package agent_servers --package acp_thread`
+- [ ] ACP thread capability method compiles: `cargo check --package acp_thread`
 
 #### Manual Verification:
-- [ ] New trait methods are properly defined in connection interface
-- [ ] ACP connection implements new methods correctly
-- [ ] Capability detection helper is available for UI layer
-- [ ] JSON schema includes new request/response types
+- [ ] New trait methods are properly defined in Agent trait (`/Users/nathan/src/agent-client-protocol/rust/agent.rs`)
+  - Verify `list_commands()` method signature at line ~115
+  - Verify `run_command()` method signature at line ~127
+- [ ] Request/response enums updated in ClientRequest (`agent.rs:~423`) and AgentResponse enums
+- [ ] Method constants added (`SESSION_LIST_COMMANDS`, `SESSION_RUN_COMMAND`) after line 415
+- [ ] PromptCapabilities extended with `supports_custom_commands: bool` field
+- [ ] ClientSideConnection methods implemented with proper error handling
+- [ ] Message dispatch logic updated in `AgentSide::decode_request()`
+- [ ] AgentConnection trait extends with new methods (`crates/acp_thread/src/connection.rs`)
+- [ ] AcpConnection implements trait methods (`crates/agent_servers/src/acp.rs`)
+- [ ] AcpThread has `supports_custom_commands()` helper method
 
 ---
 
@@ -259,43 +407,65 @@ impl SlashCommandCompletion {
 
 #### 2. Completion Trigger Detection
 **File**: `crates/agent_ui/src/acp/completion_provider.rs`
-**Changes**: Extend `is_completion_trigger()` method
+**Changes**: Extend `is_completion_trigger()` method following existing patterns
+
+**Current Pattern Analysis**: The completion provider implements the `CompletionProvider` trait and integrates with the editor's completion system. The `is_completion_trigger()` method at line 763 currently only handles "@" mentions.
 
 ```rust
-// Modify around line 763 to add slash command detection
-pub fn is_completion_trigger(
-    &self,
-    buffer: &Entity<Buffer>,
-    position: language::Anchor,
-    text: &str,
-    _trigger_in_words: bool,
-    cx: &mut Context<Editor>,
-) -> bool {
-    // Existing @ mention logic...
-    if let Some(_) = MentionCompletion::try_parse(&line, position.column) {
-        return true;
-    }
-    
-    // Add slash command detection
-    if let Some(thread) = &self.thread {
-        if thread.read(cx).supports_custom_commands(cx) {
-            if let Some(_) = SlashCommandCompletion::try_parse(&line, position.column) {
-                return true;
+// Modify the existing is_completion_trigger() method around line 763
+impl CompletionProvider for ContextPickerCompletionProvider {
+    fn is_completion_trigger(
+        &self,
+        buffer: &Entity<Buffer>,
+        position: language::Anchor,
+        text: &str,
+        _trigger_in_words: bool,
+        cx: &mut Context<Editor>,
+    ) -> bool {
+        let buffer = buffer.read(cx);
+        let position = position.to_point(&buffer);
+        let line_start = Point::new(position.row, 0);
+        let mut lines = buffer.text_for_range(line_start..position).lines();
+        let Some(line) = lines.next() else {
+            return false;
+        };
+
+        // Existing @ mention logic - KEEP THIS
+        if let Some(_) = MentionCompletion::try_parse(&line, position.column) {
+            return true;
+        }
+        
+        // ADD: Slash command detection (only if agent supports commands)
+        if let Some(thread) = &self.thread {
+            if thread.read(cx).supports_custom_commands(cx) {
+                if let Some(_) = SlashCommandCompletion::try_parse(&line, position.column) {
+                    return true;
+                }
             }
         }
+        
+        false
     }
-    
-    false
 }
 ```
 
+**Pattern Notes**: 
+- Integrates with existing `@` mention system without conflicts
+- Only triggers when agent capability `supports_custom_commands` is true
+- Uses same line parsing approach as existing mention system
+- Maintains backward compatibility
+
 #### 3. Command Completion Generation
 **File**: `crates/agent_ui/src/acp/completion_provider.rs`
-**Changes**: Extend `completions()` method
+**Changes**: Extend `completions()` method using existing async patterns
+
+**Current Pattern Analysis**: The completion provider's `completions()` method at line 639 returns `Task<Result<Vec<project::CompletionResponse>>>` and uses `cx.spawn()` for async operations. It handles different completion types via pattern matching.
 
 ```rust
-// Add around line 700 in completions() method after mention handling
-// Handle slash command completions
+// Modify the existing completions() method around line 700
+// ADD this after the existing mention completion logic:
+
+// Handle slash command completions (only if agent supports them)
 if let Some(thread) = &self.thread {
     if thread.read(cx).supports_custom_commands(cx) {
         if let Some(slash_completion) = SlashCommandCompletion::try_parse(&line, cursor_offset) {
@@ -309,7 +479,7 @@ if let Some(thread) = &self.thread {
     }
 }
 
-// Add new method around line 850
+// ADD new method following existing async patterns (around line 850):
 fn complete_slash_commands(
     &self,
     completion: SlashCommandCompletion,
@@ -322,23 +492,28 @@ fn complete_slash_commands(
     };
     
     cx.spawn(async move |cx| {
+        // Get session info using existing patterns
         let session_id = thread.read_with(cx, |thread, _| thread.session_id().clone())?;
         let connection = thread.read_with(cx, |thread, _| thread.connection().clone())?;
         
-        // Fetch commands from agent
-        let commands = connection.list_commands(&session_id, cx).await?;
+        // Fetch commands from agent via new ACP method
+        let response = connection.list_commands(&session_id, cx).await?;
         
-        // Filter commands matching typed prefix
-        let matching_commands: Vec<_> = commands
+        // Filter commands matching typed prefix (fuzzy matching like mentions)
+        let matching_commands: Vec<_> = response.commands
             .into_iter()
-            .filter(|cmd| cmd.name.starts_with(&completion.name))
+            .filter(|cmd| {
+                // Support both prefix matching and fuzzy matching
+                cmd.name.starts_with(&completion.name) ||
+                cmd.name.to_lowercase().contains(&completion.name.to_lowercase())
+            })
             .collect();
         
-        // Convert to completion responses
+        // Convert to project::Completion following existing patterns
         let mut completions = Vec::new();
         for command in matching_commands {
             let new_text = format!("/{}", command.name);
-            let completion = project::Completion {
+            let completion_item = project::Completion {
                 old_range: completion.source_range.clone(),
                 new_text,
                 label: command.name.clone().into(),
@@ -349,6 +524,7 @@ fn complete_slash_commands(
                 } else {
                     None
                 },
+                // Custom confirmation handler for command execution
                 confirm: Some(Arc::new(SlashCommandConfirmation {
                     command: command.name,
                     requires_argument: command.requires_argument,
@@ -356,9 +532,10 @@ fn complete_slash_commands(
                 })),
                 ..Default::default()
             };
-            completions.push(completion);
+            completions.push(completion_item);
         }
         
+        // Return single completion response (like existing mentions)
         Ok(vec![project::CompletionResponse {
             completions,
             is_incomplete: false,
@@ -367,6 +544,13 @@ fn complete_slash_commands(
 }
 ```
 
+**Integration Notes**:
+- Follows same async pattern as existing mention completions at line 639
+- Uses `thread.read_with()` pattern for safe entity access
+- Implements fuzzy matching similar to existing completion types
+- Returns single `CompletionResponse` following established patterns
+- Integrates custom confirmation handler via `confirm` field
+
 #### 4. Command Confirmation Handler
 **File**: `crates/agent_ui/src/acp/completion_provider.rs`
 **Changes**: Add confirmation handler for slash commands
@@ -453,13 +637,30 @@ pub fn run_command(
 - [ ] Code compiles successfully: `./script/clippy`
 - [ ] No linting errors: `cargo clippy --package agent_ui --package acp_thread`
 - [ ] Type checking passes: `cargo check --package agent_ui --package acp_thread`
+- [ ] Completion provider compiles: `cargo check --package agent_ui --lib`
+- [ ] Slash command parsing works: Test `SlashCommandCompletion::try_parse()` with various inputs
 
 #### Manual Verification:
-- [ ] Typing "/" in agent panel triggers completion when agent supports commands
-- [ ] No "/" completion appears when agent doesn't support commands
-- [ ] Command list fetched from agent via `list_commands()` RPC
-- [ ] Command selection triggers `run_command()` RPC
-- [ ] Menu dismisses properly on Escape or click-outside
+- [ ] SlashCommandCompletion struct added to `crates/agent_ui/src/acp/completion_provider.rs`
+  - Verify `try_parse()` method implementation
+  - Test parsing of "/", "/create", "/research_codebase" patterns
+- [ ] ContextPickerCompletionProvider updated:
+  - `is_completion_trigger()` method extended (around line 763)
+  - `completions()` method handles slash commands (around line 700)
+  - `complete_slash_commands()` method added (around line 850)
+- [ ] SlashCommandConfirmation struct implements CompletionConfirm trait
+  - Handles immediate execution for commands without arguments
+  - Allows continued typing for commands requiring arguments
+- [ ] AcpThread has `run_command()` method for command execution
+- [ ] Integration Testing:
+  - [ ] Typing "/" in agent panel triggers completion when `supports_custom_commands = true`
+  - [ ] No "/" completion appears when `supports_custom_commands = false`
+  - [ ] Command list fetched from agent via `list_commands()` RPC call
+  - [ ] Command selection triggers `run_command()` RPC call
+  - [ ] Menu shows command descriptions from agent
+  - [ ] Fuzzy matching works (typing "/cr" shows "create_plan")
+  - [ ] Menu dismisses properly on Escape or click-outside
+  - [ ] Commands execute and stream results back to thread view
 
 ---
 
@@ -468,11 +669,19 @@ pub fn run_command(
 ### Overview
 Prepare the Claude Code ACP adapter to implement the new slash command RPC methods by adding command parsing and execution.
 
+### **CRITICAL ARCHITECTURE NOTE** 
+The TypeScript types in `claude-code-acp` are **automatically generated** from the Rust protocol definitions. The ACP repository uses a code generation pipeline:
+
+1. **Rust → JSON Schema**: `cargo run --bin generate` creates `schema/schema.json` from Rust types
+2. **JSON Schema → TypeScript**: `node typescript/generate.js` creates TypeScript types from the schema
+
+**This means the new `ListCommandsRequest`, `RunCommandRequest`, etc. types will be automatically available in TypeScript after we extend the Rust protocol in Phase 1.**
+
 ### Changes Required:
 
 #### 1. Command Parsing Module
 **File**: `claude-code-acp/src/command-parser.ts` (new file)
-**Changes**: Add markdown command parser
+**Changes**: Add markdown command parser (TypeScript types will be auto-generated from Phase 1)
 
 ```typescript
 import * as fs from 'fs';
@@ -579,133 +788,199 @@ export class CommandParser {
 }
 ```
 
-#### 2. ACP Agent Method Implementation
-**File**: `claude-code-acp/src/acp-agent.ts`
-**Changes**: Add new RPC method handlers
+#### 2. Regenerate TypeScript Types
+**Prerequisites**: After completing Phase 1 Rust protocol extension
+**Commands**: Generate TypeScript types from updated Rust definitions
 
-```typescript
-// Add import
-import { CommandParser, CommandInfo } from './command-parser';
+```bash
+# From agent-client-protocol repository root:
+cd /Users/nathan/src/agent-client-protocol
+npm run generate
+```
 
-// Add to ClaudeAcpAgent class around line 50
-private commandParser?: CommandParser;
+This will automatically create TypeScript types for:
+- `ListCommandsRequest`
+- `ListCommandsResponse` 
+- `RunCommandRequest`
+- `CommandInfo`
+- Updated `PromptCapabilities` with `supports_custom_commands`
 
-// Modify constructor around line 100
-constructor(options: ClaudeAcpAgentOptions) {
-  // ... existing initialization
-  
-  // Initialize command parser if .claude/commands exists
-  if (options.cwd) {
-    this.commandParser = new CommandParser(options.cwd);
-  }
-}
+#### 3. ACP Agent Method Implementation
+**File**: `claude-code-acp/src/acp-agent.ts`
+**Changes**: Add new RPC method handlers following existing session management patterns
 
-// Add capability declaration in initialize() around line 150
-async initialize(request: InitializeRequest): Promise<InitializeResponse> {
-  return {
-    protocol_version: VERSION,
-    agent_capabilities: {
-      prompt_capabilities: {
-        image: true,
-        audio: false,
-        embedded_context: true,
-        supports_custom_commands: !!this.commandParser, // Enable if commands exist
-      },
-    },
-    auth_methods: ['claude-code'],
-  };
-}
+**Current Architecture Analysis**: The `ClaudeAcpAgent` at line 51 implements the ACP `Agent` interface with UUID-based session management. Sessions use Claude SDK `Query` objects with MCP proxy integration. The `prompt()` method at line 140 shows the pattern for query execution and result streaming.
 
-// Add new RPC method handlers around line 400
-async listCommands(request: ListCommandsRequest): Promise<ListCommandsResponse> {
-  if (!this.commandParser) {
-    return { commands: [] };
+```typescript
+// Step 1: Add import for command parser and auto-generated ACP types
+import { CommandParser, CommandInfo } from './command-parser';
+import type { 
+  ListCommandsRequest, 
+  ListCommandsResponse, 
+  RunCommandRequest 
+} from '@zed-industries/agent-client-protocol';
+
+// Step 2: Extend ClaudeAcpAgent class (add to class definition around line 51)
+export class ClaudeAcpAgent implements Agent {
+  private sessions: Map<string, Session> = new Map();
+  private client: Client;
+  private commandParser?: CommandParser;  // ADD THIS
+
+  // Step 3: Modify constructor to initialize command parser (around line 60)
+  constructor(
+    client: Client,
+    options: { cwd?: string } = {}
+  ) {
+    this.client = client;
+    
+    // Initialize command parser if .claude/commands directory exists
+    if (options.cwd && fs.existsSync(path.join(options.cwd, '.claude', 'commands'))) {
+      this.commandParser = new CommandParser(options.cwd);
+    }
   }
 
-  try {
-    const commands = await this.commandParser.listCommands();
+  // Step 4: Update initialize() method to advertise capability (around line 68)
+  async initialize(request: InitializeRequest): Promise<InitializeResponse> {
     return {
-      commands: commands.map(cmd => ({
-        name: cmd.name,
-        description: cmd.description,
-        requires_argument: cmd.requires_argument,
-      }))
+      protocol_version: VERSION,
+      agent_capabilities: {
+        prompt_capabilities: {
+          image: true,
+          audio: false,
+          embedded_context: true,
+          supports_custom_commands: !!this.commandParser, // Advertise support
+        },
+      },
+      auth_methods: [/* existing auth methods */],
     };
-  } catch (error) {
-    console.error('Failed to list commands:', error);
-    return { commands: [] };
   }
-}
 
-async runCommand(request: RunCommandRequest): Promise<void> {
-  if (!this.commandParser) {
-    throw new Error('Commands not supported');
-  }
-
-  const command = await this.commandParser.getCommand(request.command);
-  if (!command) {
-    throw new Error(`Command not found: ${request.command}`);
-  }
+  // Step 5: Implement listCommands following existing async patterns (after line 218)
+  async listCommands(request: ListCommandsRequest): Promise<ListCommandsResponse> {
+    if (!this.commandParser) {
+      return { commands: [] };
+    }
 
-  // Execute command by sending its content as a system prompt to Claude SDK
-  const session = this.sessions.get(request.session_id);
-  if (!session) {
-    throw new Error('Session not found');
+    try {
+      const commands = await this.commandParser.listCommands();
+      return {
+        commands: commands.map(cmd => ({
+          name: cmd.name,
+          description: cmd.description,
+          requires_argument: cmd.requires_argument,
+        }))
+      };
+    } catch (error) {
+      console.error('Failed to list commands:', error);
+      return { commands: [] };
+    }
   }
 
-  try {
-    let systemPrompt = command.content;
-    
-    // If command requires arguments and args provided, append them
-    if (command.requires_argument && request.args) {
-      systemPrompt += `\n\nArguments: ${request.args}`;
+  // Step 6: Implement runCommand integrating with existing session flow
+  async runCommand(request: RunCommandRequest): Promise<void> {
+    if (!this.commandParser) {
+      throw new Error('Commands not supported');
     }
 
-    // Create new query with command content as system prompt
-    const query = query({
-      prompt: systemPrompt,
-      options: {
-        cwd: session.cwd,
-        mcpServers: session.mcpServers,
-        allowedTools: session.allowedTools,
-        disallowedTools: session.disallowedTools,
-      },
-    });
+    const command = await this.commandParser.getCommand(request.command);
+    if (!command) {
+      throw new Error(`Command not found: ${request.command}`);
+    }
 
-    // Stream results back to session
-    for await (const chunk of query) {
-      // Convert query response to session update format
-      const update = this.convertQueryChunkToSessionUpdate(chunk);
-      await this.sendSessionUpdate(request.session_id, update);
+    const session = this.sessions.get(request.session_id);
+    if (!session) {
+      throw new Error('Session not found');
     }
 
-  } catch (error) {
-    console.error('Command execution failed:', error);
-    // Send error as session update
-    await this.sendSessionUpdate(request.session_id, {
-      type: 'agent_message_chunk',
-      content: {
-        type: 'text',
-        text: `Error executing command: ${error.message}`,
-      },
-    });
+    try {
+      // Build prompt from command content following existing patterns
+      let commandPrompt = command.content;
+      
+      if (command.requires_argument && request.args) {
+        commandPrompt += `\n\nArguments: ${request.args}`;
+      }
+
+      // Execute via existing session input stream (recommended approach)
+      // This integrates with existing prompt() flow and MCP proxy
+      session.input.push({
+        role: 'user',
+        content: commandPrompt
+      });
+
+      // Results will be streamed back via existing query execution loop
+      // at line 150 in prompt() method, no additional streaming needed
+
+    } catch (error) {
+      console.error('Command execution failed:', error);
+      // Send error via existing session update mechanism
+      await this.client.sessionUpdate({
+        session_id: request.session_id,
+        type: 'agent_message_chunk',
+        content: {
+          type: 'text',
+          text: `Error executing command: ${error.message}`,
+        },
+      });
+    }
   }
 }
 ```
 
+**Integration Notes**:
+- **Auto-Generated Types**: All ACP protocol types are automatically generated from Rust definitions
+- **Session Reuse**: Uses existing session's input stream and MCP configuration
+- **Result Streaming**: Leverages existing `prompt()` method's streaming loop at line 150
+- **Error Handling**: Uses established session update patterns from line 191
+- **Tool Access**: Commands inherit session's MCP server and tool configurations
+
 ### Success Criteria:
 
 #### Automated Verification:
-- [ ] TypeScript compilation passes: `npm run typecheck` (in claude-code-acp)
-- [ ] ESLint passes: `npm run lint` (in claude-code-acp)
-- [ ] Command parser unit tests pass: `npm test command-parser` 
+- [ ] **Prerequisites completed**: Phase 1 Rust protocol extension must be completed first
+- [ ] **TypeScript types generated**: `cd /Users/nathan/src/agent-client-protocol && npm run generate`
+- [ ] **Types available**: Verify new types exist in `agent-client-protocol/typescript/schema.ts`
+- [ ] TypeScript compilation passes: `cd /Users/nathan/src/claude-code-acp && npm run typecheck`
+- [ ] ESLint passes: `cd /Users/nathan/src/claude-code-acp && npm run lint`
+- [ ] Agent compiles: `cd /Users/nathan/src/claude-code-acp && npm run build`
+- [ ] Command parser unit tests pass: `cd /Users/nathan/src/claude-code-acp && npm test -- --testNamePattern="command-parser"`
 
 #### Manual Verification:
-- [ ] `.claude/commands/*.md` files are correctly parsed for metadata
-- [ ] `list_commands()` returns available commands with descriptions
-- [ ] `run_command()` executes command content via Claude SDK
-- [ ] Command results stream back as session updates
-- [ ] Error handling works for missing commands or execution failures
+- [ ] **Code Generation Pipeline**:
+  - [ ] Rust protocol changes trigger successful schema generation: `cargo run --bin generate`
+  - [ ] JSON schema contains new method definitions: `grep -A5 -B5 "session/list_commands\|session/run_command" /Users/nathan/src/agent-client-protocol/schema/schema.json`
+  - [ ] TypeScript types generated correctly: Check for `ListCommandsRequest`, `RunCommandRequest` types in schema.ts
+- [ ] CommandParser class implemented (`claude-code-acp/src/command-parser.ts`):
+  - `listCommands()` method reads `.claude/commands/*.md` files
+  - `parseCommandFile()` extracts H1 titles and descriptions correctly
+  - `getCommand()` returns full command content for execution
+  - Proper error handling for missing directories and files
+  - Command caching works correctly
+- [ ] ClaudeAcpAgent class extended (`claude-code-acp/src/acp-agent.ts`):
+  - Constructor initializes `commandParser` when `.claude/commands` exists
+  - `initialize()` method advertises `supports_custom_commands` capability correctly
+  - `listCommands()` method implemented and returns properly formatted response
+  - `runCommand()` method integrated with existing session management
+  - Command execution uses existing session input stream 
+  - Error handling streams errors back via session updates
+- [ ] **Type Integration**:
+  - [ ] Auto-generated types imported correctly from `@zed-industries/agent-client-protocol`
+  - [ ] TypeScript compiler recognizes new protocol method signatures
+  - [ ] No type errors when implementing new agent methods
+- [ ] Integration Testing:
+  - [ ] Agent advertises `supports_custom_commands = true` when `.claude/commands` directory exists
+  - [ ] Agent advertises `supports_custom_commands = false` when directory doesn't exist
+  - [ ] `list_commands()` RPC returns commands from `.claude/commands/*.md` files  
+  - [ ] Commands include correct name, description, requires_argument fields
+  - [ ] `run_command()` executes command content via Claude SDK integration
+  - [ ] Command results stream back as session updates to ACP client
+  - [ ] Commands have access to session's MCP servers and tool permissions
+  - [ ] Error handling works for missing commands, directories, execution failures
+  - [ ] Command arguments are properly appended when provided
+- [ ] End-to-End Testing:
+  - [ ] Create test `.claude/commands/test.md` file with sample command
+  - [ ] Verify command appears in Zed's "/" completion menu
+  - [ ] Verify command executes and streams results to agent panel
+  - [ ] Verify commands work with existing MCP proxy and tool permissions
 
 ---
 
@@ -739,8 +1014,26 @@ async runCommand(request: RunCommandRequest): Promise<void> {
 
 ## Migration Notes
 
+### User Experience
 No migration needed - this is a new feature that gracefully degrades for agents that don't support custom commands. Existing agent panel behavior is preserved.
 
+### Developer Coordination
+**Important**: This feature requires coordinated releases across multiple repositories:
+
+1. **ACP Protocol**: Must be released first with new slash command methods
+2. **Zed**: Can only merge after ACP release is available  
+3. **Agent Implementations**: Can adopt new capabilities independently
+
+### Version Compatibility
+- **Backward Compatible**: Old agents continue working without slash command menus
+- **Forward Compatible**: New Zed version works with old agents (feature simply disabled)
+- **Graceful Degradation**: UI adapts based on agent-advertised capabilities
+
+### Rollout Strategy
+1. **Phase 1 Release**: ACP protocol extension (no visible user changes)
+2. **Phase 2 Release**: Zed UI implementation (menu appears only with compatible agents)
+3. **Phase 3+ Rollout**: Agent implementations adopt new capabilities over time
+
 ## References
 
 - Original research: `thoughts/shared/research/2025-08-28_15-34-28_custom-slash-commands-acp.md`