Your first Codex task: a small, testable code change

TechSkill Editorial

TechSkill Blog

October 12, 2026 - 9 min read

Key Takeaways

    Give Codex its first task as one small, measurable change: name the file, current behavior, desired result, and verification method. Ask for an explanation and a brief plan first, then authorize the edit. Finally, read the changed code and the actual test results.

    This guide is for someone starting work on a small project who can read a simple Python function and has Python 3 available. In the teaching example, you will process a list of tags: trim surrounding whitespace, convert letters to lowercase, and remove duplicates while preserving order.

    Tie your first Codex task to one specific behavior

    “Improve the project” leaves the tool to decide what to change. For your first attempt, choose a function whose expected result you can write down beforehand. Here that function is normalize_tags, which processes tags according to agreed rules.

    According to OpenAI's Codex CLI guide (source 1), Codex can inspect files, edit them, and run local commands. Use a separate folder for this exercise and keep important work files out of it.

    Create two files, tags.py and test_tags.py. Run the task in a Codex project or session opened in that folder. This article does not cover installing Codex; it assumes you already have a working environment.

    Define the expected result before changing the code

    Our function receives a list of strings. Its requirements are:

    Condition Expected behavior
    A tag has surrounding whitespace Remove the surrounding whitespace
    Letters are uppercase Apply lower()
    The processed tag is empty Omit it from the result
    A processed value appears again Keep the first occurrence
    Tags are different Preserve first-seen order
    A list item is not a string Raise TypeError

    For example, [' AI ', 'ai', '', 'Codex', 'codex', ' '] must become ['ai', 'codex']. That is one checkable condition for completing the task.

    Compare duplicates after processing. If you compare the original values first, ' AI ' and 'ai' are different items and both will remain.

    Reproduce the problem with a small example

    Put this starting version in tags.py. It is a teaching example created for this guide and intentionally does not satisfy all the requirements above.

    def normalize_tags(tags):
        return sorted(set(tags))
    

    This code removes duplicates from the original values and sorts the list. It does not process whitespace or letter case, and it may change first-seen order.

    Put these five requirement-based tests in test_tags.py:

    import unittest
    from tags import normalize_tags
    
    
    class NormalizeTagsTests(unittest.TestCase):
        def test_normalizes_and_deduplicates(self):
            self.assertEqual(
                normalize_tags([" AI ", "ai", "", "Codex", "codex", "  "]),
                ["ai", "codex"],
            )
    
        def test_preserves_first_seen_order(self):
            self.assertEqual(normalize_tags(["Codex", "AI", "codex"]),
                             ["codex", "ai"])
    
        def test_empty_input(self):
            self.assertEqual(normalize_tags([]), [])
    
        def test_whitespace_only(self):
            self.assertEqual(normalize_tags(["", " ", "\t"]), [])
    
        def test_rejects_non_string(self):
            with self.assertRaises(TypeError):
                normalize_tags(["ai", 7])
    

    From the folder containing both files, run:

    python3 -m unittest -v test_tags
    

    Running the starting code shown in this article produced three failures out of five tests. This is expected: you now have a way to reproduce the problem and specific conditions the change must satisfy.

    unittest is part of Python's standard library, so this example needs no additional package. Check the command format in the official Python instructions (source 2).

    Give Codex the goal, boundaries, and verification command

    To understand the code, first ask: “Read tags.py and explain why it does not satisfy the requirements. Do not change files yet.” Once the explanation is clear, give it a concrete task:

    Goal: make normalize_tags in tags.py process a list of tags
    according to the agreed rules.
    
    First read tags.py, test_tags.py, and the relevant project
    instructions, if an instructions file exists.
    Show a brief plan and wait for my approval before editing.
    
    Behavior:
    - use strip() and lower();
    - remove empty values;
    - compare duplicates after processing;
    - preserve first-seen order;
    - raise TypeError for a non-string item.
    
    Change only tags.py. Do not weaken the existing test requirements.
    Do not add a package. Do not use the network or a database.
    Do not commit, push, or publish without separate approval.
    
    Verification: python3 -m unittest -v test_tags
    At the end, show the changed code, the command you ran,
    its result, and remaining limitations.
    If you could not run verification, state the exact reason.
    

    This template is for the exercise at hand. In a real project, replace the file names, rules, and verification command. OpenAI's prompting guide (source 3) also recommends naming the desired behavior, relevant context, constraints, and verification method for a coding task.

    A restriction written in the task does not change technical access settings. Check file and network boundaries separately in the official permissions guide (source 4). Do not grant more access than the exercise needs.

    Read the change and rerun the tests

    Here is one implementation that satisfies the requirements. After you approve the plan, the contents of tags.py can be replaced with this code:

    def normalize_tags(tags):
        result = []
        seen = set()
        for tag in tags:
            if not isinstance(tag, str):
                raise TypeError("tags must contain only strings")
            value = tag.strip().lower()
            if value and value not in seen:
                seen.add(value)
                result.append(value)
        return result
    

    seen stores values already added, while result preserves their order. A new tag is appended only when it is nonempty after processing and has not appeared before.

    strip() removes surrounding whitespace, and lower() converts cased letters to lowercase. This behavior is described in the Python string documentation (source 5).

    Rerunning the same command passed all five tests. We also checked that the function does not change the input list. That is an additional check; the five tests shown do not test input-list preservation separately.

    Before accepting the change, check:

    • whether only the agreed file changed;
    • whether the function name and input parameter remain intact;
    • whether test requirements were weakened;
    • whether the stated command actually ran;
    • whether an unnecessary package or network action was introduced.

    A passing test checks the conditions written into it. Five tests do not cover every possible input. This example does not define full linguistic equivalence, transliteration, or processing other types of input data.

    If Codex cannot verify the result, clarify the blocker

    If the response says Python is unavailable or a test could not run, do not treat that as proof of execution. Ask the tool to show the command and error; then fix the environment or run the test yourself.

    If the code works but the change is too broad, restate a specific boundary: “Keep only the normalize_tags change; improvements to other files are outside this task.” Do not ask it to blindly undo other people's changes.

    When you move to a complex project, add its other required checks alongside the test. A user-interface change needs an actual run and visual inspection; a single function test cannot confirm page behavior.

    Common questions about your first Codex task

    Can I write my first task in Georgian?

    You can formulate the task in Georgian too. Keep file names, code identifiers, and commands exact. If an explanation is unclear, ask for simpler wording.

    Should I build a whole app for my first attempt?

    If you are still learning to verify code changes, choose a small function. A full app requires more decisions and environment setup. Start a larger project once you can read and check a change.

    Should I publish code automatically when the tests pass?

    The result of this exercise is a local change. In a real project, publication has its own review and approval process; passing tests does not make that decision by itself.

    After your first attempt, think of a different input list and write down the expected result before running the code. Compare your expectation with the result and add a new condition only when needed.

    If your next goal is a product prototype, read the Vibe coding guide for product managers. Apply the same practice of checking a small change to the prototype.

    Full source addresses

    To open a source, copy its full address into your browser.

    1. OpenAI: Codex CLI: https://learn.chatgpt.com/docs/codex/cli
    2. Python: unittest: https://docs.python.org/3/library/unittest.html#command-line-interface
    3. OpenAI: Prompting: https://learn.chatgpt.com/docs/prompting
    4. OpenAI: Permissions: https://learn.chatgpt.com/docs/permission-modes
    5. Python: String methods: https://docs.python.org/3/library/stdtypes.html#str.strip

    Updated: October 12, 2026

    Subscribe to the TechSkill Blog

    Discover where product building is heading next

    Share this post

    By sharing your email, you agree to our Privacy Policy and Terms of Service

    TechSkill

    This content will be available here soon.

    Back to courses