romegasoftware/laravel-autopilot

Semi-autonomous error resolution for local development

Installs: 1

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/romegasoftware/laravel-autopilot

dev-main 2026-02-04 19:04 UTC

This package is auto-updated.

Last update: 2026-02-04 19:04:57 UTC


README

Semi-autonomous error resolution for local development. Autopilot monitors Laravel logs and frontend errors, then dispatches Claude CLI agents to fix issues while you keep testing.

Requirements

  • PHP 8.4+
  • Laravel 12+
  • Claude CLI available in PATH

Installation

composer require romegasoftware/laravel-autopilot --dev

Enable in your .env:

AUTOPILOT_ENABLED=true
VITE_AUTOPILOT_ENABLED=true

Publish the config (optional):

php artisan vendor:publish --tag=autopilot-config

Usage

Run the watcher standalone:

php artisan autopilot:watch

Or integrate into your dev script:

{
    "scripts": {
        "dev": [
            "Composer\\Config::disableProcessTimeout",
            "npx concurrently -c \"#c4b5fd,#fb7185,#fdba74\" \"php artisan serve\" \"npm run dev\" \"php artisan autopilot:watch\" --names=server,vite,autopilot"
        ]
    }
}

Frontend Integration

Autopilot captures frontend errors via a small client library. The package provides TypeScript modules you import directly.

1. Initialize the Client

In your main entry file (e.g., resources/js/app.tsx):

const shouldEnableAutopilot =
    import.meta.env.DEV && import.meta.env.VITE_AUTOPILOT_ENABLED === 'true';

if (shouldEnableAutopilot) {
    import('laravel-autopilot/autopilot-client').then(({ initAutopilot }) => {
        initAutopilot();
    });
}

2. React Error Boundary

Wrap your app in the error boundary to capture React component errors:

import { AutopilotErrorBoundary } from 'laravel-autopilot/AutopilotErrorBoundary';

const shouldEnableAutopilot =
    import.meta.env.DEV && import.meta.env.VITE_AUTOPILOT_ENABLED === 'true';

// Passthrough component when autopilot is disabled
const Passthrough = ({ children }: { children: ReactNode }) => <>{children}</>;
const AutopilotBoundary = shouldEnableAutopilot ? AutopilotErrorBoundary : Passthrough;

createInertiaApp({
    setup({ el, App, props }) {
        createRoot(el).render(
            <AutopilotBoundary>
                <App {...props} />
            </AutopilotBoundary>
        );
    },
});

Custom fallback UI:

<AutopilotErrorBoundary
    fallback={<div className="p-4 bg-red-100">Something broke!</div>}
>
    <App {...props} />
</AutopilotErrorBoundary>

3. Axios Interceptor (422 Validation Errors)

Install the interceptor on your Axios instance to capture validation errors:

// resources/js/bootstrap.js
import axios from 'axios';

window.axios = axios;
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

if (import.meta.env.DEV && import.meta.env.VITE_AUTOPILOT_ENABLED === 'true') {
    import('laravel-autopilot/axios-interceptor').then(({ installAutopilotInterceptor }) => {
        installAutopilotInterceptor(window.axios);
    });
}

4. Manual Error Reporting

Report errors manually when needed:

import { reportError } from 'laravel-autopilot/autopilot-client';

try {
    await riskyOperation();
} catch (error) {
    reportError('Custom operation failed', {
        stack: error.stack,
        url: window.location.href,
    });
}

5. Vite Configuration

Add the package alias to your vite.config.ts:

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel({
            input: ['resources/js/app.tsx'],
            refresh: true,
        }),
    ],
    resolve: {
        alias: {
            'laravel-autopilot': '/vendor/romegasoftware/laravel-autopilot/resources/js',
        },
    },
});

Configuration

Full configuration options in config/autopilot.php:

<?php

return [
    // Master toggle
    'enabled' => env('AUTOPILOT_ENABLED', false),

    // Claude CLI settings
    'claude' => [
        'binary' => env('AUTOPILOT_CLAUDE_BINARY', 'claude'),
        'model' => env('AUTOPILOT_CLAUDE_MODEL'),
        'timeout' => env('AUTOPILOT_TIMEOUT', 300),
        'max_parallel_agents' => env('AUTOPILOT_MAX_AGENTS', 3),
        'path' => env('AUTOPILOT_CLAUDE_PATH'),
    ],

    // Log monitoring
    'logs' => [
        'path' => storage_path('logs/laravel.log'),
        'levels' => ['error', 'critical', 'alert', 'emergency'],
        'poll_interval_ms' => 500,
    ],

    // Frontend error capture
    'frontend' => [
        'enabled' => true,
        'capture_react_errors' => true,
        'capture_console_errors' => true,
        'capture_unhandled_rejections' => true,
    ],

    // 422 validation error handling
    'validation_errors' => [
        'enabled' => env('AUTOPILOT_CAPTURE_422', true),
        'include_request_data' => true,
        'ignore_fields' => ['password', 'password_confirmation', 'credit_card', 'cvv'],
    ],

    // Error filtering
    'ignore' => [
        'patterns' => [
            '/Undefined array key.*session/',
            '/CSRF token mismatch/',
        ],
        'exceptions' => [
            Illuminate\Auth\AuthenticationException::class,
            Illuminate\Session\TokenMismatchException::class,
            Symfony\Component\HttpKernel\Exception\NotFoundHttpException::class,
        ],
        'paths' => [
            'vendor/',
            'node_modules/',
        ],
    ],

    // Deduplication
    'deduplication' => [
        'ttl' => 3600,
        'store_path' => storage_path('logs/autopilot_seen_errors.json'),
        'include_stack_trace' => false,
    ],

    // Cooldown to prevent agent spam
    'cooldown' => [
        'after_dispatch' => 5,
        'after_completion' => 30,
        'max_attempts' => 3,
    ],

    // HMR protection (prevents errors during Vite hot reload)
    'hmr_protection' => [
        'cooldown_after_file_change' => 5,
        'frontend_cooldown_after_completion' => 10,
        'ignore_patterns' => [
            '/\[vite\].*hot update/',
            '/\[HMR\]/',
            '/ChunkLoadError/',
            '/Loading chunk.*failed/',
            '/Failed to fetch dynamically imported module/',
        ],
        'lock_modified_files' => true,
    ],

    // Context included with errors
    'context' => [
        'include_route_name' => true,
        'include_controller' => true,
        'max_stack_frames' => 10,
    ],

    // Output settings
    'output' => [
        'stream_agent_output' => true,
        'agent_output_prefix' => '[agent-%d] ',
    ],

    // Customize agent prompts
    'prompts' => [
        'prefix' => <<<'PROMPT'
You are fixing an error in a Laravel application during local development.

IMPORTANT CONTEXT:
- This is a Laravel 12 / Inertia v2 / React 19 application
- Follow existing code patterns in the codebase
- Run tests after making changes to verify the fix
- Keep changes minimal and focused on the error
PROMPT,

        'suffix' => <<<'PROMPT'

After fixing, verify your changes work by:
1. Running relevant tests if they exist
2. Checking for TypeScript errors with `npm run typecheck` if you modified frontend code
PROMPT,
    ],
];

How It Works

  1. Backend errors: The watcher tails storage/logs/laravel.log and detects new errors based on configured severity levels.

  2. Frontend errors: The client captures:

    • React component errors (via error boundary)
    • Console errors (console.error)
    • Unhandled promise rejections
    • 422 validation errors (via Axios interceptor)
  3. Dispatching agents: When an error is detected, Autopilot:

    • Checks deduplication cache to avoid re-processing
    • Applies ignore patterns and exception filters
    • Respects cooldown periods
    • Spawns a Claude CLI agent with error context
  4. HMR protection: The client ignores errors that occur during Vite hot module replacement to prevent false positives when agents modify files.

Environment Variables

Variable Default Description
AUTOPILOT_ENABLED false Master toggle for backend
VITE_AUTOPILOT_ENABLED false Master toggle for frontend
AUTOPILOT_CLAUDE_BINARY claude Path to Claude CLI
AUTOPILOT_CLAUDE_MODEL (default) Override Claude model
AUTOPILOT_TIMEOUT 300 Agent timeout in seconds
AUTOPILOT_MAX_AGENTS 3 Max parallel agents
AUTOPILOT_CLAUDE_PATH - Prepend to PATH for node/claude resolution
AUTOPILOT_CAPTURE_422 true Capture validation errors

Logs & Deduplication

Autopilot stores its logs and error tracking in storage/logs/:

File Purpose
storage/logs/autopilot.log Autopilot activity log (agent dispatches, completions, errors)
storage/logs/autopilot_seen_errors.json Tracks error signatures to prevent duplicate agent dispatches

Retriggering Failed Fixes

If an agent failed to fix an error and you want to retry, clear the error from the seen errors cache:

# Clear all seen errors (retrigger everything)
rm storage/logs/autopilot_seen_errors.json

# Or edit the JSON to remove specific entries
cat storage/logs/autopilot_seen_errors.json

The JSON file uses hashed error signatures:

{
    "seen": {
        "e5be2f2968f8b135": 1770226514,
        "745eee2a90c95b32": 1770226536
    },
    "attempts": {
        "e5be2f2968f8b135": 1,
        "745eee2a90c95b32": 2
    },
    "last_updated": "2026-02-04T18:46:38+00:00"
}
  • seen: Hash → Unix timestamp of first occurrence
  • attempts: Hash → Number of agent dispatch attempts

Remove a hash from both seen and attempts to allow that error to trigger a new agent.

Notes

  • Autopilot only registers when APP_ENV=local and AUTOPILOT_ENABLED=true
  • Frontend client only activates when import.meta.env.DEV is true
  • Errors are deduplicated within a session to prevent agent spam
  • The watcher gracefully handles log rotation