Skip to content

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.md plus 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/skills paths, 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:

md
---
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 a trigger field; triggering is handled via semantic matching of the description (detailed below). The directory is also not ~/.codex/skills, but rather the .agents/skills paths (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:

text
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 execution

Only 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 commit Skill 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-conventions Skill, 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.md instructions.

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.md body (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.

Skills Progressive Disclosure

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.md when 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.

text
$commit

Typing $ 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:

DimensionExplicit Invocation ($ / /skills)Implicit Invocation (Semantic Matching)
How it triggersTyping $ or selecting in /skillsStating your task; Codex matches it
Codex DecisionNone, runs as requestedRuns matching against description
Accuracy depends onSelecting the right nameHow well the description is written
Suitable forPrecise control over which skill runs and whenLetting 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 /skills for 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:

ScopeLocationAccessible By
REPO (active directory)$CWD/.agents/skillsThe active directory you started Codex in—for skills specific to a module / microservice
REPO (parent directory)$CWD/../.agents/skillsParent directory of the active path—for shared scopes in nested structures
REPO (repository root)$REPO_ROOT/.agents/skillsTop level of the repository—base skills available across all subdirectories of the repository
USER (personal)$HOME/.agents/skillsAvailable for you across all repositories
ADMIN (machine-level)/etc/codex/skillsShared across all users on this machine / container (SDK scripts, automation, default admin skills)
SYSTEM (built-in)Bundled with Codex by OpenAIAvailable 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 like config.toml go (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 the AGENTS.md discovery 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:

text
$skill-creator

It 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:

bash
$skill-installer linear

You 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-installer is "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):

toml
# File path: ~/.codex/config.toml
[[skills.config]]
path = "/path/to/skill/SKILL.md"
enabled = false

Set 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:

yaml
# File path: <skill_dir>/agents/openai.yaml
policy:
  allow_implicit_invocation: false

allow_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:

ObjectiveMethod / CommandFile / Command Location
Create a new Skill quickly$skill-creatorType 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 Skillallow_implicit_invocation: falseagents/openai.yaml in the skill directory
Place your Skill filesCreate 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.toml using [[skills.config]], and close implicit triggers in agents/openai.yaml using allow_implicit_invocation: falsenote configs go to .codex while 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 mkdir in macOS / Linux directly; run in PowerShell on Windows (replacing mkdir -p with mkdir or 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

bash
mkdir -p ~/.agents/skills/explain-self

Expected: 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:

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

bash
codex

In the session, run:

text
/skills

Expected: 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:

text
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 $:

text
$explain-self what is this error about: ZeroDivisionError: division by zero

Expected: 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 $namesverifying implicit and explicit triggers for the same capability, while keeping the .agents path 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:

SubjectAnswerKey Takeaway
What is a Skill?Directory containing SKILL.md + optional scripts/resourcesFrontmatter must define name and description
Why it saves contextProgressive disclosureName + description loaded at start, body expanded only when selected; budget is about 2% / 8000 characters
How to triggerTwo pathsExplicitly via $ or /skills, or implicitly matched via description
Where it goes.agents/skills pathsRepo scope or user scope $HOME/.agents/skills, not ~/.codex/skills
How to manageCreate / install / disableUse $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?