shipfastlabs/agent-detector
Lightweight PHP 8.2+ utility to detect if your app is running inside an AI agent or automated dev environment. Supports Claude, Cursor, Gemini, Codex, Replit, Devin, and more via env vars or file checks, with a simple API and helper function.
Installation:
composer require shipfastlabs/agent-detector
Ensure your project uses PHP 8.2+ (required by the package).
First Use Case: Add detection to a console command or middleware to block agent-driven operations:
use AgentDetector\AgentDetector;
// In a console command (e.g., app/Console/Commands/ExampleCommand.php)
protected function handle() {
$result = AgentDetector::detect();
if ($result->isAgent) {
$this->error("Agent detected: {$result->name}. Aborting.");
return;
}
// Proceed with command logic...
}
Where to Look First:
AgentDetector::detect(): Returns a result object with isAgent (bool) and name (string).detectAgent(): Standalone function for quick checks.CLAUDE_CODE, REPL_ID).Quick Test: Run a script with an agent env var to confirm detection:
AI_AGENT=test-agent php artisan your:command
Middleware for HTTP Routes: Restrict API endpoints or admin routes from agents:
// app/Http/Middleware/BlockAgents.php
public function handle(Request $request, Closure $next) {
if (AgentDetector::detect()->isAgent) {
abort(403, 'Agents not allowed.');
}
return $next($request);
}
Register in app/Http/Kernel.php:
protected $middleware = [
\App\Http\Middleware\BlockAgents::class,
];
Command Guards:
Prevent sensitive CLI operations (e.g., tinker, migrate) in agents:
// app/Console/Kernel.php
protected function commands() {
$this->load(__DIR__.'/Commands');
if (!AgentDetector::detect()->isAgent) {
$this->call('tinker'); // Only allow in non-agent contexts
}
}
Dynamic Configuration:
Adapt Laravel settings (e.g., APP_DEBUG, logging) based on agent context:
// In a service provider (e.g., AppServiceProvider)
public function boot() {
$agent = AgentDetector::detect();
if ($agent->isAgent) {
config(['app.debug' => false]);
Log::channel('agent')->info("Agent detected: {$agent->name}");
}
}
Custom Agent Support:
Set AI_AGENT env var for your CI/CD or internal tools:
export AI_AGENT=github-actions
php artisan your:command
Combine with Laravel’s Security Layers:
Use alongside APP_DEBUG, APP_ENV, or middleware like TrustProxies for defense in depth.
if (AgentDetector::detect()->isAgent && !app()->environment('local')) {
abort(403);
}
Queue Workers: Detect agents in job handlers to skip non-interactive tasks:
// app/Jobs/ProcessData.php
public function handle() {
if (AgentDetector::detect()->isAgent) {
$this->skipIfAgentLogic();
return;
}
// Normal job logic...
}
Event Listeners: Log agent-triggered events for audit trails:
// app/Listeners/LogAgentActivity.php
public function handle($event) {
$agent = AgentDetector::detect();
if ($agent->isAgent) {
Log::channel('security')->info(
"Agent {$agent->name} triggered {$event->class}"
);
}
}
Testing: Mock agent detection in PHPUnit:
use AgentDetector\AgentDetector;
use AgentDetector\KnownAgent;
beforeEach(function () {
$_ENV['CLAUDE_CODE'] = 'test';
});
it('detects Claude agent', function () {
$result = AgentDetector::detect();
expect($result->knownAgent())->toBe(KnownAgent::Claude);
});
Env Var Reliability:
APP_ENV or APP_DEBUG as fallbacks.
$isAgent = AgentDetector::detect()->isAgent || app()->environment('ci');
$knownAgents = [KnownAgent::Claude, KnownAgent::Cursor];
$isKnownAgent = in_array($result->knownAgent(), $knownAgents, true);
Queue/Event Contexts:
app() container:
// Store detection result in cache or session for later use
cache()->put('agent_detected', $result, now()->addMinutes(5));
Custom Agent Quirks:
AI_AGENT env var is case-sensitive and may conflict with other tools.
Tip: Use a unique prefix (e.g., MYAPP_AI_AGENT=github-actions).Laravel-Specific Edge Cases:
.env may not reflect in CLI unless loaded via php artisan (not raw PHP).
Fix: Use env() helper or getenv() directly:
if (getenv('CLAUDE_CODE')) { ... }
APP_ENV is fully resolved.
Tip: Cache the result early:
if (!app()->bound('agent_detected')) {
app()->singleton('agent_detected', AgentDetector::detect());
}
Performance:
AgentDetector::detect() are lightweight but may hit env vars multiple times.
Optimization: Cache the result in a service provider:
// app/Providers/AppServiceProvider.php
public function register() {
$this->app->singleton('agent', function () {
return AgentDetector::detect();
});
}
Then inject via constructor:
public function __construct(private readonly AgentDetectorResult $agent) {}
Verify Env Vars: Dump all env vars to debug:
dd(getenv());
Or check for specific agents:
dd([
'Claude' => getenv('CLAUDE_CODE'),
'Cursor' => getenv('CURSOR_AGENT'),
]);
Test in Target Environments:
GITHUB_ACTIONS=true php artisan your:command
Log Detection Results: Add logging to audit agent activity:
Log::debug('Agent detection', [
'is_agent' => $result->isAgent,
'name' => $result->name,
'env_vars' => getenv(),
]);
Add New Agents: Extend the package by contributing to the GitHub repo or fork it:
// Example: Add support for a new agent "MyAgent"
if (getenv('MY_AGENT_TOKEN')) {
return new AgentDetectorResult(true, 'MyAgent');
}
Custom Detection Logic: Override the detector in a service provider:
$this->app->singleton(AgentDetector::class, function () {
$default = new AgentDetector();
return new class($default) extends AgentDetector {
public function detect() {
$result = parent::detect();
// Add custom logic (e.g., check for a proprietary header)
if ($this->isCustomAgent()) {
$result->name = 'CustomAgent';
}
return $result;
}
};
});
Laravel-Specific Extensions:
AgentAwareMiddleware:
// app/Http/Middleware/AgentAware.php
How can I help you explore Laravel packages today?