Curated library of AI agent skills for Ruby on Rails development. Covers code review, architecture, security, testing (RSpec), engines, service objects, DDD patterns, and workflow automation.
73
91%
Does it follow best practices?
Impact
—
No eval scenarios have been run
Passed
No known issues
Use this skill when the domain concepts are clear enough that the next question is how to model them in Rails.
Core principle: Model real domain pressure, not textbook DDD vocabulary.
DO NOT introduce repositories, aggregates, or domain events just to sound "DDD".
DO NOT fight Rails defaults when a normal model or service expresses the domain clearly.
ALWAYS start from domain invariants, ownership, and lifecycle before choosing a pattern.rails-tdd-slices and rspec-best-practices before implementation.| DDD concept | Rails-first default | Avoid by default | Typical home |
|---|---|---|---|
| Entity | ActiveRecord model when persisted identity matters | Extra wrapper object with no added meaning | app/models/ |
| Value object | PORO — immutable, equality by value | Shoving logic into helpers or primitives | app/models/ or near the domain |
| Aggregate root | The model that guards invariants and is the single entry point | Splitting invariants across multiple models | app/models/ |
| Domain service | PORO for behavior spanning multiple entities | Arbitrary model chosen just to hold code | app/services/ |
| Application service | Orchestrator for one use case | Fat controller or callback chains | app/services/ |
| Repository | Only when a real persistence boundary exists beyond ActiveRecord | Repositories for every query | app/repositories/ (rare) |
| Domain event | Explicit object when multiple downstream consumers justify it | Callback-driven hidden side effects | app/events/ or project namespace |
When using this skill, return for each domain concept:
generate-tasks, rails-tdd-slices, etc.# app/models/money.rb
class Money
attr_reader :amount_cents, :currency
def initialize(amount_cents, currency = "USD")
@amount_cents = Integer(amount_cents)
@currency = currency.upcase.freeze
freeze
end
def ==(other)
other.is_a?(Money) && amount_cents == other.amount_cents && currency == other.currency
end
alias eql? ==
def hash
[amount_cents, currency].hash
end
endapp/models/money.rbbelongs_to or a database table — this is a calculation value, not an entity.# app/services/orders/create_order.rb
module Orders
class CreateOrder
Result = Struct.new(:success?, :order, :errors, keyword_init: true)
def self.call(**args) = new(**args).call
def initialize(user:, product_id:, quantity:)
@user, @product_id, @quantity = user, product_id, quantity
end
def call
order = @user.orders.build(product: Product.find(@product_id), quantity: @quantity)
order.save ? Result.new(success?: true, order: order, errors: [])
: Result.new(success?: false, order: nil, errors: order.errors.full_messages)
rescue ActiveRecord::RecordNotFound
Result.new(success?: false, order: nil, errors: ["Product not found"])
end
end
endapp/services/orders/create_order.rbOrder.| Mistake | Reality |
|---|---|
| Turning every concept into a service | Many behaviors belong naturally on entities or value objects |
| Creating repositories for all reads and writes | ActiveRecord already provides a strong default persistence boundary |
| Treating aggregates as folder names only | Aggregates exist to protect invariants, not to look architectural |
| Adding domain events for one local callback | Events justify their cost only when multiple downstream consumers exist |
| Pattern choice justified only with "DDD says so" | The reason must be an invariant, ownership boundary, or clear coordination need |
| Skill | When to chain |
|---|---|
| ddd-ubiquitous-language | When the terms are not clear enough to model yet |
| ddd-boundaries-review | When the modeling problem is really a context boundary problem |
| generate-tasks | After the tactical design is clear and ready for implementation planning |
| rails-tdd-slices | When the next step is choosing the best first failing spec |
| rails-code-conventions | When validating the modeling choice against Rails simplicity and repo conventions |
api-rest-collection
create-prd
ddd-boundaries-review
ddd-rails-modeling
ddd-ubiquitous-language
generate-tasks
rails-agent-skills
rails-architecture-review
rails-background-jobs
rails-bug-triage
rails-code-conventions
rails-code-review
rails-engine-compatibility
rails-engine-docs
rails-engine-extraction
rails-engine-installers
rails-engine-release
rails-engine-reviewer
rails-engine-testing
rails-graphql-best-practices
rails-migration-safety
rails-review-response
rails-security-review
rails-stack-conventions
rails-tdd-slices
refactor-safely
rspec-best-practices
rspec-service-testing
ruby-api-client-integration
ruby-service-objects
strategy-factory-null-calculator
ticket-planning
yard-documentation