Split your Laravel app into domain modules.
Each domain of your app becomes its own Composer package, with its models, migrations, routes, tests and service provider. Modules declare the modules they depend on, and one Artisan command checks that the code respects it, on every pull request.
lomkit/laravel-osdd · PHP 8.3+ · Laravel 13 · MIT license
Every domain mixed in app/, database/ and config/Each layer requires the layers it uses
No boundary violation in 4 layers.
Three commands
From one app/ folder to checked modules
The package calls each module a layer. Create them with Artisan, and let the boundary check catch the shortcuts.
Output shortened to the lines of each command that matter here.
The layer graph
Dependencies you can see, and a check that enforces them
Each layer lists the layers it requires in its own composer.json. Point at a layer to see what it may use and who depends on it.
functional/orders
- Requires
- functional/catalogfunctional/users
- Required by
- functional/billing
osdd:checkfails if it uses a class of a layer it does not require.osdd:removerefuses it while functional/billing requires it.
$ php artisan osdd:graph
graph LR
…six node lines
functional_billing --> functional_orders
functional_billing --> functional_users
functional_billing --> technical_payments
functional_orders --> functional_catalog
functional_orders --> functional_users
$ php artisan osdd:check
# no cycle in the layer requirements
Everything a domain needs
A layer gets the tooling Laravel gives app/
Built for coding agents
Your agent stops writing in app/
The package ships a Laravel Boost skill. It teaches your agent where code goes in a modular app: read the map first, require a layer before using it, generate inside the right layer.
Set up the Boost skillphp artisan osdd:list --json
Reads every layer: path, namespace, providers, requirements, health.
php artisan osdd:graph --format=json
Checks that functional/billing requires functional/orders.
php artisan osdd:model Refund --layer=functional/billing
Writes the model inside the layer, never in app/.
php artisan osdd:check --format=json
Gets a machine-readable verdict on the boundaries.
osdd:list --json, one layer (excerpt)
{
"name": "functional/billing",
"path": "functional/billing",
"namespace": "Functional\\Billing\\",
"requires": ["functional/orders", "functional/users"],
"health": { "installed": true, "test_suite": true }
}Give your next domain its own package
Start on a fresh Laravel 13 app with osdd:start, or move an existing app one domain at a time.
Laravel OSDD (Open Source Driven Development) is MIT licensed and maintained by Lomkit.