Analyzes Rails codebases for layered architecture violations, reviews PRs, plans features and gradual adoption, implements patterns like authorization, view components, and AI integration.
From layered-railsnpx claudepluginhub palkan/skills --plugin layered-railsThis skill is limited to using the following tools:
examples/refactoring-scenarios.mdreferences/anti-patterns.mdreferences/core/architecture-layers.mdreferences/core/extraction-signals.mdreferences/core/specification-test.mdreferences/gems/action-policy.mdreferences/gems/active-agent.mdreferences/gems/active-delivery.mdreferences/gems/active-job-performs.mdreferences/gems/alba.mdreferences/gems/anyway-config.mdreferences/gems/rubanok.mdreferences/gems/view-component.mdreferences/gems/workflow.mdreferences/patterns/concerns.mdreferences/patterns/filter-objects.mdreferences/patterns/form-objects.mdreferences/patterns/policy-objects.mdreferences/patterns/presenters.mdreferences/patterns/query-objects.mdProvides UI/UX resources: 50+ styles, color palettes, font pairings, guidelines, charts for web/mobile across React, Next.js, Vue, Svelte, Tailwind, React Native, Flutter. Aids planning, building, reviewing interfaces.
Fetches up-to-date documentation from Context7 for libraries and frameworks like React, Next.js, Prisma. Use for setup questions, API references, and code examples.
Calculates TAM/SAM/SOM using top-down, bottom-up, and value theory methodologies for market sizing, revenue estimation, and startup validation.
Design and review Rails applications using layered architecture principles.
Rails applications are organized into four architecture layers with unidirectional data flow:
┌─────────────────────────────────────────┐
│ PRESENTATION LAYER │
│ Controllers, Views, Channels, Mailers │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ APPLICATION LAYER │
│ Service Objects, Form Objects, etc. │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ DOMAIN LAYER │
│ Models, Value Objects, Domain Events │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ INFRASTRUCTURE LAYER │
│ Active Record, APIs, File Storage │
└─────────────────────────────────────────┘
Core Rule: Lower layers must never depend on higher layers.
/layers:analyze for full analysis or /layers:analyze:callbacks, /layers:analyze:gods for specific checks/layers:review for layered architecture review/layers:spec-test on specific files/layers:gradual [goal] to plan incremental layerification| Violation | Example | Fix |
|---|---|---|
| Model uses Current | Current.user in model | Pass user as explicit parameter |
| Service accepts request | param :request in service | Extract value object from request |
| Controller has business logic | Pricing calculations in action | Extract to service or model |
| Anemic models | All logic in services | Keep domain logic in models |
See Anti-Patterns Reference for complete list.
If the specification of an object describes features beyond the primary responsibility of its abstraction layer, such features should be extracted into lower layers.
How to apply:
See Specification Test Reference for detailed guide.
| Pattern | Layer | Use When | Reference |
|---|---|---|---|
| Service Object | Application | Orchestrating domain operations | service-objects.md |
| Query Object | Domain | Complex, reusable queries | query-objects.md |
| Form Object | Presentation | Multi-model forms, complex validation | form-objects.md |
| Filter Object | Presentation | Request parameter transformation | filter-objects.md |
| Presenter | Presentation | View-specific logic, multiple models | presenters.md |
| Serializer | Presentation | API response formatting | serializers.md |
| Policy Object | Application | Authorization decisions | policy-objects.md |
| Value Object | Domain | Immutable, identity-less concepts | value-objects.md |
| State Machine | Domain | States, events, transitions | state-machines.md |
| Concern | Domain | Shared behavioral extraction | concerns.md |
"Where should this code go?"
| If you have... | Consider... |
|---|---|
| Complex multi-model form | Form Object |
| Request parameter filtering/transformation | Filter Object |
| View-specific formatting | Presenter |
| Complex database query used in multiple places | Query Object |
| Business operation spanning multiple models | Service Object (as waiting room) |
| Authorization rules | Policy Object |
| Multi-channel notifications | Delivery Object (Active Delivery) |
Remember: Services are a "waiting room" for code until proper abstractions emerge. Don't let app/services become a bag of random objects.
| Command | Purpose |
|---|---|
/layers:review | Review code changes from layered architecture perspective |
/layers:spec-test | Run specification test on specific files |
/layers:analyze | Full codebase abstraction layer analysis |
/layers:analyze:callbacks | Score model callbacks, find extraction candidates |
/layers:analyze:gods | Find God objects via churn × complexity |
/layers:gradual [goal] | Plan gradual adoption of layered patterns |
For deep dives on specific topics:
| Topic | Reference |
|---|---|
| Authorization (RBAC, ABAC, policies) | authorization.md |
| Notifications (multi-channel delivery) | notifications.md |
| View Components | view-components.md |
| AI Integration (LLM, agents, RAG, MCP) | ai-integration.md |
| Configuration | configuration.md |
| Callbacks (scoring, extraction) | callbacks.md |
| Current Attributes | current-attributes.md |
| Instrumentation (logging, metrics) | instrumentation.md |
For library-specific guidance:
| Gem | Purpose | Reference |
|---|---|---|
| action_policy | Authorization framework | action-policy.md |
| view_component | Component framework | view-component.md |
| anyway_config | Typed configuration | anyway-config.md |
| active_delivery | Multi-channel notifications | active-delivery.md |
| alba | JSON serialization | alba.md |
| workflow | State machines | workflow.md |
| rubanok | Filter/transformation DSL | rubanok.md |
| active_agent | AI agent framework | active-agent.md |
| active_job-performs | Eliminate anemic jobs | active-job-performs.md |
When to extract from models:
| Signal | Metric | Action |
|---|---|---|
| God object | High churn × complexity | Decompose into concerns, delegates, or separate models |
| Operation callback | Score 1-2/5 | Extract to service or event handler |
| Code-slicing concern | Groups by artifact type | Convert to behavioral concern or extract |
| Current dependency | Model reads Current.* | Pass as explicit parameter |
Callback Scoring:
| Type | Score | Keep? |
|---|---|---|
| Transformer (compute values) | 5/5 | Yes |
| Normalizer (sanitize input) | 4/5 | Yes |
| Utility (counter caches) | 4/5 | Yes |
| Observer (side effects) | 2/5 | Maybe |
| Operation (business steps) | 1/5 | Extract |
See Extraction Signals Reference for detailed guide.
Recommended order within model files:
class User < ApplicationRecord
# 1. Gems/DSL extensions
has_secure_password
# 2. Associations
belongs_to :account
has_many :posts
# 3. Enums
enum :status, { pending: 0, active: 1 }
# 4. Normalization
normalizes :email, with: -> { _1.strip.downcase }
# 5. Validations
validates :email, presence: true
# 6. Scopes
scope :active, -> { where(status: :active) }
# 7. Callbacks (transformers only)
before_validation :set_defaults
# 8. Delegations
delegate :name, to: :account, prefix: true
# 9. Public methods
def full_name = "#{first_name} #{last_name}"
# 10. Private methods
private
def set_defaults
self.locale ||= I18n.default_locale
end
end
Well-layered code:
app/services become permanent residence for code