Codex generates working code that doesn’t feel like your codebase. Naming uses get* when you use find*. Error handling throws strings when your code throws typed AppError’s. Tests use expect(x).toBe(y)when your style isassert.strictEqual(actual, expected)`. The code reviews badly — not because it’s wrong, but because it’s wrong-shaped.
Conventions don’t show up to an LLM from a few file reads. They have to be made visible — encoded as rules with concrete examples Codex can read. AGENTS.md is the contract; pointing Codex at canonical example files is the enforcement.
Common causes
Ordered by hit rate, highest first.
1. Convention isn’t documented anywhere
The team agreed in chat last quarter to use find* for “may return null” and get* for “must exist or throw.” Codex can’t see chat — and the agreement was never written down. Codex picks whichever it saw first.
How to spot it: Ask your team: “Where is this convention documented?” If nobody can point to a file, Codex couldn’t either.
2. Convention is documented but Codex didn’t read the doc
STYLE.md exists, but Codex’s read pattern only touched src/. Documents named with anything other than AGENTS.md/CLAUDE.md/README.md are often skipped.
How to spot it: Rename STYLE.md to AGENTS.md (or merge it in). If Codex now follows the rule, the path was the issue.
3. Codex took a “popular online” pattern over yours
The team uses kebab-case-test-ids (data-testid="user-card-name"). Codex generates camelCaseTestIds because that’s more common in Storybook examples. Convention loses to internet meme.
How to spot it: New code matches a popular-blog pattern more than your existing code. Common with linting, testing, and naming.
4. AGENTS.md states the rule but provides no example
“Use the team’s error pattern.” What pattern? Codex needs a concrete example to copy from — a one-line rule isn’t enough.
How to spot it: AGENTS.md has a section heading but no code block or file pointer below it. Rules without examples often get ignored.
5. Conventions conflict within the repo
Half the codebase uses findUserById, half uses getUserById (legacy migration in progress). Codex picks whichever it reads first. No clear canonical means random output.
How to spot it: grep -c "findUserById" src/ && grep -c "getUserById" src/ — both nonzero means inconsistent. Codex can’t pick correctly because no winner has been declared.
6. Convention is enforced by linter but Codex didn’t run lint
The convention IS encoded — in .eslintrc rules like naming-convention: camelCase — but Codex generates code and skips running lint. The error only surfaces in CI.
How to spot it: Run pnpm lint path/to/new-file.ts after Codex’s patch. Lint errors = encoded convention Codex bypassed.
Shortest path to fix
Ordered by ROI. Steps 1–3 fix the most common cases.
Step 1: For each broken convention, add rule + example to AGENTS.md
Don’t write rules in isolation. Always pair them with a real file Codex can read:
## Naming conventions
- `find*` for nullable lookups (returns `T | null`).
Example: `src/services/user/findUserById.ts`
- `get*` for required lookups (throws on missing).
Example: `src/services/user/getUserById.ts`
## Error handling
All thrown errors must extend `AppError` from `src/lib/errors.ts`.
Example pattern: see `src/api/billing/handlers.ts:42`
## Test style
Use `vitest` with `assert` (NOT `expect`).
Canonical example: `src/services/user/user.test.ts`
The example file is what Codex actually copies from. The rule is just navigation.
Step 2: Point at the example in the task prompt
Add a new lookup for `getOrgById`.
Follow the exact pattern in `src/services/user/getUserById.ts`:
- Same function shape
- Same error throw style
- Same test layout (see `getUserById.test.ts`)
Generate the file + its test together.
A pointer to a real file beats any amount of prose convention.
Step 3: When divergent, reject + re-prompt referencing the canonical
If Codex generates the wrong shape:
Your output uses `expect(x).toBe(y)` — that's jest style.
This codebase uses `assert.strictEqual(actual, expected)`.
See `src/services/user/user.test.ts` for the canonical pattern.
Re-generate the test using the canonical style.
Each rejection trains the session. After 1–2 corrections, Codex stays on pattern for the rest.
Step 4: For visible markers, require them as outputs
For data-testid, ARIA attributes, custom decorators — list them as required outputs:
New components must include:
- `data-testid="<kebab-name>"` on every interactive element
- `aria-label` for icon-only buttons
- Storybook story file at `<Component>.stories.tsx`
Reject any component missing any of these.
Step 5: Run lint as part of the verifier
Lint encodes a lot of conventions Codex bypasses. Make it part of “done”:
After writing, run:
pnpm eslint <new-files> --max-warnings 0
If any warning/error, fix it before saying done.
Pair this with a strict ESLint config (naming-convention, import/order, custom rules) and many conventions are enforced automatically.
Step 6: For monorepos, per-package AGENTS.md
Different packages can have different conventions. Don’t force one root rulebook. Add per-package files:
apps/web/AGENTS.md → Next.js App Router conventions
packages/ui/AGENTS.md → Component library conventions
packages/db/AGENTS.md → Prisma + repository pattern conventions
Codex picks up the closest file walking from the edited file upward.
Prevention
- Every convention in AGENTS.md pairs with a concrete example file — rules-only sections are ignored
- Resolve inter-repo inconsistencies first (declare a winner) before relying on Codex to follow convention
- Encode as much as possible in ESLint/Biome/Prettier so the linter enforces what AGENTS.md describes
- Per-package AGENTS.md in monorepos — closest file wins
- When a divergent output ships, treat it as a documentation gap, not a Codex failure — add the rule + example
- Quarterly: run Codex against the project’s style and check whether output drifts; if it does, the docs are stale
Related
- Codex ignores project structure
- Codex generated code does not fit existing style
- Codex makes unsafe assumptions
- Codex beginner guide
- Codex code review workflow
- Codex vs Claude Code
Tags: #Codex #Coding agent #Troubleshooting #Debug #Conventions