lc-generate-action
Create a Laractions action class with proper boilerplate.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
Create a Laractions action class with proper boilerplate.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
Create a Larascraper scraper (v2 or v3) for a target website, chaining browser actions (click, type, wait, scroll), conditional flow (when/repeatUntil), captcha solving, and file/PDF downloads. Detects the installed major and generates the matching style.
Add or edit a Laracrate file collection in config/laracrate.php with the correct anatomy (disk, access, types, variants, previews, extract/embed, flags, per-model scoping).
Runtime-verified Laravel inspection using the Laravel Boost MCP server (Tinker, Database Query/Schema, Last Error) instead of static grep. Falls back to Docker/Tinker if Boost is not installed.
Scaffold spatie/laravel-permission setup - add the HasRoles trait to a model and generate a roles & permissions seeder.
Audit spatie/laravel-permission usage - permissions used in code but undefined, defined but unused, unprotected routes, guard mismatches, and cache pitfalls.
Extract business logic from a controller or Livewire component method into a Laractions Action class.
| name | lc:generate-action |
| description | Create a Laractions action class with proper boilerplate. |
| argument-hint | [Model/ActionName] |
| user-invocable | true |
| allowed-tools | Read Grep Bash Edit Write Glob |
Create a Laractions action class following the project's conventions, and register it in the corresponding model.
| Subcommand | Description |
|---|---|
| (no argument) | Prompt for model name and action name, then generate. |
[Model/ActionName] | Generate the specified action class and register it in the model. |
This is a generator skill -- it always creates files. There is no analyze-only or fix mode.
Grep to check if edulazaro/laractions exists in composer.json.Laractions is not installed. Install it with:
composer require edulazaro/laractions
Read the installed Action.php from vendor to understand the current API:
Read to load vendor/edulazaro/laractions/src/Action.php.create(), run(), dispatch(), handle()queue(), delay(), retry()actor(), on(), with()trace(), enableLogging(), log()$rules for validation$tries, $delay, $queue class propertiesvendor/edulazaro/laractions/src/Concerns/HasActions.php to understand the trait.The argument should be in the format Model/ActionName (e.g., Property/ToggleShowcase, Client/CreateCopyForGroup).
/, split into model name and action name./ is provided, ask the user for both the model name and the action name.Derive the following:
PropertyToggleShowcaseAction (append Action suffix if not already present)toggle_showcase (snake_case of the action name without the Action suffix)app/Actions/{Model}/{ActionClass}.phpGlob to find existing actions in app/Actions/{Model}/ directory.Read to examine one or two to understand:
$rules, trace(), enableLogging(), etc.app/Models/{Model}.php) to understand:
$actions array (existing action registrations)HasActions)Create the file using Write at app/Actions/{Model}/{ActionClass}.php:
<?php
namespace App\Actions\{Model};
use App\Models\{Model};
use EduLazaro\Laractions\Action;
class {ActionClass} extends Action
{
protected {Model} ${model};
public function handle(): void
{
// Action logic here
}
}
Key requirements:
App\Actions\{Model}EduLazaro\Laractions\Actionprotected Property $property)use statements, never inline qualified class names.text() helper for any translatable strings (Laratext, not __())IMPORTANT: Generate only the clean skeleton by default. Do NOT add $rules, $tries, $delay, $queue, trace(), enableLogging(), or log() unless the user explicitly asks for them. The generated action should be minimal:
class {ActionClass} extends Action
{
protected {Model} ${model};
public function handle(): void
{
//
}
}
Validation rules (user asks for validation):
protected array $rules = [
'email' => 'required|email',
'name' => 'required|string|max:255',
];
Queue configuration (user asks for async/queue support):
protected int $tries = 3;
protected int $delay = 0;
protected string $queue = 'default';
Logging (user asks for logging):
$this->log('Starting operation', ['id' => $this->{model}->id]);
Read to load the model file at app/Models/{Model}.php.$actions array property.Edit to add the new action registration:protected array $actions = [
// ... existing actions
'action_key' => ActionClass::class,
];
use import for the new action class at the top of the model file if not already present.If the model does not have:
use EduLazaro\Laractions\Concerns\HasActions; trait -- add it$actions array property -- create itRead to verify the action class file was created correctly.Read to verify the model was updated correctly.php -l on both files to check syntax (Docker-aware: detect container from docker-compose.yml).EduLazaro\Laractions\Action$actions is snake_caseuse import is present in the model fileHasActions trait is used in the modelAfter successful creation, show how to use the action:
// Synchronous execution
$result = ${model}->action('action_key')->run($param1, $param2);
// With named parameters
$result = ${model}->action('action_key')
->with(['param1' => $value1])
->run();
// Asynchronous execution (queued)
${model}->action('action_key')
->queue('default')
->dispatch($param1, $param2);
// With delay and retries
${model}->action('action_key')
->queue('default')
->delay(60)
->retry(3)
->dispatch($param1);
// With actor tracking
$user->act(ActionClass::class)
->on(${model})
->run($param1);
// With audit trail
${model}->action('action_key')
->trace()
->run($param1);
// With logging enabled
${model}->action('action_key')
->enableLogging()
->run($param1);
Based on common patterns in the project, here are templates for different action types:
public function handle(array $data): void
{
$this->{model}->update($data);
}
public function handle(Organization|int|string $organization, int|string|null $officeId = null): {Model}
{
$orgInstance = $organization instanceof Organization ? $organization : Organization::find($organization);
return {Model}::create([
'organization_id' => $orgInstance->id,
'office_id' => $officeId,
// ... copy fields from $this->{model}
]);
}
public function handle(): void
{
$this->{model}->update([
'active' => !$this->{model}->active,
]);
}
protected array $rules = [
'name' => 'required|string',
];
public function handle(): array
{
$errors = [];
if (!$this->{model}->name) {
$errors[] = text('name_required', 'Name is required');
}
return $errors;
}
public function handle(array $oldValues, array $newValues): void
{
foreach ($newValues as $field => $newValue) {
$oldValue = $oldValues[$field] ?? null;
if ($oldValue !== $newValue) {
Activity::create([
'activitable_type' => '{model}',
'activitable_id' => $this->{model}->id,
'field' => $field,
'old_value' => $oldValue,
'new_value' => $newValue,
]);
}
}
}
protected int $tries = 3;
protected int $delay = 0;
protected string $queue = 'default';
public function handle(): void
{
$this->log('Starting heavy operation', ['id' => $this->{model}->id]);
// ... heavy logic (API calls, file processing, etc.) ...
$this->log('Operation completed');
}
public function handle(string $reason = ''): void
{
$this->{model}->update(['status' => 'approved']);
// Actor is available via $this->actor if set
}
Actions can be dispatched to a queue for asynchronous processing:
// Basic queue dispatch
$model->action('action_name')->dispatch($param1);
// Specify queue name
$model->action('action_name')->queue('emails')->dispatch($param1);
// With delay (seconds)
$model->action('action_name')->delay(120)->dispatch($param1);
// With retry attempts
$model->action('action_name')->retry(5)->dispatch($param1);
// Full configuration
$model->action('action_name')
->queue('high')
->delay(60)
->retry(3)
->dispatch($param1, $param2);
No special code is needed in the action class itself for basic queue support. Laractions wraps the action in an ActionJob (implements ShouldQueue) automatically.
For actions that should always run on a specific queue, set class-level defaults:
protected int $tries = 3;
protected int $delay = 0;
protected string $queue = 'emails';
protected Property $property, protected Client $client).__invoke(), so they can be used as callables: $action($param) is equivalent to $action->run($param).HasActions support mockAction() to replace actions with mocks.