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
nameanddescriptionfields 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:
- Metadata listing: All skill names and descriptions render into a "Available skills" section
- 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_reloadis 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>
-
Open
<plugin-path>/.codex-plugin/plugin.jsonand replace[TODO: ...]placeholders. -
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:
- Check the description: Does it clearly describe when to use the skill?
- Verify parsing: Run
quick_validate.pyto ensure frontmatter is valid - Test invocation: Try explicit
$skill-namesyntax to bypass matching - Check scope: Ensure the skill is in the correct directory for its intended scope
- 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.