# ce-dhh-rails-style

> A skill from Every's compound-engineering plugin that writes Ruby and Rails in DHH's 37signals style — REST purity, fat models and thin controllers, `Current` attributes, Hotwire over heavy JS, and 'clarity over cleverness.' It deliberately rejects devise, pundit, sidekiq, and rspec in favor of vanilla Rails: ~150 lines of custom auth on the User model, Solid Queue for jobs, and Minitest for tests.

**Use case**: Write Rails code the way Basecamp, HEY, and Campfire do — vanilla framework, rich domain models, no gem sprawl

**Canonical URL**: https://agentcookbooks.com/skills/ce-dhh-rails-style/

**Topics**: claude-code, skills, rails, code-quality

**Trigger phrases**: "write this Rails code in DHH style", "37signals conventions for this model", "should this be a service object or a fat model"

**Source**: [Every](https://github.com/EveryInc/compound-engineering-plugin/tree/main/plugins/compound-engineering/skills/ce-dhh-rails-style)

**License**: MIT

---

## What it does

`ce-dhh-rails-style` applies the 37signals / DHH coding philosophy to Ruby on Rails — see [skills/ce-dhh-rails-style](https://github.com/EveryInc/compound-engineering-plugin/tree/main/plugins/compound-engineering/skills/ce-dhh-rails-style) in [Every's compound-engineering plugin](https://github.com/EveryInc/compound-engineering-plugin). Use it when writing Rails, refactoring existing code toward that style, or settling a convention debate. It enforces a distinctive set of conventions: REST purity (map resources, don't invent custom controller actions), fat models and thin controllers, database-backed state records instead of boolean columns, `Current` attributes, Hotwire (Turbo / Stimulus) over heavy JS frameworks, native modern CSS, and authorization logic placed directly on the `User` model. The throughline is "clarity over cleverness" and "the best code is the code you don't write."

It is as opinionated about what to *avoid* as what to do. It rejects popular gems — devise, pundit, sidekiq, rspec — in favor of vanilla Rails: roughly 150 lines of custom auth, Solid Queue for background jobs, Minitest for testing, and rich domain models instead of service objects. It routes to detailed reference files covering controllers, models, frontend patterns, architecture, testing, and gem decisions, so the rules come with worked examples rather than slogans.

## When to use it

- Writing or refactoring Rails code that should read like Basecamp / HEY / Campfire
- Settling a "service object vs. fat model" or "do we add devise" debate against a coherent philosophy
- Code review on a Rails PR — does this reach for a gem where vanilla Rails would do?
- Onboarding an agent to a 37signals-style codebase so its generated code matches house style

When *not* to reach for it:

- Non-Rails Ruby, or Rails apps whose team has deliberately chosen a different stack (heavy SPA front end, an RSpec shop) — the skill will fight your conventions
- When a gem the skill rejects is genuinely load-bearing in your app — it's opinionated, not situational
- Greenfield non-web Ruby where the Rails idioms don't apply

## Install

Part of the compound-engineering plugin (not a standalone `~/.claude/skills/` drop-in). In Claude Code:

```
/plugin marketplace add EveryInc/compound-engineering-plugin
/plugin install compound-engineering
```

Then invoke `/ce-dhh-rails-style` while writing or reviewing Rails code. The plugin namespaces every skill with `ce-`. MIT-licensed.

## What a session looks like

1. **Ask for a feature.** "Add the ability to archive a project."
2. **REST purity.** Instead of `ProjectsController#archive`, model it as a resource: `Projects::ArchivesController#create`.
3. **State as a record.** Rather than `project.archived = true`, create an `Archival` record (who archived it, when) — a database-backed state record, not a boolean column.
4. **Fat model.** The archiving logic lives on the `Project` / `Archival` models; the controller stays thin.
5. **Auth on User.** `user.can_archive?(project)` lives on the model, not in a pundit policy.
6. **Frontend.** A Turbo Stream updates the project card in place and a Stimulus controller handles the toggle — no React.
7. **Jobs and tests.** Any async work goes to Solid Queue; the test is Minitest, not RSpec.

The discipline that makes it work: "the best code is the code you don't write." On every choice the skill's instinct is to reach for a built-in Rails primitive before a gem or a new abstraction.

## Receipts

_TODO — to be filled in from a real session. Once the skill has been run on a real Rails feature, this section will capture: which convention generated the most friction against an existing non-DHH codebase, whether the gem-rejection rules (no devise / pundit / sidekiq / rspec) were practical or dogmatic on a real feature, how the ~150-line custom auth compared to reaching for devise, and whether "state record instead of boolean" actually paid off or just added a table._

## Source and attribution

From [Every's compound-engineering plugin](https://github.com/EveryInc/compound-engineering-plugin/tree/main/plugins/compound-engineering/skills/ce-dhh-rails-style) — the MIT-licensed plugin (Dan Shipper & Kieran Klaassen) packaging Every's engineering workflow.

License: MIT.

Quoting the governing rule verbatim: *"The best code is the code you don't write."* Every convention in the skill — REST resources over custom actions, vanilla Rails over gems, fat models over service objects — is an application of that one line.