agentleFS
pekralpekral/cursor-rules/skills/refactor-entry-point-to-action/SKILL.md

refactor-entry-point-to-action

Skill10 starsChanged 3 months agoMITView on GitHub

Use when refactoring controller, job, command, listener, or Livewire entry-point logic into a dedicated Action class while preserving behavior and response contracts.

We split this skill into the rules it gives an agent

21 rules. About 0 are common, 11 are distinctive, and 10 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈11

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 10

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    If the current project uses Laravel, also apply @rules/laravel/laravel.mdc, @rules/laravel/architecture.mdc, @rules/laravel/filament.mdc, …

    line 19
  2. Distinctive:

    Do not report review output to any third-party service.

    line 21
  3. Very specific:

    After changes (MODE=apply only), run an internal architecture-first review and fix important findings immediately.

    line 22
  4. Very specific:

    Create one dedicated Action per use case under app/Actions/<Domain>/.

    line 43
  5. Distinctive:

    Do not place inline data mapping/transformation inside the Action.

    line 50
  6. Very specific:

    Do not use direct Eloquent queries or DB:: calls inside the Action.

    line 51
  7. Very specific:

    Keep reads in repositories (Pekral\Arch\Repository\Mysql\BaseRepository) and writes/updates/deletes in model managers …

    line 52
  8. Distinctive:

    Add or update PHPDoc where needed for PHPStan clarity.

    line 54
  9. Distinctive:

    Only after Read, Map, and Verify are complete may the Test Coverage Gate and the extraction proceed.

    line 67
  10. Distinctive:

    Create or reuse a dedicated Action in the correct domain folder.

    line 76
  11. Very specific:

    Update the entry point to delegate via $action(...) and keep its public contract unchanged.

    line 80
  12. Very specific:

    Run @skills/process-code-review/SKILL.md inline (per its own contract) and fix critical or medium findings before finishing.

    line 84
  13. Distinctive:

    Do not leave business orchestration in the entry point.

    line 87
  14. Very specific:

    Do not place Actions outside app/Actions/.

    line 88
  15. Distinctive:

    Do not add multiple public business methods to an Action.

    line 89
  16. Very specific:

    Do not place validation logic directly inside an Action (incl.

    line 90
  17. Distinctive:

    Do not place data mapping/transformation directly inside an Action — extract into a Data Builder.

    line 91
  18. Distinctive:

    Do not return or construct an HTTP response inside an Action — the Action returns domain data, the controller builds the response.

    line 92
  19. Very specific:

    Do not bypass repository/model-manager/service boundaries.

    line 93
  20. Distinctive:

    Do not introduce unrelated behavioral changes.

    line 94
  21. Distinctive:

    After the refactor, coverage scoped to the changed files was re-verified and stayed 100% with the pre-existing assertions passing unchanged.

    line 105

≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Modes

This skill runs in one of two modes, selected by the caller via MODE (default apply):

  • apply (default) — perform the entry-point → Action refactoring: create / update the Action, move orchestration, run fixers / checkers, and chain the After Completion review. The Execution and Done-when steps below behave as written.
  • cr (read-only lens — invoked by @skills/code-review/SKILL.md, code-review-github, code-review-jira) — never modify code, never create files, never stage / commit / push, never run fixers or checkers, and never chain code-review / process-code-review. Scope the analysis to entry points (controller / job / command / listener / Livewire) touched by the PR diff that still hold business orchestration, and return — as markdown only — the proposed Action extraction for each: the entry-point Class::method, the orchestration that should move out, the target app/Actions/<Domain>/<ActionName> and Data Validator, and the rule reference. The CR folds these into its Refactoring (DRY / tech debt) section (in-scope) or Refactoring proposals section (out-of-scope). Execution steps 3–11 below apply to MODE=apply only.

Constraints

  • Apply @rules/refactoring/general.mdc — incremental migration only, never a big-bang rewrite. The Test Coverage Contract in that rule is binding: 100% coverage of the target lines must exist in a dedicated test(scope): cover <area> before refactor commit before the entry-point change lands, and the assertion logic of those tests must remain unchanged through the refactor commit.
  • Apply @rules/php/core-standards.mdc.
  • If the current project uses Laravel, also apply @rules/laravel/laravel.mdc, @rules/laravel/architecture.mdc, @rules/laravel/filament.mdc, and @rules/laravel/livewire.mdc
  • Preserve behavior, signatures, response contracts, and tenant/account scope. Rewrite the entry-point code strictly per the applied rules — anything that would deviate (parameter count, naming, nesting, layer placement, validation home) is rewritten until it complies.
  • Do not report review output to any third-party service.
  • After changes (MODE=apply only), run an internal architecture-first review and fix important findings immediately. In MODE=cr there are no changes — emit the Action-extraction proposal and stop.

Use when

  • A controller, job, command, listener, or Livewire component method contains business orchestration that should be moved into an Action.
  • You want a thin entry point that delegates one use case to one Action.

Manual invocation in Cursor

Always include:

  • Entry-point file path
  • Target method (Class::method)
  • Expected Action class name and domain folder (optional — the skill proposes a default name and domain when not provided, instead of asking the user)
  • Any response/signature compatibility constraints

Example input:

  • Refactor entry point <Class::method> in <path> to Action pattern.
  • Keep behavior and response contract unchanged.
  • Create or reuse Action in app/Actions/<Domain>/<ActionName>.php and delegate from the entry point.
  • Respect @rules/laravel/architecture.mdc.

Required architecture

  • Entry point must become thin and delegate directly to an Action via $action(...).
  • Create one dedicated Action per use case under app/Actions/<Domain>/.
  • Action class must be final readonly.
  • Action must expose exactly one public business method: __invoke(...) with an explicit return type.
  • The Action returns a typed DTO for any structured result, never a raw array. When the extracted use case hands back more than one value, declare a final readonly DTO under app/Dto/<Domain> with the Data suffix and return that — an associative array, a multi-key payload, or an array shape with named keys is never an Action return type, and the framework / vendor-contract exemption does not apply to a project-owned __invoke(). Scalars, void, an Eloquent model, and homogeneous lists / Collections of one type need no wrapper. Where the entry point previously built an array inline, the shaping moves to a Data Builder or a DTO named constructor and the controller serializes the DTO at the response boundary — the array does not survive the refactor (see @rules/laravel/architecture.mdc Action return contract: a DTO, never an array).
  • Action must orchestrate only: it delegates validation, mapping, and persistence to the dedicated layers.
  • The Action returns plain domain data, never an HTTP response. Keep response() / response()->json() / redirect() / back() / view() and any Response / JsonResponse / RedirectResponse construction in the entry point — the controller stays the owner of client↔server communication. The Action's __invoke() returns a Model / DTO / Collection / scalar / void, and the controller builds the HTTP response from it. This is part of preserving the response contract.
  • Do not place inline validation inside the Action. Extract every validation-style guard — instanceof / null / range / amount checks that reject or skip input via throw, return, or continue, plus throw_if() / throw_unless() calls — into a dedicated Data Validator (default location app/DataValidators/<Domain>/, but follow the project's existing convention; Pekral\Arch\DataValidation\DataValidator trait when the package is installed). Every validation rule set the refactor touches lives as a reusable trait in app/Concerns/ — Data Validators and the entry point's FormRequest both compose their rules from those traits, and a rule array is never left inline in rules(), in a Livewire validate() call, or in the Data Validator itself. Extract the trait even when only one class consumes it today (see @rules/laravel/architecture.mdc Validation Rules (Traits)).
  • Do not place inline data mapping/transformation inside the Action. Any payload-building, model/collection mapping, key renaming, default fallback, or value formatting (e.g. a private buildPayload() helper) must be extracted into a Data Builder (Pekral\Arch\DataBuilder\DataBuilder trait when the package is installed) that the Action calls.
  • Do not use direct Eloquent queries or DB:: calls inside the Action.
  • Keep reads in repositories (Pekral\Arch\Repository\Mysql\BaseRepository) and writes/updates/deletes in model managers (Pekral\Arch\ModelManager\Mysql\BaseModelManager) / services according to project architecture.
  • When the orchestration touches the database in a loop, prefer ModelManager batch methods (batchUpdate, batchInsert) and bulk delete/read patterns (whereIn(...)->delete(), findBy{Attribute}In(...) keyed in memory) over per-row queries (see @rules/sql/optimalize.mdc "Batch over per-row operations"). Per-row queries inside the Action are allowed only when iterations have an unavoidable side-effect dependency that must be justified in a code comment.
  • Add or update PHPDoc where needed for PHPStan clarity.
  • Livewire entry points — Blade view co-refactor. When the entry point being refactored is a Livewire component, also inspect its Blade view (resources/views/livewire/<...>.blade.php). Walk it against the triggers in @rules/laravel/livewire.mdc HTML / Blade Layout Splitting (repeated markup, >150 Blade lines, self-contained wire:* cluster, self-contained data shape, cross-page reuse, independent loading / empty / error state, distinct named UI concern). For every match, propose the extraction in the refactor plan: name the extracted concern, pick the correct component type per the rule's Component-type decision (Livewire only for stateful / lifecycle / server-interactive blocks; Blade for stateless presentation — never a Livewire wrapper around a pure presentational block), and place the new component under the concern's domain folder (app/Livewire/<Domain>/ or resources/views/components/<domain>/). The extracted children must satisfy the Reusability contract in the rule (typed input, one concern, no business logic, events not parent reach-through, independently renderable, concern-based name). Apply-mode requirement: the extractions must land in a dedicated refactor(scope): split <view> into reusable components commit that follows the Action-extraction commit and respects the Test Coverage Contract in @rules/refactoring/general.mdc in spirit — every rendered branch of the touched view is covered by a Livewire / Blade feature test committed before the layout refactor, and those feature tests stay green through the refactor commit unchanged. PHP --coverage-clover does not measure .blade.php line-by-line, so the binding gate is feature-test parity, not a numeric coverage percentage on the view file. CR-mode requirement: the proposals must be emitted as markdown findings (file:line, concern name, Livewire-vs-Blade choice, target folder, rule reference) and the skill stops without modifying code.

Read, Map & Verify before refactoring (mandatory pre-flight)

MODE=cr: perform Read and Map read-only to ground the extraction proposal in the real code; Verify is the read-only audit. Do not modify code.

Reading, mapping, and verifying come first; refactoring comes last. This pre-flight is blocking — do not edit a single line of production code until all three steps pass, and never act on an assumption you have not confirmed by reading the code.

  1. Read — open and read the actual entry point and the code it orchestrates (called Services / Repositories / ModelManagers, the Blade view for Livewire components, related tests, configuration). Confirm what the orchestration does by reading it, not by guessing from names.
  2. Map — map the change's blast radius: the entry point's response contract and signature, its callers and routes, the orchestration that must move into the Action, and the existing Actions / Data Validators / app/Concerns/ traits to reuse instead of reinventing.
  3. Verify — check your assumptions against the real code and its observed behavior so the extraction preserves behavior, signatures, and tenant/account scope. If reading and mapping contradict the task framing, stop and surface the discrepancy instead of refactoring on a wrong premise.

Only after Read, Map, and Verify are complete may the Test Coverage Gate and the extraction proceed.

Execution

MODE=cr: run steps 1–2 read-only, then emit the Action-extraction proposal described under Modes and stop — do not run steps 3–12 (they author tests, create files, run fixers, and chain reviews).

  1. Inspect the target entry point and identify orchestration responsibilities.
  2. Scan touched files for obvious pre-existing issues that would block or compromise the refactor. Fix only safe, relevant issues; keep unrelated cleanup out of scope.
  3. Test Coverage Gate (blocking pre-flight). Verify coverage of the current entry-point method that the refactor will touch, using the project's available coverage tooling scoped to that file (per @rules/php/core-standards.mdc Testing section). Every line, branch, and condition must already be at 100%. If coverage is below 100% on the target lines, stop and write the missing tests first via @skills/create-test/SKILL.md, then commit them in a dedicated test(scope): cover <area> before refactor commit per @rules/git/general.mdc Allowed Types. The pre-refactor coverage commit and the refactor commit are always two separate commits. Only after the gate is green may the refactor proceed.
  4. Create or reuse a dedicated Action in the correct domain folder.
  5. Move orchestration from the entry point into the Action __invoke(...).
  6. Extract inline validation into a dedicated Data Validator (using validation traits from app/Concerns/) if needed.
  7. Preserve repository/service/manager boundaries and multitenancy/account scope.
  8. Update the entry point to delegate via $action(...) and keep its public contract unchanged.
  9. Do not modify assertion logic of pre-existing tests inside the refactor commit. The pre-refactor coverage commit fixed the behavior-preservation contract; the refactor commit changes structure only. Mechanical renames forced by the refactor itself (namespace move, constructor / argument shape forced by the extracted DTO) are the only allowed test edits and must be flagged in the commit body. If an assertion would have to change to make the refactor green, you are no longer refactoring — split the behavior change into its own commit. New tests covering newly introduced code paths (e.g. the Data Validator's failure modes that did not exist before) belong in a separate test(scope): … commit after the refactor. After the refactor commit, re-run the coverage tooling scoped to the changed files and confirm coverage stayed 100% with the pre-existing assertions passing unchanged — a refactored line that is no longer covered signals an untested path to fix, never a number to restore by editing the pre-refactor tests (step 4 of the Test Coverage Contract in @rules/refactoring/general.mdc).
  10. Discover available fixers and checkers (prefer Phing targets from build.xml/phing.xml; fall back to Composer scripts in composer.json). Run fixers first, then checkers/analyzers on all changed files. Resolve all reported issues by rewriting the flagged code, never by adding a suppression annotation (@rules/php/core-standards.mdc PHP Practices).
  11. Run the review inline. Invoke @skills/code-review/SKILL.md directly in this skill's context, passing the refactor commit range plus the instruction to return Critical / Moderate / Minor findings with their reproducer fields. Do not dispatch the review as a subagent — run it sequentially in the current context.
  12. Run @skills/process-code-review/SKILL.md inline (per its own contract) and fix critical or medium findings before finishing.

Do not

  • Do not leave business orchestration in the entry point.
  • Do not place Actions outside app/Actions/**.
  • Do not add multiple public business methods to an Action.
  • Do not place validation logic directly inside an Action (incl. instanceof / null / amount skip-guards and throw_if() / throw_unless()) — extract into a Data Validator.
  • Do not place data mapping/transformation directly inside an Action — extract into a Data Builder.
  • Do not return or construct an HTTP response inside an Action — the Action returns domain data, the controller builds the response.
  • Do not bypass repository/model-manager/service boundaries.
  • Do not introduce unrelated behavioral changes.
  • Do not add speculative flexibility, configurability, or error handling while extracting the Action. The extraction moves orchestration as-is into the Action and the Data Validator; new parameters, mode switches, strategy hooks, retry knobs, or guards for scenarios the original entry point did not handle belong to a separate feat(scope): … commit and a separate issue. Apply the Simplicity First rule from @skills/class-refactoring/SKILL.md Refactoring Guidelines and the YAGNI rules in @rules/php/core-standards.mdc Design Principles.

Done when

MODE=apply:

  • The target entry point is thin and delegates to a dedicated Action.
  • The Action follows project Action-pattern rules.
  • Validation is delegated to a dedicated Data Validator (using validation traits from app/Concerns/) when applicable.
  • Behavior, signatures, and response format remain unchanged.
  • The pre-refactor coverage commit reports 100% coverage on the entry-point lines that were refactored, and the assertion logic in those tests is unchanged through the refactor commit (mechanical renames flagged in the commit body excepted).
  • After the refactor, coverage scoped to the changed files was re-verified and stayed 100% with the pre-existing assertions passing unchanged.
  • New tests covering paths introduced by the refactor (e.g. Data Validator failure modes) live in a separate test(scope): … commit after the refactor.
  • Fixers and checkers ran clean on all changed files.
  • Internal architecture-focused review was completed and important findings were fixed.

MODE=cr: the Action-extraction proposal was emitted as markdown for every qualifying entry point in the diff (entry-point Class::method, orchestration to move out, target Action / Data Validator, rule reference) and no files were created or modified.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.