mischasigtermans/taylor-says

Claude Code plugin channeling Taylor Otwell's Laravel philosophy.

8 stars0 forksUpdated Jan 15, 2026
npx skills add mischasigtermans/taylor-says

README

Taylor Says

Claude Code plugin channeling Taylor Otwell's Laravel philosophy. "Laravel is not Spring."

Taylor reviews your Laravel code for over-engineering, unnecessary abstractions, and violations of Laravel conventions. Direct, opinionated, and occasionally brutal.

Available through the Ryde Ventures plugin marketplace.

Installation

# Add the Ryde Ventures marketplace (one-time)
/plugin marketplace add rydeventures/claude-plugins

# Install the plugin
/plugin install taylor-says@rydeventures-claude-plugins

Quick Start

# Review uncommitted changes (default behavior)
@taylor

# Review a specific file
@taylor review app/Services/UserService.php

# Simplify uncommitted changes (applies fixes directly)
@taylor simplify

# Simplify a specific file
@taylor simplify app/Services/UserService.php

# Hunt for over-engineering in your codebase
@taylor find unnecessary abstractions in my codebase

# Review an entire directory
@taylor review all files in app/Actions/

# Find dead code
@taylor find interfaces with only one implementation

# Audit a pattern
@taylor check if my repository classes are actually needed

Modes

ModeCommandBehavior
Review@taylorAnalyze, give feedback, no changes
Simplify@taylor simplifyAnalyze AND apply fixes directly

Simplify mode focuses on structural changes: deleting unnecessary abstractions, inlining single-use Actions, removing dead code. It won't over-simplify — if removing an abstraction bloats the controller, Taylor leaves it alone.

What Taylor Looks For

Red Flags

  • Repository patterns wrapping Eloquent
  • Service classes that just proxy model methods
  • Interfaces with single implementations
  • Actions that call one model method
  • Enterprise Java patterns in Laravel

The Laravel Way

  • Eloquent used directly (it's not an anti-pattern)
  • Controllers that do things (30 lines is fine)
  • Form Requests for validation
  • Observers for model lifecycle events
  • Policies for authorization

Example Review

Input: A BookmarkService that wraps Eloquent operations

class BookmarkService
{
    public function createBookmark(User $user, Chat $chat, string $messageId, string $role, string $content): ?Bookmark
    {
        try {
            return DB::transaction(function () use ($user, $chat, $messageId, $role, $content): Bookmark {
                $existing = Bookmark::forUser($user->id)
                    ->where('chat_id', $chat->id)
                    ->where('content_hash', sha1($content . $role))
                    ->first();

                if ($existing) {
                    return $existing;
                }

                return Bookmark::create([/* ... */]);
            });
        } catch (Throwable $exception) {
            Log::error('Failed to create bookmark', ['error' => $exception->getMessage()]);
            return null;
        }
    }
}

Taylor says:

Critical Issues

Service class that proxies models. BookmarkService is the poster child for this anti-pattern. You have 150 lines of service code that exists primarily to call Bookmark::create() and Bookmark::delete(). The model is clean. The service is unnecessary ceremony.

Database transaction around a single query. The transaction wraps a first() and a create(). If you're worried about race conditions on bookmark uniqueness, use a unique constraint and firstOrCreate(). The database handles this.

Error swallowing. You're catching Throwable, logging it, and returning null. The caller has no idea what went wrong. If creation fails, it should fail loudly. Laravel's exception handler will log it AND you'll actually know something's broken.

The Laravel Way

Delete the service. Put the logic where it belongs:

// In your Bookmark model
public static function toggle(User $user, Chat $chat, string $messageId, string $role, string $content): ?self
{
    $hash = sha1($content . $role);

    $existing = static::forUser($user->id)
        ->where('chat_id', $chat->id)
        ->where('content_hash', $hash)
        ->first();

    if ($existing) {
        $existing->delete();
        return null;
    }

    return static::create([/* ... */]);
}

I once spent three days building an "elegant" abstraction layer that nobody ever extended or swapped out. It still haunts me. This service has that same energy - solving a problem that doesn't exist yet and probably never will.

Delete BookmarkService.php. Ship it.

Representative Quotes

"Stop writing Java in PHP."

"The interface exists purely to satisfy some abstract notion of 'clean architecture' rather than solving a real problem."

"Elegance means solving the problem directly."

"If your service just proxies to Eloquent, delete it."

"Enterprise PHP cosplaying as Laravel."

K

...

Read full README

Statistics

Stars8
Forks0
Open Issues0
LicenseMIT License
CreatedJan 4, 2026