> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/agentclientprotocol/typescript-sdk/llms.txt
> Use this file to discover all available pages before exploring further.

# Production Examples

> Real-world implementations of ACP agents and clients in production environments

## Overview

While the [simple examples](/examples/simple-agent) demonstrate the core concepts, production implementations showcase how ACP is used in real-world applications with additional patterns for error handling, state management, and integration with AI models.

## Featured Production Implementation

### Gemini CLI Agent

<Card title="Google Gemini CLI" icon="google" href="https://github.com/google-gemini/gemini-cli">
  A complete, production-ready ACP agent implementation using Google's Gemini AI models
</Card>

The [Gemini CLI Agent](https://github.com/google-gemini/gemini-cli/blob/main/packages/cli/src/zed-integration/zedIntegration.ts) is an excellent reference for building production-grade agents. It demonstrates:

<CardGroup cols={2}>
  <Card title="LLM Integration" icon="brain">
    Complete integration with Google's Gemini API including streaming responses and function calling
  </Card>

  <Card title="Robust Error Handling" icon="shield-exclamation">
    Comprehensive error handling, retry logic, and graceful degradation
  </Card>

  <Card title="Advanced Tool Management" icon="toolbox">
    Dynamic tool registration, execution, and result handling
  </Card>

  <Card title="Production Patterns" icon="diagram-project">
    Real-world patterns for state management, logging, and debugging
  </Card>
</CardGroup>

## Production Architecture Patterns

### Agent Architecture

<Steps>
  <Step title="Modular Design">
    Separate concerns into distinct components:

    ```typescript theme={null}
    class ProductionAgent {
      private llmClient: LLMClient;           // AI model integration
      private toolRegistry: ToolRegistry;      // Available tools
      private sessionManager: SessionManager;  // Session state
      private permissionHandler: PermissionHandler; // Permission logic
      
      constructor(connection: AgentSideConnection) {
        // Initialize components
      }
    }
    ```
  </Step>

  <Step title="State Management">
    Maintain comprehensive session state:

    ```typescript theme={null}
    interface ProductionSession {
      id: string;
      conversationHistory: Message[];
      pendingToolCalls: Map<string, ToolCall>;
      activeAbortController: AbortController | null;
      context: {
        cwd: string;
        environment: Record<string, string>;
        capabilities: ClientCapabilities;
      };
    }
    ```
  </Step>

  <Step title="Error Boundaries">
    Implement robust error handling at each layer:

    ```typescript theme={null}
    async prompt(params: PromptRequest): Promise<PromptResponse> {
      try {
        return await this.executePrompt(params);
      } catch (error) {
        if (error instanceof CancellationError) {
          return { stopReason: "cancelled" };
        }
        if (error instanceof PermissionDeniedError) {
          return { stopReason: "permission_denied" };
        }
        // Log and report unexpected errors
        this.logger.error("Prompt execution failed", error);
        throw error;
      }
    }
    ```
  </Step>

  <Step title="Streaming Integration">
    Stream LLM responses in real-time:

    ```typescript theme={null}
    for await (const chunk of llmClient.stream(prompt)) {
      if (abortSignal.aborted) break;
      
      await this.connection.sessionUpdate({
        sessionId,
        update: {
          sessionUpdate: "agent_message_chunk",
          content: { type: "text", text: chunk.text },
        },
      });
    }
    ```
  </Step>
</Steps>

### Client Architecture

<Steps>
  <Step title="Agent Lifecycle Management">
    Manage agent processes robustly:

    ```typescript theme={null}
    class AgentManager {
      private agentProcess: ChildProcess | null = null;
      private connection: ClientSideConnection | null = null;
      
      async start(): Promise<void> {
        // Spawn agent with proper error handling
        this.agentProcess = spawn(agentCommand, agentArgs, {
          stdio: ['pipe', 'pipe', 'pipe'],
        });
        
        // Handle process events
        this.agentProcess.on('error', this.handleProcessError);
        this.agentProcess.on('exit', this.handleProcessExit);
        
        // Establish connection
        await this.initializeConnection();
      }
      
      async stop(): Promise<void> {
        // Graceful shutdown
        await this.connection?.close();
        this.agentProcess?.kill('SIGTERM');
      }
    }
    ```
  </Step>

  <Step title="Permission Policies">
    Implement sophisticated permission handling:

    ```typescript theme={null}
    class PermissionPolicy {
      async evaluate(
        toolCall: ToolCall,
      ): Promise<'auto_approve' | 'request_user' | 'auto_deny'> {
        // Auto-approve safe operations
        if (toolCall.kind === 'read' && this.isInWorkspace(toolCall.path)) {
          return 'auto_approve';
        }
        
        // Auto-deny dangerous operations
        if (this.isDangerousPath(toolCall.path)) {
          return 'auto_deny';
        }
        
        // Ask user for everything else
        return 'request_user';
      }
    }
    ```
  </Step>

  <Step title="UI Integration">
    Connect ACP to your application's UI:

    ```typescript theme={null}
    class UIBridge {
      async sessionUpdate(update: SessionUpdate): Promise<void> {
        switch (update.sessionUpdate) {
          case 'agent_message_chunk':
            this.chatView.appendMessage(update.content.text);
            break;
          case 'tool_call':
            this.toolPanel.showToolExecution(update);
            break;
          case 'agent_thought_chunk':
            this.reasoningPanel.appendThought(update.content.text);
            break;
        }
      }
    }
    ```
  </Step>
</Steps>

## Best Practices from Production

### Logging and Observability

<CodeGroup>
  ```typescript Structured Logging theme={null}
  import { Logger } from 'winston';

  class ObservableAgent implements Agent {
    private logger: Logger;
    
    async prompt(params: PromptRequest): Promise<PromptResponse> {
      this.logger.info('Prompt received', {
        sessionId: params.sessionId,
        promptLength: params.prompt.length,
      });
      
      const startTime = Date.now();
      try {
        const result = await this.executePrompt(params);
        
        this.logger.info('Prompt completed', {
          sessionId: params.sessionId,
          duration: Date.now() - startTime,
          stopReason: result.stopReason,
        });
        
        return result;
      } catch (error) {
        this.logger.error('Prompt failed', {
          sessionId: params.sessionId,
          duration: Date.now() - startTime,
          error: error.message,
        });
        throw error;
      }
    }
  }
  ```

  ```typescript Protocol Tracing theme={null}
  class TracedConnection extends AgentSideConnection {
    async send(message: Message): Promise<void> {
      this.tracer.logOutbound(message);
      await super.send(message);
    }
    
    protected handleIncoming(message: Message): void {
      this.tracer.logInbound(message);
      super.handleIncoming(message);
    }
  }
  ```
</CodeGroup>

### Performance Optimization

<CodeGroup>
  ```typescript Batching Updates theme={null}
  class BatchedSessionUpdates {
    private pending: SessionUpdate[] = [];
    private flushTimer: NodeJS.Timeout | null = null;
    
    queue(update: SessionUpdate): void {
      this.pending.push(update);
      
      if (!this.flushTimer) {
        this.flushTimer = setTimeout(() => this.flush(), 16); // ~60fps
      }
    }
    
    private async flush(): Promise<void> {
      const updates = this.pending.splice(0);
      this.flushTimer = null;
      
      // Send batched updates
      for (const update of updates) {
        await this.connection.sessionUpdate(update);
      }
    }
  }
  ```

  ```typescript Parallel Tool Execution theme={null}
  async executeConcurrentTools(
    toolCalls: ToolCall[],
  ): Promise<ToolResult[]> {
    // Execute independent tools in parallel
    const results = await Promise.allSettled(
      toolCalls.map(async (toolCall) => {
        await this.notifyToolStart(toolCall);
        try {
          const result = await this.executeTool(toolCall);
          await this.notifyToolComplete(toolCall, result);
          return result;
        } catch (error) {
          await this.notifyToolError(toolCall, error);
          throw error;
        }
      })
    );
    
    return results.map((r) => 
      r.status === 'fulfilled' ? r.value : null
    );
  }
  ```
</CodeGroup>

### Security Considerations

<Note>
  Production implementations must carefully consider security:

  * **Path validation**: Always validate and sanitize file paths
  * **Permission boundaries**: Enforce strict permission policies
  * **Resource limits**: Limit agent resource consumption (CPU, memory, file I/O)
  * **Audit logging**: Log all sensitive operations
  * **Input sanitization**: Validate all user inputs before passing to agents
</Note>

```typescript Path Security theme={null}
class SecurePathValidator {
  constructor(private workspaceRoot: string) {}
  
  validate(requestedPath: string): string {
    // Resolve to absolute path
    const resolved = path.resolve(this.workspaceRoot, requestedPath);
    
    // Ensure it's within workspace
    if (!resolved.startsWith(this.workspaceRoot)) {
      throw new SecurityError('Path outside workspace');
    }
    
    // Check for sensitive directories
    const sensitive = ['.git', '.env', 'node_modules/.env'];
    if (sensitive.some(dir => resolved.includes(dir))) {
      throw new SecurityError('Access to sensitive path denied');
    }
    
    return resolved;
  }
}
```

### Testing Strategies

<CodeGroup>
  ```typescript Mock Client theme={null}
  class MockClient implements Client {
    public receivedUpdates: SessionUpdate[] = [];
    public permissionResponses: Map<string, PermissionOutcome> = new Map();
    
    async sessionUpdate(params: SessionNotification): Promise<void> {
      this.receivedUpdates.push(params.update);
    }
    
    async requestPermission(
      params: RequestPermissionRequest
    ): Promise<RequestPermissionResponse> {
      const outcome = this.permissionResponses.get(params.toolCall.toolCallId);
      if (!outcome) {
        throw new Error('Unexpected permission request');
      }
      return { outcome };
    }
  }

  // Use in tests
  const mockClient = new MockClient();
  mockClient.permissionResponses.set('call_1', {
    outcome: 'selected',
    optionId: 'allow',
  });
  ```

  ```typescript Integration Tests theme={null}
  import { describe, it, expect } from 'vitest';

  describe('Agent Integration', () => {
    it('handles complete prompt flow', async () => {
      const { agent, client } = await setupTestEnvironment();
      
      const sessionId = await createSession(agent);
      const promptPromise = agent.prompt({
        sessionId,
        prompt: [{ type: 'text', text: 'Test prompt' }],
      });
      
      // Verify updates were sent
      await waitFor(() => {
        expect(client.receivedUpdates).toHaveLength(3);
      });
      
      const result = await promptPromise;
      expect(result.stopReason).toBe('end_turn');
    });
  });
  ```
</CodeGroup>

## Common Integration Patterns

### MCP Server Integration

Integrate with Model Context Protocol servers:

```typescript theme={null}
const sessionResult = await connection.newSession({
  cwd: process.cwd(),
  mcpServers: [
    {
      name: 'filesystem',
      command: 'npx',
      args: ['-y', '@modelcontextprotocol/server-filesystem', workspaceRoot],
    },
    {
      name: 'github',
      command: 'npx',
      args: ['-y', '@modelcontextprotocol/server-github'],
      env: {
        GITHUB_TOKEN: process.env.GITHUB_TOKEN,
      },
    },
  ],
});
```

### Multi-Session Management

Handle multiple concurrent sessions:

```typescript theme={null}
class SessionManager {
  private sessions: Map<string, Session> = new Map();
  
  async create(params: NewSessionRequest): Promise<Session> {
    const session = new Session(params);
    this.sessions.set(session.id, session);
    return session;
  }
  
  get(sessionId: string): Session | null {
    return this.sessions.get(sessionId) ?? null;
  }
  
  async close(sessionId: string): Promise<void> {
    const session = this.sessions.get(sessionId);
    if (session) {
      await session.cleanup();
      this.sessions.delete(sessionId);
    }
  }
}
```

## Additional Resources

<CardGroup cols={2}>
  <Card title="Gemini CLI Source" icon="github" href="https://github.com/google-gemini/gemini-cli/blob/main/packages/cli/src/zed-integration/zedIntegration.ts">
    View the complete Gemini CLI Agent implementation
  </Card>

  <Card title="Protocol Specification" icon="book" href="/concepts/protocol-overview">
    Deep dive into the ACP protocol details
  </Card>

  <Card title="API Reference" icon="code" href="https://agentclientprotocol.github.io/typescript-sdk/">
    Complete TypeScript SDK documentation
  </Card>

  <Card title="Community Examples" icon="users" href="https://github.com/agentclientprotocol/typescript-sdk/discussions">
    Share and discover community implementations
  </Card>
</CardGroup>

## Contributing Your Examples

Built something with ACP? We'd love to feature it! Share your implementation:

1. Open a [GitHub Discussion](https://github.com/agentclientprotocol/typescript-sdk/discussions)
2. Include a link to your code
3. Describe what makes your implementation unique
4. Share any lessons learned

<Info>
  Outstanding community examples may be featured in the official documentation.
</Info>
