jessegall / code-commandments
A Laravel package for enforcing code commandments through prophets who judge and absolve transgressions
Installs: 468
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/jessegall/code-commandments
Requires
- php: ^8.2
- illuminate/console: ^10.0|^11.0|^12.0
- illuminate/filesystem: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
- nikic/php-parser: ^5.0
- symfony/console: ^6.0|^7.0|^8.0
- symfony/finder: ^6.0|^7.0|^8.0
Requires (Dev)
- orchestra/testbench: ^8.0|^9.0|^10.0
- phpunit/phpunit: ^10.0|^11.0
- dev-main
- v1.3.1
- v1.3.0
- v1.2.9
- v1.2.8
- v1.2.7
- v1.2.6
- v1.2.5
- v1.2.4
- v1.2.3
- v1.2.2
- v1.2.1
- v1.2.0
- v1.1.0
- v0.1.63
- v0.1.62
- v0.1.61
- v0.1.60
- v0.1.59
- v0.1.58
- v0.1.57
- v0.1.56
- v0.1.55
- v0.1.54
- v0.1.53
- v0.1.52
- v0.1.51
- v0.1.50
- v0.1.49
- v0.1.48
- v0.1.47
- v0.1.46
- v0.1.45
- v0.1.44
- v0.1.43
- v0.1.42
- v0.1.41
- v0.1.40
- v0.1.39
- v0.1.38
- v0.1.37
- v0.1.36
- v0.1.35
- v0.1.34
- v0.1.33
- v0.1.32
- v0.1.31
- v0.1.30
- v0.1.29
- v0.1.28
- v0.1.27
- v0.1.26
- v0.1.25
- v0.1.24
- v0.1.23
- v0.1.22
- v0.1.21
- v0.1.20
- v0.1.19
- v0.1.18
- v0.1.17
- v0.1.16
- v0.1.15
- v0.1.14
- v0.1.13
- v0.1.12
- v0.1.11
- v0.1.10
- v0.1.9
- v0.1.8
- v0.1.7
- v0.1.6
- v0.1.5
- v0.1.4
- v0.1.3
- v0.1.2
- v0.1.1
- v0.1.0
This package is auto-updated.
Last update: 2026-02-10 17:02:43 UTC
README
This is a personal tool I built for my own projects. It's public in case others find it useful or want to fork it for their own coding standards.
A PHP package that enforces coding standards through automated validation, designed specifically for Claude Code (Anthropic's AI coding assistant). Works as a standalone CLI tool or as a Laravel package.
Why This Exists
When working with Claude Code, I needed a way to:
- Teach Claude my coding standards - So it writes code the way I want from the start
- Automatically check Claude's output - Catch violations immediately after Claude makes changes
- Provide actionable feedback - Give Claude clear instructions on what to fix
This package hooks into Claude Code's hook system to create a feedback loop:
┌─────────────────────────────────────────────────────────────────┐
│ Claude Code Session │
├─────────────────────────────────────────────────────────────────┤
│ 1. Session starts │
│ └─> Hook runs: commandments:scripture │
│ └─> Claude learns all coding rules │
│ │
│ 2. Claude writes/modifies code │
│ │
│ 3. After changes complete │
│ └─> Hook runs: commandments:judge --git │
│ └─> Claude sees any violations │
│ └─> Claude fixes them automatically │
│ │
│ 4. Repeat until code is "righteous" (no violations) │
└─────────────────────────────────────────────────────────────────┘
All output is plain text optimized for AI assistants - concise, actionable, no decorative ASCII art.
Installation
composer require --dev jessegall/code-commandments
Laravel
Publish the configuration file:
php artisan vendor:publish --tag=commandments-config
Standalone (non-Laravel)
Run the init command to set up everything at once (config file, Claude Code hooks, CLAUDE.md):
vendor/bin/commandments init
Then edit the generated commandments.php to define your scrolls using __DIR__-based paths:
return [ 'scrolls' => [ 'backend' => [ 'path' => __DIR__ . '/src', 'extensions' => ['php'], 'prophets' => [ \JesseGall\CodeCommandments\Prophets\Backend\NoRawRequestProphet::class, ], ], ], ];
Auto-detect mode
Use --auto-detect to automatically scan your project structure and generate a working config:
vendor/bin/commandments init --auto-detect
This scans the current directory and its immediate subdirectories, detects project types (PHP and/or frontend), and generates commandments.php with appropriate scrolls, paths, and all available prophets pre-configured.
Detection rules:
- PHP: directory has
composer.jsonand anapp/orsrc/folder containing.phpfiles - Frontend: directory has
package.jsonand contains.vue,.ts, or.tsxfiles
For monorepos with multiple subprojects, each detected project gets its own scrolls (e.g. api-backend, dashboard-frontend).
Run commands via the commandments binary:
vendor/bin/commandments judge vendor/bin/commandments repent vendor/bin/commandments scripture
Sacred Terminology
| Technical Term | Biblical Term |
|---|---|
| Violation | Sin / Transgression |
| Fix/Auto-fix | Repent / Absolution |
| Warning | Prophecy |
| Validator | Prophet |
| Validator class | [Name]Prophet |
| Validators folder | Prophets/ |
| Pass | Righteous / Blessed |
| Fail | Sinful / Fallen |
| Review | Confession |
| Mark as reviewed | Absolve |
| Groups | Scrolls |
Commands
All commands are available via both Laravel artisan and the standalone CLI:
| Laravel | Standalone |
|---|---|
php artisan commandments:judge |
vendor/bin/commandments judge |
php artisan commandments:repent |
vendor/bin/commandments repent |
php artisan commandments:scripture |
vendor/bin/commandments scripture |
The standalone CLI also accepts --config=path to specify a custom config file location.
Judge the Codebase
# Judge all scrolls php artisan commandments:judge # Judge a specific scroll php artisan commandments:judge --scroll=backend # Judge with a specific prophet php artisan commandments:judge --prophet=NoRawRequest # Judge a specific file php artisan commandments:judge --file=app/Http/Controllers/UserController.php # Judge multiple specific files (comma-separated) php artisan commandments:judge --files=app/Models/User.php,app/Services/AuthService.php # Only judge files changed in git php artisan commandments:judge --git # Mark files as absolved after manual review php artisan commandments:judge --absolve
Seek Absolution (Auto-fix)
# Auto-fix all sins that can be absolved php artisan commandments:repent # Preview what would be fixed php artisan commandments:repent --dry-run # Fix a specific file php artisan commandments:repent --file=app/Http/Controllers/UserController.php # Fix multiple specific files (comma-separated) php artisan commandments:repent --files=app/Models/User.php,app/Services/AuthService.php
Read the Scripture (List Commandments)
# List all prophets php artisan commandments:scripture # List with detailed descriptions and examples php artisan commandments:scripture --detailed # List prophets from a specific scroll php artisan commandments:scripture --scroll=frontend
Summon a New Prophet (Laravel only)
# Create a new backend prophet php artisan make:prophet NoMagicNumbers --scroll=backend # Create a new frontend prophet php artisan make:prophet NoInlineStyles --scroll=frontend --type=frontend # Create a prophet that can auto-fix php artisan make:prophet NoUnusedImports --repentable # Create a prophet that requires manual review php artisan make:prophet ComplexLogicReview --confession
Claude Code Integration
Automated Hooks
Claude Code supports hooks - shell commands that run at specific points during a session. This package leverages hooks to create an automated feedback loop.
Laravel projects:
php artisan commandments:install-hooks
Standalone projects (included in init, or run separately):
vendor/bin/commandments init
Both commands create .claude/settings.json with hooks and a CLAUDE.md file. The standalone version uses vendor/bin/commandments instead of php artisan.
Example hooks configuration:
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "vendor/bin/commandments scripture 2>/dev/null || true"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "vendor/bin/commandments judge --git 2>/dev/null; exit 0"
}
]
}
]
}
}
How it works:
| Hook | When it runs | What it does |
|---|---|---|
SessionStart |
When Claude Code session begins | Shows all commandments so Claude knows the rules |
Stop |
After Claude finishes a response | Runs judge --git to check changed files |
The --git flag ensures only new/modified files are checked, keeping feedback focused and fast.
Typical workflow:
- You ask Claude to implement a feature
- Claude writes the code
- Hook automatically runs
commandments:judge --git - If violations found, Claude sees them and fixes automatically
- Repeat until code passes all checks
Configuration
Configure your scrolls in config/commandments.php:
return [ 'scrolls' => [ 'backend' => [ 'path' => app_path(), 'extensions' => ['php'], 'exclude' => ['Console/Kernel.php'], 'prophets' => [ // Simple registration (no config needed) Backend\NoRawRequestProphet::class, Backend\NoJsonResponseProphet::class, // With per-prophet configuration Backend\ControllerPrivateMethodsProphet::class => [ 'max_private_methods' => 3, 'min_method_lines' => 3, ], ], ], 'frontend' => [ 'path' => resource_path('js'), 'extensions' => ['vue', 'ts', 'js'], 'prophets' => [ Frontend\NoFetchAxiosProphet::class, Frontend\CompositionApiProphet::class, // Configure max lines thresholds Frontend\LongVueFilesProphet::class => [ 'max_vue_lines' => 200, ], Frontend\LongTsFilesProphet::class => [ 'max_ts_lines' => 200, ], // Configure allowed Tailwind patterns for style overrides Frontend\StyleOverridesProphet::class => [ 'allowed_patterns' => [ // Width/height '/^(min-|max-)?(w|h)-/', '/^size-/', // Flexbox '/^flex$/', '/^inline-flex$/', '/^items-/', '/^justify-/', // Transitions & animations '/^transition/', '/^duration-/', '/^animate-/', // Interactions '/^cursor-/', '/^opacity-/', ], ], ], ], ], 'confession' => [ 'tablet_path' => storage_path('commandments/confessions.json'), ], ];
Per-Prophet Configuration
Prophets can be registered in two ways:
-
Simple registration - Just the class name when no config is needed:
Backend\NoRawRequestProphet::class, -
With configuration - Class name as key, config array as value:
Backend\ControllerPrivateMethodsProphet::class => [ 'max_private_methods' => 3, ],
Per-Prophet Exclusions
You can exclude specific paths for individual prophets. This is useful when a rule shouldn't apply to certain files:
'prophets' => [ // Exclude legacy controllers from this rule Backend\ConstructorDependencyInjectionProphet::class => [ 'exclude' => ['Http/Controllers/Legacy', 'Http/Controllers/Api/V1'], ], // Combine exclusions with other config options Backend\ControllerPrivateMethodsProphet::class => [ 'max_private_methods' => 3, 'exclude' => ['Http/Controllers/ReportController.php'], ], ],
The exclusion uses substring matching - if the path contains any of the excluded strings, that prophet will skip the file.
Configurable Prophets
| Prophet | Config Key | Default | Description |
|---|---|---|---|
LongVueFilesProphet |
max_vue_lines |
200 | Maximum lines in Vue files |
LongTsFilesProphet |
max_ts_lines |
200 | Maximum lines in script sections |
ControllerPrivateMethodsProphet |
max_private_methods |
3 | Max private methods in controllers |
ControllerPrivateMethodsProphet |
min_method_lines |
3 | Min lines for method to count |
StyleOverridesProphet |
allowed_patterns |
[] | Additional Tailwind patterns to allow |
StyleOverridesProphet Patterns
The StyleOverridesProphet flags appearance classes on base components (Button, Card, etc.) but allows layout classes by default. You can extend the allowed patterns:
Frontend\StyleOverridesProphet::class => [ 'allowed_patterns' => [ // These are in ADDITION to built-in layout patterns '/^(min-|max-)?(w|h)-/', // Width/height '/^flex$/', // Flex display '/^items-/', // Flex alignment '/^cursor-/', // Cursor styles '/^transition/', // Transitions ], ],
Built-in allowed patterns (always allowed):
- Margin/padding:
m-,p-,space-,gap- - Grid layout:
col-span-,row-span-, etc. - Flex behavior:
flex-1,grow,shrink,self- - Positioning:
absolute,relative,top-,z- - Display:
hidden,block,inline-block
Built-in Prophets
Backend (PHP)
- NoRawRequestProphet - Thou shalt not access raw request data
- NoJsonResponseProphet - Thou shalt not return raw JSON responses
- NoDirectRequestInputProphet - Thou shalt not access request data directly in controllers
- NoEventDispatchProphet - Thou shalt use event() helper for dispatching
- NoRecordThatOutsideAggregateProphet - Thou shalt not use recordThat() outside aggregates
- NoValidatedMethodProphet - Thou shalt not use validated() method
- NoInlineValidationProphet - Thou shalt not use inline validation
- TypeScriptAttributeProphet - Thou shalt use #[TypeScript] on Resources
- ReadonlyDataPropertiesProphet - Thou shalt not declare readonly properties in Data class body
- FormRequestTypedGettersProphet - Thou shalt use typed getters in FormRequest
- HiddenAttributeProphet - Thou shalt hide sensitive model attributes
- NoCustomFromModelProphet - Thou shalt not use custom fromModel methods
- ControllerPrivateMethodsProphet - Thou shalt not have too many private methods in controllers
- KebabCaseRoutesProphet - Thou shalt use kebab-case for route URIs
- ConstructorDependencyInjectionProphet - Thou shalt inject dependencies via constructor
- NoInlineBootLogicProphet - Thou shalt not inline boot logic
- ComputedPropertyMustHookProphet - Thou shalt hook computed properties
- QueryModelsThroughQueryMethodProphet - Thou shalt query models through ::query()
- NoAuthUserInDataClassesProphet - Thou shalt use #[FromAuthenticatedUser] attribute
Frontend (Vue/TypeScript)
- NoFetchAxiosProphet - Thou shalt not use fetch() or axios directly
- TemplateVForProphet - Thou shalt wrap v-for in template elements
- TemplateVIfProphet - Thou shalt wrap v-if/v-else in template elements
- RouterHardcodedUrlsProphet - Thou shalt not hardcode URLs in router calls
- WayfinderRoutesProphet - Thou shalt not hardcode URLs in href attributes
- CompositionApiProphet - Thou shalt use Composition API
- ArrowFunctionAssignmentsProphet - Thou shalt use named function declarations
- SwitchCaseProphet - Thou shalt not use switch statements
- LongVueFilesProphet - Thou shalt keep Vue files concise
- LongTsFilesProphet - Thou shalt keep TypeScript files concise
- RepeatingPatternsProphet - Thou shalt not repeat template patterns
- ScriptFirstProphet - Thou shalt put script before template
- PropsTypeScriptProphet - Thou shalt type props with TypeScript
- EmitsTypeScriptProphet - Thou shalt type emits with TypeScript
- InlineEmitTransformProphet - Thou shalt not transform data in emit handlers
- InlineTypeCastingProphet - Thou shalt not type cast in templates
- WatchIfPatternProphet - Thou shalt not use watch with if conditions
- PageDataAccessProphet - Thou shalt use typed page props
- DeepNestingProphet - Thou shalt not deeply nest template elements
- StyleOverridesProphet - Thou shalt not override child component styles
- ExplicitDefaultSlotProphet - Thou shalt use explicit default slots
- MultipleSlotDefinitionsProphet - Thou shalt type slots with defineSlots
- ConditionalArrayBuildingProphet - Consider disabled flags pattern for array building
- SwitchCheckboxVModelProphet - Thou shalt use v-model on Switch/Checkbox
- LoopsWithIndexedStateProphet - Review indexed state in loops (requires confession)
- ContentLikePropsProphet - Review content-like props (requires confession)
- InlineDialogProphet - Review inline dialog definitions (requires confession)
Creating Custom Prophets
Basic PHP Prophet
<?php namespace App\Prophets\Backend; use JesseGall\CodeCommandments\Commandments\PhpCommandment; use JesseGall\CodeCommandments\Results\Judgment; class NoMagicNumbersProphet extends PhpCommandment { public function description(): string { return 'Thou shalt not use magic numbers'; } public function detailedDescription(): string { return 'Magic numbers should be extracted to named constants...'; } public function judge(string $filePath, string $content): Judgment { $ast = $this->parse($content); if ($ast === null) { return $this->skip('Unable to parse PHP file'); } // Your judgment logic here... return $this->righteous(); } }
Using the Pipeline API
The package provides fluent pipeline APIs for both PHP and Vue file analysis.
PHP Pipeline (PhpPipeline)
use JesseGall\CodeCommandments\Support\Pipes\Php\PhpPipeline; public function judge(string $filePath, string $content): Judgment { return PhpPipeline::make($filePath, $content) ->onlyControllers() // Filter to Laravel controllers only ->pipe(ExtractMethods::class) ->pipe(FilterPrivateMethod::class) ->mapToSins(fn ($ctx) => /* create sins */) ->judge(); }
Available helper methods:
| Method | Description |
|---|---|
onlyControllers() |
Filter to Laravel controller classes |
onlyDataClasses() |
Filter to Laravel Data classes |
onlyFormRequestClasses() |
Filter to FormRequest classes |
returnRighteousIfNoClass() |
Return righteous if no class found |
returnRighteousWhenClassHasAttribute($attr) |
Skip if class has specific attribute |
Vue Pipeline (VuePipeline)
use JesseGall\CodeCommandments\Support\Pipes\Vue\VuePipeline; public function judge(string $filePath, string $content): Judgment { return VuePipeline::make($filePath, $content) ->inTemplate() // Extract template, return righteous if not found ->matchAll('/pattern/') ->sinsFromMatches('Message', 'Suggestion') ->judge(); }
Available helper methods:
| Method | Description |
|---|---|
inTemplate() |
Extract template section, return righteous if not found |
inScript() |
Extract script section, return righteous if not found |
onlyPageFiles() |
Filter to files in Pages/ directory |
onlyComponentFiles() |
Filter to files in Components/ directory |
excludePartialFiles() |
Exclude files in Partials/ directory |
matchAll($pattern) |
Find all regex matches in current section |
sinsFromMatches($msg, $suggestion) |
Convert matches to sins |
mapToSins($callback) |
Custom sin mapping |
mapToWarnings($callback) |
Custom warning mapping |
Accessing Configuration
Prophets can access their configuration via $this->config():
class MyProphet extends PhpCommandment { public function judge(string $filePath, string $content): Judgment { $maxLines = (int) $this->config('max_lines', 100); $patterns = $this->config('allowed_patterns', []); // Use config values... } }
Then configure in config/commandments.php:
'prophets' => [ MyProphet::class => [ 'max_lines' => 150, 'allowed_patterns' => ['/^custom-/'], ], ],
Vue/TypeScript Auto-fixing
For Vue and TypeScript auto-fixing, install the Node.js dependencies:
cd vendor/jessegall/code-commandments/node
npm install
Testing
./vendor/bin/phpunit
License
MIT License