·14 min read·ai-cli-tools

10 CLAUDE.md Mistakes That Make Your AI Agent Worse

The ETH Zurich study proved most context files hurt agent performance. Here are 10 concrete CLAUDE.md mistakes — with before/after examples — and how to fix each one.

DH
Danny Huang

Your CLAUDE.md Is Probably Making Things Worse

Most developers write their CLAUDE.md once, keep adding to it, and never question whether it actually helps. In February 2026, researchers at ETH Zurich published the first rigorous study on context files for AI coding agents — Evaluating AGENTS.md by Thibaud Gloaguen, Niels Mundler, Mark Muller, Veselin Raychev, and Martin Vechev. The headline result: LLM-generated context files reduced task success rates by 3% compared to no context file at all. Even human-written files only improved success by about 4%, while increasing inference costs by over 20%.

The problem is not that context files are useless. The problem is that most CLAUDE.md files are written badly — too long, too redundant, too rigid. Every bad line competes for attention with your actual task, diluting the agent's focus and burning tokens on noise.

This article covers 10 specific mistakes, each with a concrete before/after example. If your CLAUDE.md has any of these, fix it today.

Mistake 1: The File Is Too Long

The single most common failure mode. Developers start with a reasonable 30-line file, then keep appending rules, examples, and documentation until it balloons to 300+ lines.

Why it is bad: The ETH Zurich study found that longer context files consistently increased inference costs (over 20%) while providing diminishing or negative returns on task success. Frontier models can reliably follow about 150-200 instructions. Past that threshold, they start ignoring rules — and you cannot predict which ones they drop. Addy Osmani summarized the core issue: the auto-generated content is not useless, it is redundant — the agent could find it by reading the repo, and providing the same information twice just adds noise.

Before:

## Project Overview
This is a Next.js 15 application using the App Router with TypeScript...
[20 lines of overview]

## Architecture
[40 lines of architecture details]

## Code Conventions
[30 lines of conventions]

## API Documentation
[50 lines of API docs]

## Database Schema
[40 lines of schema descriptions]

## Deployment
[30 lines of deployment instructions]

## Troubleshooting
[40 lines of known issues]

After:

## Architecture
- Next.js 15 App Router, TypeScript strict, Tailwind CSS
- Database: PostgreSQL 16 via Prisma
- Auth: NextAuth.js v5 with GitHub + Google providers

## Conventions
- Server components by default; 'use client' only for interactivity
- Error handling: Result<T, E> pattern (see src/lib/result.ts)
- No default exports except pages and layouts

## Constraints
- Never modify files in prisma/migrations/
- All API routes validate input with Zod

## Commands
- Test: pnpm test | Lint: pnpm lint | Build: pnpm build

That is 15 lines. The 250 lines of API docs, schema descriptions, and troubleshooting guides belong in actual documentation files that the agent can read when it needs them — not in a file that loads on every single session.

The rule: Under 100 lines. Every line must pass this test: "If I remove this, will the agent make a mistake it cannot recover from by reading the code?"

Mistake 2: Restating Information the Agent Can Already See

Your repo has a tsconfig.json with "strict": true. Your package.json lists every dependency. Your .eslintrc defines your linting rules. Restating any of this in CLAUDE.md is pure waste.

Why it is bad: The agent reads your files. When CLAUDE.md says "This is a TypeScript project" and tsconfig.json says the same thing, the agent now has two sources of truth to reconcile. That reconciliation costs reasoning tokens and adds zero value.

Before:

## Tech Stack
- Language: TypeScript 5.4
- Runtime: Node.js 22
- Package manager: pnpm
- Framework: Next.js 15
- CSS: Tailwind CSS 4.0
- Testing: Vitest 3.0, Playwright 1.50
- Linting: ESLint 9 with flat config
- Formatting: Prettier 3.5

After:

## Architecture
- Next.js 15 App Router, PostgreSQL via Prisma, NextAuth.js v5

Everything else in that "tech stack" section is in package.json. The agent will find it on the first file read. The only things worth stating are non-obvious architectural decisions — the things that are not discoverable from a dependency list alone.

Mistake 3: No Architecture Section

The opposite of over-documenting individual technologies: providing no architectural context at all. Some CLAUDE.md files are nothing but style rules and linting preferences, with zero information about how the system fits together.

Why it is bad: Without architecture context, the agent makes structurally wrong decisions. It puts database queries in route handlers because it does not know you have a repository pattern. It creates a new auth helper because it does not know one already exists in src/lib/auth.ts. Style rules are cheap — the linter enforces those. Architecture is the one thing the agent genuinely cannot infer quickly from a cold start.

Before:

## Rules
- Use camelCase for variables
- Use PascalCase for components
- Indent with 2 spaces
- Use single quotes
- Always add trailing commas

After:

## Architecture
- Monorepo: apps/web (Next.js), apps/api (Fastify), packages/shared
- Database queries in src/repositories/, never in route handlers
- Auth: centralized in packages/shared/auth — do not create parallel auth logic
- Event system: BullMQ queues in src/jobs/, producers in src/services/

## Conventions
- Error handling: Result<T, E> (see packages/shared/result.ts)
- No default exports except pages

The naming conventions and indentation from the "before" are things your linter and Prettier already enforce. The "after" tells the agent where things live and how they connect — information it would take significant codebase exploration to discover on its own.

Mistake 4: Missing Build and Test Commands

You know how to run your project. The agent does not. A surprising number of CLAUDE.md files omit the most basic operational information: how to build, test, lint, and run the project.

Why it is bad: Without explicit commands, the agent guesses. It runs npm test when your project uses pnpm test:unit. It tries npm run build when the correct command is turbo build --filter=web. Wrong commands waste execution cycles, generate confusing errors, and force the agent into a debugging spiral over a non-issue.

Before:

## Project
A SaaS platform for inventory management.

## Code Style
[30 lines of style rules]

After:

## Project
SaaS inventory management platform. Turborepo monorepo.

## Commands
- Install: pnpm install
- Dev: pnpm dev (starts all apps)
- Test unit: pnpm test:unit
- Test e2e: pnpm test:e2e (requires running dev server)
- Lint: pnpm lint
- Build: turbo build --filter=web
- DB migrate: pnpm db:migrate
- DB seed: pnpm db:seed

Eight lines. This saves the agent from guessing on literally every operational task. If your project has a non-standard setup (monorepo, custom scripts, environment requirements), these commands are the highest-value content in your entire CLAUDE.md.

Mistake 5: Overly Rigid Rules with ALWAYS/NEVER

Developers love writing absolute rules. "ALWAYS use functional components." "NEVER use any." "ALWAYS write tests before implementation." These feel precise, but they create a brittleness that hurts more than it helps.

Why it is bad: Absolute rules leave no room for legitimate exceptions. The agent follows "NEVER use any" and spends 15 minutes writing complex generic types for a quick throwaway script. It follows "ALWAYS write tests first" and writes tests for a one-line config change. Rigid instructions also conflict with each other as the file grows — "ALWAYS use server components" clashes with the form that genuinely needs client-side state.

Before:

## Rules
- ALWAYS use functional components, NEVER use class components
- ALWAYS write tests before writing implementation code
- NEVER use `any` type
- ALWAYS use named exports, NEVER use default exports
- NEVER use inline styles
- ALWAYS add JSDoc comments to public functions
- NEVER mutate state directly

After:

## Conventions
- Prefer server components; use 'use client' only for interactivity or browser APIs
- Error handling: Result<T, E> pattern — avoid try/catch in business logic
- Named exports preferred; default exports only for pages/layouts (Next.js requirement)
- Type safety: avoid `any` — use `unknown` with type guards when the type is genuinely uncertain

The "after" uses "prefer" and "avoid" with explicit exceptions. This gives the agent judgment space while still communicating your intent. The removed rules ("always write tests first," "always add JSDoc") are workflow preferences that belong in skills, not always-on context.

Mistake 6: No Constraints Section

Conventions tell the agent what to do. Constraints tell it what never to do. Many CLAUDE.md files have extensive conventions but zero constraints, leaving the agent free to make destructive mistakes.

Why it is bad: Without explicit constraints, the agent will happily modify your migration files to "fix" a schema issue, delete "unused" test fixtures that are loaded by name, or refactor your public API in a breaking way. These are mistakes that are hard to catch in review and expensive to fix. A short constraints section is the highest-ROI content in CLAUDE.md.

Before:

## Guidelines
- Write clean, readable code
- Follow SOLID principles
- Keep functions small

Those are aspirational platitudes. Here is what actually prevents damage:

After:

## Constraints
- Never modify files in prisma/migrations/ — generate new migrations instead
- Never change the signature of functions exported from src/api/public/
- Never delete test fixture files in tests/fixtures/ (loaded dynamically by name)
- Never commit .env files or hardcode secrets
- GraphQL schema changes require running pnpm codegen after modification

Each constraint targets a specific, recoverable-but-costly mistake. "Write clean code" teaches nothing. "Never modify migration files" prevents a production incident.

Mistake 7: Duplicating Linter Rules

Your ESLint config enforces no-unused-vars. Your Prettier config enforces 2-space indentation. Your CLAUDE.md also says "no unused variables" and "indent with 2 spaces." Why?

Why it is bad: Linters enforce rules deterministically. CLAUDE.md does not. When the agent writes code that violates a linter rule, the linter catches it on the next save or CI check. Restating linter rules in CLAUDE.md does not make the agent follow them more carefully — it just wastes context window on rules that have an automated backstop. Worse, if your linter config changes and CLAUDE.md does not update, you have contradictory instructions.

Before:

## Code Style
- 2 spaces for indentation
- Semicolons required
- Single quotes for strings
- Trailing commas in multi-line structures
- Max line length: 100 characters
- No unused variables
- No console.log in production code
- Use arrow functions for callbacks
- Destructure props in function signatures

After:

## Code Style
- ESLint and Prettier are configured. Run `pnpm lint` to check.
- If lint fails after changes, fix violations before considering the task done.

Two lines replace nine. The linter is the source of truth. CLAUDE.md just needs to tell the agent that the linter exists and to respect it.

Mistake 8: Ignoring AGENTS.md Cross-Tool Compatibility

Building all your agent context exclusively in CLAUDE.md creates tool lock-in. Claude Code reads CLAUDE.md. Codex CLI, Copilot CLI, Gemini CLI, and Cursor do not — they read AGENTS.md.

Why it is bad: Teams evolve. The tool you use today might not be the tool you use in six months. If all your project context lives in CLAUDE.md, switching to Codex CLI or adding Gemini CLI as a secondary tool means either duplicating everything into AGENTS.md (violating DRY) or losing all your context engineering when using the new tool.

Before:

project-root/
  CLAUDE.md          # 80 lines of project context
  (no AGENTS.md)

After:

project-root/
  AGENTS.md          # 70 lines — canonical project context
  CLAUDE.md          # 10 lines — Claude Code-specific only
# CLAUDE.md
Read AGENTS.md for project architecture and conventions.

## Claude Code-Specific
- When compacting, preserve the full list of modified files
- Prefer subagents for research tasks

AGENTS.md holds the portable project context. CLAUDE.md holds only Claude Code-specific instructions (compaction behavior, subagent preferences, permission overrides). Every AI CLI tool gets the project context from AGENTS.md; Claude Code gets both. For a full breakdown of this layering strategy, see SKILL.md vs CLAUDE.md vs AGENTS.md.

Mistake 9: Not Versioning CLAUDE.md

Some developers put CLAUDE.md in .gitignore because they consider it a personal preference file. Others create it locally and never commit it. The file exists on one machine and nowhere else.

Why it is bad: CLAUDE.md is project documentation. It encodes architectural decisions, naming conventions, and hard constraints that apply to every contributor — human or AI. Not versioning it means team members get inconsistent agent behavior, new developers start with no context, and the file is one rm away from total loss. It also means you have no history of how your context engineering evolved — no way to correlate agent performance changes with CLAUDE.md edits.

Before:

# .gitignore
CLAUDE.md
.claude/

After:

# .gitignore
# Version control CLAUDE.md and AGENTS.md — they are project docs.
# Only ignore personal settings:
.claude/settings.local.json

Commit CLAUDE.md. Commit AGENTS.md. Commit your skills in .claude/skills/. Review changes to these files in PRs just like you review code changes. The ETH Zurich study tested repositories with developer-committed context files and found they outperformed LLM-generated ones — partly because committed files are reviewed, refined, and maintained by humans who understand the project.

Managing these context files across multiple project workspaces — keeping CLAUDE.md, AGENTS.md, and skills in sync as you switch between repositories — is where Termdock's workspace system helps. Switch workspaces with full session recovery, and every terminal in that workspace loads the correct project context automatically.

Try Termdock Session Recovery works out of the box. Free download →

Mistake 10: Stuffing Task-Specific Content That Should Be Skills

Your CLAUDE.md has a 40-line section on "How to Create a Database Migration," another 30-line section on "PR Review Checklist," and a 25-line section on "Deployment Procedure." These are not project context. They are task workflows.

Why it is bad: Task-specific workflows load into every session, even when you are doing something unrelated. Working on a CSS bug? That 40-line migration workflow is consuming context window for nothing. The Agent Skills system exists precisely to solve this — skills load only when the current task matches their description. Keeping task workflows in CLAUDE.md defeats the entire purpose of on-demand loading.

Before:

## Database Migration Workflow
1. Read the current schema in src/db/schema.ts
2. Check existing migrations in src/db/migrations/
3. Verify no pending migrations: run pnpm db:status
4. Modify the schema first
5. Generate migration: pnpm db:generate
6. Never write migration SQL by hand
7. Run pnpm db:migrate on dev
8. Run integration tests
9. If tests fail, do NOT modify the migration — drop and regenerate
[...]

## PR Review Checklist
1. Check test coverage
2. Verify no console.log statements
3. Check for hardcoded secrets
4. Verify API backward compatibility
[...]

## Deployment Steps
1. Run full test suite
2. Build production assets
[...]

After (CLAUDE.md):

## Constraints
- Never modify files in src/db/migrations/
- DB commands: pnpm db:generate, pnpm db:migrate, pnpm db:status

After (.claude/skills/database-migration/SKILL.md):

---
name: database-migration
description: >
  Use when creating, modifying, or reviewing database migrations.
  Triggers on: migration files, schema changes, Drizzle ORM modifications.
---

## Database Migration Workflow
1. Read current schema: src/db/schema.ts
2. Check existing migrations for naming conventions
3. Verify no pending migrations: pnpm db:status
4. Modify schema first, then generate: pnpm db:generate
5. Never write migration SQL by hand
6. Test: pnpm db:migrate && pnpm test:integration
7. If tests fail, drop and regenerate — never edit the migration file

The hard constraint stays in CLAUDE.md (it applies globally). The full workflow moves to a skill (it loads only when relevant). The PR review checklist becomes another skill. Deployment becomes another skill. Your baseline context drops from 100+ lines of mixed content to 15 lines of architecture and constraints.

The Checklist

Here is how to audit your CLAUDE.md right now:

CheckPass/Fail
Under 100 lines total
Has an Architecture section
Has a Constraints section
Has build/test/lint Commands
No content duplicated from linter/tsconfig/package.json
No ALWAYS/NEVER without explicit exceptions
AGENTS.md exists with portable project context
CLAUDE.md and AGENTS.md are committed to git
Task workflows are in .claude/skills/, not in CLAUDE.md
File was written by a human, not generated by /init

Summary of this table: 10 checkpoints to validate your CLAUDE.md. If more than 3 fail, your context file is likely hurting agent performance more than helping it.

If you fix even half of these mistakes, you will see measurably better agent performance — faster task completion, lower token costs, and fewer cases where the agent ignores your instructions because they are buried in noise. The AI CLI Tools Guide has a working template you can start from and a broader view of context engineering across all major tools.

DH
Free Download

Ready to streamline your terminal workflow?

Multi-terminal drag-and-drop layout, workspace Git sync, built-in AI integration, AST code analysis — all in one app.

Download Termdock →
#claude-md#agents-md#context-engineering#claude-code#ai-cli

Related Posts