Install and use Grant's enum-first roles and native Laravel Gate integration.
php artisan boost:add-skill shipfastlabs/grant
Save this content to: .claude/skills/grant-development/SKILL.md
# Grant
Use this skill when a Laravel application needs enum-defined roles and permissions with database-backed assignments.
## Primary Goal
Apply `shipfastlabs/grant` while keeping every authorization check in Laravel's native Gate API.
## Workflow
1. Install and migrate with `php artisan grant:install && php artisan migrate`.
2. Define string-backed `App\Enums\Permission` cases implementing `Shipfastlabs\Grant\Ability` and denial messages.
3. Adjust the generated string-backed `App\Enums\Role` implementing `Shipfastlabs\Grant\Role`. It ships with `Admin` mapped to all permissions and `Member` mapped to none.
4. Add `Shipfastlabs\Grant\HasRoles` to the auth user model configured in `auth.providers.users.model`.
5. Assign with `grant`, `revoke`, or `syncRoles`; the user must be persisted, and `on:` accepts another persisted model as the scope.
6. Check only with `can()`, `Gate`, `@can`, `can:` middleware, Form Requests, or Policies.
7. Use `#[Requires(Permission::...)]` on a policy method when capability and model-context checks should compose; a denial carries that permission's `deniedMessage()`.
## References
- `config/grant.php` — enum classes, super-admin role, and the assignment model class
- `app/Enums/Permission.php` and `app/Enums/Role.php` — application definitions
- `php artisan grant:list` — registered permissions
- `php artisan grant:show {user} --on='ModelClass:id'` — resolved assignments
- `php artisan grant:sync` — after changing a role's value or removing a case, remap or delete the stored assignments that no longer match; `--no-interaction` only reports them and fails
- `Shipfastlabs\Grant\Models\RoleAssignment` — Eloquent model for `role_assignments`, extend it and set `grant.model` to customize; `$user->roleAssignments` exposes the rows
- `Shipfastlabs\Grant\Facades\Grant` — `grant`, `revoke`, `syncRoles`, `hasRole`, `roles`, `permissions` when a model method is not convenient
- Publish tags: `grant` (everything), `grant-config`, `grant-migrations`
## Examples
```php
$user->grant(Role::Editor);
$user->grant(Role::Admin, on: $team);
$user->can(Permission::EditPosts);
$user->can(Permission::EditPosts, $team); // scoped roles fall back to global roles
```
For tests, add `Shipfastlabs\Grant\Testing\InteractsWithGrant` to the base test case, then use `assertCan`, `assertCannot`, and `withRole`. Add a factory state that calls `grant()` in `afterCreating` to seed roles.
## Anti-patterns
- Do not add a package-specific check wrapper; use Laravel Gate.
- Do not check roles for authorization; check permissions.
- Do not store role or permission definitions in the database.
- Do not put ownership or model-state rules in role definitions; keep them in Policies.
- Assignments are memoized per user for the request (scoped binding). Grant writes and `RoleAssignment` model events clear it; after bulk query builder writes call `Grant::flush($user)`.
- The super-admin bypass only applies to the role granted globally, never scoped.
- No admin plugin: manage roles in Filament with a multiple `Select` bound to `roles()` and `syncRoles()`; see the README section.
Use this skill when a Laravel application needs enum-defined roles and permissions with database-backed assignments.
Apply shipfastlabs/grant while keeping every authorization check in Laravel's native Gate API.
php artisan grant:install && php artisan migrate.App\Enums\Permission cases implementing Shipfastlabs\Grant\Ability and denial messages.App\Enums\Role implementing Shipfastlabs\Grant\Role. It ships with Admin mapped to all permissions and Member mapped to none.Shipfastlabs\Grant\HasRoles to the auth user model configured in auth.providers.users.model.grant, revoke, or syncRoles; the user must be persisted, and on: accepts another persisted model as the scope.can(), Gate, @can, can: middleware, Form Requests, or Policies.#[Requires(Permission::...)] on a policy method when capability and model-context checks should compose; a denial carries that permission's deniedMessage().config/grant.php — enum classes, super-admin role, and the assignment model classapp/Enums/Permission.php and app/Enums/Role.php — application definitionsphp artisan grant:list — registered permissionsphp artisan grant:show {user} --on='ModelClass:id' — resolved assignmentsphp artisan grant:sync — after changing a role's value or removing a case, remap or delete the stored assignments that no longer match; --no-interaction only reports them and failsShipfastlabs\Grant\Models\RoleAssignment — Eloquent model for role_assignments, extend it and set grant.model to customize; $user->roleAssignments exposes the rowsShipfastlabs\Grant\Facades\Grant — grant, revoke, syncRoles, hasRole, roles, permissions when a model method is not convenientgrant (everything), grant-config, grant-migrations$user->grant(Role::Editor);
$user->grant(Role::Admin, on: $team);
$user->can(Permission::EditPosts);
$user->can(Permission::EditPosts, $team); // scoped roles fall back to global roles
For tests, add Shipfastlabs\Grant\Testing\InteractsWithGrant to the base test case, then use assertCan, assertCannot, and withRole. Add a factory state that calls grant() in afterCreating to seed roles.
RoleAssignment model events clear it; after bulk query builder writes call Grant::flush($user).Select bound to roles() and syncRoles(); see the README section.How can I help you explore Laravel packages today?