Four Daily Workflows: Exploring, Debugging, Refactoring, and Testing
📚 Series Navigation: The previous article 13 · How to Write Prompts taught you "how to speak clearly"—splitting vague requirements into precise instructions Codex understands. This article translates that into practice: 80% of daily coding tasks fall into four categories, and I will provide a copy-pasteable workflow for each. Just fill in the blanks. The next article is 15 · Permissions, Sandboxes, and Approvals.
Let's start with a conversation. Last week, a colleague who just switched to Codex asked me in the chat group:
"I asked it to fix a bug. It cleared the error, and I committed the change. But the same error popped up again the next day. What happened?"
I asked: "Did you ask it to find the root cause first? Did you write regression tests?"
Him: "...Wait, isn't fixing a bug just making the error go away?"
That's the issue. He mistook "error cleared" for "problem solved," without locking down the bug. In fact, exploring, debugging, refactoring, and writing tests each have their own playbooks. Get them right, and Codex runs quickly and safely; get them wrong, and it leaves hidden landmines while appearing to succeed.
The previous article covered general "prompting guidelines"; this article applies them to the four most common daily coding tasks. Having used Codex for nearly half a year, these four workflows are what I rely on, designed to align with Codex's specific behaviors—it reads active files in the IDE, but requires you to reference them in the CLI; it performs best when it can verify its own work, so you must provide verification steps.
After reading this article, you will get:
- A copy-pasteable workflow for each of the four common tasks (exploring / debugging / refactoring / testing), including variations between IDE and CLI environments
- The rationale behind "why we play it this way" for each task type, rather than static templates
- A quick lookup summary table for the four workflows, with subclass tables at the end of each section consolidated into a final checklist
- A complete hands-on exercise fixing a real bug following the step-by-step debugging workflow
⚠️ All specific commands, slash commands, and default behaviors mentioned below are based on the Codex official documentation; model names and interface layouts are subject to change and should match what is actually displayed on your local system.
01 Understand First: Four Tasks, Four Tools
Before we begin, understand the characteristics of each task. They place completely different requirements on Codex, and using the wrong approach yields poor results.
Analogy: Choosing the right knife in the kitchen. A filleting knife is for fish, and a cleaver is for ribs; using a filleting knife to chop bones will break the blade. Exploring, debugging, refactoring, and writing tests are different knives—it is not about "knowing how to use Codex," but "choosing the right knife for the job."
The fundamental difference lies in one question: does the task edit your code?
| Task | Modifies Code? | What Codex Does | What You Should Monitor |
|---|---|---|---|
| Exploring Codebases | No (read-only) | Reads files, explains layouts | Is its explanation accurate? |
| Debugging Bugs | Yes | Replicates + locates cause + fixes | Is the root cause correct? Are there regression tests? |
| Refactoring | Yes (behavior remains same) | Rewrites equivalent code | Did the external behavior change? |
| Writing Tests | Yes (adds files) | Generates tests + covers edges | Are edge cases fully covered? |
See the difference? Exploring is zero-risk (it only reads), so you can prompt freely; debugging and refactoring edit code, so you must let it explain the changes before executing them; writing tests is in the middle, as it creates new files without touching existing code, but you must monitor that it doesn't cheat by testing only the happy path.
A general rule of thumb from the prompting guide applies to all four:
Codex performs significantly better when it can verify its own work. Include reproduction steps, verification commands, and lint or pre-commit checks.
This is the foundation of these workflows. The following four sections address one question—how to leave a validation loop for Codex in each task.
💡 Summary in one sentence: Classify the four tasks by whether they modify code—exploring is zero-risk and read-only, but code-editing tasks require planning before execution; always provide validation loops for Codex.

This diagram compares the four workflows side-by-side, displaying whether they edit code, their core approach, and what you should monitor. The next four sections explain each in detail.
02 Exploring Legacy Codebases: Three Levels of Prompting
Let's start with the most common scenario: you take over an unfamiliar codebase and need to understand it.
How did you do this in the past? You opened the folders, stared at dozens of directories, clicked through files, and spent hours getting a vague idea. Now, you don't have to—Codex treats your folder as its workspace, reads the code, and answers your questions.
Analogy: Navigating an unfamiliar mall—check the map first, find the store, and follow the path. You don't search random racks; you check the directory to see what is on each floor (architecture), find where the baby products are (module), and follow the path to the store (tracing flows). From large to small, from surface to path—this is the standard exploring flow.
Here is a critical detail regarding how you provide context—the IDE extension and the CLI retrieve context differently, and Claude Code differs here too: Claude Code's CLI automatically reads the workspace context, whereas Codex CLI does not—it requires you to reference files explicitly with @ to make them visible.
The IDE extension automatically includes your active files and selected code block in the context; in the Codex CLI, you must reference file paths explicitly with @filename (or use /mention to attach a file).
Simply put—when exploring in the IDE, open the target files and select the code block before prompting; when exploring in the CLI, reference them with @filename. This is a key difference emphasized in the docs; otherwise, the files remain invisible to Codex.
Exploring in the IDE (Fastest for local exploration)
Open the relevant files, select the code block you want to inspect (optional but recommended), and prompt:
Explain how requests flow through this selected code block.
Include:
- A brief summary of what each module is responsible for
- What data is validated and where
- One or two pitfalls to watch out for when modifying this blockFollow up to get a verifiable summary:
Summarize this request flow as a numbered list of steps, and list the files involved.Exploring in the CLI (For scrollable logs and shell access)
Launch the TUI session:
codexReference target files with @ and prompt (this is the key difference from the IDE—you must specify files; it won't read them automatically):
I want to understand the protocol used by this service. Read @foo.ts and @schema.ts,
and explain the data schemas and request/response flow. Highlight which fields are required,
which are optional, and what backward compatibility rules apply.Here is a safe practice I follow for new projects: lock down permissions to read-only during exploration. As covered in Article 12, run /permissions to switch to Read Only—ensuring it reads and explains without modifying files. Exploration should be zero-risk; closing this gate keeps things safe.
I took over a Go project with 30,000 lines of code last year and followed this approach: first, launched the CLI, referenced the entry files, and asked "overall architecture and modules" to map the services; next, located specific modules ("which files handle X"); and finally, traced flows ("summarize this request flow as a numbered list"). It took half a day, compared to two or three days in the past.
Here is the exploring playbook for both IDE and CLI:
| Step | IDE Extension | CLI |
|---|---|---|
| 1. Context | Open relevant files, select target code block | Reference files with @filename or attach with /mention |
| 2. Architecture | "Summarize overall architecture and module responsibilities" | Same, referencing target files |
| 3. Modules | "Which files handle [module/feature]" | Same |
| 4. Tracing | "Trace the request path for [flow]" | Same |
| 5. Verification | "Summarize as numbered steps + file list" | Same |
| Safety | Avoid code edits | Switch to Read Only to restrict modifications |
💡 Summary in one sentence: Explore from architecture to files to paths—three levels of prompting from large to small; remember that the IDE reads active files automatically, while the CLI requires referencing with
@, and keeping permissions read-only is safest.
03 Debugging Bugs: Replicate → Find Root Cause → Edit → Verify
Debugging is another high-frequency task, and the easiest to get wrong—which is the trap my colleague fell into.
Why does it fail? Beginners often paste an error, write "fix this," and accept a patch that makes the error disappear. However, "error cleared" is not "problem solved"—often, it simply hides the symptom, leaving the root cause to fail under different conditions.
Analogy: If a pipe leaks, you don't just put a bucket under it. Mopping up the water (making the error go away) is a temporary fix—you must trace the water to find the cracked pipe (locating the cause), replace that section, and run water to confirm it doesn't leak (verification). Debugging works the same way—find the leak first, don't just mop the floor.
The official Codex debugging playbook highlights providing a reproduction recipe rather than a high-level description. The docs note:
The reproduction steps and constraints you provide are significantly more important than a high-level description. Codex contributes command outputs, call sites, and stack traces.
Therefore, the debugging workflow consists of four steps:
- Provide Recipe & Suspicious Files: Paste the full stack trace, explain "what actions triggered it," and reference suspicious files.
- Replicate & Find Root Cause: Ask it to "replicate this bug locally first"—replicating the issue ensures its analysis of the root cause is accurate, preventing guesswork.
- Apply Fix: Once the cause is confirmed, let it apply the fix, instructing it to "keep edits minimal."
- Verify: Codex should run the replication steps again after editing; if validation scripts exist, instruct it to "run lint + relevant tests, and report the commands and results."
The fourth step is the most omitted, yet the most valuable. The official verification prompt:
Once fixed, run lint + the minimal relevant test suite. Report the commands you ran and the results.This locks down the bug—once the fix passes tests, any regression will trigger test alerts. My colleague's bug resurfaced because he didn't write regression tests to protect the fix.
Debugging in the IDE
Open the target file and its calling files (the IDE reads them as context), and prompt:
Find the bug causing \"save displays success but does not persist changes.\"
Propose a fix, and explain how to verify it in the UI.Debugging in the CLI
Launch Codex in the project root, and provide a replication recipe. Fill in this official blueprint skeleton:
codexBug: Clicking \"save\" in settings displays \"saved\" but changes do not persist.
Replication:
1) Launch app: npm run dev
2) Navigate to /settings
3) Toggle \"enable notifications\" switch
4) Click save
5) Refresh page: switch returns to original state
Constraints:
- Do not modify API schemas.
- Keep the fix minimal, and write a regression test if possible.
Replicate the bug locally first, propose a patch, and run checks.Notice the details—it lists the replication steps in order, sets constraints (don't touch APIs), and requires "replicating first." This applies the rule: "reproduction steps are more important than descriptions."
Here is the debugging playbook skeleton:
Bug: [describe symptoms]
Replication: [numbered list of steps, from startup to trigger]
Constraints: [what to preserve, edit size limits]
Suspicious Files: [reference suspicious files with @]
Instruction: Replicate first → locate root cause (do not edit yet) → apply minimal fix → run lint & tests to verify.💡 Summary in one sentence: Debug in four steps—provide replication recipes, replicate first to find causes, apply minimal fixes, and run lint & tests to verify; replication recipes are much more valuable than descriptions, and regression tests prevent bugs from returning.
04 Refactoring: Plan → Edit in Steps → Preserving Behavior → Test Before & After
Refactoring carries the highest risk because it modifies working code.
Debugging has a clear definition of success—the error is cleared and tests pass. Refactoring does not; its goal is "cleaner code, while preserving external behavior completely." If external behavior changes, you have introduced a bug under the guise of refactoring—the worst kind, as developers rarely test code they assumed was "just cleaned up."
Analogy: Replacing parts on a moving train without stopping or disturbing passengers. The train must keep running, and passengers shouldn't notice that a component is being replaced under the hood. Refactoring is this "maintenance in motion"—the external service (passenger experience) must remain identical.
Refactoring fails for two reasons: rewriting everything at once (making it impossible to verify edits step-by-step), and lacking test coverage (relying on manual inspection to verify behavior). Codex's playbook addresses both—plan first, and execute in steps.
Step 1: Draft a Refactoring Plan
The docs recommend: ask Codex to draft a plan before editing code. If you have the $plan skill enabled, invoke it (skills are called with $, which is different from the /plan slash command). The plan skill is a system-level skill and works out of the box; if it is missing, simply ask it to "draft a plan first; do not modify code yet."
The official planning prompt (notice how goals and constraints are locked down):
$plan
We want to refactor the auth subsystem. Goals:
- Separate responsibilities (token parsing / session loading / permission checks)
- Reduce circular dependencies
- Improve testability
Constraints:
- External behavior must remain unchanged.
- Public APIs must remain stable.
- Provide a step-by-step migration plan.Do not accept the first draft blindly; refine the plan with the agent—this step determines the success of the refactor:
Modify the plan:
- Specify which files are edited in each milestone.
- Add a rollback strategy.Why refine the plan? Because of the core rule—"Codex performs significantly better when you split complex tasks into smaller, focused steps, making them easier to test and review." A plan detailing files and rollbacks splits a major refactor into verifiable steps.
Step 2: Edit in Steps, Testing Each Step
Execute the plan milestone by milestone, running tests after each edit to confirm behavior remains unchanged. Follow this rule:
Never let Codex refactor code that lacks test coverage. If you ask it to refactor a utility function without tests, it might "optimize" an edge case branch it assumed was dead code, only to break production on rare inputs.
If the code lacks tests, the first step is writing tests to cover the active behavior—taking a snapshot of the active behavior to verify the refactored code against, proceeding only if the tests pass. This matches the debugging logic: provide validation loops for Codex, otherwise it relies on "looking done," which hides regressions.
I fell into this trap: I asked Codex to refactor an untested currency formatting function, and it removed a negative balance branch. It worked locally but broke production reporting. Since then, my rule is: if it lacks tests, write tests first, then refactor. No exceptions. It is slower but safe.
Here is the refactoring playbook:
| Step | Action | Key Instructions |
|---|---|---|
| 1. Plan | Ask it (or $plan) to draft a plan | Lock down goals + constraints: behavior unchanged, APIs stable |
| 2. Refine | Refine details: "files modified per step + rollback" | Split into verifiable milestones |
| 3. Protect | Write tests to cover active behavior if missing | Create a snapshot of active behavior |
| 4. Execute | Edit milestone by milestone | Avoid rewriting everything at once |
| 5. Test | Run tests after every step; behavior must match | Stop and roll back immediately if tests fail |
Large-scale refactorings can use an advanced play: refine the plan locally, and delegate the execution to the cloud to run in parallel. This matches the cloud workflows in 10 · Cloud Codex—managing planning and checks locally, and running long tasks in the cloud.
💡 Summary in one sentence: The core of refactoring is "preserving external behavior"—draft a plan first, refine files edited per step, edit in steps, and test before and after. Writing tests first and avoiding wholesale rewrites are key.
05 Writing Tests: Forcing Edge Case Coverage
The final category: writing tests for your code.
Codex is effective at writing tests—the guidelines advise letting it "follow conventions in existing tests," meaning it will scan your test folders and match the testing frameworks, assertion styles, and configurations you use without instruction. But you must watch out for one trap: if you do not instruct it, it defaults to testing only the happy path (happy path, the main success flow).
What does happy path testing look like? For a list-reversal function, it tests "reversing [1,2,3] yields [3,2,1]"—which is correct, but what about empty lists? Single-element lists? Null inputs? These edge cases (edge case, extreme or invalid inputs) are where bugs occur, and what tests must cover.
Analogy: Crash-testing a new car—you don't just drive it slowly on a straight road. You crash it into walls, slam the brakes, roll it over, and rear-end it—testing "extreme conditions." Bugs happen at the boundaries, not on normal roads. The core of writing tests is forcing Codex to cover these boundaries.
The guidelines for both environments emphasize the same rule: cover both happy paths and edge cases.
Testing in the IDE (Using selections)
Open the target file, select the function definition lines, run "Add to Codex Thread" in the command panel to add them to the context, and prompt:
Write unit tests for this function. Follow conventions in existing tests.Using "Add to Codex Thread" is an IDE-specific action—it feeds the exact selected lines to Codex, which is much more precise than describing the function.
Testing in the CLI (Referencing functions and files)
Launch Codex, reference the file with @, name the function, and explicitly require edge case coverage:
codexWrite tests for invert_list in @transform.ts.
Cover both the happy path and edge cases.The critical phrase here is "and edge cases"—omit it, and it will likely test only the success path. Compare the prompts:
| ❌ Vague Prompt | ✅ Clear Prompt |
|---|---|
| "Write tests for this function" | "Write tests for invert_list in @transform.ts. Cover the happy path, and focus on edge cases like empty lists, single elements, null inputs, and large lists." |
| Tests only the success path; coverage looks artificially high | Covers actual potential failure points |
Add an extra instruction to catch missing cases:
Also identify any edge cases I missed, and write tests for them.I include this when writing tests, and it regularly catches input combinations I missed—for a date range function, it added "daylight saving changes" and "start/end on the same day" tests, which I had forgotten to document.
Here is the testing playbook for both environments:
| Step | IDE Extension | CLI |
|---|---|---|
| 1. Target | Select function lines → "Add to Codex Thread" | Reference file with @filename and name function |
| 2. Style | "Follow conventions in existing tests" | Same |
| 3. Edges | "Cover happy path + edge cases: [list cases]" | Same |
| 4. Catch | "Identify and test missing edge cases" | Same |
| 5. Run | Run tests, and fix failures until they pass | Same |
💡 Summary in one sentence: Do not just ask for "tests"—explicitly force Codex to cover edge cases (empty values, single elements, nulls, limits); the phrase "and edge cases" is critical, and let it catch cases you missed.
06 Hands-on: Debugging a Real Bug Step-by-Step
Let's run a practice run using the "debugging" workflow—it uses all four steps, and mastering it makes the other three workflows straightforward. Here is a bug to fix.
Platform Note: The
mkdirandcdcommands work on Mac / Linux; on Windows PowerShell, run them and createcalc.pymanually in File Explorer.
Step 1: Create a playground project with a bug
mkdir bug-demo
cd bug-demoOn Mac / Linux, write the file using echo:
echo 'def average(numbers):
return sum(numbers) / len(numbers)' > calc.pyOn Windows, create calc.py manually and paste these lines:
def average(numbers):
return sum(numbers) / len(numbers)This average function calculates averages—but crashes with a division-by-zero error if an empty list is passed. This is the bug we will fix.
Expected behavior: calc.py appears in bug-demo, containing the average function lines.
Step 2: Start Codex in the directory
codexExpected behavior: The Codex TUI launches, displaying the input box.
Step 3: Apply the debugging workflow, providing a replication recipe
Type in the input box (this applies the Section 03 playbook structure, detailing replication steps, constraints, and replication instructions):
Bug: Calling average([]) in calc.py crashes.
Replication:
1) Pass an empty list [] to the average function
2) It triggers ZeroDivisionError: division by zero
Constraints:
- Keep the fix minimal, and do not modify the function signature.
Instruction: Replicate this bug locally first, locate the cause (do not edit yet), apply a minimal fix,
and write a regression test to verify it passes.Expected behavior: Codex replicates the bug and explains the root cause—len(numbers) is 0 for empty lists, causing a division-by-zero crash; next, it proposes a diff patch (like returning 0 on empty lists or raising an exception) and pauses for approval; once approved, it creates a test file (like test_calc.py) with a test case for empty lists.
Whether it pauses for approval depends on your approval settings (Auto mode may apply edits directly in the workspace). This sandbox + approval logic is the focus of Article 15; here, follow the default settings.
Step 4: Approve edits, and monitor verification
Review the diff, and select "Yes." Codex runs the tests it wrote—applying the "verify after editing" rule.
Expected behavior: The terminal displays the test results, resembling:
test_calc.py::test_average_empty_list PASSED
test_calc.py::test_average_normal PASSEDAll tests passing = the bug is fixed and protected—any future regressions will trigger test alerts.
Step 5: Exit and verify modifications
Exit Codex (type /exit), and check the file:
cat calc.py(On Windows PowerShell: type calc.py)
Expected behavior: calc.py contains the empty list check (like if not numbers: return 0). The file matches your approved diff = debugging loop verified. Success!
- If Codex didn't write tests in Step 3, check if you omitted "write a regression test" from the prompt. Do not skip this validation step.
💡 Summary in one sentence: Run through a complete debugging loop—create a bug, write a replication recipe, let it replicate and fix, and watch it verify changes with tests; mastering this makes the other workflows straightforward.
07 Summary
This article broke down 80% of daily coding tasks into four workflows:
| Task | Core Flow | Key Guidelines |
|---|---|---|
| Exploring Codebases | Architecture → Module locations → Tracing request paths | IDE reads active files, CLI requires @ references; keep permissions read-only |
| Debugging Bugs | Replication recipe → Replicate first → Minimal fix → Verify | Recipes are more valuable than descriptions; do not omit verification |
| Refactoring | Draft plan → Refine steps → Protect with tests → Edit in steps | Behavior must remain unchanged; write tests first, and avoid wholesale rewrites |
| Writing Tests | Happy paths + edge cases + catch missing cases | "Edge cases" is the critical phrase; do not test only the success path |
All four workflows share the same rule: provide a validation loop for Codex—exploring requires step summaries, debugging requires replication tests, refactoring requires testing against snapshots, and testing requires covering edge cases. Providing verification steps ensures Codex does not rely on "appearing to work" to stop.
You should now be able to handle these common tasks using their respective playbooks—knowing what to instruct Codex to do first, what details to monitor, and how the workflows vary between IDE and CLI environments. These workflows are the scaffolding for your daily work; complex tasks are simply combinations of these four blocks.
The next article 15 · Permissions, Sandboxes, and Approvals: this article mentioned "pausing for approval" and "restricting permissions to read-only," but didn't explain the underlying mechanics. How does Codex determine when to prompt you? How does the sandbox restrict its access? The next article covers permissions, sandboxes, and approvals, helping you manage how much access Codex has and when it prompts you. Think about this: debugging paused to ask for approval before writing files; if you want to allow it to edit files inside the workspace automatically but prompt you for changes outside, what setting should you use?