Course · Codex · Skills
Write the description so Codex invokes the Skill at the right moment
The Skill runs when you name it, but the whole point was that you wouldn’t have to - that Codex would notice you’re loading a new bank’s export and run the import procedure on its own. Whether that happens, and whether it happens at the right time, comes down almost entirely to one field: the description. This is the lesson where the six turns you counted two lessons back either become two turns for real, or stay a claim you haven’t tested.
How Codex decides
Section titled “How Codex decides”Codex keeps every Skill’s frontmatter - its name and description - loaded so it always knows what’s on the shelf. The full body of a Skill only loads when the Skill actually fires. So the description does double duty: it’s both the menu Codex reads and the trigger it matches against. When your message looks like the situation a description names, Codex pulls in that Skill’s instructions and follows them. When it doesn’t, the Skill stays closed and costs almost nothing.
That means the description isn’t documentation - it’s the interface. A vague one is the number-one reason a Skill sits there and never fires. To keep the menu from crowding the context window, Codex caps how much room the loaded Skill list can take, so a long-winded description competes for space with every other Skill’s. The mechanics and the limits are on the Codex Skills page; the craft is in what you put in the field.
Name what’s actually happening here: Codex reading a plain description of your situation and matching it, on its own, to a procedure it was never told to run by name. Call that recognition. It’s the one trick this whole chapter is building toward - everything from the frontmatter split to the wording rules below exists to make recognition fire on the situation you meant and stay silent on everything else.
Describe the situation, not the Skill
Section titled “Describe the situation, not the Skill”The instinct is to write a description that says what the Skill is:
description: Imports bank CSV files.True, useless. It names the Skill; it doesn’t name the moment you’d want it. Codex has nothing to match against, because you’d never say “import a bank CSV file” in those words - you’d say “here’s a statement from my new card.” Compare the version from the last lesson, which names the situation and the things you’d actually type:
description: >- Import a new bank or credit-card CSV export into budgetcli when the file's column layout isn't one budgetcli already handles. Use when the user wants to onboard a new bank, add support for a statement export, or import transactions from an unfamiliar CSV shape.The pattern that works: what it does, then when to use it, in the user’s words. That second half - “onboard a new bank… add support for a statement export… an unfamiliar CSV shape” - is a list of the phrasings you actually reach for. Front-load the key use case, because the loaded listing is space-capped and gets truncated if it runs long, so the first sentence has to carry the trigger.
Test that it actually fires
Section titled “Test that it actually fires”A Skill you only ever invoke by name might as well be a saved prompt. So prove recognition works, on the same job you traced by hand in the chapter opening: a new bank, cold. Open budgetcli, point Codex at a sample export from a bank it hasn’t seen, and say the kind of thing you’d really say - without naming the Skill:
> got a statement export from my new credit card in data/newcard.csv. can you get these transactions into budgetcli?
⎿ Using skill: import-bank-csv Read 6 rows of data/newcard.csv date → column "Posted Date" (MM/DD/YYYY) amount → column "Amount" (single signed column) description → column "Description"
Sample mapping (raw → stored): 04/12/2026, "-42.50", "CORNER MARKET" → 2026-04-12 · -4250 cents · "CORNER MARKET" 04/13/2026, "18.00", "REFUND - ACME" → 2026-04-13 · 1800 cents · "REFUND - ACME"
Mapping looks right? I'll write the importer and run the full file.That’s turn one: you described the situation in your own words, Using skill: import-bank-csv fired without you naming it, and step four of the body - convert to integer cents, no floats - already ran on this bank’s amount column before you said a word about money. Confirm, and turn two closes it:
> looks right, go ahead
⏵ Edit .agents/skills/... → write importer, run against sample → approved ⏵ Run pytest tests/test_import_newcard.py • 4 passed
Done. Importer written for the new card format, sample verified, tests passing.Two turns. Count them against the six from the chapter opening: no clarifying question about the column layout, because the body’s first two steps already ask for it before Codex reports back. No thousands-separator slip to catch in review, because step four’s rounding rule is sitting in the window at the exact moment the amount column gets parsed - the same miss that cost you two full turns the long way, gone before it happened. Same bank-shaped job, a third of the cost. That’s the payoff this chapter opened on, and this time it isn’t an estimate - it’s a transcript you can count.
It should feel like the loop got smarter. It didn’t - it just stopped asking you questions the body already answers, and stopped guessing at a rule the body already states. You’re still the one who reads “mapping looks right?” and says go ahead. Recognition removed the re-narration. It didn’t remove you from the review.
The opposite failure: firing too often
Section titled “The opposite failure: firing too often”A description tuned too broad has the reverse problem - the Skill fires when you didn’t want it. Imagine you’d written “use whenever working with a CSV.” Now Codex tries to run the full import procedure the moment you so much as open a CSV to glance at it, even when you only wanted to read a couple of rows. The cure is to make the description narrower and more specific - pin it to the genuine onboarding moment (“a new bank,” “a layout budgetcli doesn’t already handle”) rather than any mention of CSVs.
If a Skill you expect to fire doesn’t, the fix is almost always the same field, from the other direction: the description is missing the words you actually used. Add the phrasing you’d really type and try again.
You can also invoke a Skill on purpose - by referencing it by name in your prompt, or from the /skills picker in the TUI - which is the fallback when you want the procedure right now regardless of how you phrased the ask.
Taking a Skill off the automatic menu
Section titled “Taking a Skill off the automatic menu”Some procedures you never want Codex deciding to run on its own - anything expensive, slow, or state-changing where a mistimed trigger is costly. Codex gives each Skill an optional companion config file, agents/openai.yaml, inside the Skill directory, for exactly this kind of Codex-specific control. Treat the filename and the field names as version-sensitive, the same way you treat hook payloads: check the docs before you depend on either. Among other things it carries an invocation-policy switch - set implicit invocation off and the Skill drops off the agent’s automatic menu while staying available when you name it explicitly. That turns the Skill from “fires on recognition” back into “fires only when you ask” - the line between a Skill the agent reaches for and one you keep on a leash.
Our import-bank-csv doesn’t need that - it ends in a preview and waits for your “looks right” before the full import, so a mistimed trigger costs nothing but a glance. But it’s the knob to know about, and the exact field is on the Codex Skills page. The agents/openai.yaml file is also where a Skill declares dependencies on tools it needs, which is one of the threads the next chapter picks up.
Look at what just moved, on all four questions this course keeps asking. Tokens: the Skill’s stub cost about 80 every session, the body about 280 more only in the two sessions above that actually needed it - against six turns’ worth of re-explaining, re-asking, and re-correcting the long way. Turns: six down to two. Blast radius: unchanged - you still approve the write and read the mapping before it runs. Recurrence: this is the one that changed the most. The procedure now holds every time a new bank shows up, not just the time you happened to remember every step.
Keeping a Skill scoped to the right moment is half the discipline. The other half is knowing when a Skill is the wrong container entirely - when the thing you’re about to write down is really a rule, or doesn’t need writing down at all. Skill, rule, or plain prompt - when does each one fit?