You watch your Claude Code or Cursor agent run npm test for the twelfth time, edit the same expect(...).toBe(...) line, run again, fail again, revert. Or Aider ping-pongs between git diff and git restore. Tokens burn, the progress bar doesn’t move.
Fastest fix (under a minute): Stop the agent (press Esc in Claude Code, click the stop button in Cursor or Codex). Ask it to list its last 10 actions as a table. Then send one constraint that names exactly what NOT to touch and the single next step — for example, Don't touch the test. The test is correct — change the implementation to match. That single sentence breaks most loops.
Most of the time the model isn’t “incapable of fixing this.” It’s stuck in a broken feedback loop: a flaky test, an under-constrained prompt, or context that no longer matches the code on disk. This article shows how to spot a loop in 30 seconds, kill it with one prompt, and prevent it from starting next time.
Which bucket are you in?
| Symptom in the action trace | Most likely cause | Jump to fix |
|---|---|---|
| Same test goes green-red-green with no code change | Flaky test | Step 3 |
| Edits bounce between two unrelated files | Ambiguous prompt | Step 2 |
| Stuck on the same plan step for 5+ rounds | Plan is wrong, agent won’t replan | Step 2 |
| Long session, agent re-fixes already-fixed errors | Context saturated with stale logs | Step 4 |
mock/stub added then removed repeatedly | Mock vs real implementation thrash | Step 2 |
| Re-runs a command that already failed | Tool failure the agent didn’t notice | Step 1 |
| Same edit applied repeatedly, file gets duplicate blocks (Cursor) | Editor thinks the edit failed | See Cursor note below |
Common causes
Ordered by hit rate, highest first.
1. The test it keeps running is flaky
The single most common trigger. A test uses Date.now(), network calls, randomness, or snapshot timestamps, so the same code passes one run and fails the next. The agent sees red, edits, green, next run red — it thinks it broke its own fix, reverts, green again, edits again, red again.
Run 1: pass
Run 2: fail (snapshot mismatch — timestamp drift)
Run 3: pass (after agent "reverted")
Run 4: fail
How to spot it: Stop the agent and run the same command three times yourself without touching code. If you can reproduce green-red-green, the test is the problem, not the agent.
2. Ambiguous prompt — agent oscillates between interpretations
You said “fix the login bug,” but the codebase has both OAuth and magic-link paths. The agent fixes OAuth, the magic-link test fails, it switches to magic-link, the OAuth test fails — it bounces between two mutually exclusive interpretations of the goal.
How to spot it: Look at the diffs of the last 5 actions. If they touch two different files in different functions and each new edit reverts the previous one, the prompt is under-constrained.
3. Plan is wrong but agent refuses to replan
The agent committed to “change schema, then API, then UI.” Step 1 is impossible (the table already has data), but the agent stays on step 1 rewriting migrations forever instead of revisiting the plan.
How to spot it: Ask the agent to print its current plan and which step it’s on. If it says “still on step 2” for more than 5 iterations, force a replan.
4. Context window saturated with old errors
In a long Claude Code or Codex session, most of the context is stale “previous failure” logs. The agent is fitting to those old errors and can’t see that the code has changed since. Claude Code auto-compacts as you approach the context limit, but on a single grinding task the summary can still carry forward the wrong assumptions.
How to spot it: Open a fresh session, paste the current code, restate the goal. If it succeeds on the first try, context pollution was the cause.
5. Agent ping-pongs between mock and real implementation
It writes a mock to make a test pass, the next iteration decides the mock is unrealistic, edits the real implementation, the original test breaks, it goes back to the mock — loop.
How to spot it: Search the diff trail for jest.mock, vi.mock, MagicMock, or sinon.stub being added and removed across runs.
6. Tool call failed but agent didn’t notice
The Bash tool returned a non-zero exit code, but the agent parsed it as stdout and treated the command as “successful with weird output,” then ran it again. Cursor’s Agent mode has a known variant of this: it applies an edit, the apply model reports the edit as failed, so the agent retries — sometimes pasting the same block twice and creating duplicate code.
How to spot it: Check the exit codes of the last 3 tool calls. If they’re non-zero but the agent never said “the command failed” in chat, it missed the failure. In Cursor, open the file the agent is editing and look for duplicated functions or imports.
Shortest path to fix
Ordered by ROI. Steps 1 and 2 break most loops in under a minute.
Step 1: Stop the agent, read the last 10 actions
Press Esc (Claude Code) or click the stop button (Cursor / Codex). In a Codex CLI session a background command can be interrupted with Ctrl-C while its final output and exit status are preserved. Don’t let it keep burning tokens. Then ask in chat:
List the last 10 actions you took (file path + edit summary + command + result).
No commentary, just a table.
90% of the time you’ll see it bouncing between two files or editing the same line over and over.
Step 2: Break the loop with a one-sentence constraint
The most effective anti-loop prompt template:
Stop. Do not edit X anymore.
The real situation is Y.
Next, do only one thing: Z.
Do not touch any other file.
Concrete examples:
| Loop type | Constraint prompt |
|---|---|
| Edits test expectations repeatedly | ”Don’t touch the test. The test is correct — change the implementation to match.” |
| Adds/removes mocks repeatedly | ”Keep the real implementation. Delete all mocks and run the integration test to see the real error.” |
| Rewrites migrations repeatedly | ”Schema is frozen. Restart the plan from step 1 but only touch the UI layer.” |
| Bouncing between two files | ”You may only edit src/auth/login.ts. All other files are read-only.” |
If the agent has already made a tangle of partial edits, roll the code back first so it starts from a clean state. In Claude Code, press Esc twice on an empty prompt (or run /rewind) to open the checkpoint menu — Claude auto-checkpoints your code before each edit, and you can choose Restore code, Restore conversation, or both. Note that checkpoints only track edits made through Claude’s file-editing tools; files changed by rm, mv, or other bash commands are not captured, so use git for anything destructive.
Step 3: Pin the test or success criterion
If the agent is chasing a flaky test, stabilize the test first:
# Run the same test 5 times — is it stable?
for i in {1..5}; do npm test -- --testNamePattern="login flow"; done
If you see 2+ failures, mock time / network / randomness before resuming:
// vitest setup
vi.useFakeTimers();
vi.setSystemTime(new Date('2026-01-01'));
Once the test is stable, let the agent resume.
Step 4: Open a fresh session with clean context
If none of the above works, the last lever is to reset context. In Claude Code you have two cheaper options before a full restart:
/clearwipes the in-session conversation history (yourCLAUDE.mdand project files are untouched)./compactsummarizes the conversation so far and replaces the full history with that summary. You can steer it:/compact Focus on the failing auth test and the current implementation.
If the session is too far gone, start clean:
- Copy the full current file contents (not the diff).
- Open a new session.
- Restart with this template:
Goal: [one-sentence goal]
Current code (already edited N rounds):
[paste full file]
Current failing test / error:
[paste full error]
Constraints: don't touch tests, don't touch config, only edit src/X.ts.
Output your plan first. Wait for my approval before editing.
A fresh context isn’t polluted by old failures and usually succeeds on the first try.
Step 5: Set a hard iteration cap
Prevent the next loop from happening. In Claude Code, add to CLAUDE.md:
## Agent behavior constraints
- Maximum 5 build/test iterations per task
- If still failing after 3 iterations, stop and report status for human decision
- Do not edit the same block of code in the same file more than 3 times
The same idea works for the other agents, but the file each one reads has changed — get this wrong and your rules silently do nothing:
| Agent | Where to put rules (as of June 2026) | Stale name to avoid |
|---|---|---|
| Claude Code | CLAUDE.md (project root) | — |
| Codex | AGENTS.md (read root-down; the file closest to the working dir wins) | — |
| Cursor | .cursor/rules/*.mdc (Project Rules) | .cursorrules is deprecated and silently ignored in Agent mode |
| Aider | CONVENTIONS.md, loaded with aider --read CONVENTIONS.md or a read: entry in .aider.conf.yml | .aiderrules is not a real Aider file |
How to confirm the loop is actually broken
Don’t trust “looks fixed.” Verify before you walk away:
- Run the target command yourself, twice in a row: same green result both times means the feedback signal is now stable.
- Read the agent’s last diff and confirm it touched only the file(s) you allowed — no edits to tests or config you froze.
- In Cursor, scan the edited file for duplicate functions or imports (the apply-loop bug leaves these behind).
- Ask the agent to restate the completion criterion and confirm it is met (e.g., “
npm test -- authall green”), then run that exact command once more.
Prevention
- Set iteration caps in the right rules file for your agent (see the table above) — e.g., “stop and ask after 3 consecutive failures of the same test.”
- Inspect the agent’s reasoning / action trace, not just final output — loop patterns only show in the trace.
- Isolate flaky tests into a
flaky.test.tsfile so agents never iterate against unstable feedback. - On long tasks, force the agent to re-print “current plan + current progress” every 5 iterations, or run
/compactto keep the context lean. - Give the agent an explicit completion criterion — not “fix login” but “
npm test -- authall green.” - When a loop appears, reset context (
/clearor a fresh session) instead of trying to recover the polluted one. - In Cursor, if the agent loops on a single edit, turn off Auto model selection and pick a specific model; if it persists, copy the Request ID and report it.
FAQ
Why does my agent keep reverting its own correct fix? Almost always a flaky test. The fix is real, but the next test run fails for an unrelated reason (timestamp, network, random seed), so the agent reads it as “my fix broke something” and reverts. Stabilize the test (Step 3) before letting it continue.
How do I undo a tangle of bad edits in Claude Code?
Press Esc twice on an empty prompt or run /rewind, pick a checkpoint, and choose Restore code. Checkpoints are created automatically before each edit. They do not cover files changed by bash commands, so for anything rm/mv touched, recover with git.
Is .cursorrules still the way to constrain a Cursor agent?
No. As of 2026 the single .cursorrules file is deprecated, and it is silently ignored in Agent mode — exactly the mode where loops happen. Put rules in .cursor/rules/*.mdc instead.
Should I use /clear or /compact when the context is full?
Use /compact (optionally with a focus instruction) when you want to keep working on the same task with a slimmer history. Use /clear when you’re switching to an unrelated task and want a clean slate. For a badly polluted single task, a brand-new session with the full current file pasted in is the most reliable reset.
The agent says a command “succeeded” but nothing changed. Why? It likely misread a non-zero exit code as normal output. Check the exit codes of the last few tool calls. Re-run the command yourself; if it actually fails, paste the real error back and explicitly tell the agent the previous command failed.
Related
- AI hallucinated a file that doesn’t exist
- Cursor missed project context
- AI pre-commit review workflow
- Claude Code SEO audit
- AI dependency upgrade workflow
- AI Generated TypeScript Errors
- AI Agent Overwrote .env / Environment Variables
- AI Suggested a Stale Dependency
- How to Help Claude Code Understand Your Project: 7 Methods That Actually Work
- AI Added a Route That Bypasses Auth Middleware
- AI Invented a Wrong API Signature That Does Not Exist
- AI-Generated SQL Locks a Hot Table for Minutes
- AI Keeps Using Deprecated Syntax Despite Lint Errors
- AI Uses npm Commands in a pnpm or Yarn Project
- AI Generated Migration Works on Dev, Fails on Prod Schema
Tags: #AI coding #Debug #Troubleshooting