You open .env to run the project and every API key is now your_api_key_here, xxx, or replace_me — Claude Code, Cursor, or Aider, during a “clean up the project” or “fill in the .env template” pass, wiped your real secrets. Or worse: it deleted .env entirely, git wasn’t tracking it, and there’s no local backup. This happens weekly because agents default to treating .env as a template rather than real values. This article covers recovery first, then how to hard-lock the file so the agent never touches it again.
Common causes
Ordered by hit rate, highest first.
1. .env is gitignored, so the agent thinks it’s empty or missing
The number-one cause. .env is in .gitignore, so the agent can’t see contents via git. It reads .env.example full of placeholders, decides to “complete” the missing .env, and overwrites your real values.
# agent's "completion"
OPENAI_API_KEY=your_openai_api_key_here
DATABASE_URL=postgres://user:password@localhost:5432/db
STRIPE_SECRET_KEY=sk_test_xxxxxxxxxx
How to spot it: Open .env. If every value is your_xxx_here / xxx / textbook example data, this is it.
2. Agent “completed” example values for thoroughness
You asked it to “add a new env var REDIS_URL.” It rewrote the whole file in passing, replacing every existing value with example defaults. It thought this was “tidier.”
How to spot it: ls -la .env shows a fresh mtime even though git can’t diff it.
3. Editor extension or formatter rewrote on save
Some VS Code dotenv extensions “prettify” .env on save — quote values, align =, sort alphabetically. Some buggy versions blank values entirely. When Cursor’s agent saves the file, those extensions also fire.
How to spot it: Disable dotenv extensions, ask the agent to edit again, see whether it still mutates.
4. Agent confused .env with .env.example
It meant to update .env.example (commit the template) but the command had the wrong path and overwrote .env (your real values) with the template content.
How to spot it: Check the agent’s recent Write tool calls — target path .env or .env.example?
5. Agent ran a “generate .env” script
It ran cp .env.example .env, or a project-provided npm run setup script that unconditionally overwrites.
How to spot it: Search the agent’s command history for cp .env, mv .env, > .env, npm run setup, init.
6. Multi-worktree / multi-machine confusion
Agent was working in a worktree or sub-directory and created a new .env (empty template). When you switched back, the IDE picked up that one.
How to spot it: find . -name ".env*" -not -path "./node_modules/*" — multiple .env files mean confusion.
Shortest path to fix
Ordered by priority. Step 1 is recovery, Steps 2-5 prevent recurrence.
Step 1: Restore from backup / password manager / deploy platform
Try these sources in order of success rate:
| Source | Command / action |
|---|---|
| macOS Time Machine | tmutil restore /Users/you/project/.env |
| Git stash (if you stashed before) | git stash list then git stash show -p stash@{0} |
| 1Password / Bitwarden / company password manager | Look for the saved secret entry |
| Vercel / Netlify / Railway env panel | Project Settings → Environment Variables → copy |
| Last screenshot shared on team Slack / Notion | Search chat history |
~/.zsh_history / shell history | grep -i "API_KEY=" ~/.zsh_history for past exports |
| IDE recent files / Cursor / VS Code Timeline | Right-click .env → Timeline / Local History |
VS Code’s Local History (workbench.localHistory.enabled) is on by default and auto-saves every change — the most-overlooked but most-effective recovery source.
Step 2: Add agent ignore files alongside .gitignore
Different agents use different filenames. Cover all of them:
# .cursorignore (Cursor)
.env
.env.local
.env.*.local
# .claudeignore (some Claude Code versions)
.env*
# .aiderignore (Aider)
.env
.env.*
# .gitignore (keep this too)
.env
.env.local
This makes the agent unable to read .env in the first place, cutting off its ability to “complete” it.
Step 3: Hard-lock the rule in CLAUDE.md / AGENTS.md / .cursorrules
## File protection
- `.env` and `.env.*` (except `.env.example`) must never be read, edited, deleted, or overwritten
- To add a new env var, update only `.env.example` and list the new keys in the PR description
- Any "clean up project," "standardize config," or "fill in .env" request requires explicit user confirmation
- Real user secrets must never appear in agent output
Paste this into the project root instruction file. Claude Code, Cursor, Aider, and Codex all read these files every turn.
Step 4: Commit a safe .env.example
Give the agent a legal target so it doesn’t go for the real .env:
# Generate template from real .env (values stripped)
sed -E 's/=.*/=/' .env > .env.example
git add .env.example
git commit -m "chore: add .env.example template"
Future “add a new env var” requests update .env.example; you sync to .env by hand.
Step 5: Pre-commit hook against accidental commits
Even if the agent tries to commit .env, the hook stops it:
# .git/hooks/pre-commit (or via husky)
if git diff --cached --name-only | grep -qE '^\.env(\.|$)' | grep -v '.env.example'; then
echo "ERROR: refusing to commit .env file"
exit 1
fi
For full coverage, use git-secrets or gitleaks to scan for secret patterns (sk_live_*, AKIA*, -----BEGIN PRIVATE KEY-----) — catches the case even if the filename changes.
Prevention
- List
.env*in both.gitignoreand every agent’s ignore file (.cursorignore,.aiderignore,.claudeignore) - In CLAUDE.md / AGENTS.md /
.cursorrules, write an explicit “never touch .env” rule with concrete paths - Store real secrets in a password manager (1Password / Bitwarden) — never only in a local
.env - Periodically back up
.envto an encrypted location — macOS Vault, anage-encrypted private git repo, or a company secret manager - Commit a
.env.exampletemplate so the agent has a legitimate target for additions - Use pre-commit hooks plus gitleaks / git-secrets to block
.envfrom entering git - When switching to a worktree or sub-directory, double-check which
.envyou’re editing — avoid having multiple copies
Related
- Claude Code edited the wrong file
- How to roll back AI code changes
- AI pre-commit review workflow
- Claude Code SEO audit
- AI dependency upgrade workflow
Tags: #AI coding #Debug #Troubleshooting