Skip to main content
Lesson 5 of 20 · Codex: AI-Assisted Development

Writing Code with Codex

Lesson 5 of 20 Updated July 29, 2026 Developer
On this page
  1. From Idea to Code in One Instruction
  2. Creating a New File or Module
  3. Adding Features to Existing Code
  4. Generating Code from a Specification
  5. Working with Multiple Files
  6. Tips for Optimal Results
  7. Key Takeaways

From Idea to Code in One Instruction

Writing code is the task you’ll assign to Codex most often, and it’s where the difference between Codex and a simple snippet generator becomes most apparent. The agent doesn’t just produce an isolated code fragment that you then have to adapt. Instead, it reads your codebase, infers your conventions, and writes something that fits seamlessly into your existing architecture. Your job, therefore, is less about describing code and more about describing a place within a system.

Creating a New File or Module

When generating entirely new code, precision matters as much for context as it does for the expected functionality.

"Create a service at src/services/notification.service.ts that handles 
sending notifications via email and webhook. Use the same pattern as 
src/services/auth.service.ts. The service must expose sendEmail(to, subject, body) 
and sendWebhook(url, payload)."

Codex reads auth.service.ts to understand the current pattern, analyzes the project’s imports and dependencies, creates the file with the same structure, adds appropriate TypeScript types, and exports the functions according to project conventions. The result looks like this:

// src/services/notification.service.ts
import { z } from "zod";
import { logger } from "@/lib/logger";
import { env } from "@/lib/env";

const emailSchema = z.object({
  to: z.string().email(),
  subject: z.string().min(1),
  body: z.string().min(1),
});

export async function sendEmail(
  to: string, 
  subject: string, 
  body: string
): Promise<void> {
  const validated = emailSchema.parse({ to, subject, body });
  // ... implementation
}

export async function sendWebhook(
  url: string, 
  payload: Record<string, unknown>
): Promise<Response> {
  // ... implementation
}

One detail deserves attention: no one asked for Zod validation. Codex added it because it noticed the project uses Zod everywhere else. This is why referencing a model file pays off—a ten-word phrase saves you an entire paragraph of specification.

Adding Features to Existing Code

Agents deliver the most value on existing code, not because writing the lines is hard, but because respecting everything around them is.

"In src/api/routes/users.ts, add a GET /users/:id/activity endpoint 
that returns the user's last 50 actions. Use the same authentication 
middleware as the other routes."

Codex analyzes neighboring routes, identifies the actual middleware in use, notes the current response format, and then adds the endpoint consistently. This reconnaissance work would take you far longer than the actual coding, and it’s exactly the part people cut corners on when they’re in a hurry.

Generating Code from a Specification

For complex features, step up a level and write a proper specification. Each point becomes a requirement that the agent treats as such.

"Implement a rate limiting system for the API:
- Maximum 100 requests per minute per IP
- Maximum 1000 requests per hour per authenticated user
- Return an X-RateLimit-Remaining header
- Return 429 Too Many Requests when the limit is reached
- Store counters in Redis (already configured in the project)
- Create the middleware in src/middleware/rate-limit.ts"

This specification provides numeric values, the header name, the HTTP status code, available infrastructure, and the file location. Each detail removes an arbitrary decision Codex would otherwise make for you—a decision you’d only discover during code review.

Working with Multiple Files

A single task can legitimately span multiple application layers, provided you list the deliverables.

"Add an in-app notification system:
1. Prisma model Notification (id, userId, type, message, read, createdAt)
2. Service at src/services/notification.service.ts
3. CRUD API routes in src/api/routes/notifications.ts
4. Tests in src/api/routes/notifications.test.ts"

Codex produces all four files coherently: the service relies on the Prisma model, the routes call the service, and the tests cover the routes. Achieving this vertical consistency is difficult if you break the request into four separate tasks, where each step must rediscover what the previous one decided—and sometimes contradict it.

Tips for Optimal Results

First, remember the power of referencing existing code: “like in auth.service.ts” conveys in five words a pattern that would take you a page to describe. Name libraries explicitly—“use Zod for validation” rather than “add validation”—and specify the output format when it matters, such as a uniform { success, data, error } object across your entire API. Mention edge cases that concern you, like “handle the case where the user doesn’t exist”: left to its own devices, the agent handles the happy path and leaves you to discover the rest. Finally, anything you repeat from task to task belongs in AGENTS.md, keeping your instructions short.

Key Takeaways

  • Codex understands your codebase and respects your existing conventions
  • Reference existing files to guide style and patterns
  • Detailed specifications produce more precise results
  • Codex can create and modify multiple files in a single task
  • AGENTS.md complements your instructions with permanent rules