2025-07-30

From Chaos to Control: How I Taught Claude Code to be Consistent and Accurate

Teaching Claude Code Consistency

I started using Claude Code for Rails development with the same excitement everyone has when they first discover AI coding assistants. The promise was incredible: describe what you want, get working code instantly.

Then reality hit. Suboptimal code. Inconsistent patterns. Going off on tangents when I asked for simple changes. Every implementation looked different. Business logic crammed into models. Tests that just tested Rails itself.

The solution wasn’t to abandon AI - it was to train it properly.

The Problems I Faced

1. Inconsistent Code Style

Every time I asked Claude to create a new model or controller, it was like working with a different developer. No adherence to our conventions. Mixed patterns within the same codebase. One file used service objects, the next stuffed everything into fat models.

2. Reinventing the Wheel

Claude didn’t know our existing patterns. Ask for user authentication? It would create a whole new system instead of using our established AuthenticationService. Need error handling? New approach every time, ignoring our standardized error classes.

3. Suboptimal Patterns & Lost Focus

The worst part was the Rails anti-patterns. Business logic in models. Fat controllers doing five different things. Database queries in views. And don’t get me started on the tangents - I’d ask for a simple model change and get a complete architectural redesign of unrelated parts.

The Solution: CLAUDE.md Files

Quick Win Example

Before diving deep, here’s a simple CLAUDE.md that shows the concept in action:

# Models Directory Rules

Models should be thin. Only include:
- Validations
- Associations  
- Scopes
- Database-related configs

Business logic goes in app/services or app/commands.

Just 7 lines that set clear boundaries. Once Claude reads this, it knows exactly where business logic belongs.

And here’s a companion CLAUDE.md for the commands directory:

# Business Logic Commands

All commands should:
- Inherit from BaseCommand
- Have single public method: call
- Be idempotent when possible (safe to run multiple times)
- Return success() or error() with clear messages
- Handle their own error cases

Keep commands focused on single responsibility unless splitting creates more complexity than it solves.

What They Are

CLAUDE.md files are markdown documents placed strategically throughout your codebase. They’re living documentation that AI reads before acting on any code in that directory. Think of them as executable specifications, not just guidelines.

The Structure

project_root/
├── CLAUDE.md          # Project overview, conventions, architecture decisions
├── app/
│   ├── business_logic/
│   │   └── CLAUDE.md  # Command pattern specs
│   ├── controllers/
│   │   └── CLAUDE.md  # Controller patterns
│   ├── models/
│   │   └── CLAUDE.md  # Thin model rules
│   └── test/
│       └── CLAUDE.md  # Testing patterns & anti-patterns

The root CLAUDE.md contains project overview, critical commands (test, build, deploy), and general intentions. When Claude works on a file, it reads all CLAUDE.md files up the directory tree, so specific coding patterns live close to the code they govern while general project context stays at the root.

Key Components

1. Positive Examples

Show exactly how things should be done with real code from your project:

# GOOD: Thin model
class User < ApplicationRecord
  validates :email, presence: true, uniqueness: true

  has_many :posts
  belongs_to :organization

  scope :active, -> { where(active: true) }
end

2. Anti-Patterns

Be explicit about what NOT to do:

# NEVER DO THIS
class User < ApplicationRecord
  def send_welcome_email
    UserMailer.welcome(self).deliver_later
    update(welcomed: true)
  end
end

3. Context-Specific Rules

When to apply patterns, when exceptions are allowed, how to handle edge cases. Your documentation, your rules.

What This Looks Like in Practice

Without CLAUDE.md Guidelines

Here’s a typical Rails model that mixes concerns:

class Post < ApplicationRecord
  belongs_to :user

  def publish!
    self.published_at = Time.current
    self.status = 'published'
    save!

    NotificationMailer.post_published(self).deliver_later
    user.increment!(:published_posts_count)

    TwitterService.new.share(self) if user.twitter_connected?
    update_search_index
  end

  def archive!
    self.status = 'archived'
    self.archived_at = Time.current
    save!

    remove_from_search_index
    CacheService.expire_post(self)
  end
end

With CLAUDE.md Guidelines

Following the thin model pattern from our example CLAUDE.md:

class Post < ApplicationRecord
  belongs_to :user

  validates :title, presence: true
  validates :content, presence: true

  scope :published, -> { where(status: 'published') }
  scope :draft, -> { where(status: 'draft') }

  # Just data, validations, and associations
end

# In app/commands/publish_post_command.rb
class PublishPostCommand < BaseCommand
  def initialize(post)
    @post = post
  end

  def call
    # Idempotent - safe to run multiple times
    return success(@post) if @post.status == 'published'

    @post.update!(
      published_at: Time.current,
      status: 'published'
    )

    # These operations only happen on first publish
    NotificationMailer.post_published(@post).deliver_later
    @post.user.increment!(:published_posts_count)

    TwitterService.new.share(@post) if @post.user.twitter_connected?
    SearchIndexer.new.index(@post)

    success(@post)
  end
end

The model stays focused on data and relationships. Business logic gets its own home where it’s testable, reusable, and maintainable.

The Implementation Process

1. Audit Existing Code

First, I had Claude analyze my codebase to identify patterns already in use. This gave me a baseline of what was working and what needed fixing.

2. Create Documentation Hierarchy

Started with a root CLAUDE.md for project overview, then added specific files for each major directory. Test documentation got the most detail - that’s where consistency matters most.

3. Make It Actionable

Set clear intentions that AI can follow. The root CLAUDE.md tells Claude WHEN to use patterns:

# Project Architecture (root CLAUDE.md)

... (project overview above) ...

## Command Pattern Usage

Use commands for:
- Any operation that changes system state
- Multi-step business processes  
- Operations that send emails or trigger external services
- Any action that needs to be audited or logged

Do NOT use commands for:
- Simple data queries
- View helpers or presenters
- Configuration or settings

... (other architectural decisions below) ...

While subdirectory CLAUDE.md files show HOW to implement those patterns. This separation lets Claude understand the architecture at the right level - high-level decisions at the root, implementation details where the code lives.

4. Continuous Refinement

As you work with Claude, you’ll discover edge cases and better patterns. Update the documentation. It’s living documentation - let it evolve with your codebase.

Results and Impact

Predictable Output

Every model looks like every other model. Every command follows the same pattern. No more surprises or “creative” implementations.

Faster Development

Claude doesn’t waste time exploring different approaches. It goes straight to the correct implementation. What used to take multiple back-and-forth corrections now works on the first try.

Knowledge Preservation

Team decisions are encoded permanently. New developers learn from AI behavior. Your patterns self-document through consistent usage.

Quality Improvements

Anti-patterns get caught before they’re written. Error handling is consistent across the entire codebase. Proper separation of concerns is maintained automatically.

The Foundation for Advanced Automation

Once your CLAUDE.md files establish consistent patterns, they become the foundation for powerful automation:

  • Clear documentation = focused AI behavior
  • Focused behavior = reliable automation
  • Reliable automation = compound efficiency gains

AI stops guessing and starts following your patterns. Custom commands and specialized agents can build on your documented patterns with confidence.

Without this foundation, automation tools just amplify chaos. With it, they become force multipliers.

Get this documentation right first. Once your patterns are clear, custom Claude commands and agents become focused and reliable. Then you can start assembling workflows that actually work instead of fighting inconsistent AI behavior.

Key Takeaways

  1. AI needs context to be effective - Generic AI gives generic results. Domain-specific training is essential.

  2. Documentation as code - Must be maintained like code, lives with the code it documents, version controlled and reviewed.

  3. Explicit > Implicit - Show exact patterns to follow, list specific anti-patterns to avoid, leave no room for interpretation.

  4. Investment pays off - Time spent documenting saves multiples later. Consistency compounds value. Team knowledge becomes permanent.

Get Started: Example Prompts

For Rails Models: "Analyze my User and Post models and create a CLAUDE.md that enforces thin models with only validations, associations, and scopes. Business logic should go in service objects."

For Controllers: "Create a CLAUDE.md for my controllers directory that enforces: single responsibility actions, proper HTTP status codes, no business logic, and consistent error handling using rescue_from."

For Testing: "Generate a CLAUDE.md for my test directory that shows how to test behavior not implementation, avoid testing Rails itself, and use factories instead of fixtures."

For Service Objects: "Create a CLAUDE.md template for a service objects pattern where each service has a single public call method, returns Result objects, and handles its own errors."

Remember: Pragmatism Over Dogma

Pattern consistency matters more than pattern perfection. AI needs consistency more than SOLID principles. Pick patterns your team can understand and maintain.

Build in flexibility: - “Follow Command pattern EXCEPT when it adds no value” - “Use thin models UNLESS the alternative is worse”

AI mistakes will happen - make them easy to spot and correct.

Your First CLAUDE.md in 5 Minutes

  1. Pick one directory (start with models)
  2. Paste one of the prompts above
  3. Review what Claude generates
  4. Keep what works, fix what doesn’t
  5. Save and test with a real implementation

The perfect documentation doesn’t exist. Good enough documentation that improves your workflow does.

What patterns are you struggling to keep consistent in your codebase?


Ready to take your CLAUDE.md files to the next level? Learn how to turn your best AI prompts into reusable commands that work with your patterns for even faster, more consistent development.