Skip to content

Course · Codex · Skills

Choose between a Skill, an AGENTS.md rule, and a plain prompt

You’ve now watched recognition turn six turns into two. But “write something down so Codex does it right” describes three different containers, and reaching for the wrong one is a common way to fight the grain. This lesson is the decision: when the import procedure is genuinely a Skill, when the next thing you want to capture is really an AGENTS.md rule, and when it shouldn’t be written down at all.

Skill vs rule: what Codex does vs what it knows

Section titled “Skill vs rule: what Codex does vs what it knows”

This is the distinction that matters most, and the one most often gotten wrong. Both a Skill and AGENTS.md are “context you write down once” - but they load differently and they answer different questions.

  • An AGENTS.md rule is a standing fact. “Money is integer cents, never float.” “The category list is groceries, rent, subscriptions…” Codex reads AGENTS.md automatically before every run, so a rule is always in view - it shapes everything Codex does, whether or not you mention it.
  • A Skill is a procedure. “To onboard a new bank’s CSV: read a sample, map the columns, normalise dates, convert to cents, write an importer.” It loads only when the situation fires, runs as a sequence of steps, and is silent the rest of the time.

The test: can you run it? “Always store money as cents” isn’t something Codex runs - it’s a constraint it should hold at all times. That’s a rule. “Import a new bank’s CSV” is a multi-step thing Codex does on a specific occasion. That’s a Skill. Put a standing fact in a Skill body and it only applies when the Skill happens to fire - exactly when you don’t want a money rule to be conditional. Put a multi-step procedure in AGENTS.md and it’s loaded into every run whether you’re importing a bank that day or not, paying full context cost to sit idle.

You saw the two cooperate two lessons back: the cents-not-float rule lives in AGENTS.md as a standing constraint and the import Skill restates the rounding step at the one point where a fresh bank’s format still slips past it. That’s not redundancy - the rule governs everything; the Skill puts the check at the point of maximum risk. Rules are the floor; a Skill can reinforce the floor where a procedure tends to trip over it. The rent a rule pays for that always-on coverage is real, and it’s priced in the good-rules lesson - keep that pricing in mind for the table below.

The other failure is over-engineering - packaging something as a Skill that didn’t need packaging. The honest test is repetition:

  • One-off, or rare and varied → a plain prompt. If you’re parsing one weird file once, just ask Codex to do it in the conversation. Writing a SKILL.md for it is busywork - if the SKILL.md takes longer to write than the task it automates, you’ve over-built.
  • Same multi-step procedure, again and again → a Skill. The import job cleared this bar the moment you noticed you were re-narrating the same five steps for each new bank - and paying six turns for it every time.

A good way to arrive at a Skill is to not write it first. Do the job by hand in a normal session - onboard the first new bank as a plain prompt. When you find yourself doing the same thing a third time, you’ll already know the exact steps, the failure modes, and the wording that triggers it. Then the SKILL.md writes itself, and it’s grounded in a procedure you’ve actually validated rather than one you guessed at.

Put a number on it rather than trust the shape of the argument. Take the exact task from this chapter - onboard one unseen bank’s CSV - and run it through all three containers:

RouteThis job’s costRecurs next bank?Verdict
Skill~80 tokens every session (the stub) + ~280 tokens only when it fires; 2 turnsYes - the procedure is captured onceRight home
AGENTS.md ruleThe same ~280-token procedure, but loaded on every session, importing or not - on top of the ~284 tokens the existing rules file already spendsYes, but the coverage is paid for whether or not it’s used that dayWrong shape - pays rent idle
Plain prompt~0 tokens until you need it, but 6 turns of re-describing, re-asking, and re-correcting - the walkthrough from the chapter openingNo - you’re the memory, and the step you forget is the one that bitesWorks once, taxes forever

Same procedure, same bank, three prices. The Skill is the only route that’s both cheap on a quiet day and complete on the day it’s needed.

When you’re about to write something down for Codex, ask in this order:

  1. Is it a fact Codex should always hold, or a procedure it runs on occasion? Always-on constraint or domain fact → AGENTS.md rule. A multi-step thing it does at a specific moment → Skill.
  2. Does the procedure actually repeat? A genuine, recurring, multi-step routine → Skill. A one-off or rarely-the-same task → just prompt it; don’t build a file.
  3. If it’s a Skill, should Codex fire it on its own? Harmless if mistimed, like our preview-first import → leave implicit invocation on, let it fire on recognition. Expensive, slow, or state-changing → take it off the automatic menu with the per-Skill policy from the last lesson.

Keep those straight and you’ll almost always reach for the right container. Rules are what Codex knows; Skills are what it does; a plain prompt is for what it does once. The quiet mistake is cramming a standing fact into a Skill body, where it only loads when the Skill fires, instead of into AGENTS.md where it’s always in view - so when in doubt, ask whether the thing is a fact or an action.

You can run that judgment on the ledger it’s really about. A rule pays its full size in every run; a Skill pays a tiny always-visible stub and loads its body only when it fires; a plain prompt costs nothing until you need it - and again every time after. Four pieces of knowledge, three homes each - see what the wrong home costs:

Four things you keep teaching the agent, all currently crammed into the rules file. Each needs a home: the rules file (loaded every session), a skill (a 25-token menu line every session, full body only when invoked), or the prompt (said when it comes up). Re-home them and watch the ledger.

  • cents, not floatsfact · matters most sessions · ~22 tok

    Money is integer cents - amountCents: number, never floats.

    right home

    Twenty-two tokens a session and the float bug is extinct. A fact the agent must hold while writing any code has to be in view before it starts - that’s the rules file.

  • release checklistprocedure · runs ~2×/week · ~1.2k tok

    The release ritual: bump the version, regenerate the changelog, tag, build, smoke-test - fifteen steps in a fixed order.

    idle rent

    Fifteen steps loaded into every session to be used twice a week. The other eight sessions pay 1.2k tokens for a procedure that never runs - bulk that competes with your real rules for attention.

  • migration recipeprocedure · runs ~2×/month · ~900 tok

    Schema migrations follow expand → backfill → contract, with a fixture check and a written rollback plan.

    idle rent

    Twenty sessions pay 900 tokens each for every one that migrates. The rarer the procedure, the worse a rules file suits it.

  • today’s flakeone-off · this week only · ~25 tok

    Today’s job: chase the flaky auth test in login.spec.ts.

    rent for a one-off

    True this week, noise forever after. Next month the agent still “knows” about a flake that’s long fixed.

window cost21.5k tok/weekyou re-teach0×/weekmisplaced3 of 4

The procedures are paying rent in every session for the few that use them. Move them behind a skill stub: the knowledge stays one invocation away, and the window cost collapses.

Numbers are illustrative - the ratios are the point. Over 10 sessions a week: a rule pays full size every session, a skill pays a ~25-token stub plus its body only when it fires, a prompt pays only when said - but you’re the one saying it.

Notice which placements the widget punishes hardest: a fact filed as a skill, because a fact has no moment of invocation and just never loads, and a procedure filed as a rule, paying rent every session for the few that need it. Those are the two swaps this lesson exists to stop you making.

A Skill only orchestrates what Codex can already reach - your files, your shell, the importers already in the repo. The import procedure stays inside budgetcli because everything it touches is in budgetcli. The moment a procedure needs to touch a system outside the repo - pull a live exchange rate for a foreign-currency transaction, query an external service - or needs a check that runs every time, deterministically, no matter what Codex decides, you’ve reached the edge of what a Skill alone can do. And a Skill is still guidance, not a rule the sandbox enforces: for a security-critical condition like “never write to the real ledger,” you still want database permissions, sandboxing, and CI backing it up, the way the approvals chapter already does - not a Skill body carrying that weight alone.

Score the finished Skill on the same four questions the course has used since chapter one:

MoveTokensTurnsBlast radiusRecurs?
Read-only question (“what does this do”)~3,900 est.1None - nothing writtenNo
Fix the CSV date bug~2,100 est. (csv.py alone)4Money-adjacent - meant the date field, briefly drifted into amountPartly - the fix holds, the habit behind it didn’t exist yet
Onboard a new bank via import-bank-csv~360 est. (80 stub every session, 280 body only when it fires)2Money-adjacent - same shape as the fix above, still reviewed before writeYes - the procedure holds for every bank from here on

That last cell splits the same way the fix two rows up did. The date fix held because it’s a line in git; the habit behind it didn’t, because nothing carried the procedure forward to the next bank. The Skill is what closes that second gap - not just today’s fix committed, but tomorrow’s version of the same job already covered.

Skills close a real gap: Codex now owns the procedures you used to narrate, firing them when the situation calls. Next chapter gives it something a Skill alone can’t reach on its own: reach into external systems with MCP servers, and a deterministic check that runs no matter what the agent decides.