Agent Skills: Packaging Workflows to Teach Codex New Capabilities
📚 Series Navigation: The previous article [21 Subagents] explained "splitting a heavy task to a dedicated assistant in an isolated context and retrieving the consolidated report." This article shifts perspective: instead of splitting tasks, we package capabilities—bundling a recurring workflow into Agent Skills so Codex can call it up when needed. The next article [23 Plugins] covers packaging these capabilities to distribute them to others.
I took a look at OpenAI's official github.com/openai/skills repository.
Inside, a Skill can run with a skeleton as simple as a single SKILL.md file—metadata enclosed between two lines at the top, followed by a few lines describing "how to do it." Yet OpenAI positions this simple directory as "the authoring format for reusable workflows": you write a workflow into it, and Codex uses it when needed without you having to retype the steps.
Many people hear of Skills and think, "isn't this just a slash command under a different name? The /review command I learned in Article 12 runs on click too." To be honest, this understanding misses a layer. Slash commands run only when you explicitly invoke them. Skills, on the other hand, do not require you to call them—Codex matches your task to a Skill's description and retrieves it automatically, and it takes up almost no context window when idle.
This article covers what a Skill is, how it stores information without blowing up your context, where it goes, how it triggers, and how to write one. Information is aligned with the official Codex documentation—some legacy guides online write the directory paths and field names incorrectly, which I will highlight below so you don't trip over them.
By reading this article, you will get:
- What a Skill actually is—how a directory containing
SKILL.mdplus optional scripts/resources becomes a capability for Codex - Its key mechanism: "progressive disclosure"—why it only occupies a single description line when idle and expands only when active, which is the secret to saving context window
- The difference between the two invocation paths: explicit
$calls vs. implicit automatic matching based on descriptions, and how to write matching descriptions - Where Skills go (the
.agents/skillspaths, not~/.codex/skills), and what happens when they share names - How to create a Skill using
$skill-creator, install pre-made ones using$skill-installer, and disable specific ones
01 Understand First: What Exactly is a Skill?
The bottom line: A Skill is a directory containing a SKILL.md file, alongside optional scripts and reference materials, packaged as a specialized capability for Codex. The official docs state: "a Skill is a directory containing a SKILL.md file and optional scripts and resources."
Why do we need it? Because when you work with Codex, there are workflows you repeatedly instruct it to run. For example, every time I ask it to commit code, I have to tell it: "run tests first, write the commit message in Chinese, and use prefixes like feat: / fix:"—I typed that exact instruction at least thirty times last year. This kind of instruction-level repetition is what Skills should manage.
Analogy: A Lego assembly manual. When you buy a Lego set, the manual doesn't assemble it for you, but it guides you step-by-step: "assemble the chassis first, add the four wheels, and snap on the roof." Anyone following the manual will assemble it correctly and identically. A Skill is that manual written for Codex: you write a fixed sequence of steps (like "summarizing uncommitted changes and identifying risks") into SKILL.md, and that workflow becomes a capability Codex can follow without you having to redraw the manual every time.
What does SKILL.md look like? The minimal skeleton has two parts, as templated officially:
---
name: skill-name
description: Describe when this skill should and should not be triggered.
---
Skill instructions for Codex to follow go here.The block enclosed by --- at the top is the YAML frontmatter (metadata at the beginning of the file), which must contain the name and description fields: name is the identifier of the capability (used when calling it with $ later), and description tells Codex what the Skill does and when to use it. The Markdown body is the instructions Codex follows when the Skill is invoked.
⚠️ Here is a common pitfall where legacy guides mislead beginners: some unofficial sources write a
trigger:field (calling it a "trigger keyword") in the frontmatter and place Skills under~/.codex/skills/. The official documentation does not contain atriggerfield; triggering is handled via semantic matching of thedescription(detailed below). The directory is also not~/.codex/skills, but rather the.agents/skillspaths (covered in Section 04). Writing it following old guides will either fail to register or fail to invoke. Always align with the official documentation.
A Skill is a directory, not just a single SKILL.md file. In addition to the required SKILL.md, it can contain scripts and resources:
my-skill/
├── SKILL.md # Main instructions (required, contains name + description)
├── scripts/ # Optional: executable scripts (used for deterministic behavior or external tools)
├── references/ # Optional: reference docs queried by Codex during executionOnly SKILL.md is required; the others are optional. This leads to a practical trade-off suggested officially—prefer instructions over scripts unless you need deterministic behavior or must call external tools. In other words: letting Codex follow natural language steps is more flexible than locking it to a script; only use scripts when "this step must run exactly without deviation" or "it must run a command-line tool."
Three real-world scenarios where Skills excel:
- Every time you commit, you tell it the rules: "test first, Chinese commit, prefix约定"—write it as a
commitSkill and trigger it in one word. - The team has established API conventions (RESTful naming, unified error formats, mandatory parameter validation)—write it as an
api-conventionsSkill, and it will follow them when writing interfaces. - You have a release checklist (updating changelog, tagging, running smoke tests)—write it as a Skill and trigger it in one word on release day.
💡 Summary in one sentence: A Skill is a directory containing
SKILL.md(name+description+ instructions) plus optional scripts/resources—written once, Codex can call it up at any time; do not rush to write scripts if instructions can explain it.
02 The Core Mechanism: Progressive Disclosure—The Secret to Saving Context
This is the most critical section to master. How can you load a large bundle of Skills without blowing up the context window? The secret is: progressive disclosure (loading details only when active, keeping it quiet when idle).
Let's address why this is critical. Recall the context window from Article 02—Codex's workspace is limited, and every word inside costs tokens and reduces thinking space. If the full content of every Skill were loaded at session start, loading ten Skills would consume half the workspace.
Analogy: Menu labels vs. the kitchen in a buffet. As you walk along the buffet line, each dish has a small card in front of it listing the name (e.g., "Mapo Tofu - Mild"). You know what is available at a glance, but the recipe, ingredients, and steps in the kitchen are not exposed to you unless you choose that dish. When you take the Mapo Tofu, the cooking details load for the kitchen. Skills work exactly this way, as explained by the official docs:
At startup, Codex only loads the name, description, and file path of each skill. Only when it decides to use a skill does it load the full
SKILL.mdinstructions.
In plain terms:
- Idle: Each Skill only occupies its "name + single description line + file path" (the card on the buffet table).
- Active: When Codex decides a Skill matches the current task, it loads the full
SKILL.mdbody (retrieving the recipe for that dish).
This means you can write long checklists and references in the Skill body—they cost nothing until they are used.

This diagram shows the two phases side-by-side: on the left (Phase 1), each Skill only occupies a name, description, and path at startup; on the right (Phase 2), only the Skill matched by the task expands its full SKILL.md body, while others remain at one line.
However, this "initial list" has a character budget—a detail many developers miss, leading to issues:
To avoid cluttering the prompt, this initial list is limited to about 2% of the model's context window, or 8,000 characters when the context window is unknown. If many skills are installed, Codex will shorten descriptions; for very large skill sets, some skills may be omitted from the initial list, raising warnings.
Note that this budget only restricts the initial list—once Codex selects a Skill, it still reads the full SKILL.md. This has a practical implication: place key use cases and trigger keywords at the beginning of your description. If your descriptions are shortened due to many Skills, the keywords at the beginning are preserved and matching remains accurate. If they are buried at the end, they get cut off—this is the same lesson from Article 11 where the only useful rule was buried at line 140 of AGENTS.md: put important information first.
💡 Summary in one sentence: Progressive disclosure means loading only "name + description" when idle and expanding the full
SKILL.mdwhen active, avoiding context bloating; but the initial list has a budget (about 2% or 8000 characters), so put core trigger keywords first in the description to avoid getting them cut off.
03 Two Invocation Paths: Explicit Calling vs. Implicit Matching
Since we know how Skills save context, how are they invoked? The official docs provide two paths, and understanding the difference is key to using them.
Analogy: Ordering takeout. One way is ordering from a specific restaurant—"I want the yellow braised chicken downstairs," and the platform assigns it directly without guessing. The other way is stating your craving—"I want something spicy and good with rice," and the platform matches the best restaurants. The two invocation paths match these two ways.
Explicit Invocation: Naming It Directly
The first is explicit invocation (explicit invocation)—referring to the Skill directly in your prompt. The official method: in the CLI or IDE, run the /skills command, or type the $ symbol to refer to a skill.
$commitTyping $ pops up the list of available Skills. Selecting one (or typing the name out) tells Codex to use it. Under explicit invocation, Codex skips matching evaluations and loads the full SKILL.md directly—it runs exactly what you asked for, making it the most reliable path.
⚠️ Another old guide pitfall: some sources write explicit calling as
@skill-name. The official prefix is$(paired with/skills), not@. Do not mix them up.
Implicit Invocation: Automatic Matching via Descriptions
The second is implicit invocation (implicit invocation)—without mentioning the Skill by name, you write your prompt, and Codex compares it to each Skill's description, automatically loading the Skill if it matches. The official docs state:
When your task matches a skill's
description, Codex can choose to use that skill automatically.
This is the most convenient way to use Skills: you don't need to remember $names; if descriptions are well-written, it picks them up automatically. But this places the burden on your description—the docs state clearly:
Because implicit matching relies on the
description, write concise descriptions with clear scopes and boundaries. Put key use cases and trigger words first so Codex can match the skill even if the description is shortened.
I made a mistake with my first Skill: writing the description as "helps with code-related tasks"—which was too broad, causing it to either match everything or fail to match when needed. I changed it to "summarizes uncommitted changes and identifies risks. Use when the user asks 'what did I change', 'give me a commit message', or 'help me check diffs'"—writing the exact phrases I would say directly into the description, which made matching accurate. The description is not a human introduction; it is a hook for the matching algorithm.
Comparing the two invocation paths:
| Dimension | Explicit Invocation ($ / /skills) | Implicit Invocation (Semantic Matching) |
|---|---|---|
| How it triggers | Typing $ or selecting in /skills | Stating your task; Codex matches it |
| Codex Decision | None, runs as requested | Runs matching against description |
| Accuracy depends on | Selecting the right name | How well the description is written |
| Suitable for | Precise control over which skill runs and when | Letting Codex match automatically without remembering names |
| Can it be disabled? | No (direct naming is always valid) | Yes (see allow_implicit_invocation in Section 05) |
💡 Summary in one sentence: Explicit invocation uses
$or/skillsfor precise control; implicit invocation matches semantic descriptions automatically—and its accuracy relies on your description, so put core trigger words first and describe them using phrases you actually speak.
04 Location Scopes: The .agents/skills Paths
Knowing how they work and trigger, where do you put your Skills? This is where online guides frequently mislead beginners; copy the official table directly and do not guess.
The official docs state that Codex reads Skills from four scopes: repository (REPO), user (USER), admin (ADMIN), and system (SYSTEM). The REPO scope has a detail: Codex scans from your active directory upward to the repository root, reading .agents/skills at every level. The complete path scopes are:
| Scope | Location | Accessible By |
|---|---|---|
| REPO (active directory) | $CWD/.agents/skills | The active directory you started Codex in—for skills specific to a module / microservice |
| REPO (parent directory) | $CWD/../.agents/skills | Parent directory of the active path—for shared scopes in nested structures |
| REPO (repository root) | $REPO_ROOT/.agents/skills | Top level of the repository—base skills available across all subdirectories of the repository |
| USER (personal) | $HOME/.agents/skills | Available for you across all repositories |
| ADMIN (machine-level) | /etc/codex/skills | Shared across all users on this machine / container (SDK scripts, automation, default admin skills) |
| SYSTEM (built-in) | Bundled with Codex by OpenAI | Available for everyone (like skill-creator, plan skills) |
⚠️ Key takeaway to avoid issues: Codex skill directories are
.agents/skills(repository) and$HOME/.agents/skills(user), not~/.codex/skills/.~/.codex/is where configurations likeconfig.tomlgo (used in Section 05); do not create skill folders there—Codex will skip them and you'll think your Skills are broken. This is separate from theAGENTS.mddiscovery chain.
The logic is simple: if it's for your personal use across projects (like your commit habits), place it in the user scope $HOME/.agents/skills; if it's specific to this repository and shared with the team (like release checklists), place it in the repository scope .agents/skills and commit it, so teammates pulling the repo get it automatically. macOS/Linux uses $HOME as your home directory; Windows paths follow equivalent home paths.
What if two Skills share a name? The official docs clarify: Codex does not merge them; both appear in the skill selector. This differs from the "closest wins" override of AGENTS.md: AGENTS.md appends and resolves conflicts by proximity, while Skills coexist and list both options. The docs suggest: avoid duplicate skill names across scopes to avoid confusing yourself during selection.
Another detail: Codex automatically detects changes to skill files—modifying SKILL.md usually takes effect immediately. If it doesn't, restart Codex.
💡 Summary in one sentence: Put Skills under
.agents/skills(repo scope, scanning from active directory to root) or$HOME/.agents/skills(user scope), not~/.codex/skills; duplicate names list both rather than merging, so keep names distinct; changes usually auto-reload, otherwise restart.
05 Hands-on: Creating, Installing, and Disabling Skills
Let's look at three practical tasks: creating a Skill quickly, installing pre-made ones, and disabling specific ones.
Creating: Use $skill-creator
The official recommendation is clear—use the built-in creator first instead of coding it manually. Type in the CLI or IDE:
$skill-creatorIt guides you through three questions: what does this skill do? when should it trigger? do you need scripts or instructions? (instructions are recommended by default for simplicity—matching the "prefer instructions over scripts" advice in Section 01). Once completed, it generates the directory structure and SKILL.md for you. This is my default setup for new Skills: let it build the skeleton, and I modify the details.
You can also create it manually—following the template in Section 01, create a directory and write a SKILL.md containing name and description.
Installing: Use $skill-installer
To use Skills created by others, use $skill-installer. For example, installing Linear (a task management tool) skills:
$skill-installer linearYou can also instruct the installer to download skills from external repositories. Once installed, Codex usually detects them automatically; restart if not.
ℹ️ The official positioning for
$skill-installeris "local testing and experimentation." To distribute your own skills to others or package multiple skills together, package them as Plugins (Plugins)—which is the topic of the next article. Keep this in mind: Skill is the authoring format, while Plugin is the distribution format; design workflows as Skills first, and package them as plugins when sharing.
Disabling: Turn Off Without Deleting
If you want to temporarily disable a Skill (whether installed or built-in) without deleting it, configure it under ~/.codex/config.toml (your user-level config file; note it is .codex, not .agents):
# File path: ~/.codex/config.toml
[[skills.config]]
path = "/path/to/skill/SKILL.md"
enabled = falseSet path to the absolute path of the SKILL.md file, and enabled = false turns it off. Restart Codex after modifying config.toml to apply changes. This is useful when you have too many Skills loaded, hitting the initial list budget—disabling unused ones frees up space for others.
Advanced: Disabling Implicit Triggering (agents/openai.yaml)
To configure advanced attributes—like display names or icons in the App, declaring tool dependencies, or disabling implicit triggering—place an agents/openai.yaml file in the skill directory:
# File path: <skill_dir>/agents/openai.yaml
policy:
allow_implicit_invocation: falseallow_implicit_invocation defaults to true (allowing implicit matching). Setting it to false instructs Codex not to trigger it implicitly via description matching, while explicit $skill-name calls remain active. This is the switch from Section 03 to close implicit triggers. Use it for high-impact actions you want to trigger manually (like "deploying to production"), preventing Codex from triggering them automatically when it thinks code looks ready.
Let's summarize these actions and their directories:
| Objective | Method / Command | File / Command Location |
|---|---|---|
| Create a new Skill quickly | $skill-creator | Type directly in CLI / IDE |
| Install pre-made Skills | $skill-installer <name> | Type directly in CLI / IDE |
| Disable a Skill temporarily | [[skills.config]] | ~/.codex/config.toml |
| Disable implicit triggers for a Skill | allow_implicit_invocation: false | agents/openai.yaml in the skill directory |
| Place your Skill files | Create directory + SKILL.md | .agents/skills or $HOME/.agents/skills |
💡 Summary in one sentence: Create with
$skill-creator(instructions by default), install with$skill-installer, disable in~/.codex/config.tomlusing[[skills.config]], and close implicit triggers inagents/openai.yamlusingallow_implicit_invocation: false—note configs go to.codexwhile skills go to.agents; keep them separate.
06 Hands-on: Create a Skill in 3 Minutes and Watch It Auto-trigger
Let's run a minimal hands-on exercise without writing scripts, verifying how a Skill triggers implicitly via plain language and explicitly via $.
Platform differences: Run
mkdirin macOS / Linux directly; run in PowerShell on Windows (replacingmkdir -pwithmkdiror manually creating directories).~refers to the user home directory (C:\Users\username\on Windows). Ensure Codex is installed before starting. Command parameters follow official documentation.
Step 1: Create the User-level Skill Directory
mkdir -p ~/.agents/skills/explain-selfExpected: A directory explain-self appears under ~/.agents/skills/. Ensure it is .agents and not .codex—verifying this path prevents the most common issue.
Step 2: Write a Minimal SKILL.md
Save the following block into ~/.agents/skills/explain-self/SKILL.md:
---
name: explain-self
description: Explains a block of code or an error message in plain language. Use when the user says "what does this code do", "what is this error about", or "help me read this".
---
Explain the code or error provided by the user in plain language suitable for beginners:
1. What the code does overall (one sentence)
2. Break it down line-by-line / block-by-block
3. If it is an error, point out the likely cause and how to fix it
Do not dump heavy jargon; use analogies where helpful.Note the description includes phrases like "what does this code do" and "what is this error about"—acting as the hooks for implicit matching.
Expected: SKILL.md is saved inside the explain-self directory.
Step 3: Start Codex and Verify It Registers the Skill
codexIn the session, run:
/skillsExpected: The explain-self Skill appears in the list along with the description you wrote. Seeing it in the list confirms it was discovered. This also verifies progressive disclosure: at this stage, only its name, description, and path are loaded; the body instructions are not.
Step 4: Trigger the Skill Implicitly Using Plain Language
Type a matching phrase without mentioning $explain-self:
what does this code do: print(sum([1,2,3]) / len([1,2,3]))Expected: Codex matches the explain-self Skill automatically based on the description, and explains the code following your three instructions—giving a one-sentence summary (calculates the average of the three numbers, resulting in 2.0), breaking it down, and avoiding heavy jargon. It loaded the instructions without you calling it by name.
Step 5: Compare with Explicit Calling
Try explicit calling by typing $:
$explain-self what is this error about: ZeroDivisionError: division by zeroExpected: Triggers the same Skill, following the same instructions—the only difference is you explicitly selected it, skipping the matching logic. Both paths lead to the same capability.
Running these five steps verifies the key aspects of Skills: placing them in the correct directory (.agents rather than .codex), implicit description matching, explicit $ calling, and progressive disclosure.
💡 Summary in one sentence: Save a minimal skill to
~/.agents/skills/explain-self/SKILL.md, check it via/skills, and trigger it via plain text and$names—verifying implicit and explicit triggers for the same capability, while keeping the.agentspath in mind.
07 Summary
We have explored Agent Skills—allowing Codex to carry a bundle of workflows that can be called upon as needed.
Let's review the key points:
| Subject | Answer | Key Takeaway |
|---|---|---|
| What is a Skill? | Directory containing SKILL.md + optional scripts/resources | Frontmatter must define name and description |
| Why it saves context | Progressive disclosure | Name + description loaded at start, body expanded only when selected; budget is about 2% / 8000 characters |
| How to trigger | Two paths | Explicitly via $ or /skills, or implicitly matched via description |
| Where it goes | .agents/skills paths | Repo scope or user scope $HOME/.agents/skills, not ~/.codex/skills |
| How to manage | Create / install / disable | Use $skill-creator, $skill-installer, and [[skills.config]] |
You should now be able to: explain what a Skill is and how progressive disclosure saves context window; use explicit $ calling and implicit description matching, knowing that matching relies on the description; place Skills under .agents/skills and avoid duplicate names across scopes; and use $skill-creator to build and [[skills.config]] to disable Skills. This packaging of workflows is your key to turning Codex from a general assistant into an expert on your processes.
Keep the paths in mind: skills go under .agents, configurations go under .codex, and explicit calling uses $.
The next article [23 Plugins]—you packaged workflows into Skills, but they only run on your local machine and repositories. What if you want to package these capabilities to distribute to teammates or the community? Codex provides Plugins—"Skill is the authoring format, while Plugin is the distribution format." The next article covers packaging one or more Skills along with configurations into plugins to install elsewhere. A quick thought: if you want the whole team to use the explain-self skill you wrote, is committing it to the repository root enough, or is there another step?