Codex CLI Python Tutorial (2026) — AI-Powered Python Development Workflow

Python and AI coding assistants are a natural fit — mature ecosystem, expressive type system, rich testing tooling. Codex CLI understands Python deeply. With the right AGENTS.md configuration it auto-generates pytest suites, fixes mypy errors, and writes complete Django REST APIs — all from natural-language instructions.

This guide covers the complete workflow from project initialization to CI/CD automation, with ready-to-use prompt templates for Django, FastAPI, and the broader Python ecosystem.

1. Project Setup & AGENTS.md Configuration

Configuring AGENTS.md for your Python project is the single most impactful first step. A well-crafted AGENTS.md tells Codex your project structure, tech stack, code standards, and safety boundaries — resulting in more accurate, idiomatic code generation that fits seamlessly into your existing codebase.

Here is a complete AGENTS.md example suited for a FastAPI + Poetry project:

# Python Project — AGENTS.md

## Project Info
- Python version: 3.12
- Dependency manager: Poetry (pyproject.toml)
- Test framework: pytest + pytest-cov
- Code style: Black + isort + ruff
- Type checking: mypy (strict mode)
- Web framework: FastAPI 0.111

## Code Standards
- All functions and methods must have type annotations (including return types)
- Docstrings follow Google style
- Single function max 50 lines; split if exceeded
- Use Pydantic v2 for data validation

## Allowed Commands
- pytest, pytest-cov
- mypy, ruff, black, isort
- poetry add/remove/install
- alembic upgrade/downgrade

## Prohibited Actions
- Do NOT delete migrations/ (only add new ones)
- Do NOT modify .env (secrets managed by pydantic-settings)
- Do NOT reduce test coverage (currently > 85%)
Tip: Place AGENTS.md in the project root. For monorepos, add independent AGENTS.md files in subdirectories — Codex merges parent and child directory configs, letting each sub-project maintain its own rules while inheriting shared constraints.

Why AGENTS.md matters for Python projects

2. Auto-Generate pytest Tests

Test generation is one of Codex CLI's most powerful capabilities in the Python ecosystem. Codex analyzes your business logic, understands function signatures and intended behavior, and produces complete test suites covering happy paths, edge cases, and exception scenarios — reducing the time you spend on boilerplate test scaffolding.

Example 1: Generate Unit Tests

$ codex "Generate a complete pytest test file for the UserService class in app/services/user_service.py.
Requirements:
- Use pytest fixtures and factory_boy for test data
- Isolate database calls with unittest.mock.patch
- At least 3 tests per method: happy path, edge case, exception scenario
- Save test file to tests/services/test_user_service.py"

Example 2: Improve Test Coverage

$ codex "Run pytest --cov=app --cov-report=term-missing, identify modules below 80% coverage,
and write the missing test cases focusing on core business logic paths"

Example 3: Generate Parametrized Tests

$ codex "Generate parametrized tests for the validate_email function in app/utils/validators.py
using @pytest.mark.parametrize, covering valid addresses, invalid formats,
empty strings, Unicode characters, and other boundary inputs"

Example 4: Async Integration Tests for FastAPI

$ codex "Using httpx.AsyncClient, generate async integration tests for the /api/v1/users route
covering GET (pagination), POST (creation with validation errors),
PUT (update), and DELETE (soft delete)"

Example 5: Mock External API Calls

$ codex "Write tests for payment_service.py which calls the Stripe API.
Use pytest-mock's mocker.patch to mock stripe.PaymentIntent.create.
Cover three scenarios: successful payment, insufficient funds, and network timeout"

Example of a generated test file structure (Codex output style):

import pytest
from unittest.mock import patch, MagicMock
from app.services.user_service import UserService
from tests.factories import UserFactory

class TestUserService:
    """Tests for UserService — auto-generated by Codex CLI."""

    @pytest.fixture
    def service(self, db_session):
        return UserService(db=db_session)

    def test_get_user_success(self, service):
        user = UserFactory.create()
        result = service.get_user(user.id)
        assert result.id == user.id

    def test_get_user_not_found(self, service):
        with pytest.raises(UserNotFoundError):
            service.get_user(99999)

    @pytest.mark.parametrize("invalid_id", [0, -1, None])
    def test_get_user_invalid_id(self, service, invalid_id):
        with pytest.raises(ValueError):
            service.get_user(invalid_id)

3. Type Checking & mypy Integration

Python's type system has matured significantly since 3.10. Codex CLI can rapidly fix mypy errors, retrofit type annotations onto legacy code, and generate well-typed Pydantic models from database schemas — all while respecting your mypy configuration flags.

Example 1: Batch-Fix mypy Errors

$ codex "Run mypy app/ --strict, find all type errors, and fix them:
- Do not use Any to bypass checks
- Optional fields must correctly handle None
- Generic types must be fully specified (e.g. List[str] not List)"

Example 2: Add Type Annotations to Legacy Code

$ codex "Add complete Python 3.12 type annotations to app/legacy/data_processor.py:
- Infer types by analyzing actual usage patterns
- Use TypeVar for generic functions
- Use TypedDict or dataclass for complex data structures"

Example 3: Generate Pydantic Models from Database Schema

$ codex "Generate Pydantic v2 models from the PostgreSQL schema in schema.sql, including:
- Database models (SQLModel)
- API request/response models (BaseModel for create, update, and read)
- Field validators (field_validator)"

Example of a generated Pydantic v2 model (Codex output style):

from pydantic import BaseModel, EmailStr, field_validator
from typing import Optional
from datetime import datetime

class UserCreate(BaseModel):
    """Request model for user creation."""
    email: EmailStr
    username: str
    password: str

    @field_validator("password")
    @classmethod
    def validate_password(cls, v: str) -> str:
        if len(v) < 8:
            raise ValueError("Password must be at least 8 characters")
        return v

class UserRead(BaseModel):
    """Response model for user data."""
    id: int
    email: EmailStr
    username: str
    created_at: datetime

    model_config = {"from_attributes": True}

4. Code Style Automation (Black / Ruff / isort)

Codex CLI can enforce style consistency while generating new code, or be used as a dedicated tool to standardize an entire legacy codebase. The key is combining automated tool execution with intelligent analysis of what needs fixing.

Example 1: One-Command Format and Lint Fix

$ codex exec --approval-mode full-auto "Fix all style issues to make CI pass:
1. isort app/ tests/ --profile black
2. black app/ tests/
3. ruff check app/ tests/ --fix
Then run pytest to verify no bugs were introduced"

Example 2: Audit Legacy Codebase for Style Issues

$ codex "Review all Python files in the legacy/ directory for style issues:
1. Find PEP 8 naming violations (camelCase variables/functions)
2. Find overly long functions (> 50 lines)
3. Find public functions missing docstrings
Generate a prioritized Markdown improvement checklist"
Warning: When using --approval-mode full-auto, Codex executes commands without prompting for confirmation. Always operate on a Git branch first and ensure your AGENTS.md allowed_commands explicitly lists the formatting tools you want Codex to run.

5. Django Integration

Django is Python's most battle-tested web framework. Codex CLI fully understands Django's MVT architecture, ORM semantics, and convention-over-configuration philosophy. Use it to generate entire Django components rather than writing repetitive boilerplate by hand.

Example 1: Generate Django Models

$ codex "Create Django models for a blog system:
- Post (title, content, author FK, created_at, status choices, tags M2M)
- Comment (content, author FK, post FK, parent nullable self-ref, created_at)
- Tag (name, slug, usage_count)
Include Meta class, __str__, get_absolute_url, and custom Manager"

Example 2: Generate DRF Serializer + ViewSet

$ codex "Create a complete DRF API for the BlogPost model:
- PostSerializer (nested author and tags)
- PostViewSet (custom permissions: author can edit, everyone can read)
- URL router registered at api/v1/posts/"

Example 3: Generate Django Migration

$ codex "The Post model needs two new fields: view_count (integer, default 0)
and featured_image (ImageField, nullable). Generate the corresponding migration file"

Example 4: Generate Management Command

$ codex "Write a Django management command at management/commands/send_digest.py:
Read new posts from the past 24 hours, send a digest email to subscribed users,
and support a --dry-run flag for safe testing"

Example 5: ORM Performance Optimization

$ codex "Analyze the UserListView in views.py and fix the following query problems:
- N+1 queries (resolve with select_related/prefetch_related)
- Missing pagination
- Missing caching (use Django cache framework for hot data)"

Example of a generated Django Model (Codex output style):

from django.db import models
from django.contrib.auth import get_user_model
from django.urls import reverse

User = get_user_model()

class PostManager(models.Manager):
    def published(self):
        return self.filter(status="published")

class Post(models.Model):
    class Status(models.TextChoices):
        DRAFT = "draft", "Draft"
        PUBLISHED = "published", "Published"

    title = models.CharField(max_length=255)
    content = models.TextField()
    author = models.ForeignKey(User, on_delete=models.CASCADE, related_name="posts")
    tags = models.ManyToManyField("Tag", blank=True)
    status = models.CharField(max_length=20, choices=Status.choices, default=Status.DRAFT)
    created_at = models.DateTimeField(auto_now_add=True)

    objects = PostManager()

    class Meta:
        ordering = ["-created_at"]
        verbose_name = "Post"

    def __str__(self) -> str:
        return self.title

    def get_absolute_url(self) -> str:
        return reverse("posts:detail", kwargs={"pk": self.pk})

6. FastAPI / Modern Python Web Frameworks

FastAPI has become the go-to framework for modern Python APIs thanks to its native async support and first-class Pydantic integration. Codex CLI fully understands FastAPI's dependency injection system, route decorators, and async lifecycle — making it straightforward to generate production-ready endpoint code.

Example 1: Generate User Auth Routes

$ codex "Create FastAPI authentication routes at app/api/v1/auth.py:
- POST /register (email + password, send verification email)
- POST /login (return JWT access/refresh token)
- POST /refresh (exchange refresh token for new access token)
- POST /logout (blacklist refresh token)
Use Pydantic v2, python-jose, passlib[bcrypt]"

Example 2: Dependency Injection System

$ codex "Create FastAPI dependencies:
- get_current_user: validate JWT, return user object or raise 401
- get_db: SQLAlchemy async session with auto commit/rollback
- require_permission(perm: str): RBAC permission check"

Example 3: Celery Async Task System

$ codex "Implement an async task system with Celery + Redis:
- Email sending task (with retry and exponential backoff)
- Image processing task (Pillow compression and WebP conversion)
- Celery Beat scheduled task (clean expired tokens every night at 2am)
Include worker startup config in Dockerfile"

Example of a generated FastAPI dependency (Codex output style):

from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from sqlalchemy.ext.asyncio import AsyncSession
from typing import AsyncGenerator

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

async def get_db() -> AsyncGenerator[AsyncSession, None]:
    """Async database session dependency with auto commit/rollback."""
    async with AsyncSessionLocal() as session:
        try:
            yield session
            await session.commit()
        except Exception:
            await session.rollback()
            raise

async def get_current_user(
    token: str = Depends(oauth2_scheme),
    db: AsyncSession = Depends(get_db),
) -> User:
    """Validate JWT and return the current authenticated user."""
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
    )
    payload = decode_jwt(token)
    if payload is None:
        raise credentials_exception
    user = await db.get(User, payload["sub"])
    if user is None:
        raise credentials_exception
    return user

7. Python CI/CD Automation (GitHub Actions)

Integrating Codex CLI into your GitHub Actions pipeline lets you automatically analyze CI failures, generate missing tests, and produce improvement suggestions during code review — turning your CI pipeline into an intelligent feedback loop.

# .github/workflows/python-ci.yml
name: Python CI

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.11", "3.12"]

    services:
      postgres:
        image: postgres:15
        env:
          POSTGRES_PASSWORD: postgres
        options: >-
          --health-cmd pg_isready
          --health-interval 10s

    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}

      - name: Install Poetry
        run: pip install poetry

      - name: Install dependencies
        run: poetry install --with dev

      - name: Lint (ruff + mypy)
        run: |
          poetry run ruff check app/
          poetry run mypy app/ --strict

      - name: Test with coverage
        env:
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
          DATABASE_URL: postgresql://postgres:postgres@localhost/testdb
        run: |
          poetry run pytest --cov=app --cov-report=xml --cov-fail-under=80

      - name: AI Test Generation (on failure)
        if: failure()
        run: |
          pip install @openai/codex
          codex exec "Analyze failing tests and suggest fixes without modifying production code"
Further reading: For the complete CI/CD setup including multi-stage pipelines, secret management, matrix testing, and automated releases, see the Codex CLI CI/CD Integration Guide.

8. Quick Reference Prompt Table

Copy and adapt these high-frequency Codex prompt templates for common Python development tasks:

Scenario Prompt Template Notes
Generate dataclass "Create a Python dataclass for UserProfile with field validators and __post_init__" Auto-adds validation logic
Refactor exception handling "Replace bare except and generic Exception catches with specific exception types and meaningful error messages" Improves debuggability
Async-ify sync code "Convert synchronous functions in user_service.py to async/await, parallelizing independent calls with asyncio.gather" Performance optimization
Generate Alembic migration "Analyze changes in models.py vs the previous version and generate the corresponding Alembic migration script (with downgrade)" Database migrations
Optimize slow queries "Analyze slow queries from Django Debug Toolbar output and suggest ORM-level optimizations" Performance tuning
Generate Makefile "Generate a Makefile for this Python project with install/test/lint/format/clean/docker-build targets" Developer convenience
Generate conftest.py "Create a pytest conftest.py with async db fixture, user fixture, and API client fixture" Test infrastructure
Add structured logging "Add structured logging to the service layer using structlog, with request ID tracking and performance timing" Observability

9. FAQ

Does Codex CLI support Python projects?

Fully. Codex CLI is language-agnostic and works excellently with Python projects. Configure AGENTS.md to tell Codex your Python version, dependency manager (pip/poetry/conda), and test framework for more accurate, idiomatic code generation that fits naturally into your existing codebase.

How do I make Codex CLI generate PEP 8-compliant Python code?

In AGENTS.md, specify your style requirements: "All Python code follows PEP 8, formatted with Black, type annotations comply with mypy strict mode." Alternatively, add to your prompt: "Add complete type hints and a Google-style docstring to all generated functions." You can also instruct Codex to run black and ruff --fix automatically after generating code.

Can Codex CLI work inside a Python virtual environment?

Yes. Activate your virtual environment (venv, conda, or poetry shell) before running codex. Codex inherits the current shell environment and can execute pip install, pytest, mypy, and other commands. List the commands you want to allow in AGENTS.md's allowed_commands to prevent Codex from accidentally installing untrusted packages.

Can Codex CLI generate Django code?

Yes. Codex generates Django Models, Views, Serializers, URL configurations, Migrations, and management commands with full awareness of Django's conventions. Describe your Django version and project layout in AGENTS.md and Codex will follow Django best practices — including the admin integration, signal patterns, and custom manager conventions you'd expect from an experienced Django developer.

More language guides: ⚡ JavaScript/TypeScript Guide · 🐹 Go Developer Guide · ♻️ Refactoring Guide
← Prompt Examples Tips & Advanced Usage →