routing-and-controllers
Creating or editing a controller, or adding or editing a route in this project.
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-routing-and-controllers
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
Use cases: writing
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/routing-and-controllers
What's inside
- Skill name
routing-and-controllers- Description
- Creating or editing a controller, or adding or editing a route in this project. Covers resourceful controllers, Route::resource and Route::singleton registration, why invokable controllers are not used here, and how routes map to Wayfinder TypeScript actions.
- License
- MIT
- Instructions
- 94 lines in SKILL.md · view on GitHub
Files (1)
- SKILL.md
SKILL.md (first lines)
# Routing and Controllers
## When to Activate This Skill
Activate this skill whenever you are about to:
- Create a controller, or add, rename, or remove a method on one
- Add, change, or remove a route in `routes/web.php`, `routes/settings.php`, or any other route file
- Decide where a new operation belongs
- Debug a missing or stale Wayfinder TypeScript action
## Conventions
These are rules. Apply them to everything you add or change; do not infer the convention from whatever happens to be in the file you are editing.
1. **A controller is singular and named for the resource it serves** — `JobController`, `ExpenseDocumentDownloadController`, `JobPendingController`. The route resource is plural: `Route::resource('jobs', JobController::class)`.
2. **A controller exposes only the seven resource actions**: `index`, `show`, `create`, `store`, `edit`, `update`, `destroy`. No other public methods, and never `__invoke`.
3. **A bespoke operation becomes its own resource controller**, not a method on an existing one. The controller *is* the resource; the verb comes from the URL and the HTTP method, never from the method name.
- `POST jobs/{job}/pending` → `JobPendingController@store`
- `POST placements/{placement}/confirm` → `PlacementConfirmationController@store`
- `POST timesheets/{timesheet}/approve` → `TimesheetApprovalController@store`
4. **Register with `Route::resource`, narrowed with `->only()` or `->except()`.** Pin only when you must: `->parameters(['records' => 'client'])` when the bound model is not named after the resource; `->names([...])` when a name has to differ. Use `Route::singleton` for a resource there is only one of (e.g. `settings/xero`).
5. **A nested resource keeps its parent's URL** with an explicit registration, but the method is still one of the seven:
```php
Route::post('jobs/{job}/pending', [JobPendingController::class, 'store'])->name('job-pendings.store');
```
A hand-written `Route::get`/`post`/`put`/`patch`/`delete` is for a route that reaches **no** controller action (a closure, a redirect, a view) or for a nested resource. It is never a licence to name the method after the operation.
6. **An external system constrains the URL and the HTTP verb, not our method names.** An OAuth callback (`GET /settings/xero/callback`), a webhook (`POST /webhooks/xero`) and an emailed magic link (`GET /passwordless/login/{token}`) all still use a resource action: `show()` for the GET, `store()` for the POST. If one controller would end up carrying several unrelated operations, split it into one resource controller per operation.
7. **Route names follow resource and action** — `jobs.show`, `placement-confirmations.store`. Never a name that restates a verb (`jobs.pending`) or invents an action (`expense-documents.download`).
8. **Never copy an existing violation.** If the controller or route you are editing already breaks these rules, correct it in the same change. Do not match the code around it.
9. **An allowlist entry is debt to delete, never to add.** The guard test fails on a new invokable or a method outside the seven. If your change needs a new entry, the change is wrong.
## The Complete Workflow
When adding an operation that does not fit an existing resource:
1. **Name the resource.** Often the operation's noun: an approval, a confirmation, a download.
2. **Create the controller** — singular, `final`, with the resource action you need:
```bash
php artisan make:controller JobPendingController --no-interaction
```
```php
final class JobPendingController
{
public function store(Request $request, Job $job): RedirectResponse
{
// …
}
}
```
3. **Register the route** in `routes/web.php`, inside the group whose middleware and prefix belong to it:
```php
Route::resource('job-pendings', JobPendingController::class)->only(['store']);
// or, nested under its parent:
Route::post('jobs/{job}/pending', [JobPendingController::class, 'store'])->name('job-pendings.store');
```
4. **Regenerate the Wayfinder actions.** The Vite plugin does this on dev/build; manually:
```bash
php artisan wayfinder:generate --with-form --no-interaction
```
5. **Use the generated action** in React — one named import per controller method:
```typescript
import { show } from '@/actions/App/Http/Controllers/JobController';
<Link href={show(job).url}>View job</Link>
```
## Why Not Invokable Controllers
An invokable controller (`__invoke`) and a custom method (`markPending`, `confirm`, `download`) are the same deviation from this convention: a controller whose public interface is not the resource vocabulary. They cause three concrete problems:
- **They hide the resource.** A reader cannot tell what a `SwitchAccountController` creates, or which HTTP verb reaches `markPending`.
- **They multiply.** Every bespoke verb invites another, because the shape says "controllers are a place to put verbs".
- **They generate ambiguous frontend imports.** `ClientsController().url` names no action, and a controller that later needs a second action has to be restructured.
Wayfinder's type safety comes from the controller *method*, not from invokability, so nothing is lost by using `show()`/`store()`.
## Critical: Routes Must Be Registered for Wayfinder
**Wayfinder only generates TypeScript action files for routes that are actually registered.**
If you create a controller but don't register its route, no action file is generated and the frontend import fails.
### Troubleshooting Missing Action Files
If `import { show } from '@/actions/...'` fails:
1. Check that the route is registered in the relevant route file
2. Check that the method is one of the seven resource actions, on a route that reaches it
3. Run `php artisan wayfinder:generate --with-form --no-interaction`
4. Check that the generated file exists in `resources/js/actions/`
If still missing, activate the `troubleshooting` skill for further diagnosis.From ceilidhboy/skills, MIT.
More from ceilidhboy/skills
- 0.561score
action-pattern
ceilidhboy
Creating and using action classes to encapsulate business logic.
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
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
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
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 - 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.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.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
javascript-typescript-conventions
ceilidhboy
Provides JavaScript and TypeScript coding conventions including casing rules, naming patterns, and best practices for variables, constants, components, and…
SkillCFreshness: CClaude Code +9
Signals
- Stars
- 0
- Forks
- 0
- Open issues
- 0
- Last commit (this folder)
- Oct 20, 2026 (9 days 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
action-pattern
ceilidhboy
Creating and using action classes to encapsulate business logic.
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
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
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
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
routing-and-controllers skill. Agent Mart. https://agentmart.dev/skills/ceilidhboy-routing-and-controllers (last updated 2026-10-24)