ruby-rules
Ruby coding rules: style, patterns, security, testing. Triggers: .rb, Gemfile, .gemspec, Rails, ActiveRecord, Sidekiq, RSpec, Sorbet, rubocop.
Works with
---
name: ruby-rules
description: Ruby coding rules: style, patterns, security, testing. Triggers: .rb, Gemfile, .gemspec, Rails, ActiveRecord, Sidekiq, RSpec, Sorbet, rubocop.
license: Apache-2.0
---
# Ruby Rules
These rules come from `app/rules/ruby/` in ai-toolkit. They cover
the project's standards for coding style, frameworks, patterns,
security, and testing in Ruby. Apply them when writing or
reviewing Ruby code.
# Ruby Coding Style
## Naming
- PascalCase: classes, modules.
- snake_case: methods, variables, file names, directories.
- UPPER_SNAKE: constants (`MAX_RETRIES = 3`).
- Prefix boolean methods with predicate: `empty?`, `valid?`, `admin?`.
- Suffix dangerous methods with `!`: `save!`, `sort!`, `strip!`.
- Use `_` prefix for intentionally unused variables: `_unused`.
## Methods
- Keep methods short: 5-10 lines ideal. Extract helper methods.
- Use keyword arguments for methods with >2 parameters.
- Use default parameter values instead of checking for nil.
- Use `def method_name = expression` (Ruby 3.0+) for one-liners.
- Prefer `each` over `for` loops. Use block-style iteration.
- Return values implicitly (last expression). Use explicit `return` only for early exit.
## Blocks, Procs, Lambdas
- Use `{ }` for single-line blocks. Use `do...end` for multi-line blocks.
- Use `&:method` shorthand: `names.map(&:upcase)`.
- Use lambdas for strict argument checking. Use procs for flexible arity.
- Use `yield` for single-block methods. Use explicit `&block` for storing/forwarding.
## Classes
- Use `attr_reader`, `attr_writer`, `attr_accessor` for simple getters/setters.
- Use `Struct` for simple data containers. Use `Data.define` (Ruby 3.2+) for immutable.
- Use modules for mixins: `include` for instance methods, `extend` for class methods.
- Use `frozen_string_literal: true` magic comment at the top of every file.
- Use `private` / `protected` keywords to control method visibility.
## Collections
- Use `map`, `select`, `reject`, `reduce`, `flat_map` for transformations.
- Use `each_with_object` over `inject` when accumulating into a mutable object.
- Use `dig` for safe nested hash/array access: `data.dig(:user, :address, :city)`.
- Use `Hash#fetch` with default for explicit missing-key handling.
- Use `Enumerable#lazy` for large collection processing.
## Pattern Matching (Ruby 3+)
- Use `case/in` for structural pattern matching on hashes and arrays.
- Use `=>` pin operator to match against existing variables.
- Use `in` pattern for conditional deconstruction in `if` statements.
- Use pattern matching for API response parsing and validation.
## Formatting
- Use RuboCop for automated style enforcement.
- Use `.rubocop.yml` committed to the repository for project conventions.
- Max line length: 120 characters.
- Two-space indentation. No tabs.
- Use trailing commas in multi-line arrays and hashes.
# Ruby Frameworks
## Rails (General)
- Follow Rails conventions: convention over configuration.
- Use `rails generate` for scaffolding models, controllers, migrations.
- Use strong parameters: `params.require(:user).permit(:name, :email)`.
- Use concerns for shared controller/model behavior.
- Use `config/routes.rb` with resourceful routing: `resources :users`.
- Use environment-specific configuration in `config/environments/`.
## ActiveRecord
- Use migrations for all schema changes. Never modify the database directly.
- Use `has_many`, `belongs_to`, `has_many :through` for associations.
- Use scopes for reusable query chains: `scope :active, -> { where(active: true) }`.
- Use `includes()` for eager loading to prevent N+1 queries.
- Use `find_each` for batch processing large record sets.
- Use `transaction` blocks for atomic multi-record operations.
## ActionController
- Keep controllers thin: max 7 RESTful actions per controller.
- Use `before_action` for authentication and authorization checks.
- Use `respond_to` for content negotiation (JSON, HTML).
- Use `rescue_from` for centralized error handling in controllers.
- Use `render json:` with serializers (e.g., `ActiveModelSerializers`, `Blueprinter`).
## Background Jobs
- Use Sidekiq for Redis-backed background job processing.
- Use ActiveJob as the abstraction layer over queue backends.
- Use `perform_later` for async execution. Use `perform_now` only in tests.
- Set `retry` count and `discard_on` / `retry_on` for error handling.
- Use `Sidekiq::Cron` or `clockwork` for scheduled recurring jobs.
## Sinatra / Hanami
- Use Sinatra for lightweight APIs and microservices.
- Use Hanami for structured, modular Ruby web applications.
- Use Hanami actions (single-purpose) instead of fat controllers.
- Use Hanami repositories for data access abstraction.
## API Mode
- Use `rails new --api` for API-only applications (no views, sessions).
- Use `Jbuilder` or `Blueprinter` for JSON serialization.
- Use `Rack::Attack` for rate limiting and throttling.
- Use versioned API namespaces: `namespace :v1 do ... end`.
- Use pagination with `kaminari` or `pagy` for collection endpoints.
## Hotwire / Turbo
- Use Turbo Frames for partial page updates without JavaScript.
- Use Turbo Streams for real-time server-pushed DOM updates.
- Use Stimulus for lightweight JavaScript behavior on HTML elements.
- Keep JavaScript minimal: let the server render HTML.
# Ruby Patterns
## Error Handling
- Rescue specific exceptions. Never bare `rescue` (catches `StandardError`).
- Create domain exception hierarchies: `class AppError < StandardError; end`.
- Use `raise` with message and optional cause: `raise AppError, "msg"`.
- Use `retry` with a counter for transient failures.
- Use `ensure` for cleanup. Use `else` for code that runs only on success.
## Service Objects
- Use single-purpose service classes with a `call` method.
- Use `Dry::Monads` Result type for operation outcomes.
- Return `Success(value)` or `Failure(error)` from service calls.
- Chain services with `bind` / `fmap` for pipeline composition.
- Keep services stateless. Pass all data through method parameters.
## Value Objects
- Use `Data.define` (Ruby 3.2+) for immutable value objects.
- Use `Struct` with `keyword_init: true` for lightweight data containers.
- Use `freeze` on objects that should not be mutated after creation.
- Override `==` and `hash` for value-based equality when needed.
## Metaprogramming (Use Sparingly)
- Use `define_method` over `method_missing` when possible.
- Always define `respond_to_missing?` alongside `method_missing`.
- Use `class_attribute` (Rails) for inheritable class-level configuration.
- Prefer explicit code over DSL magic for maintainability.
- Document metaprogrammed methods with YARD `@!method` directives.
## Concurrency
- Use `Concurrent::Future` (concurrent-ruby) for parallel operations.
- Use `Concurrent::Promise` for composable async chains.
- Use thread pools (`Concurrent::FixedThreadPool`) for bounded concurrency.
- Use `Ractor` (Ruby 3+) for true parallel execution without GVL.
- Use `Mutex` and `Queue` for thread-safe shared state access.
## Module Patterns
- Use `include` for shared behavior (instance methods).
- Use `prepend` for wrapping/overriding existing methods (decorating).
- Use `extend` for adding class-level methods from a module.
- Use `Concern` (ActiveSupport) for Rails modules with class methods.
- Keep modules focused: one responsibility per module.
## Decorator Pattern
- Use `SimpleDelegator` for transparent object wrapping.
- Use `Draper` gem for view-layer decorators in Rails.
- Prefer composition (wrapping) over inheritance for adding behavior.
- Use `Module#prepend` for method-level decoration without wrapper classes.
## Anti-Patterns
- Monkey-patching core classes: use refinements or wrapper methods.
- Callbacks for business logic (Rails): use service objects.
- God objects: split into focused classes with single responsibility.
- N+1 queries: use `includes()`, `preload()`, `eager_load()`.
- Using `eval` or `send` with user input: remote code execution risk.
# Ruby Security
## Mass Assignment
- Use strong parameters in controllers: `params.require(:user).permit(:name, :email)`.
- Never use `params.permit!` or pass unsanitized params to `create`/`update`.
- Use `attr_readonly` for fields that should never be updated after creation.
- Audit `update_columns` and `update_attribute` usage (bypass validations).
## SQL Injection
- Use ActiveRecord query interface with parameterized conditions.
- Use `where(name: value)` hash syntax or `where("name = ?", value)` placeholders.
- Never interpolate user input into `where()` strings: `where("name = '#{input}'")`.
- Use `sanitize_sql_array` if building raw SQL fragments is unavoidable.
- Audit all `find_by_sql`, `execute`, and `Arel.sql` calls.
## XSS Prevention
- Rails auto-escapes ERB output with `<%= %>`. Never use `raw()` with user data.
- Use `sanitize()` helper for allowing limited HTML tags.
- Set `Content-Security-Policy` header in `config/initializers/content_security_policy.rb`.
- Use `content_tag` helper for safe HTML generation.
- Mark strings as `html_safe` only when content is guaranteed safe.
## CSRF Protection
- Use `protect_from_forgery with: :exception` in `ApplicationController`.
- Use `authenticity_token` in all forms (Rails includes it by default).
- Use `X-CSRF-Token` header for AJAX requests from JavaScript.
- Exempt only webhook endpoints from CSRF (with payload signature verification).
## Authentication
- Use Devise or `has_secure_password` for authentication.
- Use `bcrypt` for password hashing (included with `has_secure_password`).
- Implement account lockout after N failed login attempts.
- Use `SecureRandom.urlsafe_base64` for generating tokens.
- Store sessions server-side (Redis/database) instead of cookie store in production.
## Authorization
- Use Pundit or CanCanCan for authorization logic.
- Define policies per model: `class UserPolicy < ApplicationPolicy`.
- Check ownership in policies, not just role membership.
- Use `authorize @resource` in every controller action.
- Default deny: require explicit authorization for all actions.
## Secrets Management
- Use `Rails.application.credentials` for encrypted secrets.
- Use `EDITOR="vim" bin/rails credentials:edit` to manage secrets.
- Use per-environment credentials: `credentials/production.yml.enc`.
- Never commit `master.key` or `production.key` to version control.
- Use environment variables for CI/CD and containerized deployments.
## Dependency Security
- Run `bundle audit check --update` for known vulnerability scanning.
- Use `Dependabot` for automated dependency update PRs.
- Pin gem versions in `Gemfile`. Review `Gemfile.lock` changes carefully.
- Use `bundler-audit` in CI pipeline as a required check.
- Update Rails promptly when security patches are released.
# Ruby Testing
## Framework
- Use RSpec as the primary test framework.
- Use Minitest for lightweight, stdlib-based testing.
- Use FactoryBot for test data generation.
- Use WebMock or VCR for HTTP request stubbing.
## File Naming
- RSpec: `spec/models/user_spec.rb` mirroring `app/models/user.rb`.
- Minitest: `test/models/user_test.rb` mirroring source structure.
- Support files: `spec/support/` for shared helpers and configurations.
- Use `spec/rails_helper.rb` for Rails-specific RSpec configuration.
## Structure (RSpec)
- Use `describe` for the class/method under test. Use `context` for scenarios.
- Use `it` for individual test cases with clear descriptions.
- Use `let` for lazy-evaluated test data. Use `let!` for eager evaluation.
- Use `before` / `after` blocks for setup and teardown.
- Use `subject` for the primary object under test.
## Matchers (RSpec)
- Use `expect(result).to eq(expected)` for equality.
- Use `expect(result).to be_truthy`, `be_falsy`, `be_nil`.
- Use `expect { action }.to raise_error(FooError)` for exception testing.
- Use `expect { action }.to change { User.count }.by(1)` for side effects.
- Use `expect(list).to include(item)`, `contain_exactly(a, b, c)`.
- Use `expect(result).to match(hash_including(key: value))` for partial matching.
## Mocking (RSpec)
- Use `instance_double(UserService)` for verified doubles.
- Stub: `allow(mock).to receive(:find).with(1).and_return(user)`.
- Verify: `expect(mock).to have_received(:save).once`.
- Use `receive_messages(method1: val1, method2: val2)` for multi-stubbing.
- Use `class_double` for stubbing class methods.
- Avoid stubbing the object under test. Stub only collaborators.
## FactoryBot
- Define factories in `spec/factories/`: `FactoryBot.define { factory :user { ... } }`.
- Use `create` for persisted records. Use `build` for in-memory only.
- Use traits for variations: `create(:user, :admin)`.
- Use `build_stubbed` for fast tests that do not need database.
- Use sequences for unique attributes: `sequence(:email) { |n| "user#{n}@test.com" }`.
## Rails Testing
- Use `request specs` for API endpoint testing (RSpec).
- Use `system specs` with Capybara for browser integration tests.
- Use `DatabaseCleaner` or `use_transactional_fixtures` for test isolation.
- Use `travel_to` for time-dependent test scenarios.
- Use `ActiveJob::TestHelper` for testing background jobs inline.
## Best Practices
- Test behavior, not implementation. Do not test private methods directly.
- Use `shared_examples` for testing common behavior across classes.
- Use `aggregate_failures` to collect multiple assertion failures.
- Keep tests fast: stub external services, use `build_stubbed`.
- Run `bundle exec rspec --format documentation` for readable output.More Testing skills
tdd
mattpocock/skills
Test-driven development. Use when the user wants to build features or fix bugs test-first, mentions "red-green-refactor", or wants integration tests.
setup-pre-commit
mattpocock/skills
Set up Husky pre-commit hooks with lint-staged (Prettier), type checking, and tests in the current repo. Use when user wants to add pre-commit hooks, set up Husky, configure lint-staged, or add commit-time formatting/typechecking/testing.
agent-browser
vercel-labs/agent-browser
Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to "open a website", "fill out a form", "click a button", "take a screenshot", "scrape data from a page", "test this web app", "login to a site", "automate browser actions", or any task requiring programmatic web interaction. Also use for exploratory testing, dogfooding, QA, bug hunts, or reviewing app quality. Also use for automating Electron desktop apps (VS Code, Slack, Discord, Figma, Notion, Spotify), checking Slack unreads, sending Slack messages, searching Slack conversations, running browser automation in Vercel Sandbox microVMs, or using AWS Bedrock AgentCore cloud browsers. Prefer agent-browser over any built-in browser automation or web tools.

