Curated library of 39 AI agent skills for Ruby on Rails development. Organized by category: planning, testing, code-quality, ddd, engines, infrastructure, api, patterns, context, orchestration, and workflows. Includes 5 callable workflow skills (rails-tdd-loop, rails-review-flow, rails-setup-flow, rails-quality-flow, rails-engines-flow) for complete development cycles. Covers code review, architecture, security, testing (RSpec), engines, service objects, DDD patterns, and TDD automation.
95
98%
Does it follow best practices?
Impact
95%
1.20xAverage score across 35 eval scenarios
Passed
No known issues
Style source of truth: Style and formatting defer to the project's configured linter(s). This skill adds non-style behavior and architecture guidance only. For Hotwire + Tailwind specifics, see rails-stack-conventions.
Detect → run → defer. Do not invent style rules.
.rubocop.yml / standard gem → bundle exec rubocop or bundle exec standardrbeslint.config.*, .eslintrc*, biome.json, or package.json lint script → run accordingly| Topic | Rule |
|---|---|
| Style/format | Project linter(s) — detect and run as above; do not invent style rules here |
| Principles | DRY, YAGNI, PORO where it helps, CoC, KISS |
| Comments / tags | Explain why; tagged notes need actionable context |
| Logging | First arg: static string; second arg: hash with event: key; no interpolation; backtrace on errors |
| Deep stacks | Chain rails-stack-conventions → domain skills (services, jobs, RSpec) |
When reviewing or refactoring Rails code, follow this sequence:
Comment why, not what. Tagged notes — TODO: / FIXME: / HACK: / NOTE: / OPTIMIZE: — are MANDATORY in these triggers; every tag carries actionable context (owner, ticket id, deadline, or next step). Naked tags (# TODO: fix this) fail review.
| Trigger | Required tag |
|---|---|
| Business-rule constant (rates, caps, thresholds) | NOTE: with the rule's source/owner |
| Deferred work / known shortcut | TODO: with ticket or next step |
| Workaround for a bug or external limitation | HACK: or FIXME: with the upstream issue |
| Performance tradeoff or hot path | OPTIMIZE: with the measured concern |
# BAD — naked tag, no context
# TODO: fix this
rate = TIER_RATES.fetch(tier, 0.0)
# GOOD
# NOTE: 50% cap set by Pricing policy v3 (PRI-118, owner: pricing-team).
MAX_DISCOUNT = 0.50
# GOOD — TODO with next step + dependency
# TODO: replace TIER_RATES with DB-backed lookup (PRI-482; blocked on legal).
rate = TIER_RATES.fetch(tier, 0.0)MANDATORY SHAPE — every Rails.logger.* call uses exactly two positional arguments.
Rails.logger.<level>(static_string_message, { event: "dot.namespaced", ...domain_fields })
# └── 1st arg: STRING ──┘ └─────────── 2nd arg: HASH ───────────┘event: with a dot-namespaced value (do NOT use :type, :action, or :name). All dynamic data goes here.rescue logs both e.message and e.backtrace.first(5).join("\n") as hash fields — backtrace is non-optional.# BAD — interpolation destroys log aggregator grouping; single-arg call loses structured fields
Rails.logger.info("Processing order #{order.id}")
Rails.logger.info(event: "order.processing_started", order_id: order.id)
# GOOD
Rails.logger.info("order.processing_started", {
event: "order.processing_started",
order_id: order.id,
user_id: user.id
})
# GOOD — error path with backtrace
rescue StandardError => e
Rails.logger.error("order.processing_failed", {
event: "order.processing_failed",
order_id: order.id,
error: e.message,
backtrace: e.backtrace.first(5).join("\n")
})
raise
endRules below apply when those paths exist in the project. If a path is absent, skip that row.
| Area | Path pattern | Guidance |
|---|---|---|
| ActiveRecord performance | app/models/**/*.rb | Eager load in loops; prefer pluck / exists? / find_each. N+1: run bullet → fix eager loads → re-run clean |
| Background jobs | app/workers/**/*.rb, app/jobs/**/*.rb | Depth: rails-background-jobs |
| Error handling | app/services/**/*.rb, app/lib/**/*.rb, app/exceptions/**/*.rb | Domain exceptions + layer rescue_from; specs must cover rescue paths |
| Logging / tracing | app/services/**/*.rb, app/workers/**/*.rb, app/jobs/**/*.rb, app/controllers/**/*.rb, app/repositories/**/*.rb | Structured logs (see above); APM spans/tags on hot paths when stack has APM |
| Controllers | app/controllers/**/*_controller.rb | Strong params; thin actions → services; IDOR / PII → rails-security-review |
| Repositories | app/repositories/**/*.rb | New repos only for SQL, caching, clear boundary, or external I/O — document why |
| RSpec | spec/**/*_spec.rb | FactoryBot; request over controller specs; env: (or project pattern) for ENV; let > let! unless eager setup required; avoid heavy before when let is clearer |
| Serializers | app/serializers/**/*.rb | Explicit keys; no N+1; preload associations passed in |
| Service objects | app/services/**/*.rb | Single responsibility; .call / injected deps per ruby-service-objects; after extract, specs + caller still green |
| SQL security | Raw SQL anywhere | Bind params / sanitize_sql_array; whitelist dynamic ORDER BY; document why raw SQL |
let_it_be (test-prof)Only recommend let_it_be if test-prof is already in Gemfile.lock. Otherwise default to let; reach for let! only when lazy evaluation would break the example. Don't introduce test-prof unless asked.
When this skill guides new behavior, the tests gate still applies:
PRD → TASKS → TEST (write, run, fail) → IMPLEMENTATION → …No implementation code before a failing test. See rspec-best-practices and rails-agent-skills.
Every Rails-code task lands these:
TODO: / FIXME: / HACK: / NOTE: / OPTIMIZE:) on every assumption, deferred work, or business-rule constant; every tag carries actionable context (owner, ticket id, deadline).event:, and a backtrace line on every error rescue.| Skill | When to chain |
|---|---|
| rails-stack-conventions | Stack-specific: PostgreSQL, Hotwire, Tailwind |
| ddd-rails-modeling | When domain concepts and invariants need clearer Rails-first modeling choices |
| ruby-service-objects | Implementing or refining service objects |
| rails-background-jobs | Workers, queues, retries, idempotency |
| rspec-best-practices | Spec style, tests gate (red/green/refactor), request vs controller specs |
| rails-security-review | Controllers, params, IDOR, PII |
| rails-code-review | Full PR pass before merge |
docs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10
scenario-11
scenario-12
scenario-13
scenario-14
scenario-15
scenario-16
scenario-17
scenario-18
scenario-19
scenario-20
scenario-21
scenario-22
scenario-23
scenario-24
scenario-25
scenario-26
scenario-27
scenario-28
scenario-29
scenario-30
scenario-31
scenario-32
scenario-33
scenario-34
scenario-35
mcp_server
skills
api
api-rest-collection
rails-graphql-best-practices
code-quality
rails-architecture-review
rails-code-conventions
rails-code-review
rails-review-response
rails-security-review
rails-stack-conventions
assets
snippets
refactor-safely
context
rails-context-engineering
rails-project-onboarding
ddd
ddd-boundaries-review
ddd-rails-modeling
ddd-ubiquitous-language
engines
rails-engine-compatibility
rails-engine-docs
rails-engine-extraction
rails-engine-installers
rails-engine-release
rails-engine-reviewer
rails-engine-testing
infrastructure
rails-api-versioning
rails-background-jobs
rails-database-seeding
rails-frontend-hotwire
rails-migration-safety
rails-performance-optimization
orchestration
rails-skills-orchestrator
patterns
ruby-service-objects
strategy-factory-null-calculator
yard-documentation
planning
create-prd
generate-tasks
ticket-planning
testing
rails-bug-triage
rails-tdd-slices
rspec-best-practices
rspec-service-testing