You ask Cursor to fix a React component, and it cites prop names from dist/components/Foo.js (the compiled old version), producing a patch that’s totally wrong. Or you ask “how do we implement rate limiting?” and it answers from vendor/express-rate-limit/ rather than your own middleware. In both cases Cursor pulled the wrong files into the context window — build output, vendored third-party code, backup files, generated artifacts. This article shows how to diagnose it and how to lock Cursor to your real source.
Common causes
Ordered by frequency, highest first.
1. Generated files live next to source
dist/, build/, .next/, coverage/ aren’t ignored, so Cursor indexes them. Compiled JS often beats the real src/ files in embedding retrieval because it shares keywords with the source.
How to spot it: Expand “Context used” at the bottom of Cursor’s reply. Any of dist/, build/, .next/, out/, .astro/ showing up is a hit.
2. Vendored third-party libraries in the repo
Old Node / PHP projects commit vendor/ directly; frontends sometimes ship public/vendor/jquery-3.5.1.min.js. These are large and dominate retrieval, crowding out real code.
How to spot it: du -sh vendor/ public/vendor/ third_party/ 2>/dev/null. Any indexed directory > 5MB is suspect.
3. No .cursorignore at all
People assume .gitignore is enough, but .gitignore doesn’t cover local-only files — .env.local, scratch.md, old-backup-2024.tsx. Cursor sees and indexes them.
How to spot it: At repo root, ls -la | grep -E "(scratch|backup|old|\.bak|\.orig)". Anything that’s not in .cursorignore is a potential contaminant.
4. Backup and .bak / .orig files
Merge-conflict leftovers like Foo.tsx.orig, editor autosaves like Foo.tsx~, or hand-copied Foo-old.tsx. They differ from the current version by a few lines, so embeddings rank them as highly relevant and the agent ports old logic back in.
How to spot it: find . -type f \( -name "*.orig" -o -name "*.bak" -o -name "*~" -o -name "*-old.*" \) | head -20.
5. Test fixtures / snapshots steal context
__snapshots__/, fixtures/, mocks/ are often “semantically similar but behaviorally different” from real code. When you edit business logic, the agent treats snapshot strings as source of truth.
How to spot it: “Context used” shows __snapshots__ or .snap files when your prompt has nothing to do with tests.
Shortest path to fix
Step 1: Build a .cursorignore that blocks the usual contaminants
At repo root, create or expand .cursorignore:
# Build output
dist/
build/
out/
.next/
.astro/
.svelte-kit/
.nuxt/
# Dependencies and vendored
node_modules/
vendor/
public/vendor/
third_party/
# Caches, coverage, logs
.cache/
.turbo/
.parcel-cache/
coverage/
*.log
# Backups and editor temp
*.bak
*.orig
*~
*-old.*
*.swp
# Minified / bundled
*.min.js
*.min.css
*.bundle.js
*.bundle.css
# Test snapshots (case-by-case)
**/__snapshots__/
**/*.snap
# Local scratch
scratch.md
TODO.local.md
Tune per stack; the rule is “if the AI would be misled or wasted on it, hide it.”
Step 2: Force Cursor to rebuild the index
Changes to .cursorignore don’t take effect until you resync:
Cmd+Shift+P → "Cursor: Resync Index"
Or, more thoroughly:
# Quit Cursor, then
rm -rf ~/Library/Application\ Support/Cursor/User/workspaceStorage/*/cursorIndex
# Relaunch Cursor
After rebuild, the “Files Indexed” count in Settings → Codebase Indexing should drop noticeably.
Step 3: Pin source of truth with @File / @Folder in the prompt
Even with a clean ignore list, long chats occasionally mis-retrieve. The safest move is to pin explicitly:
@Folder src/components/auth @File src/lib/auth.ts
Modify AuthForm's onSubmit. Read and edit only the files I @-ed.
Do not reference anything in dist/, build/, or any *.min.js.
Adding a negative constraint (“don’t reference X”) is usually more effective than positive constraints alone.
Step 4: Sweep the repo’s “archaeology” periodically
Once a month (or in a pre-commit hook), run a cleanup pass:
# List anything the agent might mis-read
find . -type f \( \
-name "*.bak" -o -name "*.orig" -o -name "*~" \
-o -name "*-old.*" -o -name "*-backup.*" \
-o -name "*.swp" \
\) -not -path "./node_modules/*" -not -path "./.git/*"
# Confirm they're junk, then delete
find . -type f \( -name "*.bak" -o -name "*.orig" -o -name "*~" \) \
-not -path "./node_modules/*" -delete
After every merge conflict, git status for new .orig files and delete immediately.
Step 5: Verify the agent reads only the right files
Have Cursor list what it just read:
List every file you read to answer my last prompt, full paths, in
the order you read them. Exclude dist / vendor / *.min.js. If any
of those appear, tell me which @ pulled them in.
If dirty paths still show up, the ignore list is incomplete — go back to Step 1.
Prevention
- Commit
.cursorignorewhen you create a new repo, and keep it synced with.gitignorepatterns - Always put build output (
dist/,build/,coverage/) in dedicated top-level directories, never scattered undersrc/ - Put vendored third-party code under
third_party/and add it to.cursorignore; never dump it in the repo root orpublic/ - After resolving merge conflicts, run
find . -name "*.orig" -deleteimmediately to prevent index pollution - Add a line to CLAUDE.md /
.cursorrules: “Treat dist/, build/, vendor/, and .min. as build artifacts. Never read them.”