Claude Code Configurations Every Rails Engineer Should Use

Colin Soleim Colin Soleim · Apr 15, 2026
Claude Code Configurations Every Rails Engineer Should Use

If you've tried Claude Code on a large Rails codebase, you've probably noticed the gap between the demos and reality. The demos show Claude refactoring a 50-line file or writing a CRUD controller from scratch. Your codebase has 400 models, a domain model that took two years to understand, soft deletes on every table, and three different patterns for filter state persistence that nobody documented. Out of the box, Claude doesn't know any of that.

The difference between Claude Code being "kind of useful" and Claude Code being genuinely productive on a large codebase is context and configuration. Telling the tool what it needs to know about your specific system, giving it access to your data, and building repeatable workflows for the tasks you do every week.

The good news is that Rails monoliths are unusually well-suited for AI-assisted development. A RubyKaigi 2025 analysis by Rodrigo Serradura found that Ruby ranks #1 in token efficiency with Claude Code at $0.36 per task across 18 languages tested. Y Combinator CEO Garry Tan has called Rails' convention-over-configuration approach "LLM catnip" because the predictable file structure means the AI's first guess about where code lives is usually correct. When your models are in app/models, your controllers are in app/controllers, and your tests mirror the same structure, Claude doesn't waste tokens searching.

Shopify, Thoughtbot, and our team at NextLink Labs have all invested heavily in Claude Code tooling for Rails. The approaches are converging. Here's what actually works.

CLAUDE.md as a Living Architecture Document

The single most important file in your Claude Code setup is CLAUDE.md in your project root. Claude reads it at the start of every conversation. On a small project, you can skip it and Claude will figure things out by reading the code. On a codebase with 100K+ lines, that doesn't work. There are too many files, too many implicit conventions, and too many places where the "obvious" approach is wrong because of some historical decision.

Thoughtbot found this when they used Claude Code to build TellaDraft, a production Rails app, in a two-week sprint. Their CLAUDE.md started small and grew over the sprint as they discovered gaps. They added stack specifics (Rails, Postgres, Devise), API integration details for ElevenLabs and WhisperAI, coding style preferences, and testing conventions. When Claude approached context limits mid-session, they prompted it to reread the CLAUDE.md and scan the codebase, which got it back on track.

We've landed on a similar approach. Here's what we include in ours for a Rails 7.2 monorepo with about 80 models:

 
Domain model relationships. Our system has Payers (schools), Patients (students), Referral Services (the central hub), Appointments, Goals, and Goal Notes. The tricky part is that Appointments belong to Referral Services, not directly to Patients. Goals also belong to Referral Services, not Patients. If Claude doesn't know this, it will write joins through the wrong tables every time. We document these relationships explicitly, including the foreign key names and the valid status/phase values for each model.
 
Soft delete reminders. We use acts_as_paranoid across most tables. Every query Claude writes needs WHERE deleted_at IS NULL or it will return incorrect results. We put this in CLAUDE.md because it's the kind of thing that's invisible in the code until you get bitten by it.
 
Role mappings. Our backend role names don't match the frontend role names (payer_admin in Rails becomes school_admin in React). Without this documented, Claude will use the wrong role name about half the time when working on authorization logic.
 
Environment quirks. We manage Ruby and Node through asdf, and the system Ruby on macOS doesn't have the right bundler version. Claude needs to know to use absolute shim paths (/Users/you/.asdf/shims/bundle) instead of just bundle, or commands will fail silently or run against the wrong Ruby version.

What we don't put in CLAUDE.md is equally important. Don't dump your entire schema, your full API documentation, or your README. Every token in CLAUDE.md is context that Claude carries through the entire conversation. One practitioner recommends only documenting tools and APIs used by 30% or more of your team, and keeping the file under 15KB. We follow the same rule: document what Claude can't infer from reading the code, skip anything it can figure out by reading the relevant source file.

We treat CLAUDE.md the same way we treat our README. Whenever a new developer joins the project and gets stuck on something, we update it. When Claude gets something wrong because of missing context, add that context to CLAUDE.md so it doesn't happen again.

Custom MCP Servers for Database Context

We wrote a separate article about building a custom MCP server to connect Claude Code to your Rails database, so we won't repeat the implementation details here. But we want to emphasize why this matters more on large codebases than small ones.

On a small app, Claude can read your models and migrations and build a reasonable mental model of your data. On a large app with 80+ tables, polymorphic associations, STI, and years of migrations, that doesn't scale. Claude needs to be able to ask the database directly: "What columns does this table actually have? What are the real values in this enum column? How many records match this condition?"

The MCP server we built gives Claude three tools: list_tables, describe_table, and execute_query. All queries run through a Rails controller that enforces read-only transactions with a 30-second timeout. Claude can explore the schema, run ad-hoc queries, and verify its assumptions without you switching to psql.

Shopify takes the MCP concept further. Their engineering team connects AI tools to internal wikis, product management tools, and data warehouses through MCP servers, all respecting existing access controls. For their 2.8-million-line monolith, a coding agent that can only see source files is working with a fraction of the context it needs. MCP servers fill the gap by giving the agent access to the surrounding systems: the database, the issue tracker, the deployment logs.

For our setup, the most immediately useful application is debugging data issues. If a student isn't showing up on a dashboard, Claude can trace the problem from the cached computation in Solid Cache, through the precompute job's query, down to the actual database records, and tell you exactly where the discrepancy is. Without database access, it can only guess.

Claude Code Configurations Every Rails Engineer Should Use 1

Skills for Repeatable Workflows

Claude Code skills are markdown files in ~/.claude/skills/ that define step-by-step workflows. They're not useful for one-off tasks (just ask Claude directly for those). They're useful for processes you run regularly that involve multiple steps, external data sources, and consistent output formats.

We have seven custom skills. Here are the three that get the most use:

Sentry triage (/sentry-triage) pulls the top 20 unresolved errors from Sentry sorted by frequency, categorizes each one into priority tiers (P0: >500 events/week or >50 affected users, P1: >100 events/week, P2: >20/week, P3: everything else), groups them by root cause pattern, traces stacktraces back to files in the repository, generates a markdown triage report, and produces YAML ticket data for Jira import. Before building the skill, this process took about 2 hours of manual work. Now it takes about 15 minutes of review.

 

Sprint planner (/sprint-planner) reviews three inputs: the current Jira board, recent git activity, and the original Statement of Work. It cross-references what's been delivered against what the SOW requires, identifies timeline risks and scope drift, and generates 5-15 implementation tickets for the next 1-2 weeks with title, description, acceptance criteria, and epic assignment. We run this every Saturday for each active consulting engagement.

 

Git history analyzer (/git-history-analyzer) runs five git commands to surface codebase health signals: high-churn files, contributor landscape and bus factor, bug-fix frequency by file, growth patterns, and revert/hotfix detection for crisis patterns. It synthesizes these into a risk-ranked report. We run this when onboarding to a new client codebase. It gives us a codebase health report in about 5 minutes that used to take a senior engineer half a day.

 

Shopify takes a similar approach with Roast, an open-source Ruby framework they extracted from their internal AI tooling. Roast structures AI workflows using YAML config files and markdown prompt templates. Each workflow is a series of steps that can be directory-based, shell commands, inline AI prompts, or custom Ruby classes. Steps can even run in parallel using nested arrays in the YAML.

Here's what Shopify actually uses Roast for internally on their 2.8-million-line Rails monolith:

 
Test analysis at scale. They run a Roast workflow across thousands of test files to identify antipatterns, flag tests with poor coverage, and suggest improvements. At their scale, no human is reviewing every test file for quality.
 
Automated Sorbet type annotations. Their "Boba" workflow scans test files and adds type annotations automatically, something that would take weeks of manual work across a codebase that size.
 
Incident detection. A Roast workflow scans internal Slack channels for early indicators of production incidents, aggregating signals that would otherwise get lost in channel noise.

The philosophy behind both approaches (our skills, Shopify's Roast) is the same: non-determinism is the enemy of reliability. A vague prompt like "analyze the errors and create tickets" will give you different results every time. A structured workflow with explicit steps, specific thresholds, and defined output formats gives you consistent, reviewable output. The skill is a runbook, not a prompt.

Permission Whitelisting for Large Teams

If you're working on a codebase that connects to shared staging or production infrastructure, you need to think about what Claude is allowed to run. The default permission model asks you to approve each command, which gets tedious fast. The alternative, approving everything, is dangerous when a rails db:drop is one autocomplete away from rails db:migrate.

Claude Code supports a permission whitelist in .claude/settings.local.json. You explicitly list the commands, tools, and patterns that are allowed to run without prompting. Everything else still requires approval.

 
We allow common read operations without restriction: ls, grep, find, head, tail.
 
We allow specific Rails commands that are safe: bundle exec rails db:migrate, bin/rails runner, bundle install.
 
We allow our MCP tools by name and we allow npm for frontend work.
 
We don't allow without prompting: anything that modifies the database schema outside of migrations, anything that pushes to a remote, anything that kills processes by PID, and anything that touches Docker containers.

This file gets checked into the repository, so every developer on the team gets the same guardrails. If someone needs a new command whitelisted, they add it to the file and it goes through code review like any other change.

Shopify takes guardrails a step further. Even with all their AI tooling, they still require human PR review on every change. AI doesn't check in code automatically. Their CTO Farhan Thawar reports roughly 20% productivity improvements across the engineering org, but he's careful to note they measure this through demos and shipped features, not lines of code. As he puts it: "Code is cheap now. I don't want code, I want solutions."

Thoughtbot came to a similar conclusion during their TellaDraft sprint. Every single change was reviewed before committing, and every commit served as a quality control checkpoint. They also found that Claude sometimes generates tests that "just mock everything and test the mock," which passes CI but tests nothing useful. Their fix was coaching Claude through test-writing with specific examples of what a meaningful test looks like in their CLAUDE.md, and catching the rest in review.

Hooks for Guardrails That Can't Be Ignored

CLAUDE.md instructions are advisory. Claude reads them, usually follows them, but can drift, especially in long sessions with lots of context. If you have a rule that absolutely cannot be violated, use a hook instead.

Hooks are scripts that run automatically at specific points in Claude's workflow. Unlike CLAUDE.md, they're deterministic. A pre-commit hook that blocks credential files will block them every time, regardless of how long the conversation has been running or how much context has been compacted.

The most useful hooks for enterprise Rails work:

 
Pre-commit hooks that check git diff --cached for .env, .key, .pem, or credentials.yml.enc files. If any are staged, the hook blocks the commit and tells Claude why. This prevents accidental credential commits during refactoring sessions where Claude is moving files around.
 
PreToolUse hooks that prevent edits to protected files. If your config/database.yml, config/credentials/production.yml.enc, or deployment configs should never be modified by an AI assistant, a hook can enforce that. CLAUDE.md might say "don't edit production configs," but a hook will actually prevent it.
 
Post-edit hooks that auto-run your linter or formatter. If your team uses Rubocop or Prettier, a hook can run them after every file edit so Claude's output always matches your style conventions. This saves you from reviewing formatting changes in code review.

launch.json for Multi-Service Development

If your Rails app has a separate frontend (React, Next.js, etc.) or you're running multiple services, .claude/launch.json tells Claude Code how to start and preview them.

Here's our configuration:

{
  "configurations": [
    {
      "name": "rails",
      "runtimeExecutable": "/Users/you/.asdf/shims/bundle",
      "runtimeArgs": ["exec", "rails", "s", "-p", "3100"],
      "cwd": "hope-crm",
      "port": 3100
    },
    {
      "name": "react",
      "runtimeExecutable": "/Users/you/.asdf/shims/npm",
      "runtimeArgs": ["start"],
      "cwd": "hope-react",
      "port": 3001
    }
  ]
}

 

Two things to note. First, we use absolute paths to the asdf shims for bundle and npm. Claude Code doesn't source your shell profile when it starts a server, so if you use asdf, rbenv, or nvm, the default bundle or npm commands may resolve to the wrong version or fail entirely. Absolute paths fix this.

Second, if your frontend makes API calls to the Rails backend, make sure your CORS configuration allows the preview URL. Our React app runs on port 3001 and makes requests to localhost:3100. CORS is configured in config/application.rb to allow http://localhost:3001. We document this in CLAUDE.md because it's the kind of thing that causes confusing failures when Claude starts both servers and tries to preview the app.

What Senior Engineers Get Wrong

After using this setup daily for several months and watching other engineers adopt it, we've noticed a few common mistakes.

 
Putting too much in CLAUDE.md. We've seen engineers paste their entire database schema, full API endpoint lists, or multi-page architecture documents into the file. This wastes context that Claude needs for the actual work. CLAUDE.md should contain things Claude can't figure out on its own.
 
Not updating CLAUDE.md when the codebase changes. Stale instructions are worse than no instructions. If CLAUDE.md says "Appointments belong to Patients" but a migration six months ago changed it to "Appointments belong to Referral Services," Claude will confidently write incorrect code and you'll waste time debugging it. Treat it as a living document.
 
Giving Claude tasks that are too large. Thoughtbot's biggest takeaway from their two-week sprint was that smaller tasks produce better code. "Refactor the entire authentication system" will give you inconsistent results. "Create a new AuthToken model with these fields, write a test for the data migration, update the SessionsController to use it" gives Claude clear boundaries at each step.
 
Skipping database access. If your codebase uses soft deletes, polymorphic associations, STI, or any other pattern where the schema alone doesn't tell the full story, Claude will make mistakes without being able to query actual data. Setting up the MCP server takes 30 minutes and pays for itself immediately.

Getting Started

If you're working on a large Rails codebase and want to get the most out of Claude Code, start with these three things:

1. Write a CLAUDE.md that documents your domain model, implicit conventions, and environment quirks. Keep it under 15KB.

 

2. Set up the MCP database server. Read-only access with a 30-second timeout and transaction isolation. Takes 30 minutes.

 

3. Build one skill for a process you repeat weekly. Sentry triage, sprint planning, or deploy verification are good candidates. If you want a more structured approach, look at Shopify's Roast framework for YAML-driven AI workflows.

 

Add permission whitelisting and hooks as you get comfortable with the tool. The setup takes a day. The productivity gain compounds over months, because every convention you document and every workflow you automate saves time on every future session.

If you're interested in the broader case for Rails in 2026, we wrote about why we still build with Ruby on Rails and the ecosystem improvements that keep it competitive. Claude Code is one more reason the framework keeps working for us.

Colin Soleim

Author at NextLink Labs