teachyou.ai academy
← All posts
Codexprompt engineeringAI coding assistantsOpenAIdeveloper tools

Prompting OpenAI Codex Effectively

Pramod Dutta · Jul 5, 2026 · 13 min read

Codex prompting is the practice of giving OpenAI Codex enough scope, context, and verification criteria that it can plan, edit, and test code without you babysitting every step. Most people treat Codex like a chat window and get vague, half-finished diffs back. The fix is not a magic phrase, it is structuring the task the way you would brief a competent contractor who has never seen your codebase before.

This article covers the mechanics: how Codex reads your repo, what belongs in a prompt versus what belongs in AGENTS.md, how to scope tasks so the agent does not wander into unrelated files, and how to run longer autonomous loops without losing control of the diff.

Why Codex Prompting Is Different From Chat Prompting

When you prompt a chat model, the cost of a bad answer is a re-read. When you prompt Codex, the cost of a bad prompt is a bad diff touching real files, sometimes with tests it wrote to pass its own broken code. Codex prompting has to account for three things a chat prompt does not:

  • Repo state. Codex reads your working tree, so ambiguous instructions get resolved against whatever code happens to be there, not against your intent.
  • Tool use. Codex runs shell commands, edits files, and can loop on test failures. A vague goal turns into a long, expensive exploration instead of a quick miss you can immediately correct.
  • Diff review cost. A chat answer you skim. A code diff you have to actually read, and the more Codex improvises, the more you pay in review time.

Good codex prompting front-loads the constraints so the agent's exploration space is small. Bad codex prompting relies on the model guessing your intent and hopes the guess is close enough.

Set Up the Repo Before You Write a Single Prompt

Prompting quality is capped by repo quality. Before you write your first task prompt, do this once per project.

Install and authenticate the CLI:

npm install -g @openai/codex
codex login

Run it from the repo root, not from a parent directory. Codex scopes its file reads and edits to the working directory you launch it in, and giving it a narrower root means less irrelevant context gets pulled in in.

Write an `AGENTS.md` file at the repo root. This is the single highest-leverage thing you can do for Codex prompting, because it turns repeated instructions into a standing prompt instead of something you retype every session. A minimal one:

# AGENTS.md

## Stack
- Node 20, TypeScript, Express, Postgres via Prisma
- Tests: vitest, run with `npm test`
- Lint: `npm run lint`, must pass before any commit

## Conventions
- No default exports
- All API routes live in src/routes, one file per resource
- Errors are thrown as AppError subclasses, never raw strings

## Workflow
- Run `npm run lint && npm test` before declaring a task done
- Do not touch files under /legacy without explicit instruction
- Prefer small, reviewable diffs over sweeping refactors

Codex reads AGENTS.md automatically at the start of a session and treats it as standing context. Anything that would otherwise clutter every prompt (test commands, forbidden directories, naming conventions) belongs here, not in the task prompt.

Check `.gitignore` and any Codex sandbox config. If Codex needs network access to install a package or hit an API during a task, make sure your sandbox policy allows it, otherwise the run will fail silently mid-task and you will burn a cycle debugging the sandbox instead of the code.

The Anatomy of an Effective Codex Prompt

A prompt that produces a clean diff on the first try has four parts, in this order.

1. The goal, stated as an outcome, not a method.

Weak: "Look at the auth code and see if you can improve it." Strong: "Add rate limiting to POST /api/login so a single IP cannot attempt more than 5 logins per minute."

The strong version gives Codex a pass/fail condition it can test against. The weak version gives it license to refactor anything it decides is "improvable."

2. The scope, stated as boundaries.

Tell Codex what it may touch and what it may not:

Scope: only src/middleware/rateLimit.ts and src/routes/auth.ts.
Do not modify the Prisma schema or any file under src/routes/users.

Without an explicit boundary, Codex will sometimes "helpfully" touch adjacent code it judges related. That is rarely what you want in a reviewable PR.

3. The verification step, stated as a command.

Verify by running npm test -- rateLimit.test.ts and confirm it passes.
If no test file exists, write one that hits the endpoint 6 times and
asserts the 6th response is a 429.

This is the single biggest lever in codex prompting. An agent with a concrete command to run against will self-correct on failures. An agent with "make sure it works" will declare victory after a syntax check.

4. The context Codex cannot infer.

Business rules, external API quirks, or decisions that live in someone's head belong in the prompt explicitly:

Context: rate limit state should live in Redis, not in-process memory,
because we run 4 instances behind a load balancer. Redis client is
already configured at src/lib/redis.ts, reuse it.

Put together, a full task prompt looks like this:

Goal: Add rate limiting to POST /api/login so a single IP cannot
attempt more than 5 logins per minute.

Scope: only src/middleware/rateLimit.ts and src/routes/auth.ts.
Do not modify the Prisma schema or files under src/routes/users.

Context: rate limit state should live in Redis, not in-process
memory, because we run 4 instances behind a load balancer. Redis
client is already configured at src/lib/redis.ts, reuse it.

Verify: run npm test -- rateLimit.test.ts and confirm it passes.
If no test file exists, write one that hits the endpoint 6 times
and asserts the 6th response is a 429. Run npm run lint after and
fix any violations before finishing.

That is four short paragraphs, not a novel, and it removes almost all of the ambiguity that leads to a wasted run.

Scoping Tasks So Codex Doesn't Wander

The most common failure in codex prompting is scope creep: you ask for one function and get back a diff touching twelve files because the model decided the surrounding code needed cleanup too. Three techniques keep this in check.

Name the files explicitly whenever you already know them. "Fix the bug in src/utils/parseDate.ts where timezone offsets are dropped" is far tighter than "fix the date parsing bug." If you do not know the file, ask Codex to locate it first as a separate step, then confirm before asking for the fix.

Split "find" from "fix" for anything you're not sure about. Run a scoping prompt first:

Find the function responsible for parsing incoming webhook payloads
from Stripe. Report the file and line range. Do not edit anything yet.

Review the answer, then send a second prompt authorizing the actual change. This costs one extra round trip and saves you from a diff that touched the wrong function entirely.

State what "done" does not include. If you're fixing a bug, say so: "Do not refactor surrounding code, do not rename variables, do not update the changelog." Codex will otherwise interpret an open-ended goal as an invitation to tidy up everything nearby.

Prompting Patterns That Work

A few task shapes come up constantly. Here is how to phrase each one.

Bug fix with a reproduction. Always include the failing input and expected output, not just a description of the symptom:

Bug: GET /api/orders/:id returns 200 with an empty body when the
order exists but has no line items. Expected: it should return the
order object with lineItems: [].

Reproduce with: curl localhost:3000/api/orders/42 (order 42 has 0
line items in the seed data).

Fix the root cause in src/services/orderService.ts. Add a regression
test in src/services/orderService.test.ts covering an order with
zero line items.

Refactor with a safety net. Refactors are the riskiest Codex tasks because "equivalent behavior" is hard to verify by eye. Anchor it to tests:

Refactor src/lib/pricing.ts to remove the nested if/else pricing
logic and replace it with a lookup table. Behavior must be identical.

Before starting, run npm test -- pricing.test.ts and confirm all
tests pass on the current code. After the refactor, run the same
test file again and confirm it still passes with no changes to the
test file itself.

New feature with acceptance criteria. Treat this like a lightweight spec, not a one-liner:

Add CSV export to the /api/reports/monthly endpoint.

Acceptance criteria:
- New query param ?format=csv returns text/csv with a Content-Disposition
  header set to attachment; filename="monthly-report.csv"
- CSV columns: date, revenue, orders, refunds, in that order
- Existing JSON response (no format param) must be unchanged
- Add a test in src/routes/reports.test.ts covering the csv format

Scope: src/routes/reports.ts and a new src/lib/csv.ts helper only.

Test writing for existing code. Give Codex the coverage gap, not just "add tests":

src/lib/discountCalculator.ts has no test file. Write vitest tests
covering: a flat percentage discount, a fixed-amount discount, a
discount that would push the price below zero (should floor at 0),
and stacking two discounts. Do not modify discountCalculator.ts itself,
only add the test file.

The Goal Loop for Longer Autonomous Runs

For multi-step work, Codex supports a persistent self-checking loop, sometimes invoked as /goal, where the agent plans, acts, tests, reviews its own diff, and iterates until it either meets the stated goal or hits a stopping condition you define. This is where codex prompting shifts from "write one good prompt" to "write one good goal statement that survives many iterations."

A goal prompt needs to carry more weight than a single-task prompt because Codex will use it as its own checklist across an unattended run:

Goal: Migrate all date handling in src/ from the native Date object
to date-fns, keeping all existing behavior identical.

Plan before acting: list every file using Date, group them by risk
(pure formatting vs. timezone-sensitive logic), and start with the
lowest-risk files.

After each file, run npm test and npm run lint. If either fails,
fix it before moving to the next file. Do not proceed to the next
file with a red test suite.

Stop condition: all files migrated and full test suite green, or
you've completed 3 files and want a checkpoint review, whichever
comes first.

Report at the end: a list of files changed, and any date-handling
edge case you found that the existing tests did not cover.

The stop condition and the "report at the end" line matter more in a goal loop than in a single prompt, because nobody is watching each individual step. Without an explicit checkpoint, a long-running goal can burn a lot of time and diff surface before you get a chance to intervene.

Common Codex Prompting Mistakes

Asking for "best practices" with no definition. "Use best practices" means nothing to a model without a linter config or style guide to point at. Either name the standard ("follow the existing error-handling pattern in src/lib/errors.ts") or point at AGENTS.md.

Skipping the verification step because the task feels small. Small tasks are exactly where people skip verification, and exactly where a silently wrong diff slips through review because nobody expected a mistake.

Re-prompting instead of correcting. If Codex produces a diff that is 80% right, don't restart with a new prompt from scratch, tell it precisely what's wrong: "the rate limit key should be per-IP-per-route, not global per-IP, fix src/middleware/rateLimit.ts." A correction prompt that references the existing diff is faster than a full re-run and keeps the parts that were already right.

Letting the agent write its own tests for its own logic with no independent check. A test Codex writes to validate code Codex just wrote can pass while the underlying assumption is wrong. Where correctness actually matters, give it a known input/output pair up front rather than letting it invent the assertion.

Not pinning file scope on large repos. In a big monorepo, an unscoped prompt gives Codex too much surface area to search, which slows down the run and increases the odds it edits something adjacent instead of the actual target.

Verifying Codex Output Before You Trust It

Treat every Codex diff as an untrusted PR, not as a finished task, regardless of how clean the summary sounds.

  • Read the diff, not just the summary. The agent's final message describes what it believes it did. Confirm against the actual changed lines.
  • Re-run the verification command yourself. Don't take "tests pass" on faith, especially after a long goal-loop run where you were not watching each step.
  • Check for scope violations. Diff the file list against what you scoped in the prompt. Anything outside that list is worth a second look, even if it looks harmless.
  • Look for deleted or skipped tests. An agent under pressure to make a suite pass can occasionally take the easy way out and comment out or weaken a failing assertion instead of fixing the underlying bug. Grep the diff for .skip, .only, or removed assertions before merging.
  • Run it in a branch, not main. This is true for any AI-generated diff, but doubly true for anything produced by a longer autonomous run where the change set is larger than one commit's worth of easy review.

FAQ

What's the single biggest lever in codex prompting? A concrete verification command. A prompt with "run npm test -- <file> and confirm it passes" produces dramatically better first-pass results than a prompt that just describes the desired change, because it gives the agent something to self-correct against instead of a subjective judgment call.

Should I put coding conventions in every prompt or in AGENTS.md? Anything you'd repeat across more than one task belongs in AGENTS.md. Task-specific detail (which files, what the bug reproduction looks like, what the acceptance criteria are) belongs in the prompt itself.

How long should a Codex prompt be? Long enough to cover goal, scope, context, and verification, short enough that you could read it back and know exactly what "done" looks like. Four short paragraphs is usually enough for a well-scoped task; a goal-loop prompt for a multi-file migration can run longer because it has to survive many unattended iterations.

Can I use the same prompt style across different coding agents? Mostly yes. Explicit scope, concrete verification commands, and named context are good practice for any code-editing agent. What differs between tools is the standing-context mechanism (Codex uses AGENTS.md, other tools have their own convention) and how autonomous loops are invoked.

What should I do if Codex keeps making the same mistake across a session? Add it to AGENTS.md immediately rather than repeating the correction in every prompt. If Codex keeps reaching for a deprecated helper or wrong import path, one line in the conventions section fixes it for every future session, not just the current one.

Is it worth scoping a task before asking for the fix, even for something that feels obvious? For anything touching more than one file, yes. The extra round trip of a "find, don't fix yet" prompt is cheap compared to reviewing and unwinding a diff that changed the wrong function because the bug description was ambiguous.

Does giving Codex more context always produce a better diff? No, past a point extra context adds noise the model has to sort through, and irrelevant detail can pull focus toward the wrong file. Give it the context that's load-bearing for the decision (why Redis and not in-memory state, why this business rule exists) and skip the rest.