koalafacade/diamond-console
Diamond Console is a Laravel package for building polished, interactive Artisan commands. It provides a clean API for prompts, menus, and rich terminal output, helping you create better CLI experiences with less boilerplate.
Install it as a dev dependency — it is a scaffolding tool, not runtime code:
composer require --dev koalafacade/diamond-console
Laravel's package auto-discovery registers the commands, so there is no service provider to add manually. Confirm what you actually got before reading any blog post:
php artisan list | grep -i diamond
That listing is the source of truth for command names and signatures in your installed version, which matters because the package is niche (64 stars) and docs can lag releases.
Where to look first
diamond:* command list from above.php artisan vendor:publish --tag=diamond (or inspect vendor/koalafacade/diamond-console/config/) to see the configured domain root namespace, base path, and stub locations.stubs/ directory — this tells you more about the intended architecture than the README does.First use case
Scaffold one bounded context end-to-end and wire it into a single HTTP endpoint before generating anything else. The typical flow is: create the domain skeleton, generate one aggregate/entity plus its repository interface, generate one use case/action, implement the repository with Eloquent in the infrastructure layer, bind it in a service provider, call the use case from a thin controller. If that vertical slice works, the tool's conventions match your project; if it fights you, you have learned that cheaply with one domain instead of twelve.
Vertical slices per bounded context, not per layer. The package exists to give each domain its own Domain / Application / Infrastructure / Presentation folders rather than a global app/Services dumping ground. Generate a whole context, then keep every subsequent artifact inside it. Cross-context coupling is where DDD projects rot, and no generator can save you from it.
Repository interface in Domain, Eloquent in Infrastructure.
src/Billing/
Domain/ Entities, ValueObjects, Repository interfaces, DomainEvents
Application/ UseCases, DTOs, commands/queries
Infrastructure/ Eloquent models, repository implementations, migrations, providers
Presentation/ HTTP controllers, requests, resources, console commands
Bind interface to implementation in a per-context service provider. This is the single most important manual step the generators will not do correctly for you — always verify the binding after scaffolding a repository.
Use cases are single-action classes. Inject them into controllers; keep controllers to validation + dispatch + response mapping. This is what makes the generator output valuable: a use case class with an execute() (or __invoke()) is trivially unit-testable without Laravel bootstrapping.
DTOs at the boundaries. Map HTTP requests to DTOs in Presentation, use cases accept DTOs, repositories return domain objects. Resist passing Illuminate\Http\Request inward — it is the fastest way to make the generated structure meaningless.
Domain events for cross-context communication. Emit them from the domain, translate to Laravel events/dispatch in Infrastructure, and consume via queued listeners. This keeps contexts independently testable and lets you move a context to its own service later.
Migrations and models live in Infrastructure. Point Laravel at them via the context's service provider (loadMigrationsFrom, loadRoutesFrom). Keep app/Models for genuinely shared/legacy models only.
Testing discipline that matches the layout. Pure PHPUnit for Domain (no container, no DB), Laravel feature tests for Presentation + Infrastructure. If your domain tests need RefreshDatabase, the layering has leaked.
In a team: agree on naming before generating — entity vs aggregate, use case vs action, singular vs plural context names. Generators amplify whatever naming convention you choose, and renaming dozens of generated files later is worse than deciding once.
vendor:publish) and tune them to your team's conventions — docblocks, strict types, base classes — so every future generation is correct by default. This is the highest-leverage thing you can do with a package like this.composer dump-autoload after creating a new domain root. If the configured root sits outside the paths already covered by PSR-4, new classes will 404 until you add the namespace mapping and re-dump. This is the most common "the generator is broken" report.composer.json disagree. Check both before patching files by hand.make:domain Billing produces billing in one place and Billing in another, fix it in the stub, not per-file.main. Generation is a developer action; commit the output so review can see the structure. If you script it, use the non-interactive/force flags and diff the result.php artisan config:clear after changing domain paths locally; a stale cached config is a classic silent failure.-vvv, and check php artisan diamond:<cmd> --help for hidden options (path overrides, --force, --domain=). Most "wrong output" issues are a wrong target flag.composer.json, and be prepared to fork the stubs directory — since the package is dev-only scaffolding, forking or vendoring it costs you almost nothing at runtime.Domain. Pair the package with a static analysis rule (PHPStan/Deptrac layer definitions) if you actually need the boundaries held.How can I help you explore Laravel packages today?