Overreach

Reformatted files it only opened to read

只是打开看看的文件,也被它格式化了

The agent reformats, re-wraps or restyles files orthogonal to the task, and the real change disappears in whitespace noise.

Applies to: Claude Code · Cursor · Codex · Copilot agent

Symptom

Hundreds of changed lines, almost none of them functional. Quote styles, trailing commas or import order changed in files the task never needed.

Why it happens

Agents "run formatters or tidy up while they're there" (agent-review AR004). claudecodeguides.com calls it the reformatting impulse, cleaning up files Claude opens only to check an import.

Example

From the agent-review taxonomy (AR004).

diff
- const x = 1; const y = 2; const z = 3
+ const x = 1
+ const y = 2
+ const z = 3

Copy-paste fixes

Pick the files for the agents you use. Snippets are in English so they work in any repo.

Rules

Claude Code: add to CLAUDE.md

CLAUDE.md
## No drive-by formatting
- Do not reformat, re-indent, reorder imports or change quote style in code you are not functionally changing.
- Run the formatter only on the lines or files you changed (for example `npx prettier --write <changed files>`),
  never on the whole repo, unless asked.
- If a file needs a format pass, propose it as a separate commit.
Rules

Codex, Copilot coding agent and others: add to AGENTS.md

AGENTS.md
## No drive-by formatting
- Do not reformat, re-indent, reorder imports or change quote style in code you are not functionally changing.
- Run the formatter only on the lines or files you changed (for example `npx prettier --write <changed files>`),
  never on the whole repo, unless asked.
- If a file needs a format pass, propose it as a separate commit.
Cursor rule

Cursor: project rule

.cursor/rules/drive-by-reformat.mdc
---
description: "AgentFails: Reformatted files it only opened to read"
alwaysApply: true
---

## No drive-by formatting
- Do not reformat, re-indent, reorder imports or change quote style in code you are not functionally changing.
- Run the formatter only on the lines or files you changed (for example `npx prettier --write <changed files>`),
  never on the whole repo, unless asked.
- If a file needs a format pass, propose it as a separate commit.
Hook

Format only changed files (pre-commit)

lint-staged runs the formatter on staged files only, so a session can't reformat the repo through the commit hook.

package.json
{
  "lint-staged": {
    "*.{ts,tsx,js,jsx,css,md}": "prettier --write"
  }
}
CI / script

Diff budget check (run before commit or in CI)

Adapted from the diff-budget post on dev.to (yureki_lab). Reads the real git diff, so it also catches edits made through the shell. Usage: python3 scripts/diff_budget.py origin/main 6 150

scripts/diff_budget.py
#!/usr/bin/env python3
"""Fail if the diff vs BASE touches files outside .agent-scope or exceeds the budget."""
import fnmatch, os, subprocess, sys

base = sys.argv[1] if len(sys.argv) > 1 else "HEAD"
max_files = int(sys.argv[2]) if len(sys.argv) > 2 else 6
max_lines = int(sys.argv[3]) if len(sys.argv) > 3 else 150

allowed = []
if os.path.exists(".agent-scope"):
    allowed = [l.strip() for l in open(".agent-scope") if l.strip() and not l.startswith("#")]

out = subprocess.run(["git", "diff", "--numstat", base], capture_output=True, text=True, check=True).stdout
untracked = subprocess.run(["git", "ls-files", "--others", "--exclude-standard"],
                           capture_output=True, text=True, check=True).stdout.split()

files, lines, outside = 0, 0, []
rows = [r.split("\t") for r in out.strip().splitlines()] + [["0", "0", p] for p in untracked]
for added, deleted, path in rows:
    files += 1
    if added != "-":
        lines += int(added) + int(deleted)
    if allowed and not any(fnmatch.fnmatch(path, p) for p in allowed):
        outside.append(path)

problems = []
if outside:
    problems.append("out-of-scope files: " + ", ".join(outside))
if files > max_files:
    problems.append(f"{files} files changed (budget {max_files})")
if lines > max_lines:
    problems.append(f"{lines} lines changed (budget {max_lines})")

if problems:
    print("OVER BUDGET: " + "; ".join(problems))
    sys.exit(1)
print(f"within budget: {files} files, {lines} lines")

Sources and credit

Related patterns

翻车 of the week

One real agent failure and its fix, every week. Free, short, no spam.