helgesverre / claude-code-sdk
PHP SDK for Claude Code
Requires
- php: >=8.3
- ext-json: *
- symfony/process: ^7.0
Requires (Dev)
- laravel/pint: ^1.0
- orchestra/testbench: ^8.0|^9.0
- pestphp/pest: ^2.0
- pestphp/pest-plugin-arch: ^2.0
- pestphp/pest-plugin-type-coverage: ^2.0
- phpstan/phpstan: ^1.10
- spatie/ray: ^1.42
This package is auto-updated.
Last update: 2025-07-20 15:00:21 UTC
README
PHP SDK for Claude Code, This is a AI-generated port of the official Python SDK from Anthropic.
This SDK provides a type-safe, async-friendly interface for interacting with Claude Code from PHP applications.
Requirements
- PHP 8.3 or higher
- Claude Code CLI installed globally
- Node.js (for Claude Code CLI)
Installation
Install the SDK via Composer:
composer require helgesverre/claude-code-sdk
Make sure Claude Code CLI is installed:
npm install -g @anthropic-ai/claude-code
Quick Start
Basic Usage
<?php use HelgeSverre\ClaudeCode\ClaudeCode; use HelgeSverre\ClaudeCode\Types\Messages\AssistantMessage; use HelgeSverre\ClaudeCode\Types\Messages\SystemMessage; use HelgeSverre\ClaudeCode\Types\Messages\ResultMessage; use HelgeSverre\ClaudeCode\Types\ContentBlocks\TextBlock; // Send a query to Claude $messages = ClaudeCode::query("What files are in the current directory?"); // Process the streaming response foreach ($messages as $message) { match (true) { $message instanceof SystemMessage => echo "[SYSTEM] {$message->subtype}\n", $message instanceof AssistantMessage => array_map(function ($block) { if ($block instanceof TextBlock) { echo "[CLAUDE] {$block->text}\n"; } }, $message->content), $message instanceof ResultMessage => echo "[DONE] Cost: \${$message->totalCostUsd} | Time: {$message->durationMs}ms\n", default => null }; }
With Options
use HelgeSverre\ClaudeCode\ClaudeCode; use HelgeSverre\ClaudeCode\Types\Config\ClaudeCodeOptions; use HelgeSverre\ClaudeCode\Types\Enums\PermissionMode; $options = new ClaudeCodeOptions( systemPrompt: "You are a helpful coding assistant", allowedTools: ['Read', 'Write', 'Edit'], permissionMode: PermissionMode::ACCEPT_EDITS, maxTurns: 5, ); $messages = ClaudeCode::query("Help me refactor this code", $options);
Laravel Integration
Configuration
Publish the configuration file:
php artisan vendor:publish --tag=claude-code-config
Configure your settings in config/claude-code.php
or use environment variables:
CLAUDE_CODE_SYSTEM_PROMPT="You are a Laravel expert" CLAUDE_CODE_ALLOWED_TOOLS=Read,Write,Edit CLAUDE_CODE_PERMISSION_MODE=acceptEdits CLAUDE_CODE_MODEL=claude-3-sonnet
Using the Facade
use HelgeSverre\ClaudeCode\Laravel\Facades\ClaudeCode; // Simple query $messages = ClaudeCode::query("Create a new Laravel controller"); // With custom options $options = ClaudeCode::options() ->systemPrompt("You are a Laravel expert") ->allowedTools(['Read', 'Write', 'Edit']) ->maxTurns(10) ->build(); $messages = ClaudeCode::query("Help me build a REST API", $options);
Dependency Injection
use HelgeSverre\ClaudeCode\Laravel\ClaudeCodeManager; class MyService { public function __construct( private ClaudeCodeManager $claude ) {} public function generateCode(string $prompt): void { $messages = $this->claude->query($prompt); foreach ($messages as $message) { // Process messages... } } }
Configuration Options
ClaudeCodeOptions
All configuration options available:
$options = new ClaudeCodeOptions( // System prompt to set context systemPrompt: "You are a helpful assistant", // Additional system prompt to append appendSystemPrompt: "Always be concise", // Tools Claude can use allowedTools: ['Read', 'Write', 'Edit', 'Bash'], // Tools Claude cannot use disallowedTools: ['Delete'], // Permission handling mode permissionMode: PermissionMode::ACCEPT_EDITS, // Custom permission prompt tool permissionPromptToolName: "MyCustomPrompt", // Continue existing conversation continueConversation: true, // Resume from session ID resume: "session-abc123", // Maximum conversation turns maxTurns: 10, // Claude model to use model: "claude-3-sonnet", // Working directory cwd: "/path/to/project", // MCP server configurations mcpServers: [ 'my-server' => new StdioServerConfig('node', ['server.js']), ], );
Message Types
The SDK provides strongly-typed message classes with proper DTOs:
SystemMessage
System events with typed data for initialization:
use HelgeSverre\ClaudeCode\Types\Messages\SystemMessage; use HelgeSverre\ClaudeCode\Types\Config\SystemInitData; if ($message instanceof SystemMessage && $message->subtype === 'init') { // Strongly typed init data $initData = $message->data; // SystemInitData instance echo "Session ID: {$initData->sessionId}\n"; echo "Model: {$initData->model}\n"; echo "Tools: " . implode(', ', $initData->tools) . "\n"; echo "Working Directory: {$initData->cwd}\n"; }
AssistantMessage
Contains content blocks with Claude's responses:
use HelgeSverre\ClaudeCode\Types\Messages\AssistantMessage; use HelgeSverre\ClaudeCode\Types\ContentBlocks\{TextBlock, ToolUseBlock, ToolResultBlock}; foreach ($message->content as $block) { match (true) { $block instanceof TextBlock => echo "Text: {$block->text}\n", $block instanceof ToolUseBlock => echo "Tool: {$block->name} with " . json_encode($block->input) . "\n", $block instanceof ToolResultBlock => echo "Result: {$block->content} (Error: " . ($block->isError ? 'Yes' : 'No') . ")\n", }; }
UserMessage
User input and tool feedback:
use HelgeSverre\ClaudeCode\Types\Messages\UserMessage; use HelgeSverre\ClaudeCode\Types\ContentBlocks\ToolResultBlock; // Simple text message $message = new UserMessage("Hello Claude!"); // Tool feedback (from Claude's perspective) if (is_array($message->content)) { foreach ($message->content as $block) { if ($block instanceof ToolResultBlock) { echo "Tool feedback: {$block->content}\n"; echo "Tool ID: {$block->toolUseId}\n"; echo "Is Error: " . ($block->isError ? 'Yes' : 'No') . "\n"; } } }
ResultMessage
Session completion with usage metrics:
use HelgeSverre\ClaudeCode\Types\Messages\ResultMessage; echo "Total Cost: \${$message->totalCostUsd}\n"; echo "Duration: {$message->durationMs}ms\n"; echo "API Time: {$message->durationApiMs}ms\n"; echo "Turns: {$message->numTurns}\n"; echo "Session ID: {$message->sessionId}\n"; echo "Input Tokens: {$message->usage['input_tokens']}\n"; echo "Output Tokens: {$message->usage['output_tokens']}\n";
MCP Server Configuration
Configure Model Context Protocol servers:
use HelgeSverre\ClaudeCode\Types\Config\StdioServerConfig; use HelgeSverre\ClaudeCode\Types\Config\SSEServerConfig; use HelgeSverre\ClaudeCode\Types\Config\HTTPServerConfig; $options = new ClaudeCodeOptions( mcpServers: [ // Stdio server 'filesystem' => new StdioServerConfig( command: 'node', args: ['mcp-server-filesystem.js'], env: ['NODE_ENV' => 'production'] ), // SSE server 'weather' => new SSEServerConfig( url: 'https://api.example.com/mcp/sse', headers: ['Authorization' => 'Bearer token'] ), // HTTP server 'database' => new HTTPServerConfig( url: 'https://api.example.com/mcp', headers: ['API-Key' => 'secret'] ), ] );
Error Handling
The SDK provides specific exception types:
use HelgeSverre\ClaudeCode\ClaudeCode; use HelgeSverre\ClaudeCode\Exceptions\CLINotFoundException; use HelgeSverre\ClaudeCode\Exceptions\CLIConnectionException; use HelgeSverre\ClaudeCode\Exceptions\ProcessException; try { $messages = ClaudeCode::query("Help me code"); } catch (CLINotFoundException $e) { echo "Claude Code CLI not found. Install with: npm install -g @anthropic-ai/claude-code"; } catch (CLIConnectionException $e) { echo "Failed to connect to Claude Code: {$e->getMessage()}"; } catch (ProcessException $e) { echo "Process failed with exit code {$e->exitCode}: {$e->stderr}"; }
Testing
Run the test suite:
composer test
Run tests with coverage:
composer test:coverage
Run static analysis:
composer analyse
Format code:
composer format
Check code formatting:
composer format:check
Architecture
The SDK follows a clean architecture with organized namespaces:
- Types/
- Config/ - Configuration DTOs (ClaudeCodeOptions, SystemInitData)
- Messages/ - Message types (System, Assistant, User, Result)
- ContentBlocks/ - Content blocks (Text, ToolUse, ToolResult)
- Enums/ - Enumerations (PermissionMode)
- Internal/ - Core implementation (MessageParser, ProcessBridge)
- Laravel/ - Laravel integration (ServiceProvider, Facade, Manager)
- Exceptions/ - Custom exceptions (CLINotFoundException, ProcessException)
Contributing
Contributions are welcome! Please ensure:
- All tests pass
- Code follows Laravel coding standards (using Pint)
- Static analysis passes (PHPStan level 5)
- New features include tests
License
This SDK is open-source software licensed under the MIT license.