ahmedanbar / devguard
Developer CLI toolkit for Laravel projects — deploy readiness scoring and architecture enforcement.
Requires
- php: ^8.2
- laravel/prompts: ^0.1 || ^0.2 || ^0.3
- nikic/php-parser: ^5.0
- symfony/console: ^7.0
- symfony/finder: ^7.0
- vlucas/phpdotenv: ^5.6
Requires (Dev)
- laravel/pint: ^1.13
- pestphp/pest: ^2.0
- phpstan/phpstan: ^1.10
README
A modular CLI toolkit for Laravel projects. Audits production-readiness and enforces clean architecture in under 2 seconds.
$ devguard run deploy
Deploy Readiness Score: 75/100
✓ .env file exists
✗ APP_DEBUG is enabled in production [-15]
✗ No rate limiting detected on routes [-10]
⚠ LOG_CHANNEL='single' is weak for production [-2]
Suggestions:
→ Set APP_DEBUG=false to avoid leaking stack traces and config to users.
→ Apply 'throttle:api' middleware to your API routes.
→ Use 'daily' or 'stack' to get rotation and multi-channel fan-out.
Failed. Address the errors above before deploying.
Features
- Deploy Readiness Score — 7 production-readiness checks (env, debug, cache, queue, rate limit, https, logging) with a 0–100 score.
- Architecture Enforcer — 6 clean-architecture rules (folder structure, fat controllers, complexity, direct DB calls, service/repository layers).
- Interactive menu when run with no arguments.
- JSON output for CI/CD pipelines.
- Exit codes that fail builds when problems are found.
- Zero config — works out of the box; override per-project via
devguard.php.
Install
As a project dev dependency (recommended)
composer require --dev ahmedanbar/devguard ./vendor/bin/devguard
Globally
composer global require ahmedanbar/devguard devguard
Make sure ~/.composer/vendor/bin is on your PATH.
Usage
devguard # Interactive menu devguard tools # List registered tools devguard run deploy # Run a specific tool devguard run architecture # Run another devguard run all # Run every tool sequentially devguard run deploy --json # JSON output (CI-friendly) devguard run deploy --path=/some/dir # Operate on a different project devguard --help devguard --version
Exit codes
| Code | Meaning |
|---|---|
| 0 | All checks passed (warnings allowed) |
| 1 | At least one failed check |
| 2 | Tool error / unrecoverable failure |
CI pipelines can fail the build on non-zero exit.
Tools
Deploy Readiness Score
| Check | Default impact | What it looks for |
|---|---|---|
env_file_exists |
20 | .env present at project root |
debug_mode |
15 | APP_DEBUG is not true in production |
cache_configured |
10 | CACHE_STORE is a production driver |
queue_configured |
10 | QUEUE_CONNECTION isn't sync/null |
rate_limit |
10 | throttle middleware present on routes |
https_enforced |
10 | URL::forceScheme('https') or APP_URL |
logging_configured |
5 | LOG_CHANNEL isn't single/null |
Architecture Enforcer
| Rule | Severity | Detection |
|---|---|---|
folder_structure |
fail | Required Laravel directories exist |
fat_controller |
fail | Controller > 300 lines |
business_logic_in_controller |
fail/warn | Cyclomatic complexity > 10 / 6 |
direct_db_in_controller |
fail | DB::table/select/insert/... in actions |
service_layer |
warn | app/Services exists & non-empty |
repository_layer |
warn | app/Repositories exists & non-empty |
JSON output
{
"tool": "deploy",
"title": "Deploy Readiness Score",
"score": 75,
"passed": false,
"results": [
{
"name": "debug_mode",
"status": "fail",
"message": "APP_DEBUG is enabled in production",
"impact": 15,
"suggestion": "Set APP_DEBUG=false to avoid leaking stack traces and config to users."
}
]
}
Configuration
Drop a devguard.php at your project root to override defaults. Only the keys you specify are merged on top of the built-ins.
<?php return [ 'tools' => [ 'deploy' => [ 'checks' => [ 'debug_mode' => ['impact' => 25], ], ], 'architecture' => [ 'rules' => [ 'fat_controller' => ['max_lines' => 200], ], ], ], ];
Extending — add your own tool
-
Create a class implementing
DevGuard\Contracts\ToolInterface:final class MyTool implements ToolInterface { public function name(): string { return 'mytool'; } public function title(): string { return 'My Tool'; } public function description(): string { return 'Does a thing.'; } public function run(ProjectContext $ctx): ToolReport { $report = new ToolReport(tool: $this->name(), title: $this->title()); $report->add(CheckResult::pass('hello', 'It works')); return $report; } }
-
Register it in
bin/devguard(or your own entry script):$app->addTool(new MyTool());
That's it — the menu, tools list, JSON renderer, and exit-code logic all pick it up automatically.
Development
composer install composer test # pest composer stan # phpstan composer fmt # laravel pint
Tests run against fixtures under tests/Fixtures/ — a deliberately broken Laravel app and a clean one. CI runs both PHP 8.2 and 8.3.
License
MIT