Codex · EN · Part 2

Ch 06 Skills Framework

06-ch-06-Skills-Framework.md

第6章 Skills Framework

Skill Structure and Metadata

Every skill begins with a SKILL.md file containing YAML frontmatter followed by markdown instructions. The frontmatter serves as the skill's contract: it tells Codex when to trigger and what the skill provides.

---
name: openai-docs
description: Use when the user asks how to build with OpenAI products or APIs and needs up-to-date official documentation with citations, help choosing the latest model for a use case, or explicit GPT-5.4 upgrade and prompt-upgrade guidance
metadata:
  short-description: OpenAI documentation lookup
---

# OpenAI Docs

Provide authoritative, current guidance from OpenAI developer docs...

The frontmatter has three required fields:

  • name: The skill's identifier (lowercase, hyphens only, max 64 chars)
  • description: When-to-use criteria that triggers skill injection—this is the primary matching mechanism
  • metadata.short-description: Brief summary shown in UI lists (optional)

When-to-Use Criteria

The description field is critical—it's how Codex decides whether to load your skill. Write it to cover both what the skill does AND when it should trigger:

# Good: specific trigger conditions
description: "Generate or edit raster images when the task benefits from AI-created bitmap visuals. Use when Codex should create brand-new images, transform existing images, or derive visual variants from references."

# Poor: too vague
description: "A skill for working with images."

🤿 深入底层:When Codex parses a skill, it extracts the name and description fields and stores them in memory. The skill body loads only when triggered. This progressive disclosure keeps the context window small—skill metadata consumes ~100 tokens, while bodies range from 500-5000 tokens.

Rigid vs Flexible Skills

Skills fall into two categories based on how strictly they define procedures:

Rigid skills prescribe exact sequences with minimal deviation. The plugin-creator skill exemplifies this approach—it generates specific JSON structures with required fields in a precise order:

python3 .agents/skills/plugin-creator/scripts/create_basic_plugin.py my-plugin

Rigid skills work best for:

  • Fragile operations where order matters (JSON generation, certificate creation)
  • Security-sensitive tasks requiring exact parameters
  • Multi-step workflows where each step depends on previous ones

Flexible skills provide guidelines and heuristics. The skill-creator skill takes this approach—it offers principles like "concise is key" and "progressive disclosure" rather than mandating exact wording:

## Core Principles

### Concise is Key
The context window is a public good. Skills share the context window with everything else...
Default assumption: Codex is already very smart. Only add context Codex doesn't already have.

Flexible skills excel when:

  • Multiple valid approaches exist
  • Context determines the best strategy
  • The task requires creativity or judgment

Content Sections

After the frontmatter, the skill body contains markdown organized into sections. Common patterns include:

  • Quick Start: Minimal steps to get running immediately
  • Workflow: Detailed process descriptions
  • When to Use / When Not to Use: Decision boundaries
  • Examples: Concrete usage patterns
  • Reference Map: Links to bundled resources

The imagegen skill demonstrates this structure with its decision tree that helps classify requests into generation vs. editing modes:

## Decision tree

Think about two separate questions:

1. **Intent:** is this a new image or an edit of an existing image?
2. **Execution strategy:** is this one asset or many assets/variants?

Intent:
- If the user wants to modify an existing image while preserving parts of it, treat the request as **edit**.
- If the user provides images only as references for style, composition, mood, or subject guidance, treat the request as **generate**.

Bundled Resources

Skills can include optional directories alongside SKILL.md:

skill-name/
├── SKILL.md (required)
├── agents/
│   └── openai.yaml (UI metadata)
├── scripts/ (executable code)
├── references/ (documentation loaded on demand)
└── assets/ (templates, icons, output files)

The scripts directory contains executable code that runs deterministically without loading into the context. The imagegen skill's scripts/image_gen.py handles batch image generation:

# scripts/image_gen.py
# Executes directly without consuming LLM context tokens
def generate_batch(prompts: list[str]) -> list[Path]:
    # Deterministic image generation
    ...

The references directory holds documentation that loads selectively. The openai-docs skill uses this pattern:

references/
├── latest-model.md (model selection guidance)
├── upgrading-to-gpt-5p4.md (migration checklist)
└── gpt-5p4-prompting-guide.md (prompt optimization)

When a user asks about model selection, only latest-model.md loads—the other files remain dormant.

The assets directory contains files used in output rather than consumed as context. Template files, brand assets, and boilerplate code live here.

Skill Loading and Injection

Codex discovers skills through a three-scope system that determines both availability and precedence:

Rendering diagram...

Three Discovery Scopes

System skills ship with Codex and live at CODEX_HOME/skills/.system/. These include core capabilities like skill-creator, plugin-creator, and openai-docs. System skills have the lowest precedence—user or repo skills can override them.

The install_system_skills function extracts embedded skills from the binary and caches them on disk:

// codex-rs/skills/src/lib.rs
pub fn install_system_skills(codex_home: &Path) -> Result<(), SystemSkillsError> {
    // Compare fingerprint to avoid unnecessary work
    let expected_fingerprint = embedded_system_skills_fingerprint();
    if dest_system.is_dir() && read_marker(&marker_path)? == expected_fingerprint {
        return Ok(()); // Already installed, skip
    }
    
    // Write embedded skills to cache directory
    write_embedded_dir(&SYSTEM_SKILLS_DIR, &dest_system)?;
    write_marker(&marker_path, expected_fingerprint)?;
    Ok(())
}

⚠️ 避坑指南:System skills update automatically when Codex upgrades. If you need to inspect a system skill's implementation, look in the cache—but never modify them directly. Changes disappear on the next update.

User skills reside in ~/.codex/skills/ or ~/.agents/skills/ and apply across all projects. These are for personal workflows and custom tools. User skills override system skills but fall to repo skills.

Repo skills live in .codex/skills/ or .agents/skills/ within a project directory. These provide project-specific guidance and take precedence over both user and system skills. Multiple repo skills can exist in subdirectories between the project root and current working directory.

Loading Process

Skill loading happens at startup and when the current directory changes. The SkillsManager orchestrates discovery, parsing, and caching:

// codex-rs/core-skills/src/manager.rs
pub struct SkillsManager {
    codex_home: PathBuf,
    restriction_product: Option<Product>,
    cache_by_cwd: RwLock<HashMap<PathBuf, SkillLoadOutcome>>,
    cache_by_config: RwLock<HashMap<ConfigSkillsCacheKey, SkillLoadOutcome>>,
}

The loader discovers skills by scanning each root directory up to MAX_SCAN_DEPTH (6 levels) with a cap of MAX_SKILLS_DIRS_PER_ROOT (2000 directories):

// codex-rs/core-skills/src/loader.rs
fn discover_skills_under_root(root: &Path, scope: SkillScope, outcome: &mut SkillLoadOutcome) {
    let mut queue: VecDeque<(PathBuf, usize)> = VecDeque::from([(root.clone(), 0)]);
    
    while let Some((dir, depth)) = queue.pop_front() {
        if depth > MAX_SCAN_DEPTH { continue; }
        
        for entry in fs::read_dir(&dir)? {
            let path = entry.path();
            if path.is_dir() {
                queue.push_back((path, depth + 1));
            } else if path.file_name() == SKILLS_FILENAME {
                // Found SKILL.md - parse and add to outcome
                outcome.skills.push(parse_skill_file(&path, scope)?);
            }
        }
    }
}

Each SKILL.md file gets parsed for frontmatter validation and metadata extraction:

// codex-rs/core-skills/src/loader.rs
fn parse_skill_file(path: &Path, scope: SkillScope) -> Result<SkillMetadata, SkillParseError> {
    let contents = fs::read_to_string(path)?;
    let frontmatter = extract_frontmatter(&contents)
        .ok_or(SkillParseError::MissingFrontmatter)?;
    let parsed: SkillFrontmatter = serde_yaml::from_str(&frontmatter)?;
    
    // Validate field lengths
    validate_len(&name, MAX_NAME_LEN, "name")?;
    validate_len(&description, MAX_DESCRIPTION_LEN, "description")?;
    
    Ok(SkillMetadata { name, description, path_to_skills_md, scope })
}

Context-Based Injection

Skills inject into the system prompt through a two-stage process:

  1. Metadata listing: All skill names and descriptions render into a "Available skills" section
  2. Body loading: Individual skill bodies load when triggered

The render_skills_section function generates the metadata listing:

// codex-rs/core-skills/src/render.rs
pub fn render_skills_section(skills: &[SkillMetadata]) -> Option<String> {
    let mut lines = Vec::new();
    lines.push("## Skills".to_string());
    lines.push("### Available skills".to_string());
    
    for skill in skills {
        lines.push(format!("- {}: {} (file: {})", 
            skill.name, skill.description, skill.path));
    }
    
    lines.push("### How to use skills".to_string());
    // ... injection rules ...
    
    Some(format!("<codex_skills_instructions>\n{}\n</codex_skills_instructions>", 
        lines.join("\n")))
}

This renders into the system prompt as:

## Skills
### Available skills
- openai-docs: Use when the user asks how to build with OpenAI products... (file: .../openai-docs/SKILL.md)
- skill-creator: Guide for creating effective skills... (file: .../skill-creator/SKILL.md)

### How to use skills
- Discovery: The list above is the skills available in this session...
- Trigger rules: If the user names a skill (with `$SkillName`) OR the task clearly matches a skill's description...

Caching and Hot-Reload

The SkillsManager caches loaded skills by current working directory and configuration state:

// codex-rs/core-skills/src/manager.rs
pub fn skills_for_cwd(&self, input: &SkillsLoadInput, force_reload: bool) 
    -> SkillLoadOutcome 
{
    if !force_reload {
        if let Some(outcome) = self.cached_outcome_for_cwd(input.cwd.as_path()) {
            return outcome;
        }
    }
    
    // Load and cache
    let outcome = self.build_skill_outcome(roots, &skill_config_rules);
    self.cache_by_cwd.write().unwrap().insert(input.cwd.clone(), outcome.clone());
    outcome
}

Skills reload automatically when:

  • The current working directory changes
  • Configuration files are modified
  • force_reload is explicitly requested

☕ 茶水间时间:The cache key includes both the directory path AND the configuration hash. This prevents a subtle bug where role-local overrides in one session could bleed into another session that happens to share the same directory.

Using System and Custom Skills

Codex includes several built-in skills that demonstrate effective patterns. Understanding these skills helps you use them effectively and informs your own skill creation.

Brainstorming Skill

The brainstorming skill (when available) provides a structured approach to exploring problems before implementation. It forces explicit consideration of requirements, constraints, and alternatives:

## Brainstorming Checklist

1. What problem are we solving?
2. Who are the users?
3. What are the constraints?
4. What alternatives exist?
5. What are the trade-offs?

When a user says "brainstorm X" or the task involves significant design work, Codex automatically invokes this skill and works through the checklist systematically.

TDD Skill

The Test-Driven Development skill enforces the red-green-refactor cycle:

## TDD Workflow

1. **Red**: Write a failing test
2. **Green**: Write minimal code to pass
3. **Refactor**: Improve the code while keeping tests green

Do not skip the red step. A test written after code is TDD in name only.

This skill triggers on phrases like "test-driven," "TDD," or when the user explicitly mentions writing tests first.

Debugging Skill

The debugging skill provides systematic troubleshooting steps:

## Debugging Process

1. Reproduce the bug reliably
2. Gather information (logs, error messages, state)
3. Form a hypothesis
4. Test the hypothesis
5. Fix and verify

Explicit vs Implicit Invocation

Skills trigger through two mechanisms:

Explicit invocation uses the $skill-name syntax:

codex "Use $openai-docs to find the latest model recommendations"

This bypasses the description matching and directly loads the named skill.

Implicit invocation happens when the user's request matches a skill's description. The collect_explicit_skill_mentions function scans user input for skill mentions:

// codex-rs/core-skills/src/injection.rs
pub fn collect_explicit_skill_mentions(
    inputs: &[UserInput],
    skills: &[SkillMetadata],
    disabled_paths: &HashSet<PathBuf>,
) -> Vec<SkillMetadata> 
{
    let mut selected = Vec::new();
    
    // First, scan for explicit $skill-name mentions
    for input in inputs {
        if let UserInput::Text { text, .. } = input {
            let mentioned_names = extract_tool_mentions(text);
            // Match against available skills...
        }
    }
    
    selected
}

The skill mention extractor finds both plain mentions ($skill-name) and linked mentions ([$skill-name](skill://path)):

// codex-rs/core-skills/src/injection.rs
pub fn extract_tool_mentions(text: &str) -> ToolMentions<'_> {
    // Extracts both $name and [$name](path) patterns
    let mut mentioned_names = HashSet::new();
    let mut mentioned_paths = HashSet::new();
    
    // Parse text for mention patterns...
    
    ToolMentions { names: mentioned_names, paths: mentioned_paths }
}

Creating Custom Skills

Creating a skill follows a systematic process from understanding the problem to validating the result.

Skill Creation Process

Step 1: Understand with concrete examples

Before writing any code, gather specific examples of how the skill will be used:

You: What functionality should this support?
User: Processing PDF documents - extracting text, rotating pages, filling forms.
You: Can you give me some example prompts?
User: "Rotate this PDF 90 degrees", "Extract all text from this document", 
     "Fill out this form with the following data"
You: Where should I create this skill?
User: In ~/.codex/skills so it's available everywhere

Step 2: Plan reusable contents

Analyze each example to identify what belongs in scripts, references, or assets:

Analysis:
- PDF rotation: Same code each time → scripts/rotate_pdf.py
- Form filling: Needs schema reference → references/form_schema.md
- Text extraction: Can use library, no script needed

Step 3: Initialize the skill

Use the init_skill.py script to create the skill template:

python3 .agents/skills/skill-creator/scripts/init_skill.py pdf-processor \
  --path ~/.codex/skills \
  --resources scripts,references

This generates:

~/.codex/skills/pdf-processor/
├── SKILL.md (template with frontmatter)
├── agents/openai.yaml (UI metadata)
├── scripts/ (empty)
└── references/ (empty)

Step 4: Edit the skill

Write the SKILL.md frontmatter with clear triggering criteria:

---
name: pdf-processor
description: Process PDF documents including text extraction, page rotation, form filling, and metadata editing. Use when working with PDF files for document automation, data extraction, or batch processing tasks.
---

# PDF Processor

## Quick Start

Extract text: Use `pdfplumber` library
Rotate pages: Use `scripts/rotate_pdf.py <file> <degrees>`
Fill forms: See `references/form_schema.md` for field mappings

Step 5: Validate the skill

Run validation to catch common issues:

python3 .agents/skills/skill-creator/scripts/quick_validate.py ~/.codex/skills/pdf-processor

The validator checks:

  • YAML frontmatter format
  • Required fields present
  • Name length constraints (≤64 chars)
  • Description length constraints (≤1024 chars)
  • Naming conventions (lowercase, hyphens only)

Step 6: Iterate based on usage

Test the skill with real tasks and refine:

codex "Use $pdf-processor to extract text from report.pdf"
codex "Rotate scan.pdf 90 degrees using $pdf-processor"

Metadata Writing

The frontmatter metadata is the skill's most important content—it determines when the skill triggers. Write it to be both comprehensive and specific:

# Good: Covers what, when, and triggers
name: react-component-builder
description: Build React components following our team's patterns including TypeScript types, styled-components, testing setup, and folder structure. Use when creating new UI components, refactoring existing components, or setting up component architecture for features.

# Poor: Too vague, no clear triggers
name: react-helper
description: Helps with React development

Prompt Crafting

The skill body should be:

  • Concise: Respect the context window budget
  • Actionable: Provide clear steps, not abstract theory
  • Specific: Give concrete examples and patterns

The plugin-creator skill exemplifies good prompt craft:

## Quick Start

1. Run the scaffold script:
```bash
python3 .agents/skills/plugin-creator/scripts/create_basic_plugin.py <plugin-name>
  1. Open <plugin-path>/.codex-plugin/plugin.json and replace [TODO: ...] placeholders.

  2. Generate or update the repo marketplace entry:

python3 .agents/skills/plugin-creator/scripts/create_basic_plugin.py my-plugin --with-marketplace

Three actionable steps. No philosophy. Just do this, then this, then this.

### Common Patterns

**Checklist skills** enumerate steps to follow:

```markdown
## Code Review Checklist

- [ ] Security vulnerabilities
- [ ] Performance issues
- [ ] Type safety
- [ ] Error handling
- [ ] Documentation completeness

Workflow skills describe multi-step processes:

## Feature Deployment Workflow

1. Run test suite: `npm test`
2. Build production bundle: `npm run build`
3. Run integration tests: `npm run test:integration`
4. Tag release: `git tag -a v1.2.3 -m "Release message"`
5. Push to production: `git push origin main --tags`

Tool-wrapping skills provide usage guidance for specific tools:

## Docker Build Workflow

Build: `docker build -t myapp:latest .`
Test: `docker run -p 3000:3000 myapp:latest`
Push: `docker push registry.example.com/myapp:latest`

Common pitfalls:
- Don't forget the dot at the end of build command
- Tag must match registry naming convention
- Port mapping is host:container

Debugging Techniques

When a skill doesn't trigger as expected:

  1. Check the description: Does it clearly describe when to use the skill?
  2. Verify parsing: Run quick_validate.py to ensure frontmatter is valid
  3. Test invocation: Try explicit $skill-name syntax to bypass matching
  4. Check scope: Ensure the skill is in the correct directory for its intended scope
  5. Review logs: Enable debug logging to see skill discovery and matching
# Enable skill debugging
codex --log-level debug "Use $my-skill to process this file"

Skills add capabilities, but conversations need to persist across sessions—which brings us to the state and persistence system.