Claude Code Does Not Understand the Whole Project — Fix It

Claude Code keeps re-reading the same files or misses other dirs entirely? Anchor with CLAUDE.md and tighten working dir.

You ask Claude Code to make a change in a mid-sized repo, and it keeps editing src/index.ts over and over while completely ignoring the apps/web/ or packages/api/ you mentioned. In a monorepo it can’t tell workspace boundaries; it puts tests next to source files instead of in __tests__/. Same root cause every time: Claude Code is missing a project map.

Claude Code is, at heart, an LLM session with filesystem tools. Its entire mental model of your project comes from three things: the current working directory, CLAUDE.md (if one exists), and whatever paths you mention in prompts. If any of those is missing or misleading, you get “peering through a keyhole” behavior.

Common causes

Ordered by hit rate, highest first.

1. No CLAUDE.md — every session starts blind

The most common cause. On startup, Claude Code auto-reads CLAUDE.md from the working directory (plus ~/.claude/CLAUDE.md and ./.claude/CLAUDE.md walking up) and injects them into the system prompt. Without that, it has to discover structure via ls one level at a time, and gets lost in any non-trivial monorepo.

How to spot it: Run ls CLAUDE.md in the project root. Missing = this is your problem.

2. Wrong working directory

Starting Claude Code in apps/web/ makes it treat that as the entire project — it can’t see shared types in packages/shared/. Starting it in ~/code/ makes it drown in dozens of unrelated projects.

How to spot it: Run !pwd at the start of the session and compare against the real project root (usually the folder containing .git/ or package.json workspaces).

3. node_modules / dist / .next directories drown out real code

Claude Code has some default ignores, but Grep and Glob can still pull in vendored code from node_modules. You ask for “the Button component” and it returns the framework’s, not yours.

How to spot it: Ask Claude Code to list “all Button components in the repo.” If the result contains node_modules/..., this is why.

4. Monorepo without a workspace map

pnpm workspaces, Turborepo, Nx — packages reference each other via workspace:*. Claude Code won’t proactively parse pnpm-workspace.yaml or nx.json to derive the graph. You have to write it down in CLAUDE.md.

How to spot it: Ask “list every package in this repo and what depends on what.” If it only knows the current package, this is the cause.

5. Vague references in your prompt

“Fix the login bug” — it doesn’t know where login lives. “That component is wrong” — which one? Vague prompts make Claude Code default to whatever file it last touched, which is often wrong.

How to spot it: Re-read your prompt. If it has no concrete file path or function name, this is the cause.

6. Context window stuffed with low-value content

If early in the session you piped in large logs, build output, or long stack traces, the actually-relevant code gets pushed out of the active window. Claude Code starts to “forget” earlier conventions.

How to spot it: Session is long (30+ turns), and recent answers forget conventions established early.

Shortest path to fix

Step 1: Write a CLAUDE.md project map

In the project root, create CLAUDE.md (keep it under ~100 lines — longer dilutes the signal):

# Project Map

This is a pnpm monorepo with 3 workspaces:
- `apps/web/`  Next.js frontend (port 3000)
- `apps/api/`  Hono backend (port 8787, Cloudflare Worker)
- `packages/shared/`  Zod schemas + types used by both

## Conventions

- TypeScript strict mode everywhere
- Tests live in `__tests__/` next to source, Vitest
- API routes follow REST: GET /resource, POST /resource, etc.
- Never edit files under `packages/shared/dist/` — build output

## Commands

- `pnpm dev` — runs web + api concurrently
- `pnpm test` — runs all workspaces
- `pnpm typecheck` — must pass before commit

## Don't touch

- `infra/terraform/` — owned by ops
- `apps/web/public/legacy/` — frozen

Step 2: Start from the right working directory

Find the project root (folder with .git/ or pnpm-workspace.yaml) and start there:

cd ~/code/my-monorepo
claude   # or your equivalent

Don’t start in ~/code/ and then cd in — Claude Code’s initial scan has already happened.

Step 3: Add .claudeignore or declare in CLAUDE.md

If the repo has vendored code or large generated files, list them:

# .claudeignore (or inline in CLAUDE.md)
node_modules/
dist/
.next/
.turbo/
coverage/
*.generated.ts
public/legacy/

Step 4: First turn is “read these and confirm”

Don’t immediately delegate work. Start with:

First read CLAUDE.md, then `ls` the structure of apps/ and packages/
and confirm you understand the workspace layout. Then we'll begin.

Letting it build a mental model up front is much faster than letting it trial-and-error after you’ve already assigned work.

Step 5: Use absolute paths in your prompts

Not “fix the login bug” — “fix apps/web/src/pages/login.tsx line 42, the error handling inside handleSubmit.” Concrete paths skip the guess-and-grep phase entirely.

Step 6: For long sessions, /compact or restart

Past 30-40 turns or > 60% context utilization, run /compact to have Claude Code summarize state, then start a fresh window with that summary pasted in. Better than fighting until tokens run out.

Prevention

  • Treat CLAUDE.md as living documentation — update it when you add modules or change conventions
  • Put a CLAUDE.md in each workspace too; Claude Code reads the nearest one to its working directory
  • For complex tasks, use a two-step prompt: “make a plan first, confirm understanding, then execute”
  • Encode durable rules (“tests start with an in-memory mock”) in CLAUDE.md, not in every prompt
  • Proactively /compact long sessions instead of waiting for the context to be force-truncated

Tags: #Claude #Debug #Troubleshooting