jegjessing / laravel-nplusone-autofix
Reads N+1 query warnings recorded by a runtime detector, asks Claude for a minimal Eloquent fix, applies the patch, and clears the row. Ships an artisan command for Laravel 11/12/13.
Package info
github.com/jegjessing/laravel-nplusone-autofix
pkg:composer/jegjessing/laravel-nplusone-autofix
Requires
- php: ^8.2
- guzzlehttp/guzzle: ^7.8
- illuminate/console: ^11.0|^12.0|^13.0
- illuminate/database: ^11.0|^12.0|^13.0
- illuminate/http: ^11.0|^12.0|^13.0
- illuminate/support: ^11.0|^12.0|^13.0
Requires (Dev)
- orchestra/testbench: ^9.0|^10.0
- pestphp/pest: ^3.0
README
An artisan command that turns recorded N+1 query warnings into applied code fixes.
It reads rows from an nplusone_warnings table (populated by a runtime N+1
detector such as saasscaleup/laravel-n-plus-one-detector),
sends each warning plus a window of the offending source to Claude, applies the
returned patch in-place, and deletes the warning row.
⚠️ This command edits your source files. Always run it in a clean working tree and review
git diff+ your test suite before committing. Start with--dry-run.
Requirements
- PHP 8.2+
- Laravel 11, 12, or 13
- A warnings table with at least
id,sql, andlocation(path:line) columns - An Anthropic API key
Installation
From Packagist (once published)
composer require jegjessing/laravel-nplusone-autofix --dev
From GitHub before it's on Packagist
Add the repo to your app's composer.json, then require it:
{
"repositories": [
{ "type": "vcs", "url": "https://github.com/jegjessing/laravel-nplusone-autofix.git" }
]
}
composer require jegjessing/laravel-nplusone-autofix:dev-main --dev
Local path repository (development)
When the package lives beside your app on disk, wire it in with a path
repository so edits are picked up live:
{
"repositories": [
{ "type": "path", "url": "../laravel-nplusone-autofix", "options": { "symlink": true } }
]
}
composer require jegjessing/laravel-nplusone-autofix:@dev --dev
The service provider is auto-discovered — no manual registration needed.
Configuration
The defaults read the standard ANTHROPIC_* env vars, so if your app already
talks to Claude there is nothing to set up. To customise (table name, model,
source roots), publish the config:
php artisan vendor:publish --tag=nplusone-autofix-config
| Env var | Default | Purpose |
|---|---|---|
ANTHROPIC_API_KEY |
— | Required. Anthropic API key. |
ANTHROPIC_MODEL |
claude-sonnet-4-6 |
Model used to generate patches. |
ANTHROPIC_BASE_URL |
https://api.anthropic.com |
API base URL. |
NPLUSONE_AUTOFIX_MAX_TOKENS |
4096 |
Max response tokens for the patch call. |
NPLUSONE_AUTOFIX_TABLE |
nplusone_warnings |
Table the warnings are read from. |
Usage
# Preview every proposed patch, change nothing: php artisan nplusone:autofix --dry-run # Apply fixes for all recorded warnings: php artisan nplusone:autofix # Fix a single warning by id: php artisan nplusone:autofix --id=42 # Override the model for this run: php artisan nplusone:autofix --model=claude-opus-4-8 # Warnings recorded on another host (e.g. production paths like # /var/www/html/...) are re-anchored on your local project root. Point at a # different root if needed: php artisan nplusone:autofix --base-path=/home/me/project
For each warning the command:
- Resolves the stored
locationto a readable local file (remapping foreign absolute paths onto your project root via the configuredsource_roots). - Sends the SQL, location, and a ±60-line source window to Claude, which
returns a
{ file, search, replace, explanation }patch (or aborts). - Verifies the
searchtext exists and is unique, then applies it. A non-unique or missingsearchis skipped for safety. - Deletes the warning row once the file is patched.
--dry-run prints the search/replace pair and writes nothing.
Testing
composer install composer test # or: ./vendor/bin/pest
License
MIT