Codex Agent Output Conflicts With Prettier

Codex writes a file, Prettier reformats it on save, and now the diff is huge. Fix by running Prettier inside the agent loop and aligning agent style hints to your .prettierrc.

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 stash or git diff > before.patch so you can compare cleanly.
  • Note your Prettier version: cat package.json | grep '"prettier"' and npx prettier --version.
  • Note your editor’s Prettier integration: VSCode editor.formatOnSave + prettier.requireConfig setting.

Information to collect

  • .prettierrc / prettier.config.js / package.json#prettier contents.
  • AGENTS.md sections about style.
  • The exact files reformatted on save (compare git diff lines vs what the agent wrote).
  • Editor of choice + extensions (VSCode + Prettier extension, etc.).
  • Whether prettier-eslint or eslint-config-prettier is 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 diff on 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 .prettierrc so 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 global prettier.
  • Install eslint-config-prettier so ESLint never argues with Prettier.
  • Add a CI job that runs prettier --check on PR — it catches drift before merge.
  • For ASCII purity, add a pre-commit hook that rejects non-ASCII in .ts / .js files.

Common pitfalls

  • Running prettier --write on 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 prettier without pnpm exec — version pinning is silently ignored.
  • Leaving editor.formatOnSave on 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 blame and 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.

Tags: #Codex #agent #Troubleshooting #prettier #formatting