teachyou.ai academy
← All posts
CodexPythonCLI agentsdeveloper workflowtesting

An OpenAI Codex Python Workflow

Pramod Dutta · Jul 5, 2026 · 12 min read

Getting real value out of a codex python setup means treating the CLI agent like a junior engineer with fast hands and no memory: you give it a clear repo, tight instructions, and a way to check its own work. This article walks through installing OpenAI Codex, wiring it into a Python project, and building a day-to-day loop that includes virtual environments, tests, and CI. Every command below is something you can run today against a real Python repo.

Why Use Codex for Python Work

Codex is OpenAI's coding agent, available as a CLI (codex) and as an IDE extension. Point it at a repo and it can read files, propose diffs, run shell commands (including your test suite), and iterate until checks pass. For Python specifically, this matters because so much of the day-to-day loop is mechanical: create a virtualenv, install deps, run pytest, read the traceback, fix the import, run pytest again. Codex is good at exactly that loop when you give it the right guardrails.

The failure mode to avoid is treating codex python sessions like a chat window where you paste code and hope. Codex is far more useful when it has a real terminal, a real test suite, and a written contract for how your project expects code to look. That's the setup this article builds.

Installing and Configuring Codex

Install the CLI with npm or your platform's package manager:

npm install -g @openai/codex

Authenticate once:

codex login

Confirm it's working from inside a project directory:

cd my-python-project codex

This drops you into an interactive session where Codex can see the current directory. You can also run one-shot, non-interactive commands, which is the pattern you want for scripting and CI:

codex exec "add type hints to src/parser.py and run mypy"

Two config knobs matter for Python work. The first is the approval mode, which controls how much Codex can do without asking:

codex --ask-for-approval on-failure

on-failure lets Codex run commands freely (installing packages, running tests) and only stops to ask when something fails in a way it can't resolve. For a first pass on an unfamiliar repo, start stricter with untrusted or on-request, then loosen once you trust the sandbox.

The second knob is the sandbox itself. Codex can run with filesystem writes restricted to the project directory and network access disabled by default:

codex --sandbox workspace-write

For Python this is worth knowing because pip install needs network access. If your workflow depends on installing dependencies mid-session, either pre-install them before invoking Codex, use a lockfile-based environment that's already resolved, or explicitly allow network in your sandbox policy for that session.

Setting Up a Python Project Codex Can Work In

Codex works best on a project with a real, runnable test suite and clear entry points. Before your first codex python session, make sure the basics are in place:

python -m venv .venv source .venv/bin/activate pip install -e ".[dev]" pytest -q

If pytest -q doesn't run clean on main, fix that first. Codex will otherwise burn its first several turns just figuring out that the failures aren't its fault.

Use pyproject.toml as the single source of truth for dependencies and tool config (ruff, mypy, pytest), rather than scattering settings across setup.cfg, tox.ini, and requirements.txt. Codex reads config files as part of its context-gathering, and one canonical file is easier for it to parse correctly than five overlapping ones.

A minimal pyproject.toml block that gives Codex enough signal to run checks on its own:

[tool.pytest.ini_options] addopts = "-q" testpaths = ["tests"]

[tool.ruff] line-length = 100

[tool.mypy] python_version = "3.12" strict = true

With this in place, Codex can run pytest, ruff check ., and mypy src without you telling it the exact invocation every time.

Writing an AGENTS.md for a Python Repo

The single highest-leverage file for a codex python workflow is AGENTS.md at the repo root. Codex reads it automatically at the start of a session, the same way a human contributor would read a CONTRIBUTING guide. Keep it short and concrete:

# AGENTS.md

## Setup - Python 3.12, managed with venv. - Install: pip install -e ".[dev]" - Activate: source .venv/bin/activate

## Testing - Run the full suite: pytest -q - Run a single file: pytest -q tests/test_parser.py - Do not skip failing tests to make the suite pass; fix the code or the test.

## Style - Format and lint with ruff check . --fix and ruff format . - Type-check with mypy src - Functions over classes unless state needs to be held. - No bare except:; catch specific exceptions.

## Commit hygiene - One logical change per commit. - Run pytest -q and mypy src before proposing a diff as done.

This file does two things. It shortcuts the exploration Codex would otherwise do by trial and error (finding the right test command, the right lint command), and it encodes house style so you stop re-explaining the same preferences in every session. If your repo has subprojects with different conventions, you can nest additional AGENTS.md files in subdirectories; Codex merges the closest one with the root.

A Day-to-Day Codex Python Workflow

A workflow that holds up on real projects looks like this:

  1. Open a fresh branch before starting a session, so Codex's changes are isolated and reviewable as a diff.
  2. Give Codex a specific, scoped task, not "improve the codebase." For example: "the parse_csv function in src/parser.py doesn't handle quoted commas correctly, fix it and add a regression test."
  3. Let Codex run in on-failure approval mode so it can install, test, and iterate without pinging you for every shell command.
  4. Review the diff yourself with git diff before merging. Codex is good, not infallible, and Python's dynamic typing means subtle behavior changes won't always show up as a red test.
  5. Ask Codex to run the full suite and the linter as a final step, not just the test file it touched, since a fix in one module can quietly break an import elsewhere.

In the CLI, a scoped task looks like:

codex exec "the parse_csv function in src/parser.py doesn't handle \ quoted commas correctly. Reproduce the bug with a failing test in \ tests/test_parser.py, then fix the function so the test passes. \ Run the full test suite before finishing."

Note the shape of that prompt: reproduce first, then fix, then verify against the whole suite. That order matters more for codex python sessions than for smaller scripting languages, because Python's import system and mutable defaults create bugs that only show up several call sites away from the change.

Test-Driven Development with Codex

Codex handles TDD-shaped instructions unusually well because it can execute the loop itself instead of you eyeballing pass/fail. A reliable pattern:

codex exec "write a failing pytest test for the requirement below, \ confirm it fails, then implement the minimum code to make it pass, \ then run the full suite: \ Requirement: retry() should retry a callable up to n times with \ exponential backoff, and raise the last exception if all attempts fail."

This works because Codex can genuinely run pytest, read the failure output, and act on it, rather than guessing what a test result would look like. For anything involving timing or concurrency, be explicit about how you want it tested. Python's time.sleep in a retry loop will make your test suite slow if Codex doesn't think to mock it, so say so directly:

codex exec "same as above, but mock time.sleep in the test so the \ suite doesn't actually wait for the backoff delays."

For a bug fix rather than a new feature, invert the order and ask Codex to reproduce first:

codex exec "there's a bug where get_user() returns None instead of \ raising UserNotFoundError when the id doesn't exist. Write a test \ that reproduces this, confirm it fails against current code, then fix it."

This "reproduce, then fix" discipline is worth enforcing even when you're in a hurry, because it's the difference between Codex fixing the actual bug and Codex fixing the symptom it happened to notice first.

Handling Virtual Environments and Dependencies

Codex runs shell commands inside whatever environment is active in the working directory, so activate your venv before starting a session if you want Codex operating inside it consistently:

source .venv/bin/activate codex

If you use uv instead of plain venv and pip, tell Codex explicitly in AGENTS.md, since it will otherwise default to pip:

## Setup - Dependency manager: uv - Install: uv sync - Run tests: uv run pytest -q

For dependency changes, be specific about the constraint file you want touched. "Add httpx as a dependency" is ambiguous if you have both pyproject.toml and a lockfile; say "add httpx to pyproject.toml under [project.dependencies] and update uv.lock."

One recurring rough edge in codex python sessions is Codex installing a package globally instead of into the project's environment, especially when the sandbox blocks network access mid-task and it falls back to a system Python. Avoid this by pre-resolving dependencies before the session (uv sync or pip install -e ".[dev]") so Codex rarely needs to hit the network at all.

Running Codex in CI for Python

Beyond interactive use, codex exec is scriptable, which makes it usable for automated tasks like dependency bumps or applying a lint fix across a repo. A simple CI-triggered job:

codex exec --full-auto "run ruff check . --fix and ruff format ., \ then run mypy src and pytest -q. If everything passes, stop. \ If something fails and the fix is a one-line type annotation or \ import, fix it and re-run. Otherwise leave the failure for a human."

--full-auto combines sandboxed writes with automatic approval, which is appropriate in a CI container that's already isolated but risky on your laptop. Scope what you let it touch: point it at a lint-and-typecheck pass rather than "fix all failing tests," since the latter can produce a large diff with no human in the loop to sanity-check it.

For a scheduled job (say, a weekly pass that clears ruff warnings introduced since the last release), pipe the result into a pull request rather than pushing straight to main:

git checkout -b codex/weekly-lint codex exec --full-auto "fix all ruff warnings in the repo without changing behavior" git add -A git commit -m "chore: clear ruff warnings" git push origin codex/weekly-lint gh pr create --title "chore: weekly lint pass" --fill

This keeps Codex's autonomous runs behind a review gate, which matters more for Python than for, say, a statically typed language, since Python's type checker can't catch every behavior change a "harmless" refactor might introduce.

Debugging with Codex

When a Python traceback shows up, paste it into Codex along with the command that produced it rather than describing the bug in your own words. Codex is more accurate reasoning from the actual stack trace than from a paraphrase:

codex exec "this command fails: pytest tests/test_orders.py -k refund. \ Here is the traceback: <paste>. Find the root cause and fix it, \ then confirm the specific test passes and the full suite still passes."

For flaky or intermittent failures, ask Codex to run the test multiple times before concluding it's fixed, since a single green run doesn't rule out a race condition:

codex exec "run pytest tests/test_worker.py -k concurrent 20 times \ in a loop and report the failure rate before and after your fix."

This is a case where Codex having real shell access pays off: it can actually loop the command itself instead of you doing it by hand.

Common Pitfalls

A few things trip up teams new to a codex python workflow:

  • No AGENTS.md, so every session re-derives project conventions. Write it once, keep it under a page, update it when conventions change.
  • Approval mode set to full trust from day one. Start with on-request on a repo you don't know well, watch what Codex proposes, then loosen.
  • Vague tasks. "Clean up the codebase" produces a large, hard-to-review diff. "Remove the unused legacy_parser module and its imports" produces a five-minute review.
  • Skipping the full suite. Asking Codex to verify only the file it touched misses cross-module breakage that's common in Python because of dynamic imports and monkeypatching in tests.
  • Committing generated code without reading the diff. Codex is a strong first pass, not a substitute for review, especially around exception handling and edge cases that don't show up in the existing test data.

FAQ

Does Codex need a Python virtual environment to work correctly? It doesn't strictly require one, but you should activate a venv before starting a session so Codex installs and runs code against the same interpreter and dependency set you use yourself. Without it, Codex may fall back to a system Python and produce results that don't match your project's environment.

Can Codex run and fix failing pytest tests on its own? Yes. Point it at the failing test or let it discover the failure by running pytest -q, and it will read the traceback, propose a fix, and re-run the suite to confirm. Give it explicit permission to iterate ("run the full suite before finishing") so it doesn't stop after a partial pass.

Is AGENTS.md required for codex python projects? Not required, but it removes most of the guesswork Codex would otherwise redo every session: which test command to run, which linter, which style rules. A short AGENTS.md pays for itself after two or three sessions.

How is Codex different from asking a chat model to write Python in a browser tab? Codex operates with real terminal access inside your repo: it can install dependencies, execute your actual test suite, read the real output, and iterate, rather than you copying code back and forth. That closed loop is what makes it useful for anything beyond a single function.

Should I let Codex run in full-auto mode on my main branch? No. Use a feature branch for any Codex session, and reserve --full-auto for CI containers or narrowly scoped, low-risk tasks like lint fixes. Review the diff before merging, the same as you would for a human contributor's pull request.

Does Codex work with uv, Poetry, or Pipenv instead of plain pip and venv? Yes, but tell it which one you use in AGENTS.md, including the exact install and test-run commands. Without that guidance Codex will default to pip and venv conventions, which can create a mismatched lockfile if your project actually uses uv or Poetry.

Can I use Codex for Python dependency upgrades? Yes, this is one of the more reliable automated uses: scope the task to a single package or a lockfile refresh, run it on a branch, and have Codex verify the full test suite and linter pass before opening a pull request. Avoid asking it to bump every dependency in one pass, since a mixed-package failure is harder to bisect than a single-package one.