action-pattern
Creating and using action classes to encapsulate business logic.
Skill by ceilidhboy
Install
Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.
npx agentmarket install skill/ceilidhboy-action-pattern
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions
What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.
- Tools
- No tools found
- Secrets
- None asked for
- Install scripts
- None found
Network hosts it talks to 1
codeload.github.com· found in install command
Files it touches
~/.claude/skills/action-pattern
What's inside
- Skill name
action-pattern- Description
- Creating and using action classes to encapsulate business logic. Actions replace traditional Service classes with reusable, composable, single-responsibility classes that follow a consistent `execute()` convention.
- License
- MIT
- Instructions
- 287 lines in SKILL.md · view on GitHub
Files (1)
- SKILL.md
SKILL.md (first lines)
# Action Pattern
## Overview
The Action pattern encapsulates business logic into reusable, composable, single-responsibility classes. Actions replace traditional "Service" classes and provide a clean, testable way to organize application behavior.
## Core Principles
### 1. Single Responsibility Principle (SRP)
Each action should have **one reason to change**. If a class is doing multiple things, it should be split into multiple actions, not multiple methods within the same class.
**Key Question**: Does this action have more than one responsibility? If yes, split it into separate actions.
**Note**: This same principle applies to **tasks** in the task list. See [single-task-responsibility](../single-task-responsibility/SKILL.md) skill for guidance on recognizing when task implementation violates SRP and requires stopping to consult the user.
### 2. The `execute()` Method
Every action **must** have a public `execute()` method. This is the convention and must not be flexible.
- **Method signature**: Parameters and return type depend entirely on the action's functionality
- **Naming**: Always `execute()` — never `handle()`, `__invoke()`, or other alternatives
- **Statelessness**: The method should be callable multiple times with different parameters without side effects
**One exception — vendor interfaces.** A class implementing a framework interface whose contract names the method keeps that name: the interface is the authority, not this convention. Laravel Fortify is the case in practice — it publishes `app/Actions/Fortify/CreateNewUser.php` and `ResetUserPassword.php` and expects `create()` and `reset()` through `CreatesNewUsers` and `ResetsUserPasswords`.
The namespace carries the distinction, so no judgement is needed at review time:
- `app/Actions/<Domain>/` — our actions: `final readonly class`, one public `execute()`.
- `app/Actions/<Vendor>/` — vendor-published interface implementations. Their method names are imposed by the interface they implement.
Two consequences worth knowing:
- **Do not relocate vendor-published actions out of their vendor directory.** Fortify's installer writes its stubs to `app_path('Actions/Fortify/...')`, so moving them means a later `php artisan fortify:install` — or a starter-kit update — re-publishes them and leaves two classes with the same name, only one of which is bound.
- **A listener is not an action.** A class whose job is to handle a framework event belongs in `app/Listeners/` and keeps Laravel's default `handle()` method, which is what a bare class-string `Event::listen()` registration resolves to. Renaming it to `execute()` to satisfy this convention breaks the registration — and either way it was in the wrong namespace.
### 3. Fixed Dependencies vs. Variable Parameters
Actions have two types of inputs:
**Fixed Dependencies** (Constructor Injection):
- Dependencies that don't change across calls
- Injected via the constructor
- Resolved automatically by Laravel's container
- Examples: other actions, services
**Variable Parameters** (Execute Method):
- Data that changes between calls
- Passed to the `execute()` method
- Enable the same action instance to be reused with different inputs
- Example: `BuildOpportunities` receives `$priceBreaks` as a parameter
```php
class BuildOpportunities
{
// Fixed dependency: injected in constructor
public function __construct(
private FetchPropertiesForPriceBreak $fetchProperties,
private MapPropertiesToOpportunities $mapToOpportunities,
) {}
// Variable parameter: passed to execute()
public function execute(array $priceBreaks): array
{
// Use both fixed dependencies and variable parameters
}
}
```
### 4. Composability and Container Resolution
Actions are composable — they can depend on other actions:
- All fixed dependencies must be resolvable from Laravel's container by type alone
- Actions can depend on other actions via constructor injection
- **Avoid circular dependencies** — actions should form a directed acyclic graph
- The container automatically resolves dependencies; explicit instantiation is rarely needed
### 5. Statelessness and Readonly Classes
Actions must be **stateless**. They should not maintain instance properties that affect behavior across multiple `execute()` calls.
**Why**: If you create an action and call `execute()` twice with different parameters, the second call should not be affected by the first.
**Implementation**: Action classes should be declared as `readonly` since they are stateless and only hold immutable dependencies:
```php
final readonly class BuildOpportunities
{
public function __construct(
private FetchPropertiesForPriceBreak $fetchProperties,
private MapPropertiesToOpportunities $mapToOpportunities,
) {}
public function execute(array $priceBreaks): array
{
// ...
}
}
```
The `readonly` keyword enforces immutability at the class level and makes the stateless nature explicit.
## When to Use the Action Pattern
Activate this skill when:
- **Extracting logic from controllers**: Business logic belongs in actions, not controllers
- **Creating new actions**: Ensure they follow the pattern correctly
- **Refactoring code that violates SRP**: If a class is doing multiple things, consider splitting it into multiple actions
- **Code is required by multiple parts of the application**: If behavior is needed in multiple places, extract it into an action
## Controller Integration
Controllers should delegate business logic to actions. Actions are injected into controller **methods**, not constructors, unless the action is used by **every** public method in the controller.
**Rule**: Only inject an action into the constructor if it's used by all public methods. Otherwise, inject it into the specific methods that need it.From ceilidhboy/skills, MIT.
More from ceilidhboy/skills
- 0.561score
routing-and-controllers
ceilidhboy
Creating or editing a controller, or adding or editing a route in this project.
SkillAFreshness: AClaude Code +9 - 0.555score
pr-review
ceilidhboy
Review a GitHub pull request by orchestrating reviewer + oracle sub-agents directly from the orchestrating session, consolidating their findings into a single…
SkillAFreshness: AClaude Code +9 - 0.529score
pest-testing-conventions
ceilidhboy
Pest 4 testing conventions, workflows, and troubleshooting for Laravel projects.
SkillBFreshness: BClaude Code +9 - 0.529score
project-bootstrap
ceilidhboy
Use when setting up a new Laravel + Inertia + React project, onboarding a new project to company standards, or told to "apply company tooling" or "standardise…
SkillBFreshness: BClaude Code +9 - 0.529score
formatting-enforcement
ceilidhboy
Retrofit formatting enforcement onto an existing Laravel project that has accumulated drift (badly formatted code committed under an always-green lint CI) or…
SkillBFreshness: BClaude Code +9 - 0.525score
html-output
ceilidhboy
HTML output generator for output that would benefit from being presented in a visually rich document.
SkillBFreshness: BClaude Code +9 - 0.524score
github-cli-workarounds
ceilidhboy
Workarounds for shell escaping issues when using the GitHub CLI (`gh`) for creating issues, gists, and pull requests with content containing special…
SkillBFreshness: BClaude Code +9 - 0.524score
serena-conventions
ceilidhboy
Use when navigating code with Serena tools — finding symbols, reading method bodies, inserting code, or deciding between Serena and context-mode for code tasks.
SkillBFreshness: BClaude Code +9 - 0.521score
bug-fix
ceilidhboy
Activate before creating, modifying, or deleting any production code file.
SkillBFreshness: BClaude Code +9 - 0.520score
adr-creation
ceilidhboy
Creates and maintains dual-format ADRs — Markdown (source of truth for agents) and HTML (rich explainer for humans with diagrams).
SkillBFreshness: BClaude Code +9 - 0.474score
settings-system
ceilidhboy
Multi-tenant polymorphic settings system with agency-scoped records and global fallback chain.
SkillCFreshness: CClaude Code +9 - 0.474score
creating-pull-requests
ceilidhboy
Company pull request workflow and branch policy.
SkillCFreshness: CClaude Code +9
Signals
- Stars
- 0
- Forks
- 0
- Open issues
- 0
- Last commit (this folder)
- Sep 25, 2026 (1 month ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- MIT
- Repository
- github.com/ceilidhboy/skills
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
More from ceilidhboy
- 0.561score
routing-and-controllers
ceilidhboy
Creating or editing a controller, or adding or editing a route in this project.
SkillAFreshness: AClaude Code +9 - 0.555score
pr-review
ceilidhboy
Review a GitHub pull request by orchestrating reviewer + oracle sub-agents directly from the orchestrating session, consolidating their findings into a single…
SkillAFreshness: AClaude Code +9 - 0.529score
project-bootstrap
ceilidhboy
Use when setting up a new Laravel + Inertia + React project, onboarding a new project to company standards, or told to "apply company tooling" or "standardise…
SkillBFreshness: BClaude Code +9 - 0.529score
formatting-enforcement
ceilidhboy
Retrofit formatting enforcement onto an existing Laravel project that has accumulated drift (badly formatted code committed under an always-green lint CI) or…
SkillBFreshness: BClaude Code +9 - 0.529score
pest-testing-conventions
ceilidhboy
Pest 4 testing conventions, workflows, and troubleshooting for Laravel projects.
SkillBFreshness: BClaude Code +9 - 0.525score
html-output
ceilidhboy
HTML output generator for output that would benefit from being presented in a visually rich document.
SkillBFreshness: BClaude Code +9
Cite this page
action-pattern skill. Agent Mart. https://agentmart.dev/skills/ceilidhboy-action-pattern (last updated 2026-10-24)