From Junior Dev to Rails Craftsman
The journey of teaching an LLM not just to write Rails, but to think like the people who built it.
When I first started experimenting with teaching an LLM Rails, my goal was simple: make it as good as a junior developer.
A junior can scaffold models, follow patterns, and copy-paste from the docs. They’re helpful, but they’ll also trip on anything outside the basics. I wanted to see if I could push an LLM further, the same way you’d mentor a human dev: start at junior, then build toward intermediate.
But the real question I wanted to answer was this:
Could an AI write Rails code the way 37signals would — or even like DHH himself?
That was the bar I set. Not just “working Rails apps,” but Rails apps that looked and felt like the framework’s creators had built them.
The First Step: A Junior-Level AI
I began with a single rules file inside Cursor. It was short and lean, giving the LLM just enough guardrails to stay inside Rails conventions.
It worked fine for simple tasks, but it plateaued quickly. The code was shallow. The logic is repetitive. The AI was still thinking like a junior, following directions without really understanding the framework.
It had no Rails soul.
From One File to a Kitchen of Stations
The turning point was reimagining my approach as a chef’s kitchen, not a chaotic pantry. Instead of one overstuffed rules file, I split Rails into specialized stations, each with its own Cursor rules file packed with idiomatic examples to give the AI depth of knowledge specific to the area it would work in. My file system became a well-orchestrated setup:
Models: Active Record rules for associations (belongs_to, has_many), validations (validates :name, presence: true), and callbacks (before_save).
Controllers: RESTful controller logic, strong parameters, and filters for convention-driven actions.
Views: Lean partials, ERB, Turbo Drive, Turbo Frames, etc.
Helpers: Custom helpers to simplify view logic, eliminate repetition, and boost testability with Rails-native elegance.
JavaScript: Stimulus controllers and Turbo Streams for dynamic, Rails-native interactivity.
CSS: Tailwind and DaisyUI for modern, framework-aligned styling.
Beyond: Rules for jobs, mailers, caching, migrations, security, Active Storage, Action Text, Action Cable, and routes.
An examples/ folder: Idiomatic Rails snippets for each station, showcasing best practices.
📸 Here’s my Cursor rules directory. Just about every major part of Rails has its own file, plus an examples
folder with idiomatic code.
This structure transformed the AI’s output. Code became consistent, hallucinations dropped, and it stopped reaching for unnecessary gems. It started feeling like a developer who knew Rails.
Testing the Setup
I tasked the AI with building a new Rails app from scratch. The results were transformative: clean scaffolding, RESTful controllers, validated models, and dynamic frontends with Stimulus and Tailwind. It wasn’t flawless, but it was no longer a toy; it was a teammate ready to grow.
Enter Claude: The Philosophical Edge
Next, I brought in Claude with a single Claude.md file, designed not for granular rules but for a Rails worldview. Light on examples, heavy on philosophy, it captured why Rails works the way it does: architectural principles, Edge Rails concepts, and the mindset of a senior engineer.
I ran an experiment:
Claude: Big-picture architect, drafting features with Rails’ intent in mind.
Cursor: Detail-oriented developer, refining code with station-specific rules.
Together, they formed a hybrid team. Claude sketched the vision; Cursor polished the execution. The result? Code that felt closer to senior-level Rails than I’d ever seen from an AI.
Stress-Testing with Personas
I kept Claude.md lean (about 15% of the context window), then stress-tested it:
A 20-year Rails veteran persona critiqued the file and exposed gaps.
A DHH-inspired persona evaluated it against Rails’ philosophy and guardrails. Did anything contradict the intent of the framework? Was something missing that would help Claude code more like Rails itself? I only folded in suggestions that Claude confirmed would improve its output.
Finally, I studied two 37signals apps I bought from once.com. These aren’t tutorials — they’re real production apps written by the team that created Rails. Their style and patterns went straight into Claude’s worldview.
This provided a huge improvement in the code written. Claude stopped coding like an obedient junior and started coding with the perspective of someone who had lived inside Rails for a decade.
Claude itself estimated this setup could code at a senior level. Grok agreed. ChatGPT 5 disagreed and called it “junior.” (Funny that the AIs can’t even agree with each other.) From my testing, it feels somewhere between intermediate and senior, and more importantly, it feels like Rails code in the Rails way.
The Secret Sauce: Personas as Mentors
One of the most powerful cheats I found in this process was creating personas.
I didn’t just load up rules and hope the AI did better. I created critics. Mentors. Voices to test the system from different angles.
The Rails vet persona surfaced blind spots.
The DHH-inspired persona enforced philosophy and guardrails, pointing out what was missing to make the code feel more like Rails.
Claude itself validated whether those changes would actually improve the code output before I merged them.
This approach works beyond coding:
Finance? Create a “20-year Wall Street analyst” persona to critique your strategy.
Design? Spin up a “modern minimalist design guru” persona to refine your layouts.
Writing? Create a “Hemingway” persona to tear down your prose.
The point isn’t to follow their advice blindly. It’s to use them as sparring partners; a way to stress-test and refine your ideas from different vantage points.
The Hybrid Team
From the beginning, I didn’t set out to pick one tool or LLM over another, but rather how to use tools and different LLMs together.
Claude = architect + lead engineer. It drafts new features, scaffolds systems, and codes with Rails’ philosophy baked in.
Cursor = intermediate-to-advanced developer. It edits, refactors, and polishes code inside the right station.
Together, they act like a real team. One leads, one sharpens.
To support them, I built a custom Ruby MCP doc search engine that works inside both Claude Code and Cursor. It lets the AI pull directly from the Edge Rails Guides and API, plus Turbo, Stimulus, Tailwind, and DaisyUI.
This mimics a developer who knows when to check the manual, ensuring clean, fast, convention-driven apps.
How You Can Start
Don’t overwhelm your LLM with endless rules. Apprentice it:
Start with one focused context (e.g., models).
Write a half-page of rules with Rails-native examples—associations, validations, callbacks.
Build a small feature and iterate.
Here’s a quick Cursor rules example to try tonight:
---
description: "Rails model rules for structure, associations, validations, and behaviors"
autoAttached: true
globs:
- "app/models/**/*.rb"
- "app/models/concerns/**/*.rb"
---
# Example rules
- Use `belongs_to`, `has_many`, or `has_one` for associations.
- Add validations like `validates :name, presence: true`.
- Use callbacks like `before_save` for business logic.
The Bigger Picture
This is just the start. I’ve apprenticed an LLM into Rails, but next up is a design agent for modern, non-AI-looking UI. Then a copywriting agent, followed by a marketing agent. The goal? An AI-native product team where each agent specializes, collaborates, and ships.
But it all started here, with the question:
Can an AI write Rails code the way 37signals or DHH would?
I’m not there yet, but this system: Claude’s philosophy, Cursor’s precision, and persona-driven critiques, is the closest I’ve come.