mohamed-ashraf-elsaed/claude-agent-sdk-laravel
composer require mohamed-ashraf-elsaed/claude-agent-sdk-laravel
php artisan vendor:publish --provider="ClaudeAgentSdk\ClaudeAgentSdkServiceProvider" --tag="config"
.env:
ANTHROPIC_API_KEY=your_claude_api_key_here
CLAUDE_CODE_CLI_PATH=/path/to/claude-code-cli # Defaults to global npm install
php artisan claude:check
use ClaudeAgentSdk\Agent;
$agent = new Agent();
$response = $agent->run('Write a Laravel controller for a user resource with CRUD operations.');
dump($response->content); // Outputs the generated code
config/claude-agent-sdk.php (adjust sandbox paths, API limits, etc.)app/Providers/ClaudeAgentSdkServiceProvider.php (register bindings)app/Console/Commands/ (extend with custom agent logic)Wrap external tools (e.g., database queries, HTTP calls) as structured tools for the agent:
use ClaudeAgentSdk\Tool;
$tool = new Tool('db_query', 'Execute a raw SQL query', [
'query' => 'string',
'params' => 'array'
]);
$agent->addTool($tool);
Use the agent to modify files within a restricted directory:
$agent = new Agent(['sandbox_path' => storage_path('app/agents')]);
$agent->run('Create a new file named `example.txt` with "Hello, Claude!"');
Delegate tasks to specialized subagents:
$subagent = new Agent(['role' => 'code_reviewer']);
$response = $subagent->run('Review this PR: ' . file_get_contents('pr_description.md'));
Attach hooks to transform or validate agent outputs:
$agent->on('response', function ($response) {
if (str_contains($response->content, 'ERROR')) {
throw new \RuntimeException('Agent failed');
}
});
Force the agent to return JSON/structured data:
$response = $agent->run('Return a JSON object with keys "name" and "version" for this package.');
$structured = json_decode($response->content, true);
Bind the agent as a singleton for global access:
$this->app->singleton(Agent::class, function ($app) {
return new Agent(config('claude-agent-sdk.defaults'));
});
Wrap agent execution in a job:
use ClaudeAgentSdk\Jobs\RunAgentJob;
RunAgentJob::dispatch('Analyze this codebase for security risks')
->onQueue('agents');
Expose agent endpoints securely:
Route::middleware('auth:sanctum')->post('/agent/run', function (Request $request) {
$agent = app(Agent::class);
return response()->json($agent->run($request->input('prompt')));
});
Use the AgentTestCase trait for isolated tests:
use ClaudeAgentSdk\Testing\AgentTestCase;
class UserAgentTest extends AgentTestCase {
public function test_user_creation() {
$response = $this->runAgent('Create a user with email test@example.com');
$this->assertStringContainsString('User created', $response->content);
}
}
Command not found if claude-code isn’t in $PATH.CLAUDE_CODE_CLI_PATH in .env or config:
CLAUDE_CODE_CLI_PATH=/usr/local/bin/claude-code
chmod -R 775 storage/
429 Too Many Requests errors if hitting Anthropic’s limits.config/claude-agent-sdk.php:
'api' => [
'max_retries' => 3,
'retry_delay' => 1000, // ms
],
$tool->validateSchema(); // Throws on errors
memory_limit..env:
MEMORY_LIMIT=4G
config(['claude-agent-sdk.debug' => true]);
Logs appear in storage/logs/claude-agent-sdk.log.
Use the --verbose flag in config:
'cli' => [
'verbose' => true,
],
| Error | Likely Cause | Solution |
|---|---|---|
Invalid API key |
Wrong ANTHROPIC_API_KEY |
Verify .env and regenerate key |
Sandbox not writable |
File permissions | chmod -R 775 storage/app/agents |
Tool not found |
Incorrect tool name in prompt | Use exact tool names (case-sensitive) |
JSON decode error |
Malformed structured output | Add ->on('response', fn($r) => $r->validateJson()) |
Extend ClaudeAgentSdk\Agent for domain-specific logic:
class CodeReviewAgent extends Agent {
public function __construct() {
parent::__construct([
'role' => 'Senior Code Reviewer',
'tools' => [
new Tool('git_diff', 'Show changes in a PR'),
new Tool('phpstan_analyze', 'Run static analysis'),
],
]);
}
}
Load tools from a database or config file:
$tools = config('agent.tools');
foreach ($tools as $toolConfig) {
$agent->addTool(new Tool(...$toolConfig));
}
Trigger agents via HTTP webhooks:
Route::post('/webhook/agent', function (Request $request) {
$agent = app(Agent::class);
return $agent->run($request->input('prompt'))
->then(fn($r) => response()->json($r->content));
});
Coordinate multiple agents in a workflow:
$researcher = new Agent(['role' => 'Researcher']);
$writer = new Agent(['role' => 'Technical Writer']);
$topic = $researcher->run('Research Laravel 13 features');
$document = $writer->run("Write a blog post about: {$topic->content}");
Enforce strict output formats:
$agent->on('response', function ($response) {
$data = json_decode($response->content, true);
if (!isset($data['success'], $data['result'])) {
throw new \InvalidArgumentException('Invalid response format');
}
});
How can I help you explore Laravel packages today?