Tutorials

How to Compose Multiple Rulesets per Repo

Composing rulesets: combining organization-wide, technology-specific, and team-specific rules into a single effective rule set that the AI reads. Techniques for layering, overriding, and managing multi-source rules.

6 min read·July 5, 2025

One repo, three stacks, four rule layers. Composition turns multiple rule sources into one effective set the AI follows.

Single-file, include-based, and directory-based patterns, override resolution, and automated composition

Why One Rule File Is Not Enough

Simple projects: one CLAUDE.md file with all rules. It works perfectly for a single-stack project with one team. But: a monorepo with a React frontend, Go backend, and Python ML pipeline — one file that covers all three stacks is unwieldy and confusing. Rules about React component patterns are irrelevant when the AI is generating Go code. Rules about Python type hints clutter the context when working on the frontend.

The composition model: multiple rule sources layered together. Organization rules (apply to all code in the org — security, testing, code quality). Technology rules (apply to code in a specific language — TypeScript patterns, Go conventions, Python idioms). Team rules (apply to this specific project — domain terminology, API patterns, project structure). The AI reads all applicable layers and follows them, with more specific rules overriding more general ones.

The benefit: each layer is maintained by the people who know it best. The security team maintains security rules. The Go community lead maintains Go rules. The project team maintains project-specific rules. No single person needs to understand all rules across all layers.

Composition Patterns

Pattern 1 — Single file with sections: the simplest composition. One CLAUDE.md with clearly marked sections: ## Organization Standards, ## TypeScript Conventions, ## Project-Specific Rules. Each section: maintained by its respective owner. Works well for teams where one person can manage the entire file. Breaks down when: multiple people need to update different sections simultaneously, or the file exceeds 100 rules. AI rule: 'For small teams (< 20 developers) with one main tech stack: single file with sections is sufficient. Simple, no tooling needed.'

Pattern 2 — Include-based composition: the CLAUDE.md file includes content from multiple source files. Manually: copy content from org-rules.md + typescript-rules.md + team-rules.md into CLAUDE.md. Automated: a build script concatenates the source files into CLAUDE.md on each change. This pattern: keeps source rules in separate files (easy to maintain) while producing a single file the AI reads (easy for the tool to consume). AI rule: 'For medium teams (20-100 developers) with multiple stacks: include-based composition. Each source file: independently maintained. A script produces the final CLAUDE.md.'

Pattern 3 — Directory-based composition: tools like Cursor and Windsurf support rule directories (.cursor/rules/, .windsurf/rules/). Each file in the directory: contains rules for a specific context (frontend.md, backend.md, testing.md). The tool applies relevant rules based on the file being edited. For Claude Code: the CLAUDE.md file is the main entry point, but it can reference other files with 'See also: docs/rules/...' Claude reads referenced files. AI rule: 'For large teams (100+ developers) with multi-stack repos: directory-based composition. Each file targets a specific area. The tool applies the right rules to the right context.'

💡 A Build Script Prevents Manual Composition Errors

Manually copy-pasting from 3 source files into CLAUDE.md: you will forget to update it. The organization rules change. You update the source. You forget to regenerate CLAUDE.md. The AI follows the old organization rules for 2 weeks until someone notices. A build script (even a simple cat org-rules.md ts-rules.md team-rules.md > CLAUDE.md): runs in 1 second and never forgets. Add it to a pre-commit hook for zero-effort automation.

Override Resolution and Conflict Handling

Override principle: more specific rules override more general rules. Organization rule: 'Use async/await for all async operations.' Technology rule (Go): 'Use goroutines and channels for concurrent operations' (Go does not have async/await). The Go-specific rule overrides the organization rule for Go code. The organization rule applies to TypeScript, Python, and other languages. AI rule: 'When rules conflict: the most context-specific rule wins. Technology overrides organization. Team overrides technology. The AI follows the most specific applicable guidance.'

Explicit overrides: when a team rule intentionally deviates from an organization rule, make it explicit. Do not just state the team rule and hope the AI figures out the conflict. Instead: 'Override: organization rule says use structured logger. This project uses Pino directly because the structured logger wrapper adds 2ms latency per log, which exceeds our p99 budget for the hot path. Use pino.info() instead of logger.info().' The explicit override: documents the reason and prevents future developers from 'fixing' the deviation. AI rule: 'Explicit overrides with rationale prevent: accidental reversion (someone removes the team rule thinking it is a mistake) and confusion (why is this project different?).'

Conflict detection: when adding a new rule, check for conflicts with existing rules at all layers. Search for: contradictory keywords (class vs function, sync vs async, throw vs return), overlapping scope (two rules about error handling that specify different patterns), and implicit conflicts (a rule that changes the import pattern may conflict with a bundler configuration rule). AI rule: 'Before adding a rule: search the full rule set (all layers) for potential conflicts. A 2-minute search: prevents hours of debugging inconsistent AI output.'

⚠️ Never Edit the Generated File Directly

The composition script generates CLAUDE.md from 3 source files. A developer adds a rule directly to the generated CLAUDE.md (not to the source file). Next time the script runs: the hand-added rule is overwritten and lost. The developer's rule: gone without anyone noticing. Rule: all edits go to source files. The generated file is output only — never hand-edited. Add a comment at the top: '# AUTO-GENERATED — Do not edit directly. Edit source files in rules/ directory.'

Maintaining Composed Rulesets

Version tracking: each rule source has its own version. Organization rules v2.3. TypeScript rules v1.8. Team rules v3.1. When the composed CLAUDE.md is generated: include a comment at the top with the source versions. This enables: quick identification of which source changed when the AI behavior changes, targeted updates (only rebuild when a source changes), and rollback (revert to previous source version if a change causes issues). AI rule: 'Include source versions in the generated CLAUDE.md. Example: Generated from: org-rules v2.3, typescript-rules v1.8, team-rules v3.1. Date: 2026-03-29.'

Automated composition: for include-based or directory-based patterns, automate the composition. A pre-commit hook or CI job that: concatenates source files into the final CLAUDE.md, validates the composed file (no syntax errors, no obvious conflicts), and commits the updated CLAUDE.md alongside source changes. AI rule: 'Never manually edit the generated CLAUDE.md if using composition. Edit the source files. The composition script regenerates the CLAUDE.md. Manual edits to the generated file: overwritten on next generation.'

Testing composition: after generating the composed rule set, test with a standard prompt: 'Create a new API endpoint with error handling and a test.' Verify: the AI follows rules from all layers (organization security rule, technology error pattern, team naming convention). If any layer is not reflected: the composition may have a formatting issue or the AI's context is too full. AI rule: 'Test the composed rule set with a prompt that exercises all layers. If the output only follows one layer: the composition has a problem.'

ℹ️ Explicit Override Rationale Prevents Accidental Reversion

Team rule: 'Use Pino directly instead of the organization's structured logger wrapper.' A new developer joins. They see this and think: 'This is wrong — the org rule says use the structured logger. Let me fix it.' They remove the team rule. Production latency increases 2ms per log call. With rationale: 'Override: org structured logger adds 2ms latency per call, exceeding our p99 budget for the hot path. Use Pino directly.' The new developer: reads the reason, understands, and leaves the override in place.

Ruleset Composition Summary

Summary of techniques for composing multiple rulesets.

  • Why compose: monorepos, multi-stack projects, organizational layers need different rules per context
  • Pattern 1 (single file): sections for each layer. Best for small teams, single stack
  • Pattern 2 (include-based): separate source files → build script → single CLAUDE.md. Best for medium teams
  • Pattern 3 (directory-based): .cursor/rules/ or .windsurf/rules/. Tool applies relevant rules per context
  • Overrides: specific overrides general. Technology overrides org. Team overrides technology
  • Explicit overrides: state the deviation AND the reason. Prevent accidental reversion
  • Conflict detection: search all layers for contradictions before adding new rules
  • Maintenance: version tracking per source, automated composition, test after generation