2025-12-24
Composable Rules: Getting Claude Code to Actually Honor Your Conventions

I had already solved project memory. Reference files and domain-specific CLAUDE.md files throughout my codebase kept Claude Code consistent with my conventions.
When Claude shipped the rules feature for .claude/rules/, I blew it off. Why rush to adopt something when I’d already solved the problem?
But I finally tried it. What an improvement.
The rules feature is cleaner, more organized, and way easier to manage than scattered CLAUDE.md files. I was well on the way of centralizing this into a consolidated references directory, but the Claude rules feature is a better solution.
You drop markdown files in .claude/rules/, Claude loads them automatically. Better separation of concerns. Better composability.
Now I had a different problem: setting up those rules for every new project.
The Manual Setup Problem
You can’t just copy your entire .claude/rules/ folder from one Rails project to another. Each project uses different gems and libraries.
Project A uses Pundit for authorization and Postgres. Project B uses SQLite and no authorization gem. If you copy all your rules, Project B gets Pundit conventions it doesn’t need and Postgres patterns for a database it’s not using.
What I Built
I organized my battle-tested Rails conventions into composable rule sets. Run one command, it detects what your project actually uses, and copies only the relevant rules.
I’m calling it the Hustler marketplace. Lean plugins for small businesses and small teams. Easy, pragmatic, low complexity.
The first plugin is hustler-rails for Rails conventions.
Why “Hustler”
Small businesses and small teams need tools that just work. No complexity, no over-engineering, no corporate bloat.
Lean plugins. Pragmatic solutions. Low noise.
How Composable Rules Work
Rules use frontmatter to declare when they apply:
---
paths: app/policies/**/*.rb, app/controllers/**/*.rb
dependencies: [pundit]
---
# Pundit - Authorization
Always put authorization in policies, not controllers...[and details about coding them]
The paths field is Claude Code’s feature for conditional rule loading, it accepts comma-separated glob patterns. This example loads authorization rules when working on either controllers or policies, so Claude always has the full authorization context regardless of which file you’re editing.
The dependencies field is my own convention that helps the init command detect which rules to copy. The extra fields don’t conflict.
Universal rules have no dependencies and always get copied. Dependency-specific rules only get copied if your project uses that gem.
The plugin detects dependencies by common sources like:
Gemfile.lockfor Ruby gemsconfig/database.ymlfor database adapterpackage.json, importmap, CDN links for JS libraries
Run /hustler-rails:init and it composes the right rule set for your project.
Real Example
/hustler-rails:init
Output:
Detected dependencies:
- pundit (authorization)
- beercss (UI framework)
- sqlite3 (database)
Copying rules:
✓ models/conventions.md
✓ controllers/conventions.md
✓ testing/conventions.md
✓ authorization/pundit-policies.md
✓ views/beercss-components.md
✓ database/sqlite-patterns.md
Skipped (not detected):
- devise (not in Gemfile.lock)
- postgresql (using sqlite3)
📦 41 rule files copied to .claude/rules/hustler-rails/
Some of these dependenmcies are my personal favorites for non-corporate projects, but it’s no big deal to add support for other configurations
You get conventions for what you’re actually using. Nothing more.
Why Copy Instead of Reference?
The plugin copies rules into your project rather than keeping them in the plugin and referencing them. This lets you tweak rules per project without forking the whole plugin.
Maybe you mostly follow my testing conventions, but your project has one special case. Edit .claude/rules/hustler-rails/testing/conventions.md and adjust it. Your change only affects this project.
Future idea: an override system where rules stay in the plugin and per-project adjustments live separately. Haven’t built that yet.
What’s Included
- Thin model patterns
- Command pattern for business logic
- RESTful controller patterns
- Test structure and anti-patterns
- Authorization with Pundit
- Component patterns for BeerCSS and Turbo
- SQLite-specific patterns (multi-db, FTS5 search)
- Query optimization patterns
Organized by domain: models, controllers, views, testing, authorization, database, jobs.
Beyond Rails
The marketplace has two other plugins:
hustler-studio (coming soon): Project-agnostic workflows for TDD, refactoring, planning, and quality gates. Adapts to your conventions by reading your project’s CLAUDE.md and rules.
prompting: Prompt writing and optimization. Stack-agnostic.
The Pattern for Other Stacks
Composable rules aren’t Rails-specific. The pattern works for any framework: detect dependencies, copy relevant rules.
Someone could build this for Django, Laravel, Next.js, NestJS, Phoenix, FastAPI. Same pattern, different dependency detection.
If you want to collaborate on adding support for more gems or building plugins for other stacks, the marketplace is open.
Getting Started
Install the marketplace:
/plugin marketplace add bcasci/hustle-marketplace
Install the Rails plugin:
/plugin install hustler-rails
Bootstrap your project:
/hustler-rails:init
You’ll get composable rules tailored to your dependencies.
Want to Contribute?
Think more rules should be added? Have different architecture preferences? Build your own plugin following the same pattern, or collaborate with me to add it to this marketplace.