Codex writes a clean-looking patch. You open the file in your editor and Prettier-on-save rewrites every line — quotes flip, trailing commas appear, semicolons get added or stripped, line breaks rearrange. Now the git diff is twice as long as the actual change. Worse, when the agent tries to follow up on its own edit later, it cannot match its original lines anymore. Pre-commit hooks fail. CI lint flags the file. The “ten lines changed” turns into 300.
This is not a Codex bug; it is a missing handshake. The agent does not know your .prettierrc exists, or it knows but the prompt did not load it, or it ran format but with default settings instead of project settings. The fix is to make Prettier part of the agent’s “done” definition, and to feed the relevant rules into the agent’s style hints so its first draft already matches what Prettier will produce.
Common causes
Ordered by hit rate.
1. Agent never ran Prettier; editor did
The agent finished, saved the file, declared “done”. On your machine, editor-on-save Prettier reformatted the file. The clean-looking output gets transformed at the last second.
How to spot it: git diff looks much larger than the agent reported. Run prettier --check <file> — many lines fail.
2. Agent ran a different Prettier than the project’s
pnpm prettier --write vs npx prettier@3.2 --write vs globally-installed prettier — different versions produce different output. Codex used a global install but your project uses a pinned 3.0.x.
How to spot it: npx prettier --version inside the project differs from what the agent ran. Diff is uniform formatting differences (e.g. all ' → ").
3. Style hints in AGENTS.md disagree with .prettierrc
AGENTS.md says “use single quotes” but .prettierrc has "singleQuote": false. Agent obeys AGENTS.md; Prettier wins on save. They are fighting.
How to spot it: Manually diff AGENTS.md style claims against .prettierrc / prettier.config.js. Any disagreement = noisy diffs forever.
4. Mixed Prettier and ESLint formatters
ESLint with eslint-plugin-prettier AND a standalone Prettier on save produce slightly different orderings of arrow parens, trailing commas in JSX. Agent picked one, the chain of tools picked the other.
How to spot it: Files reformat differently depending on which tool you run last. Run pnpm prettier --check . && pnpm eslint . — if both pass after prettier --write but eslint --fix then changes lines back, you have a conflict.
5. Agent inserted invisible characters Prettier reformats
Smart quotes, non-breaking spaces, en-dashes — Codex sometimes inserts these in comments or strings. Prettier (or some plugin) normalizes them.
How to spot it: cat -A <file> | grep -E '\xc2\xa0|\xe2\x80' finds non-ASCII. Compare to the agent’s output text.
6. Files with // prettier-ignore directives
Existing code uses // prettier-ignore to preserve a hand-aligned block. Agent edits inside the block — Prettier respects the ignore, but the agent’s careful alignment may not match the existing alignment.
How to spot it: grep -rn "prettier-ignore" <files> lists the protected zones. Cross-check with agent’s edited regions.
Before you start
- Save a snapshot:
git stashorgit diff > before.patchso you can compare cleanly. - Note your Prettier version:
cat package.json | grep '"prettier"'andnpx prettier --version. - Note your editor’s Prettier integration: VSCode
editor.formatOnSave+prettier.requireConfigsetting.
Information to collect
.prettierrc/prettier.config.js/package.json#prettiercontents.- AGENTS.md sections about style.
- The exact files reformatted on save (compare
git difflines vs what the agent wrote). - Editor of choice + extensions (VSCode + Prettier extension, etc.).
- Whether
prettier-eslintoreslint-config-prettieris installed.
Step-by-step fix
Ordered by ROI.
Step 1: Make Prettier part of the agent’s “done” loop
In the task prompt:
After every file edit, run:
pnpm prettier --write <files-edited>
Confirm: pnpm prettier --check <files-edited> returns 0.
If non-zero, fix and re-run before declaring done.
Now the agent’s last action matches what your editor will produce — zero post-save reformat.
Step 2: Align AGENTS.md style claims to .prettierrc
Open .prettierrc (or prettier.config.js) and translate every option into AGENTS.md:
## Formatting (matches .prettierrc — do not deviate)
- printWidth: 100
- semi: false → no trailing semicolons
- singleQuote: true → use single quotes
- trailingComma: "all"
- arrowParens: "always" → (x) => x not x => x
- bracketSpacing: true → { foo } not {foo}
Codex’s first draft now matches Prettier’s output — eliminating the diff inflation.
Step 3: Pin the Prettier version the agent calls
Force the project’s pinned version:
After every edit:
pnpm exec prettier --write <files>
# NOT: npx prettier --write (may pull a different version)
# NOT: prettier --write (may use global install)
pnpm exec / yarn dlx / npm exec route to the project’s locked Prettier.
Step 4: Resolve ESLint + Prettier conflicts permanently
Install eslint-config-prettier if not already:
pnpm add -D eslint-config-prettier
Add to ESLint config last:
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier']
This disables ESLint rules that conflict with Prettier. Now eslint --fix and prettier --write produce identical output.
Step 5: Normalize invisible chars in agent output
Add to the task prompt:
Output rules:
- ASCII only in code (no smart quotes, no en-dashes, no nbsp)
- For comments: standard ASCII " ' - --
- For string literals: only what the user requested literally
For paranoia, run a sanitizer after edits:
sed -i 's/\xc2\xa0/ /g; s/\xe2\x80\x9c/"/g; s/\xe2\x80\x9d/"/g' <files>
Step 6: Handle prettier-ignore zones explicitly
In the task prompt, list protected zones:
The following blocks are `// prettier-ignore` protected — preserve their existing alignment exactly. Do not edit unless required:
- src/data/timezones.ts:42-78
- src/config/menus.tsx:120-180
If you must edit inside one, match the existing indent / alignment byte-for-byte.
Step 7: Optional — disable editor format-on-save during agent runs
If you cannot get the agent’s Prettier to match editor’s, temporarily:
"editor.formatOnSave": false
Then run Prettier yourself at the end of the session. Removes the editor as a hidden actor.
Verify
git diffon the agent’s output: line count should match what the agent reported, not 5x.pnpm prettier --check <files>returns 0 immediately after agent finishes.- Open the file in your editor, save without typing anything: zero changes.
- Pre-commit hook (
lint-staged+prettier --check) passes on first try.
Long-term prevention
- AGENTS.md formatting section is auto-generated from
.prettierrcso they cannot drift. - Every agent task template includes “run prettier on touched files before done”.
- Use
pnpm exec(or equivalent) in agent tool calls — never globalprettier. - Install
eslint-config-prettierso ESLint never argues with Prettier. - Add a CI job that runs
prettier --checkon PR — it catches drift before merge. - For ASCII purity, add a pre-commit hook that rejects non-ASCII in
.ts/.jsfiles.
Common pitfalls
- Running
prettier --writeon the whole project after an agent edit — masks which lines the agent actually touched and bloats the diff. - Editing AGENTS.md style section but forgetting to update
.prettierrc(or vice versa) — they will fight again next month. - Trusting
npx prettierwithoutpnpm exec— version pinning is silently ignored. - Leaving
editor.formatOnSaveon while you “just check” the agent’s diff — the moment you click into the file, it gets reformatted. - Ignoring “trailing comma” disagreements as cosmetic — they break
git blameand inflate every future diff.
FAQ
Q: I added Prettier to the agent loop but the editor still reformats on save. Why?
Check prettier.requireConfig in your editor settings — if false, the editor uses defaults, ignoring .prettierrc. Set it true and editor will only run Prettier when a config is found.
Q: My team uses Biome / dprint, not Prettier. Same fix?
Yes — substitute biome format --write or dprint fmt for the Prettier commands. The structural fix (formatter inside the agent loop + style hints aligned to config) is identical.
Q: Can I just tell Codex to not format at all?
You can, but then you owe it a clear “we will reformat outside the agent” workflow. The diffs will still be noisy on commit. Better to align the agent’s first draft to what Prettier will produce.
Q: What about .prettierignore?
Same story — make sure AGENTS.md lists patterns the agent should not touch, matching .prettierignore. Otherwise the agent edits a generated file that Prettier refuses to format and you get inconsistency.
Related
- Codex misses project conventions
- Codex generated code does not fit existing style
- Codex Agent stops mid-task without error
- Codex Agent spawns too many redundant tool calls
- Codex patch conflicts with existing code
- Codex environment setup fails
- Codex Agent Skips Files Containing Binary Data
- Codex Cannot Access a Private Repo
- Codex PR Description Says “Refactored Components” and Nothing Else
- Codex Stalls on a Merge Conflict or Resolves It the Wrong Way
- Codex Added a Package but the Lockfile Did Not Change
- Codex Creates a New TypeScript Interface Duplicating One That Already Exists
- Codex Says Tests Passed but Actually Skipped the Failures
- Codex Bails Out When the Patch Gets Too Large