Use this file when adding support for zpmlabs/laravel-package-quick-demo to another Laravel package.
php artisan boost:add-skill zpmlabs/laravel-package-quick-demo
Save this content to: AGENTS.md
# Agent Instructions — Laravel Package Quick Demo
Use this file when adding support for `zpmlabs/laravel-package-quick-demo` to another Laravel package.
The package README is good for humans. This file is stricter and is intended for coding agents such as Codex, Copilot Agent, Cursor Agent, Claude Code, or similar tools.
---
## Objective
Add a working, isolated quick demo to a Laravel package.
After implementation, the package user should be able to run:
```bash
php artisan quick-demo:install blog-demo
```
and immediately test the package demo without manually editing `.env`, `config/database.php`, `routes/web.php`, or copying demo files by hand.
---
## Hard rules
Do not violate these rules.
* Do not modify the host application's `.env` file.
* Do not modify the host application's `config/database.php` file.
* Do not modify the host application's `routes/web.php` file.
* Do not create demo tables in the default database connection.
* Do not seed the default database connection.
* Do not register unprefixed demo routes.
* Do not use generic demo keys such as `demo`, `test`, or `example`.
* Do not publish files into generic folders such as `public/demo`, `resources/views/demo`, or `storage/app/demo`.
* Do not overwrite generated files unless the command is run with `--force`.
* Keep all code, class names, method names, comments, and docs in English.
---
## Required package dependency
Add this package to the target package dependencies:
```json
{
"require": {
"zpmlabs/laravel-package-quick-demo": "^0.1"
}
}
```
Use the latest compatible version if the package already exists with a newer release.
---
## Recommended demo structure
Create this structure inside the target package:
```txt
examples/
database/
demo.sqlite.stub
migrations/
2026_01_01_000001_create_demo_posts_table.php
routes/
demo.php
views/
index.blade.php
show.blade.php
assets/
demo.css
demo.js
storage/
images/
demo-cover.jpg
config/
demo.php
```
Only create folders that are needed.
For a database-only demo, this is enough:
```txt
examples/
database/
demo.sqlite.stub
migrations/
2026_01_01_000001_create_demo_records_table.php
```
---
## Demo key naming
Use a package-specific demo key.
Good:
```txt
blog-demo
users-demo
orders-demo
comments-demo
```
Bad:
```txt
demo
test
example
sample
```
The demo key is used for route prefixes, view namespaces, and generated paths, so it must be unique and predictable.
---
## Database naming
Use a package-specific database name.
Good:
```txt
blog_demo
users_demo
orders_demo
```
Bad:
```txt
demo
sqlite
test
example
```
Example:
```php
databaseName: 'blog_demo'
```
This should create:
```txt
database/quick-demos/blog_demo.sqlite
```
and register connection:
```txt
quick_demo_blog_demo
```
---
## Table naming
Use demo-specific table names.
Good:
```txt
demo_posts
demo_users
demo_orders
```
Bad:
```txt
posts
users
orders
```
Do not reuse real application table names unless the demo intentionally targets existing application data, which should be avoided by default.
---
## Service provider registration
Register the demo in the target package service provider `boot()` method.
```php
<?php
namespace Vendor\BlogPackage;
use Illuminate\Support\ServiceProvider;
use ZPMLabs\LaravelPackageQuickDemo\Facades\QuickDemo;
use ZPMLabs\LaravelPackageQuickDemo\Support\DemoDefinition;
class BlogPackageServiceProvider extends ServiceProvider
{
public function boot(): void
{
QuickDemo::register(
DemoDefinition::make(
key: 'blog-demo',
name: 'Blog Demo',
databaseName: 'blog_demo',
databaseStubPath: __DIR__ . '/../examples/database/demo.sqlite.stub',
migrationsPath: __DIR__ . '/../examples/migrations',
seeders: [
\Vendor\BlogPackage\Database\Seeders\BlogDemoSeeder::class,
],
routesPath: __DIR__ . '/../examples/routes/demo.php',
viewsPath: __DIR__ . '/../examples/views',
assetsPath: __DIR__ . '/../examples/assets',
storagePath: __DIR__ . '/../examples/storage',
configPath: __DIR__ . '/../examples/config/demo.php',
)
);
}
}
```
Only include paths that actually exist.
If there are no routes, omit `routesPath`.
If there are no views, omit `viewsPath`.
If there are no assets, omit `assetsPath`.
If there are no storage files, omit `storagePath`.
If there is no config file, omit `configPath`.
---
## SQLite stub
Create:
```txt
examples/database/demo.sqlite.stub
```
An empty file is acceptable:
```bash
mkdir -p examples/database
touch examples/database/demo.sqlite.stub
```
Prefer an empty SQLite stub plus migrations and seeders over a prebuilt SQLite database.
---
## Migration pattern
Every demo migration must explicitly use the quick-demo connection.
```php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use ZPMLabs\LaravelPackageQuickDemo\Facades\QuickDemo;
return new class extends Migration
{
public function getConnection(): string
{
return QuickDemo::connectionName('blog-demo');
}
public function up(): void
{
Schema::connection($this->getConnection())->create('demo_posts', function (Blueprint $table): void {
$table->id();
$table->string('title');
$table->text('body')->nullable();
$table->boolean('is_published')->default(true);
$table->timestamps();
});
}
public function down(): void
{
Schema::connection($this->getConnection())->dropIfExists('demo_posts');
}
};
```
Do not use:
```php
Schema::create('posts', function (Blueprint $table): void {
// Wrong for demo package tables.
});
```
---
## Seeder pattern
Every demo seeder must write to the quick-demo connection.
```php
<?php
namespace Vendor\BlogPackage\Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use ZPMLabs\LaravelPackageQuickDemo\Facades\QuickDemo;
class BlogDemoSeeder extends Seeder
{
public function run(): void
{
DB::connection(QuickDemo::connectionName('blog-demo'))
->table('demo_posts')
->insert([
[
'title' => 'First demo post',
'body' => 'This post belongs to the isolated quick demo database.',
'is_published' => true,
'created_at' => now(),
'updated_at' => now(),
],
]);
}
}
```
Do not use the default connection:
```php
DB::table('posts')->insert([...]);
```
---
## Model pattern
Every demo model must use the quick-demo connection.
```php
<?php
namespace Vendor\BlogPackage\Models;
use Illuminate\Database\Eloquent\Model;
use ZPMLabs\LaravelPackageQuickDemo\Facades\QuickDemo;
class DemoPost extends Model
{
protected $table = 'demo_posts';
protected $guarded = [];
public function getConnectionName(): string
{
return QuickDemo::connectionName('blog-demo');
}
}
```
Use demo-specific model names when possible:
```txt
DemoPost
DemoUser
DemoOrder
```
---
## Route pattern
Create:
```txt
examples/routes/demo.php
```
Example:
```php
<?php
use Illuminate\Support\Facades\Route;
use Vendor\BlogPackage\Http\Controllers\BlogDemoController;
Route::get('/', [BlogDemoController::class, 'index'])->name('index');
Route::get('/posts/{post}', [BlogDemoController::class, 'show'])->name('show');
```
The quick-demo package mounts these routes under:
```txt
/quick-demo/blog-demo
```
and names them under:
```txt
quick-demo.blog_demo.
```
Do not manually add routes to the host application's `routes/web.php`.
---
## Controller pattern
Use demo models and demo views.
```php
<?php
namespace Vendor\BlogPackage\Http\Controllers;
use Vendor\BlogPackage\Models\DemoPost;
class BlogDemoController
{
public function index()
{
return view('quick-demo-blog-demo::index', [
'posts' => DemoPost::query()->latest()->get(),
]);
}
public function show(DemoPost $post)
{
return view('quick-demo-blog-demo::show', [
'post' => $post,
]);
}
}
```
---
## View pattern
Put views in:
```txt
examples/views
```
Use the generated namespace:
```txt
quick-demo-blog-demo
```
Example:
```php
return view('quick-demo-blog-demo::index');
```
Do not use generic view namespaces like:
```txt
demo::index
example::index
```
---
## Asset pattern
Put assets in:
```txt
examples/assets
```
They will be published to:
```txt
public/vendor/quick-demos/blog-demo
```
Use them in Blade:
```blade
<link rel="stylesheet" href="{{ asset('vendor/quick-demos/blog-demo/demo.css') }}">
<script src="{{ asset('vendor/quick-demos/blog-demo/demo.js') }}" defer></script>
```
Do not publish demo assets directly to `public/` root.
---
## Storage pattern
Put demo storage files in:
```txt
examples/storage
```
They will be copied to:
```txt
storage/app/quick-demos/blog-demo
```
Use:
```php
storage_path('app/quick-demos/blog-demo/images/demo-cover.jpg')
```
Do not copy files to generic storage folders.
---
## Config pattern
Put optional demo config in:
```txt
examples/config/demo.php
```
It will be copied to:
```txt
config/quick-demos/blog-demo.php
```
Do not modify existing application config files.
---
## Hook pattern
Use hooks only when normal migrations, seeders, routes, views, assets, storage, and config are not enough.
Example registration:
```php
DemoDefinition::make(
key: 'blog-demo',
name: 'Blog Demo',
databaseName: 'blog_demo',
afterInstall: \Vendor\BlogPackage\Demo\AfterInstallBlogDemo::class,
)
```
Hook class:
```php
<?php
namespace Vendor\BlogPackage\Demo;
use ZPMLabs\LaravelPackageQuickDemo\Support\QuickDemoContext;
class AfterInstallBlogDemo
{
public function handle(QuickDemoContext $context): void
{
// Custom demo setup logic.
}
}
```
Available context fields:
```php
$context->definition;
$context->databasePath;
$context->connectionName;
$context->routePrefix;
$context->routeNamePrefix;
$context->viewNamespace;
$context->assetsDestination;
$context->storageDestination;
$context->configDestination;
$context->options;
```
---
## Validation checklist
After implementing the demo, run these commands in a Laravel test app:
```bash
composer dump-autoload
php artisan quick-demo:list
php artisan quick-demo:show blog-demo
php artisan quick-demo:install blog-demo --fresh --force
php artisan route:list
```
Confirm all of the following:
* The demo appears in `quick-demo:list`.
* `quick-demo:show blog-demo` displays correct paths.
* The SQLite database exists in `database/quick-demos`.
* The generated connection name is package-specific.
* Demo migrations ran on the quick-demo connection.
* Demo seeders inserted data into the quick-demo database.
* No demo tables were created in the default database.
* Demo routes are mounted under `/quick-demo/{demo-key}`.
* Demo route names are prefixed.
* Demo views render correctly.
* Demo assets load correctly.
* Demo storage files are copied if configured.
* Demo config is copied if configured.
* `.env` was not changed.
* `config/database.php` was not changed.
* `routes/web.php` was not changed.
---
## Common mistakes to avoid
Do not do this:
```php
Schema::create('posts', function (Blueprint $table): void {
// Wrong connection and wrong table name for demo isolation.
});
```
Do this instead:
```php
Schema::connection(QuickDemo::connectionName('blog-demo'))->create('demo_posts', function (Blueprint $table): void {
// Correct.
});
```
Do not do this:
```php
DB::table('posts')->insert([...]);
```
Do this instead:
```php
DB::connection(QuickDemo::connectionName('blog-demo'))->table('demo_posts')->insert([...]);
```
Do not do this:
```php
Route::get('/demo', DemoController::class);
```
Do this instead:
```php
// examples/routes/demo.php
Route::get('/', [BlogDemoController::class, 'index'])->name('index');
```
The quick-demo package will add the route prefix.
---
## Expected final result
A user should be able to do this:
```bash
composer require vendor/blog-package
php artisan quick-demo:list
php artisan quick-demo:install blog-demo
php artisan serve
```
Then open:
```txt
http://localhost:8000/quick-demo/blog-demo
```
No manual setup should be required.
Use this file when adding support for zpmlabs/laravel-package-quick-demo to another Laravel package.
The package README is good for humans. This file is stricter and is intended for coding agents such as Codex, Copilot Agent, Cursor Agent, Claude Code, or similar tools.
Add a working, isolated quick demo to a Laravel package.
After implementation, the package user should be able to run:
php artisan quick-demo:install blog-demo
and immediately test the package demo without manually editing .env, config/database.php, routes/web.php, or copying demo files by hand.
Do not violate these rules.
.env file.config/database.php file.routes/web.php file.demo, test, or example.public/demo, resources/views/demo, or storage/app/demo.--force.Add this package to the target package dependencies:
{
"require": {
"zpmlabs/laravel-package-quick-demo": "^0.1"
}
}
Use the latest compatible version if the package already exists with a newer release.
Create this structure inside the target package:
examples/
database/
demo.sqlite.stub
migrations/
2026_01_01_000001_create_demo_posts_table.php
routes/
demo.php
views/
index.blade.php
show.blade.php
assets/
demo.css
demo.js
storage/
images/
demo-cover.jpg
config/
demo.php
Only create folders that are needed.
For a database-only demo, this is enough:
examples/
database/
demo.sqlite.stub
migrations/
2026_01_01_000001_create_demo_records_table.php
Use a package-specific demo key.
Good:
blog-demo
users-demo
orders-demo
comments-demo
Bad:
demo
test
example
sample
The demo key is used for route prefixes, view namespaces, and generated paths, so it must be unique and predictable.
Use a package-specific database name.
Good:
blog_demo
users_demo
orders_demo
Bad:
demo
sqlite
test
example
Example:
databaseName: 'blog_demo'
This should create:
database/quick-demos/blog_demo.sqlite
and register connection:
quick_demo_blog_demo
Use demo-specific table names.
Good:
demo_posts
demo_users
demo_orders
Bad:
posts
users
orders
Do not reuse real application table names unless the demo intentionally targets existing application data, which should be avoided by default.
Register the demo in the target package service provider boot() method.
<?php
namespace Vendor\BlogPackage;
use Illuminate\Support\ServiceProvider;
use ZPMLabs\LaravelPackageQuickDemo\Facades\QuickDemo;
use ZPMLabs\LaravelPackageQuickDemo\Support\DemoDefinition;
class BlogPackageServiceProvider extends ServiceProvider
{
public function boot(): void
{
QuickDemo::register(
DemoDefinition::make(
key: 'blog-demo',
name: 'Blog Demo',
databaseName: 'blog_demo',
databaseStubPath: __DIR__ . '/../examples/database/demo.sqlite.stub',
migrationsPath: __DIR__ . '/../examples/migrations',
seeders: [
\Vendor\BlogPackage\Database\Seeders\BlogDemoSeeder::class,
],
routesPath: __DIR__ . '/../examples/routes/demo.php',
viewsPath: __DIR__ . '/../examples/views',
assetsPath: __DIR__ . '/../examples/assets',
storagePath: __DIR__ . '/../examples/storage',
configPath: __DIR__ . '/../examples/config/demo.php',
)
);
}
}
Only include paths that actually exist.
If there are no routes, omit routesPath.
If there are no views, omit viewsPath.
If there are no assets, omit assetsPath.
If there are no storage files, omit storagePath.
If there is no config file, omit configPath.
Create:
examples/database/demo.sqlite.stub
An empty file is acceptable:
mkdir -p examples/database
touch examples/database/demo.sqlite.stub
Prefer an empty SQLite stub plus migrations and seeders over a prebuilt SQLite database.
Every demo migration must explicitly use the quick-demo connection.
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use ZPMLabs\LaravelPackageQuickDemo\Facades\QuickDemo;
return new class extends Migration
{
public function getConnection(): string
{
return QuickDemo::connectionName('blog-demo');
}
public function up(): void
{
Schema::connection($this->getConnection())->create('demo_posts', function (Blueprint $table): void {
$table->id();
$table->string('title');
$table->text('body')->nullable();
$table->boolean('is_published')->default(true);
$table->timestamps();
});
}
public function down(): void
{
Schema::connection($this->getConnection())->dropIfExists('demo_posts');
}
};
Do not use:
Schema::create('posts', function (Blueprint $table): void {
// Wrong for demo package tables.
});
Every demo seeder must write to the quick-demo connection.
<?php
namespace Vendor\BlogPackage\Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use ZPMLabs\LaravelPackageQuickDemo\Facades\QuickDemo;
class BlogDemoSeeder extends Seeder
{
public function run(): void
{
DB::connection(QuickDemo::connectionName('blog-demo'))
->table('demo_posts')
->insert([
[
'title' => 'First demo post',
'body' => 'This post belongs to the isolated quick demo database.',
'is_published' => true,
'created_at' => now(),
'updated_at' => now(),
],
]);
}
}
Do not use the default connection:
DB::table('posts')->insert([...]);
Every demo model must use the quick-demo connection.
<?php
namespace Vendor\BlogPackage\Models;
use Illuminate\Database\Eloquent\Model;
use ZPMLabs\LaravelPackageQuickDemo\Facades\QuickDemo;
class DemoPost extends Model
{
protected $table = 'demo_posts';
protected $guarded = [];
public function getConnectionName(): string
{
return QuickDemo::connectionName('blog-demo');
}
}
Use demo-specific model names when possible:
DemoPost
DemoUser
DemoOrder
Create:
examples/routes/demo.php
Example:
<?php
use Illuminate\Support\Facades\Route;
use Vendor\BlogPackage\Http\Controllers\BlogDemoController;
Route::get('/', [BlogDemoController::class, 'index'])->name('index');
Route::get('/posts/{post}', [BlogDemoController::class, 'show'])->name('show');
The quick-demo package mounts these routes under:
/quick-demo/blog-demo
and names them under:
quick-demo.blog_demo.
Do not manually add routes to the host application's routes/web.php.
Use demo models and demo views.
<?php
namespace Vendor\BlogPackage\Http\Controllers;
use Vendor\BlogPackage\Models\DemoPost;
class BlogDemoController
{
public function index()
{
return view('quick-demo-blog-demo::index', [
'posts' => DemoPost::query()->latest()->get(),
]);
}
public function show(DemoPost $post)
{
return view('quick-demo-blog-demo::show', [
'post' => $post,
]);
}
}
Put views in:
examples/views
Use the generated namespace:
quick-demo-blog-demo
Example:
return view('quick-demo-blog-demo::index');
Do not use generic view namespaces like:
demo::index
example::index
Put assets in:
examples/assets
They will be published to:
public/vendor/quick-demos/blog-demo
Use them in Blade:
<link rel="stylesheet" href="{{ asset('vendor/quick-demos/blog-demo/demo.css') }}">
<script src="{{ asset('vendor/quick-demos/blog-demo/demo.js') }}" defer></script>
Do not publish demo assets directly to public/ root.
Put demo storage files in:
examples/storage
They will be copied to:
storage/app/quick-demos/blog-demo
Use:
storage_path('app/quick-demos/blog-demo/images/demo-cover.jpg')
Do not copy files to generic storage folders.
Put optional demo config in:
examples/config/demo.php
It will be copied to:
config/quick-demos/blog-demo.php
Do not modify existing application config files.
Use hooks only when normal migrations, seeders, routes, views, assets, storage, and config are not enough.
Example registration:
DemoDefinition::make(
key: 'blog-demo',
name: 'Blog Demo',
databaseName: 'blog_demo',
afterInstall: \Vendor\BlogPackage\Demo\AfterInstallBlogDemo::class,
)
Hook class:
<?php
namespace Vendor\BlogPackage\Demo;
use ZPMLabs\LaravelPackageQuickDemo\Support\QuickDemoContext;
class AfterInstallBlogDemo
{
public function handle(QuickDemoContext $context): void
{
// Custom demo setup logic.
}
}
Available context fields:
$context->definition;
$context->databasePath;
$context->connectionName;
$context->routePrefix;
$context->routeNamePrefix;
$context->viewNamespace;
$context->assetsDestination;
$context->storageDestination;
$context->configDestination;
$context->options;
After implementing the demo, run these commands in a Laravel test app:
composer dump-autoload
php artisan quick-demo:list
php artisan quick-demo:show blog-demo
php artisan quick-demo:install blog-demo --fresh --force
php artisan route:list
Confirm all of the following:
quick-demo:list.quick-demo:show blog-demo displays correct paths.database/quick-demos./quick-demo/{demo-key}..env was not changed.config/database.php was not changed.routes/web.php was not changed.Do not do this:
Schema::create('posts', function (Blueprint $table): void {
// Wrong connection and wrong table name for demo isolation.
});
Do this instead:
Schema::connection(QuickDemo::connectionName('blog-demo'))->create('demo_posts', function (Blueprint $table): void {
// Correct.
});
Do not do this:
DB::table('posts')->insert([...]);
Do this instead:
DB::connection(QuickDemo::connectionName('blog-demo'))->table('demo_posts')->insert([...]);
Do not do this:
Route::get('/demo', DemoController::class);
Do this instead:
// examples/routes/demo.php
Route::get('/', [BlogDemoController::class, 'index'])->name('index');
The quick-demo package will add the route prefix.
A user should be able to do this:
composer require vendor/blog-package
php artisan quick-demo:list
php artisan quick-demo:install blog-demo
php artisan serve
Then open:
http://localhost:8000/quick-demo/blog-demo
No manual setup should be required.
How can I help you explore Laravel packages today?