| name | modular-code-enforcement |
| description | Enforces strict modular code architecture: SRP, no monolithic index files, no catch-all utils, 200 LOC hard limit. This rule is NON-NEGOTIABLE. Violations BLOCK all further work until resolved. |
Modular Code Architecture ā Zero Tolerance Policy
This rule is NON-NEGOTIABLE. Violations BLOCK all further work until resolved.
Rule 1: index files are ENTRY POINTS, NOT dumping grounds
index files (index.ts, __init__.py, index.js, etc.) MUST ONLY contain:
- Re-exports (
export { ... } from "./module")
- Factory function calls that compose modules
- Top-level wiring/registration (hook registration, plugin setup)
index files MUST NEVER contain:
- Business logic implementation
- Helper/utility functions
- Type definitions beyond simple re-exports
- Multiple unrelated responsibilities mixed together
If you find mixed logic in an index file: Extract each responsibility into its own dedicated file BEFORE making any other changes. This is not optional.
Rule 2: No Catch-All Files ā utils/helpers/service are CODE SMELLS
A single utils, helpers, service, or common file is a gravity well ā every unrelated function gets tossed in, and it grows into an untestable, unreviewable blob.
These file names are BANNED as top-level catch-alls. Instead:
| Anti-Pattern | Refactor To |
|---|
utils with formatDate(), slugify(), retry() | date-formatter, slugify, retry |
service handling auth + billing + notifications | auth-service, billing-service, notification-service |
helpers with 15 unrelated exports | One file per logical domain |
Design for reusability from the start. Each module should be:
- Independently importable ā no consumer should need to pull in unrelated code
- Self-contained ā its dependencies are explicit, not buried in a shared grab-bag
- Nameable by purpose ā the filename alone tells you what it does
If you catch yourself typing utils or service, STOP and name the file after what it actually does.
Rule 3: Single Responsibility Principle ā ABSOLUTE
Every source file MUST have exactly ONE clear, nameable responsibility.
Self-test: If you cannot describe the file's purpose in ONE short phrase (e.g., "parses YAML frontmatter", "matches rules against file paths"), the file does too much. Split it.
| Signal | Action |
|---|
| File has 2+ unrelated exported functions | SPLIT NOW ā each into its own module |
| File mixes I/O with pure logic | SPLIT NOW ā separate side effects from computation |
| File has both types and implementation | SPLIT NOW ā types file + implementation file |
| You need to scroll to understand the file | SPLIT NOW ā it's too large |
Rule 4: 200 LOC Hard Limit ā CODE SMELL DETECTOR
Any source file exceeding 200 lines of code (excluding prompt strings, template literals containing prompts, and markdown content) is an immediate code smell.
When you detect a file > 200 LOC:
- STOP current work
- Identify the multiple responsibilities hiding in the file
- Extract each responsibility into a focused module
- Verify each resulting file is < 200 LOC and has a single purpose
- Resume original work
Prompt-heavy files (agent definitions, skill definitions) where the bulk of content is template literal prompt text are EXEMPT from the LOC count ā but their non-prompt logic must still be < 200 LOC.
How to Count LOC
Count these (= actual logic):
- Import statements
- Variable/constant declarations
- Function/class/interface/type definitions
- Control flow (
if, for, while, switch, try/catch)
- Expressions, assignments, return statements
- Closing braces
} that belong to logic blocks
Exclude these (= not logic):
- Blank lines
- Comment-only lines (
//, /* */, /** */)
- Lines inside template literals that are prompt/instruction text
- Lines inside multi-line strings used as documentation/prompt content
Quick method: Read the file ā subtract blank lines, comment-only lines, and prompt string content ā remaining count = LOC.
Example:
ā LOC = 5 (lines 1, 4, 5, 9, 10). Not 10.
When in doubt, round up ā err on the side of splitting.
How to Apply
When reading, writing, or editing ANY source file:
- Check the file you're touching ā does it violate any rule above?
- If YES ā refactor FIRST, then proceed with your task
- If creating a new file ā ensure it has exactly one responsibility and stays under 200 LOC
- If adding code to an existing file ā verify the addition doesn't push the file past 200 LOC or add a second responsibility. If it does, extract into a new module.
Inspired by: oh-my-opencode modular-code-enforcement rule