AI Coding Agent Loops Without Making Progress

Your agent keeps trying the same fix or oscillates between two states. How to spot the loop in 30 seconds and kill it with one prompt.

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 traceMost likely causeJump to fix
Same test goes green-red-green with no code changeFlaky testStep 3
Edits bounce between two unrelated filesAmbiguous promptStep 2
Stuck on the same plan step for 5+ roundsPlan is wrong, agent won’t replanStep 2
Long session, agent re-fixes already-fixed errorsContext saturated with stale logsStep 4
mock/stub added then removed repeatedlyMock vs real implementation thrashStep 2
Re-runs a command that already failedTool failure the agent didn’t noticeStep 1
Same edit applied repeatedly, file gets duplicate blocks (Cursor)Editor thinks the edit failedSee 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 typeConstraint 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:

  • /clear wipes the in-session conversation history (your CLAUDE.md and project files are untouched).
  • /compact summarizes 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:

  1. Copy the full current file contents (not the diff).
  2. Open a new session.
  3. 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:

AgentWhere to put rules (as of June 2026)Stale name to avoid
Claude CodeCLAUDE.md (project root)
CodexAGENTS.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
AiderCONVENTIONS.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:

  1. Run the target command yourself, twice in a row: same green result both times means the feedback signal is now stable.
  2. Read the agent’s last diff and confirm it touched only the file(s) you allowed — no edits to tests or config you froze.
  3. In Cursor, scan the edited file for duplicate functions or imports (the apply-loop bug leaves these behind).
  4. Ask the agent to restate the completion criterion and confirm it is met (e.g., “npm test -- auth all 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.ts file 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 /compact to keep the context lean.
  • Give the agent an explicit completion criterion — not “fix login” but “npm test -- auth all green.”
  • When a loop appears, reset context (/clear or 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.

Tags: #AI coding #Debug #Troubleshooting