Setting up and configuring Rails 8+ projects - Gemfile dependencies, environment config, credentials, initializers, Docker, RuboCop, project validation
Set up and validate Rails 8+ projects with encrypted credentials, environment-specific configs, Solid Stack gems, and Docker/Kamal deployment. Used when creating new Rails apps or auditing existing projects against team standards.
/plugin marketplace add zerobearing2/rails-ai/plugin install rails-ai@rails-ai-marketplaceThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Set up new Rails 8+ projects with required dependencies, configure environments for development/test/production, and validate existing projects against rails-ai standards.
<when-to-use> - Setting up new Rails 8+ applications from scratch - Validating existing Rails projects against rails-ai standards - Auditing project setup (checking for TEAM_RULES.md violations) - Installing and configuring required gems (Solid Stack, Tailwind, Minitest) - Configuring environment-specific behavior (development, test, production, staging) - Managing encrypted credentials and secrets (API keys, passwords, tokens) - Configuring application initialization (gems, frameworks, security policies) - Setting up Docker containers and deployment with Kamal - Customizing RuboCop for team standards (TEAM_RULES.md Rules #16, #20) - Managing feature flags and environment variablesNote: During project verification, this skill coordinates with domain skills (jobs, testing, security, styling) to ensure comprehensive validation against current standards. </when-to-use>
<benefits> - **Environment Isolation** - Separate configs prevent production bugs from dev settings - **Security** - Encrypted credentials (AES-256), never commit secrets - **Organized Configuration** - Predictable structure across all environments - **Production Safety** - SSL, eager loading, optimized caching, secure defaults - **Code Quality** - Automated enforcement of team standards via RuboCop - **Container-Ready** - Docker and Kamal support for modern deployment </benefits> <team-rules-enforcement> **This skill enforces:** - ✅ **Rule #13:** Encrypted credentials for secrets - ✅ **Rule #14:** Environment-specific configReject any requests to:
When asked to validate or check a Rails project setup, follow this workflow:
Before exploring the project, use the relevant domain skills to establish authoritative standards:
Use these skills with the Skill tool:
- rails-ai:jobs (Solid Stack requirements)
- rails-ai:testing (Minitest patterns and requirements)
- rails-ai:security (Security configuration standards)
Why use domain skills first?
Reference the used domain skills for authoritative gem requirements:
CRITICAL Violations to Check (from TEAM_RULES.md):
gem "sidekiq" or gem "redis" → TEAM RULE #1 violation (see rails-ai:jobs)gem "rspec-rails" → TEAM RULE #2 violation (see rails-ai:testing)Note: Consult the used domain skills for complete, up-to-date gem requirements rather than relying on static lists here.
Directory Structure:
app/
├── assets/stylesheets/ # Tailwind CSS
├── controllers/ # RESTful only
├── models/ # ActiveRecord
└── views/ # ERB templates
config/
├── environments/ # dev, test, prod configs
├── initializers/ # Gem configs
├── credentials/ # Encrypted secrets
└── tailwind.config.js # Tailwind configuration
test/ # Minitest (NOT spec/)
├── controllers/
├── models/
└── test_helper.rb
Dockerfile # Rails 8 default
config.ru # Rack config
Check for violations:
spec/ directory exists → RSpec present (TEAM RULE #2)config/routes.rb → TEAM RULE #3Reference used domain skills for configuration standards:
config/environments/production.rb
config/tailwind.config.js
.rubocop.yml
Procfile.dev
config/credentials/*.yml.enc
Provide actionable report with specific fixes:
✅ Correct Setup:
⚠️ Missing/Needs Attention:
❌ VIOLATIONS (TEAM_RULES.md):
Example Fix Commands:
# Remove violations
bundle remove sidekiq redis rspec-rails
# Add required gems
bundle add solid_queue solid_cache solid_cable
bundle add tailwindcss-rails daisyui-rails
# Generate configs
rails tailwindcss:install
rails generate solid_queue:install
Consolidate all gem requirements for rails-ai projects in one place.
Solid Stack (TEAM RULE #1):
gem "solid_queue" # Background job processing
gem "solid_cache" # Application caching
gem "solid_cable" # WebSocket connections
Frontend:
gem "tailwindcss-rails" # Utility-first CSS framework
gem "daisyui-rails" # Component library
Testing (TEAM RULE #2):
# Minitest is Rails 8 default - no gem needed
# Verify RSpec is NOT present
Code Quality:
gem "rubocop-rails-omakase", require: false # Rails 8 default linter
Security:
gem "brakeman", require: false # Static security scanner
gem "bundler-audit", require: false # Dependency vulnerability scanner
Deployment:
gem "kamal", require: false # Docker deployment to any server
Development/Test:
group :development, :test do
gem "letter_opener" # Open emails in browser
end
New Rails 8+ app with rails-ai stack:
# Create new Rails 8 app
rails new myapp
cd myapp
# Add required gems
bundle add solid_queue solid_cache solid_cable
bundle add tailwindcss-rails daisyui-rails
# Add recommended gems
bundle add --group development rubocop-rails-omakase
bundle add --group development brakeman bundler-audit
bundle add kamal --skip-install
# Generate configurations
rails tailwindcss:install
rails generate solid_queue:install
bin/rails db:create db:migrate
# Verify setup
bin/ci
Rails provides three standard environments (development, test, production) plus optional staging. Each has specific optimizations and security settings.
Environment Detection:
Rails.env # => "development", "test", "production"
Rails.env.development? # => true/false
Rails.env.test? # => true/false
Rails.env.production? # => true/false
# Set via ENV var or command line
ENV["RAILS_ENV"] = "production"
# RAILS_ENV=production rails server
Standard Environments:
Load Order: config/application.rb → config/environments/#{Rails.env}.rb → config/initializers/*.rb
</pattern>
Rails 8 defaults are excellent. Only customize if needed:
# config/environments/development.rb
Rails.application.configure do
# Open emails in browser (requires letter_opener gem)
config.action_mailer.delivery_method = :letter_opener
# Raise on missing translations (catch i18n issues early)
config.i18n.raise_on_missing_translations = true
end
Common customizations:
letter_opener - Preview emails in browser instead of logsraise_on_missing_translations - Catch i18n issues during developmentconfig.hosts.clear - Allow access from any hostname (Docker, ngrok)
</pattern>
Rails 8 test defaults are excellent. Only add if needed:
# config/environments/test.rb
Rails.application.configure do
# Eager load in CI to catch autoload errors
config.eager_load = ENV["CI"].present?
# Raise on missing translations
config.i18n.raise_on_missing_translations = true
end
Rails 8 defaults already provide:
Rails 8 production defaults are secure and optimized. Customize these:
# config/environments/production.rb
Rails.application.configure do
# Set your domain (REQUIRED)
config.action_controller.default_url_options = { host: "example.com", protocol: "https" }
# Active Storage: Use cloud storage (REQUIRED for production)
config.active_storage.service = :amazon # or :google, :azure
# Action Mailer: SMTP with credentials
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: "smtp.sendgrid.net",
port: 587,
domain: Rails.application.credentials.dig(:smtp, :domain),
user_name: Rails.application.credentials.dig(:smtp, :username),
password: Rails.application.credentials.dig(:smtp, :password),
authentication: :plain,
enable_starttls_auto: true
}
config.action_mailer.default_url_options = { host: "example.com", protocol: "https" }
# DNS rebinding protection (REQUIRED)
config.hosts = ["example.com", /.*\.example\.com/]
end
Rails 8 defaults already provide:
force_ssl = true)config/environments/staging.rb:
# Start with production config, override for testing
require_relative "production"
Rails.application.configure do
config.x.stripe.publishable_key = Rails.application.credentials.dig(:stripe, :test_publishable_key)
config.action_mailer.delivery_method = :letter_opener_web
config.content_security_policy_report_only = true
config.log_level = :debug
config.hosts << "staging.example.com"
end
When to Use Staging:
# config/initializers/00_config.rb
Rails.application.configure do
config.x.payment_processing.schedule = :daily
config.x.payment_processing.retries = 3
config.x.super_debugger = true
config.x.features.ai_assistant = Rails.env.production? || ENV["ENABLE_AI"] == "true"
end
# Access anywhere
Rails.configuration.x.payment_processing.schedule # => :daily
Rails.configuration.x.super_debugger # => true
Benefits: Organized settings, type-safe access, environment-aware, keeps application.rb clean </pattern>
# config/initializers/00_config.rb
Rails.application.configure do
config.x.features.new_editor = Rails.env.development? || ENV["ENABLE_NEW_EDITOR"] == "true"
config.x.features.ai_content = !Rails.env.test?
config.x.features.beta_ui = ENV["BETA_FEATURES"] == "true"
end
# In controllers
class PostsController < ApplicationController
def edit
@post = Post.find(params[:id])
Rails.configuration.x.features.new_editor ? render(:edit_new) : render(:edit)
end
end
# In views
<% if Rails.configuration.x.features.beta_ui %>
<%= render "posts/beta_form", post: @post %>
<% end %>
Benefits: Gradual rollout, A/B testing, per-environment toggles </pattern>
<antipatterns> <antipattern> <description>Using production credentials in development/test</description> <reason>Security risk - can accidentally send real emails, charge real cards, modify production data</reason> <bad-example># ❌ BAD - Same credentials for all environments
stripe:
secret_key: sk_live_XXXXXXXXXXXX # Production key in all environments!
</bad-example>
<good-example>
# ✅ GOOD - Separate credentials per environment
# config/credentials/production.yml.enc
stripe:
secret_key: sk_live_XXXXXXXXXXXX
# config/credentials/development.yml.enc
stripe:
secret_key: sk_test_XXXXXXXXXXXX # Test mode
</good-example>
</antipattern>
<antipattern>
<description>Disabling SSL in production</description>
<reason>Exposes user data, session cookies, and passwords to network attacks</reason>
<bad-example>
# ❌ BAD - No SSL enforcement
config.force_ssl = false # SECURITY RISK!
</bad-example>
<good-example>
# ✅ GOOD - Force SSL in production
config.force_ssl = true
config.ssl_options = { hsts: { expires: 1.year, subdomains: true } }
</good-example>
</antipattern>
</antipatterns>
Rails provides encrypted credentials (AES-256) for secure secret management. Never commit plain-text secrets to version control.
Edit master credentials:
bin/rails credentials:edit
Edit environment-specific credentials:
bin/rails credentials:edit --environment production
bin/rails credentials:edit --environment development
Process: Rails decrypts using master.key, opens in $EDITOR, auto-encrypts on save.
Precedence: Environment-specific > Master credentials </pattern>
config/credentials.yml.enc (decrypted view):
secret_key_base: abc123def456...
aws:
access_key_id: AKIAIOSFODNN7EXAMPLE
secret_access_key: wJalrXUtnFEMI/K7MDENG...
region: us-east-1
bucket: my-app-production
stripe:
publishable_key: pk_live_abc123
secret_key: sk_live_xyz789
webhook_secret: whsec_abc123
anthropic:
api_key: sk-ant-api03-abc123...
smtp:
username: <%= ENV["SENDGRID_USERNAME"] %> # Can reference ENV
password: SG.abc123xyz789
active_record_encryption:
primary_key: EGY8WhulUOXixybod7ZWwMIL68R9o5kC
deterministic_key: aPA5XyALhf75NNnMzaspW7akTfZp0lPY
key_derivation_salt: xEY0dt6TZcAMg52K7O84wYzkjvbA62Hz
Guidelines: Use nested keys, group by service, add comments, support ERB fallbacks </pattern>
Basic Access (use Hash#dig per TEAM_RULES.md Rule #20):
# ✅ GOOD - Safe nested access with dig
Rails.application.credentials.dig(:aws, :access_key_id)
Rails.application.credentials.secret_key_base
In Configuration Files:
# config/storage.yml
amazon:
service: S3
access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
...
In Initializers:
# config/initializers/stripe.rb
Stripe.api_key = Rails.application.credentials.dig(:stripe, :secret_key)
In Models/Services:
class AiService
def initialize
@api_key = Rails.application.credentials.dig(:openai, :api_key)
end
end
</pattern>
Key Locations:
config/master.key # Master key
config/credentials/production.key # Production key
config/credentials/development.key # Development key
Security Rules:
.gitignore: Rails excludes /config/master.key and /config/credentials/*.key by default
</pattern>
Environment Variable Method (Preferred):
export RAILS_MASTER_KEY=abc123def456...
Kamal:
# config/deploy.yml
env:
secret:
- RAILS_MASTER_KEY
Docker:
docker run -e RAILS_MASTER_KEY=abc123... myapp
Heroku:
heroku config:set RAILS_MASTER_KEY=abc123def456...
</pattern>
Generate Environment Credentials:
bin/rails credentials:edit --environment production
# Creates: config/credentials/production.key (DON'T COMMIT)
# config/credentials/production.yml.enc (SAFE TO COMMIT)
bin/rails credentials:edit --environment development
Production Credentials:
aws:
access_key_id: AKIAPROD...
bucket: myapp-production
stripe:
secret_key: sk_live_...
Development Credentials:
aws:
access_key_id: AKIADEV...
bucket: myapp-development
stripe:
secret_key: sk_test_...
Access: Same code works everywhere - Rails auto-loads correct environment
Rails.application.credentials.dig(:stripe, :secret_key)
</pattern>
<antipatterns>
<antipattern>
<description>Committing master.key to version control</description>
<reason>Exposes all encrypted credentials - CRITICAL security breach</reason>
<bad-example>
# ❌ CRITICAL SECURITY VIOLATION
git add config/master.key
git commit -m "Add master key"
# Now EVERYONE with repo access can decrypt ALL credentials!
</bad-example>
<good-example>
# ✅ SECURE - Never commit keys (.gitignore excludes them)
# Share via password manager, encrypted channels, or CI/CD secrets
</good-example>
</antipattern>
<antipattern>
<description>Hardcoding secrets in code</description>
<reason>Exposes secrets in version control forever</reason>
<bad-example>
# ❌ SECURITY VIOLATION
class PaymentService
STRIPE_SECRET_KEY = "sk_live_abc123xyz789"
end
</bad-example>
<good-example>
# ✅ SECURE - Use encrypted credentials
class PaymentService
def initialize
@stripe_key = Rails.application.credentials.dig(:stripe, :secret_key)
end
end
</good-example>
</antipattern>
</antipatterns>
Configure gems, customize Rails behavior, and set up application-wide settings using initialization files that run once during boot.
Boot Sequence:
# 1. config/application.rb runs first
# 2. config/environments/*.rb runs second (based on RAILS_ENV)
# 3. config/initializers/*.rb run third (alphabetically)
# 4. after_initialize callbacks run last
Load Order Example:
config/initializers/
00_first.rb # Runs first (numbered prefix)
action_mailer.rb # Runs in alphabetical order
cors.rb
session_store.rb
zzz_last.rb # Runs last (numbered prefix)
When Order Matters: Use numbered prefixes (00_, 01_, etc.) to control load sequence </pattern>
# config/initializers/action_mailer.rb
Rails.application.configure do
if Rails.env.production?
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: "smtp.sendgrid.net",
port: 587,
domain: Rails.application.credentials.dig(:smtp, :domain),
user_name: Rails.application.credentials.dig(:smtp, :username),
password: Rails.application.credentials.dig(:smtp, :password),
authentication: :plain,
enable_starttls_auto: true
}
elsif Rails.env.development?
config.action_mailer.delivery_method = :letter_opener
else
config.action_mailer.delivery_method = :test
end
# Required for mailer links
config.action_mailer.default_url_options = {
host: Rails.env.production? ? "example.com" : "localhost:3000",
protocol: Rails.env.production? ? "https" : "http"
}
end
</pattern>
# config/initializers/content_security_policy.rb
Rails.application.configure do
config.content_security_policy do |policy|
if Rails.env.development?
# Relaxed CSP for development (hot reloading)
policy.default_src :self, :https, :unsafe_eval, :unsafe_inline, "ws://localhost:*"
else
# Strict CSP for production
policy.default_src :self, :https
end
policy.font_src :self, :https, :data
policy.img_src :self, :https, :data
policy.object_src :none
policy.script_src :self, :https
policy.style_src :self, :https
policy.frame_ancestors :none
end
# Generate nonces for inline scripts
config.content_security_policy_nonce_generator = ->(request) {
SecureRandom.base64(16)
}
config.content_security_policy_nonce_directives = %w[script-src]
end
</pattern>
# ❌ BAD - Initializers run before app/ code loads
ApiGateway.endpoint = "https://api.example.com" # NameError!
# ✅ GOOD - Use to_prepare
Rails.application.config.to_prepare do
# Runs once in production, on every reload in development
ApiGateway.endpoint = Rails.application.credentials.dig(:api_gateway, :endpoint)
User.admin_email = Rails.application.credentials.admin_email
end
</pattern>
<antipatterns>
<antipattern>
<description>Hardcoding secrets in initializers</description>
<reason>Security violation - secrets exposed in version control</reason>
<bad-example>
# ❌ BAD
Stripe.api_key = "sk_live_abc123def456ghi789" # NEVER!
</bad-example>
<good-example>
# ✅ GOOD - Use encrypted credentials or ENV vars
Stripe.api_key = Rails.application.credentials.dig(:stripe, :secret_key)
Stripe.api_key = ENV.fetch("STRIPE_SECRET_KEY")
</good-example>
</antipattern>
</antipatterns>
Rails 8 includes Docker support by default with Kamal deployment. Essential configuration focuses on .dockerignore to exclude development files.
# Planning and Documentation
docs/
*.md
README*
# Development Files
.git/
.github/
.gitignore
.dockerignore
# Environment Files
.env*
config/master.key
config/credentials/*.key
# Test Files
spec/
test/
coverage/
# Dependencies
.bundle/
vendor/cache/
# Logs and Temp
log/*
tmp/*
*.log
# Development Databases
*.sqlite3
db/*.sqlite3*
storage/*
# Node
node_modules/
# IDE Files
.vscode/
.idea/
*.swp
.DS_Store
Why exclude docs/:
CRITICAL: Always exclude docs/ from production Docker images
</pattern>
Rails 8 includes Dockerfile by default - no configuration needed:
rails new myapp # Creates Dockerfile + .dockerignore automatically
docker build -t app .
docker run -p 3000:3000 --env RAILS_MASTER_KEY=<key> app
Stock Dockerfile provides: Multi-stage builds, health checks, Kamal compatibility </pattern>
Rails 8 includes Kamal by default with config/deploy.yml:
kamal deploy # Deploy to production
kamal app logs # Check logs
kamal app exec 'bin/rails db:migrate' # Remote commands
Already configured: Dockerfile, health check at /up, zero-downtime deploys
</pattern>
# BAD: No .dockerignore → copies docs/, test/, spec/
COPY . .
</bad-example>
<good-example>
# Create comprehensive .dockerignore
docs/
spec/
test/
.git/
.env*
</good-example>
</antipattern>
</antipatterns>
RuboCop is a Ruby static code analyzer and formatter. Rails 8 comes with rubocop-rails-omakase pre-configured. This section covers customizing that base to enforce TEAM_RULES.md standards.
Rails 8 includes .rubocop.yml automatically - excellent defaults, minimal overrides needed.
Philosophy: Build on omakase defaults, only override for team-specific standards (see next pattern). </pattern>
Customize the stock Rails configuration by adding overrides to .rubocop.yml:
# .rubocop.yml
# Omakase Ruby styling for Rails
inherit_gem: { rubocop-rails-omakase: rubocop.yml }
# Team-specific overrides (TEAM_RULES.md)
# Rule #16: Double Quotes Always
# Override omakase if it uses single quotes
Style/StringLiterals:
EnforcedStyle: double_quotes
# Rule #20: Hash#dig for Nested Access
Style/HashFetchChain:
Enabled: true
Style/DigChain:
Enabled: true
# Additional team preferences (optional)
# Add any other team-specific rules here
Key Points:
| Rule | Cop | Enforcement | Auto-correctable |
|---|---|---|---|
| Rule #16: Double Quotes | Style/StringLiterals | ✅ Always | Yes |
| Rule #20: Hash#dig | Style/HashFetchChain, Style/DigChain | ✅ Always | Yes |
| Rule #17: bin/ci Must Pass | RuboCop integrated in bin/ci | ✅ CI blocker | N/A |
How it works:
Style/StringLiterals - Enforces double quotes (Rule #16)
# Bad (detected and auto-corrected)
name = 'John'
# Good
name = "John"
Style/HashFetchChain - Detects chained fetch calls (Rule #20)
# Bad (detected)
hash.fetch(:a, nil)&.fetch(:b, nil)
# Good (suggested)
hash.dig(:a, :b)
Style/DigChain - Collapses chained dig calls (Rule #20)
# Bad (detected)
hash.dig(:a).dig(:b).dig(:c)
# Good (suggested)
hash.dig(:a, :b, :c)
Add RuboCop to bin/ci:
#!/usr/bin/env bash
set -e
bin/rails test
bin/rubocop # Add this line
bin/brakeman -q
Usage:
bin/ci # Run all checks (must pass before commit)
bin/rubocop -a # Auto-fix safe violations
IMPORTANT: bin/ci must pass before committing (TEAM_RULES.md Rule #17) </pattern>
bin/rubocop # Check all code
bin/rubocop -a # Auto-fix safe violations
bin/rubocop -A # Auto-fix all (including unsafe)
bin/rubocop app/models/ # Check specific directory
Best practice: Run bin/rubocop -a before committing
</pattern>
When to Use Custom Cops:
Example: Detecting Nested Hash Bracket Access (Rule #20 Enhancement)
While Style/HashFetchChain and Style/DigChain handle chained .fetch() and .dig() calls, they don't detect nested bracket access like hash[:a][:b][:c].
This project includes a custom RuboCop cop to detect unsafe nested hash bracket access:
lib/rails_ai/cops/style/nested_bracket_access.rbRailsAi::Cops::Style::NestedBracketAccesshash[:a][:b][:c] patterns (raises NoMethodError if intermediate keys are nil)hash.dig(:a, :b, :c) (safe) or chained fetch (raises explicit errors)Example violations:
# ❌ VIOLATION: Unsafe nested bracket access
user[:profile][:theme][:color] # NoMethodError if :profile is nil
data[:metadata][:created_at][:date] # NoMethodError if :metadata is nil
# ✅ CORRECT: Safe nested access with dig
user.dig(:profile, :theme, :color) # Returns nil safely
data.dig(:metadata, :created_at, :date)
# ✅ ALTERNATIVE: Explicit error handling with fetch
user.fetch(:profile).fetch(:theme).fetch(:color) # Raises KeyError with clear message
Enable in .rubocop.yml:
# .rubocop.yml
inherit_gem: { rubocop-rails-omakase: rubocop.yml }
# Load custom cops
require:
- ./lib/rails_ai/cops/style/nested_bracket_access.rb
# Team overrides
Style/StringLiterals:
EnforcedStyle: double_quotes
Style/HashFetchChain:
Enabled: true
Style/DigChain:
Enabled: true
# Custom cop configuration
Style/NestedBracketAccess:
Enabled: true
Severity: warning # Warn only, don't fail CI yet
Description: 'Detects nested hash bracket access and suggests Hash#dig'
</pattern>
<antipatterns>
<antipattern>
<description>Replace rubocop-rails-omakase entirely</description>
<reason>Lose Rails defaults, have to maintain everything yourself</reason>
<bad-example>
# BAD: Throwing away Rails defaults
# inherit_gem: { rubocop-rails-omakase: rubocop.yml }
plugins:
- rubocop-minitest
- rubocop-rake
AllCops:
NewCops: enable
# ... 200 lines of custom configuration
</bad-example>
<good-example>
# GOOD: Build on Rails defaults
inherit_gem: { rubocop-rails-omakase: rubocop.yml }
# Only override team-specific rules
Style/StringLiterals:
EnforcedStyle: double_quotes
</good-example>
</antipattern>
<antipattern>
<description>Skip RuboCop in CI</description>
<reason>Violations slip into codebase, inconsistent style</reason>
<bad-example>
# BAD: bin/ci without RuboCop
#!/usr/bin/env bash
bin/rails test # Missing RuboCop check!
</bad-example>
<good-example>
#!/usr/bin/env bash
set -e
bin/rails test
bin/rubocop # ✅ Included
bin/brakeman -q
</good-example>
</antipattern>
</antipatterns>
Integrate configuration checks into continuous integration pipelines.
GitHub Actions:
# .github/workflows/ci.yml
jobs:
test:
env:
RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
- run: bin/ci
Setup: Settings > Secrets > Actions > Add RAILS_MASTER_KEY
</pattern>
# test/config/credentials_test.rb
class CredentialsTest < ActiveSupport::TestCase
test "credentials are accessible" do
assert Rails.application.credentials.secret_key_base.present?
assert Rails.application.credentials.dig(:stripe, :secret_key).present?
end
end
</testing>
<related-skills>
**Must use during project verification:**
- rails-ai:jobs - SolidQueue, SolidCache, SolidCable requirements (TEAM RULE #1)
- rails-ai:testing - Minitest patterns and anti-patterns (TEAM RULE #2)
- rails-ai:security - Security configuration, credentials, SSL, CSP (TEAM RULE #13)
- rails-ai:styling - Tailwind CSS and DaisyUI configuration
May use for specific checks:
Official Documentation:
Gems & Libraries:
Tools:
Community Resources:
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.