Directory Organization Strategies to Prevent AI Agents from Touching Unrelated Code in a Bloated Monolith
When you attach Claude Code or Aider to a massive repository with hundreds of thousands of lines, they start reading the wrong files right away. Since the model's context window is limited, it aggregates irrelevant files, fills up the token limit, and ends up modifying unrelated code.
This problem cannot be solved simply by writing longer prompts. You need to reduce the physical radius of code the agent explores and embed mechanically verified rules locally.
1. Isolating Directories That Cause Circular References
In a monolith repository, there are typically three points where agents get trapped in endless exploration: the common utils folder containing random helper functions (src/utils/), the service layer where business logic is intertwined (src/services/), and the global models directory (src/models/). When these three folders start referencing each other, the agent reads dozens of files just to fix a single line of code.
Grouping and isolating tech-layered folders into domain units reduces the exploration scope.
| Classification |
Layer-Centric Structure |
Domain-Separated Structure |
Agent Behavior Changes |
| Folder Basis |
Tech layer separation (/controllers, /services) |
Domain separation (/domains/order) |
Explores only necessary files within a single folder |
| Dependency Connection |
Direct import of global entities |
Communication via domain interface boundaries |
Blocks cascading loading of unrelated files |
| Common Logic |
Functions mixed in a single src/utils/ |
Separated into domain-specific utils and common packages |
Prevents unnecessary global context pollution |
The sequence for moving directories without stopping the service you are working on is as follows:
- Identify the dependency relationships excessively called by the agent and determine the domain to isolate.
- Create a service boundary interface to cut off direct references between domains.
- Move related business logic to the
src/domains/{domain_name}/ folder and update path aliases in tsconfig.json.
- Place a dedicated configuration file (
CLAUDE.md) for that domain inside the separated sub-directory.
2. Converting Ambiguous Natural Language Rules into Numerical Constraints
Agents easily overlook coding conventions written as lengthy natural language descriptions. Clear numerical values and prohibitions must be placed at the top of configuration files to ensure guidelines are followed accurately.
`markdown
Project Constraints (Placed at the top of CLAUDE.md)
- Security and Exception Handling
- NEVER allow raw SQL string concatenation. ALWAYS use parameterized queries with ORM.
- NEVER throw generic Exception or Error. ALWAYS throw domain-specific exceptions inheriting from BaseDomainException.
- ALWAYS enforce tenant_id filtering in all database queries under src/domains/.
- Code Structure Numerical Constraints
- Functions MUST NOT exceed 40 lines of code.
- Cyclomatic complexity MUST be kept under 8 per function.
- ALWAYS return Result<T, E> pattern for business layer operations instead of null.
`
If a configuration file exceeds 200 lines, instructions toward the end are frequently omitted.
- Keep build commands and global commit rules under 200 lines in the root directory's
CLAUDE.md.
- Distribute sub-folder rules, such as
src/domains/order/, into dedicated rule files inside those respective directories.
- Write individual developer settings in
CLAUDE.local.md and register them in .gitignore to prevent conflicts.
3. Automatically Verifying Agent-Modified Code with Local Hooks
Syntax errors or regression bugs in code produced by the agent should be caught automatically at commit time. Using Lefthook, which operates as a Go single binary, allows you to run parallel checks more lightweight than Node.js-based tools.
Place lefthook.yml at the root to separate lightweight static checks from heavy test stages.
`yaml
pre-commit:
parallel: true
commands:
linter:
glob: ".{ts,tsx}"
run: npx eslint --fix {staged_files}
stage_fixed: true
formatter:
glob: ".{ts,tsx,json,md}"
run: npx prettier --write {staged_files}
stage_fixed: true
security-scan:
run: gitleaks git --staged --no-banner
pre-push:
parallel: false
commands:
typecheck:
run: npx tsc --noEmit
unit-tests:
run: npm run test:unit -- --passWithNoTests
`
The commit-stage pre-commit checks only staged files within 10 seconds, while full type checking and unit tests are deferred to the push-stage pre-push.
Register the .claude/hooks/block-no-verify.mjs interceptor to prevent agents from bypassing hooks using the --no-verify option.
`javascript
import fs from 'fs';
const input = fs.readFileSync(0, 'utf8');
const parsed = JSON.parse(input);
if (parsed.tool_input?.command?.includes('--no-verify')) {
console.error("Policy Violation: --no-verify flag is strictly prohibited.");
process.exit(1);
}
process.exit(0);
`
If a hook fails, console error outputs flow into the next prompt, causing the agent to fix the code on its own.
4. Preventing Token Waste by Limiting Exploration Scope
Tokens are depleted rapidly once agents start reading build outputs or lock files. Closing off file search ranges prevents unintended cost generation.
Create .ignore or .aiderignore in the project root and register large artifacts.
`text
node_modules/
dist/
build/
coverage/
*.min.js
*.svg
*.lock
package-lock.json
public/assets/
db/migrations/
`
Specify the working directory when executing from the terminal to block global scans as well.
`bash
aider "Refactor Order validation logic" --path=src/domains/order/ --exclude=src/domains/order/tests/
`
Switching to planning mode to review changes before modifying code, writing failing unit tests first, and making only passing code written ensures the agent's working radius stays safe.