# Modular Code Enforcement

> 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.

- Skill: `tools-only/modular-code-enforcement` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds add tools-only/modular-code-enforcement`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tools-only/modular-code-enforcement/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: tools-only (https://skillmd.com/u/tools-only)
- Updated: 2026-09-08
- Page: https://skillmd.com/skills/tools-only/modular-code-enforcement

---


# 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**:
1. **STOP** current work
2. **Identify** the multiple responsibilities hiding in the file
3. **Extract** each responsibility into a focused module
4. **Verify** each resulting file is < 200 LOC and has a single purpose
5. **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**:
```typescript
// 1  import { foo } from "./foo";          ← COUNT
// 2                                         ← SKIP (blank)
// 3  // Helper for bar                      ← SKIP (comment)
// 4  export function bar(x: number) {       ← COUNT
// 5    const prompt = `                     ← COUNT (declaration)
// 6      You are an assistant.              ← SKIP (prompt text)
// 7      Follow these rules:                ← SKIP (prompt text)
// 8    `;                                   ← COUNT (closing)
// 9    return process(prompt, x);           ← COUNT
// 10 }                                      ← COUNT
```
→ 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:

1. **Check the file you're touching** — does it violate any rule above?
2. **If YES** — refactor FIRST, then proceed with your task
3. **If creating a new file** — ensure it has exactly one responsibility and stays under 200 LOC
4. **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](https://github.com/code-yeongyu/oh-my-opencode) modular-code-enforcement rule

