Install
$ agentstack add skill-foysal50x-skills-laravel-patterns ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Laravel Patterns
Placement rules for domain-driven Laravel applications: Action, Service, Repository, Query Class, Value Object. 60 rules across 9 sections.
Core philosophy: practicality over purity. Never take a greedy decision.
- Eloquent is already a good abstraction for most data access.
- A Repository over Eloquent does not fully decouple you from Eloquent. That is acceptable and expected — do not chase purity.
- Both extremes are bugs: a layer for every model (dead boilerplate) and none at all (queries scattered everywhere).
- A Query Class is the internal implementation technique of a Repository, not a competing pattern.
- Value Objects keep signatures clean and carry pure behavior. They never touch a
Builder. - Domains are bounded contexts. One domain never imports another's internals.
When to Apply
Reference these rules when:
- Creating any class under
app/Domain/ - Deciding between a Service, a Repository and inline code
- Reviewing a pull request that adds a layer
- Refactoring queries scattered across Actions, Services or Blade
- Splitting a monolithic
app/into bounded contexts - Wiring one domain to another
Start Here
Run the Decision Gate before writing any class: references/decision-gate.md.
Default answer: keep it in the Action, use Eloquent directly.
Q1. Single end-to-end use case? → ACTION
Q2. Called by 2+ Actions, or worth isolating? → SERVICE
Q3. Used in only one Action? → KEEP IT IN THE ACTION
Q4. Single-record CRUD (find / create /
update / delete)? → ELOQUENT DIRECTLY
(from an Action or Repository)
Q5. Backend may swap, OR the query earns a
name and its own tests? → REPOSITORY (+ Query Classes)
Ambiguous between Q4 and Q5? Choose Q4 — except for a list endpoint, which is always Q5.
Non-Negotiables
These are the mistakes that survive review because each one looks locally reasonable:
- Query construction never appears in a Controller, Form Request, Resource, Blade view or Middleware — however small the query is.
- A paginated, filtered or ownership-scoped list is a named query behind a Repository, not "simple CRUD".
- An Action that only forwards to one collaborator is deleted; the caller calls the collaborator.
- An interface, its implementation and its container binding land in the same change. Never an empty
Repositories/. - One concept has one home: a shared module owns the mechanism, each domain owns the content describing its own data.
- Every route is authorized in exactly one place — see the
laravel-rest-apiskill.
Pick the Rule
| About to write | Read | |----------------|------| | Any new class under app/Domain/ | gate-run-decision-gate-first | | An index / list / search endpoint | gate-reads-go-through-a-named-query, query-whitelist-sortable-columns | | A create, update or delete use case | gate-action-for-use-case, action-one-use-case-end-to-end | | An Action that only calls one thing | action-not-a-pass-through | | A Repository interface | gate-repository-earns-its-name, repo-ship-implementation-and-binding | | A query with filters, sorting or eager loads | query-owns-all-query-construction, query-single-handle-method | | Logic a second Action now needs | gate-service-only-when-reused | | A method with more than four parameters | vo-more-than-four-params, vo-group-related-parameters | | Code that touches another domain | domain-no-cross-domain-models, domain-events-for-reactions | | A notification, report or export class | layout-shared-module-owns-mechanism | | Anything reading configuration | config-never-env-outside-config | | A sort or filter arriving as a string | vo-named-constructor-parses-input | | A file you cannot place | layout-scope-based-co-location |
Build Order
A vertical slice lands in this order — each step exists only if the step above it earned it:
Contracts/RepositoryInterface.php— the Q5 trigger named in the docblockQueries/Query.php— onehandle(), all clausesRepositories/EloquentRepository.php— implements the interface- the binding in
DomainServiceProvider— same change, never later Actions/Action.php— only when state changes- the edge: Form Request → Controller → Resource (
laravel-rest-api) - tests per layer (
laravel-testing)
Before You Write Code
- Every API named in these rules is verified against Laravel
^12.0 || ^13.0and PHP^8.3. If you need something these rules do not name, check the docs — never infer an API from its name. - Version-gated APIs are marked inline ("Laravel 13 only"). Read the project's
composer.jsonfirst; on Laravel 12 use the fallback the rule gives. - Where the project already differs from a rule, follow the project. Name the rule you set aside and why, rather than half-converting the codebase.
- When two rules collide, the higher-impact section wins — sections are ordered by impact.
- One example is not the whole rule. Open
rules/{slug}.mdbefore adapting it to a case the example does not show.
Rule Sections by Priority
| # | Section | Impact | Prefix | |---|---------|--------|--------| | 1 | The Decision Gate | CRITICAL | gate- | | 2 | Actions | HIGH | action- | | 3 | Services | HIGH | service- | | 4 | Repositories | HIGH | repo- | | 5 | Query Classes | HIGH | query- | | 6 | Value Objects and Parameter Isolation | MEDIUM-HIGH | vo- | | 7 | Directory and Namespace Layout | MEDIUM | layout- | | 8 | Inter-Domain Communication | HIGH | domain- | | 9 | Configuration and Environments | MEDIUM | config- |
Quick Reference
1. The Decision Gate (CRITICAL)
gate-run-decision-gate-first— Name the trigger before creating any classgate-action-for-use-case— One use case means one Actiongate-service-only-when-reused— Extract a Service only when two Actions need itgate-eloquent-directly-by-default— Use Eloquent directly by defaultgate-repository-earns-its-name— A Repository must name its triggergate-query-class-and-repository-together— Query Classes and Repositories arrive togethergate-reads-go-through-a-named-query— A list endpoint is a named query
2. Actions (HIGH)
action-one-use-case-end-to-end— An Action orchestrates one use case end to endaction-keep-single-use-logic-inline— Keep single-use logic inside the Actionaction-naming-verb-noun— Name ActionsActionaction-maps-request-to-value-objects— Map HTTP input to domain types at the edgeaction-not-a-pass-through— Never create an Action that only forwards
3. Services (HIGH)
service-two-or-more-actions— A Service serves two or more Actionsservice-stateless-and-focused— Services are stateless and context-agnosticservice-never-imports-query-classes— A Service never imports a Query Classservice-not-a-disguised-repository— A Service whose body is a query is a mislabeled Repositoryservice-naming-business-decision— Name Services after the business decision
4. Repositories (HIGH)
repo-interface-in-domain-contracts— Interface inContracts/, implementation inRepositories/repo-domain-intent-methods— Repository methods express intent, not CRUDrepo-never-returns-builder— A Repository interface never returns aBuilderrepo-never-accepts-request— A Repository never accepts aRequestrepo-no-base-repository— No genericBaseRepositoryrepo-small-focused-interface— Keep Repository interfaces under ~6 methodsrepo-bind-in-service-provider— Bind the interface in a service providerrepo-ship-implementation-and-binding— Interface, implementation and binding in one changerepo-inline-simple-delegate-complex— Inline simple queries, delegate complex ones
5. Query Classes (HIGH)
query-single-handle-method— Exactly one public method,handle()query-internal-to-repositories— Query Classes are internal to Repositoriesquery-name-the-business-question— Name the business question, not the DB operationquery-final-readonly-no-base-class— Plainfinal readonly, no abstract basequery-can-write— A Query Class may writequery-return-builder-or-execute— Return aBuilderor execute, one per queryquery-compose-query-classes— Compose instead of duplicating clausesquery-whitelist-sortable-columns— Whitelist sortable columns in the Query Classquery-owns-all-query-construction— All query construction lives here
6. Value Objects and Parameter Isolation (MEDIUM-HIGH)
vo-group-related-parameters— Group contextually related parametersvo-more-than-four-params— More than four parameters must be groupedvo-never-touches-builder— A Value Object never touches aBuildervo-no-single-scalar-wrapper— Never wrap a single unrelated scalarvo-pass-domain-objects-directly— Pass essential domain objects directlyvo-date-range-and-presets— Express named date ranges through an interfacevo-parameterized-presets— Parameterize presets instead of copying classesvo-composite-filter-per-query— Collapse a query's inputs into one composite filtervo-named-constructor-parses-input— Parse the wire format in a named constructor
7. Directory and Namespace Layout (MEDIUM)
layout-domain-first-structure— Organize by domain, not by layerlayout-scope-based-co-location— Scope decides placementlayout-no-top-level-service-repository-query— No top-level layer folderslayout-optional-folders-are-deliberate— A missing folder is a decisionlayout-contracts-vs-support—Contracts/holds interfaces,Support/holds implementationslayout-shared-module-owns-mechanism— A shared module owns the mechanism, not other domains' messages
8. Inter-Domain Communication (HIGH)
domain-public-vs-private-surface— A domain has a public surface and a private onedomain-no-cross-domain-models— Never import another domain's Models, Repositories or Queriesdomain-events-for-reactions— Use Domain Events for cross-domain reactionsdomain-open-host-service-for-sync— Use an Open Host Service for synchronous readsdomain-shared-kernel-concepts-only— The Shared Kernel holds concepts, never callsdomain-anti-corruption-layer— Wrap external upstreams in an Anti-Corruption Layer
9. Configuration and Environments (MEDIUM)
config-secrets-in-env-structure-in-config— Secrets in.env, structure inconfig/config-never-env-outside-config— Never callenv()outsideconfig/config-per-environment-overrides— Override per environment, not per branchconfig-cache-in-production— Cache config, routes and events in production
Reference Material
Read on demand — do not load all of these at once:
references/decision-gate.md— the gate, layer definitions, who may call whatreferences/directory-layout.md— full tree, folder meanings, CI guardsreferences/inter-domain-decision-guide.md— picking Event vs Open Host Service vs Shared Kernel vs ACLreferences/anti-patterns.md— 18 forbidden patterns with their grep signalsreferences/pre-completion-checklist.md— 31-question self-check before declaring doneexamples/orders-domain/— one worked vertical slice with every layer in place
How to Use
Load in this order and stop when the answer is clear:
- This file — the Quick Reference names every rule, and usually settles the question.
- One rule file for the reasoning and both examples (~405 tokens each):
rules/gate-eloquent-directly-by-default.md
rules/query-internal-to-repositories.md
- A
references/file only when a rule points at one.
AGENTS.md is every rule compiled into one document (~22k tokens), for agents that read the AGENTS.md convention. Do not load it when the individual rule files are reachable.
Related Skills
laravel-eloquent— what goes inside a Query Class: casts, scopes, N+1, pagination, transactions, raw SQLlaravel-rest-api— the edge: routing, binding, form requests, resources, authorization, error mappinglaravel-async— events, queued jobs, caching and schedulinglaravel-testing— how to test each layer defined here
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: Foysal50x
- Source: Foysal50x/skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.