How to Write a Custom Skill for oh-my-codex with the SKILL.md Format
Writing a custom skill for oh-my-codex requires creating a SKILL.md file with YAML front-matter and specific XML-style markdown sections in a dedicated directory under ./.codex/skills/<skill-name>/.
The oh-my-codex repository by Yeachan-Heo treats every reusable command as a skill—a self-contained markdown contract that the runtime parses and executes sequentially. When you write a custom skill using the SKILL.md format, you define machine-readable instructions that the engine interprets without executing arbitrary embedded code, making it safe to extend capabilities without modifying the core codebase.
SKILL.md Architecture and File Structure
Every skill resides in its own directory, typically under ./.codex/skills/<skill-name>/ for local projects or ./skills/<skill-name>/ for global installation. The SKILL.md file inside this directory serves as both the manifest and execution script.
The runtime, implemented in src/agent/, parses this file using regular-expression markers to extract:
- YAML front-matter declaring
name,description, and optionalargument-hint - XML-style markdown sections such as
<Purpose>,<Use_When>, and<Steps>that drive the interactive dialog and tool execution
Before loading, the validation logic in src/skill/validator.ts checks that mandatory sections exist, that YAML syntax is valid, and that declared triggers are unique. Any failure produces a ✗ Error: prefix message identifying the specific validation fault.
Required SKILL.md Sections
A valid SKILL.md must contain specific sections in the order expected by the parser. Each section uses XML-style tags within the markdown body.
Front-Matter Configuration
The file must begin with YAML front-matter between triple dashes:
---
name: hello-world
description: Print a friendly greeting; optionally persist it to a file.
argument-hint: "[name] [--output <path>]"
---
The name field determines the invocation command (/<name>), while argument-hint provides usage guidance displayed in help text.
and <Use_When>
The <Purpose> section contains a one-sentence high-level goal describing what the skill achieves. The <Use_When> section defines trigger conditions—comma-separated keywords or phrases—that help the dispatcher match user intent efficiently and avoid false positives.
<Do_Not_Use_When> and <Why_This_Exists>
Guard-rails in <Do_Not_Use_When> prevent misuse by specifying scenarios where the skill should refuse activation. The <Why_This_Exists> section provides maintenance context and design rationale, helping future contributors understand architectural decisions.
<Execution_Policy>
This section declares high-level execution rules governing:
- Synchronization: Whether steps run sequentially or support parallelism
- Model selection: Tier specifications (e.g.,
tier="LOW") for delegation - Error handling: Validation requirements and fallback strategies
- Path handling: Whether to create directories automatically or validate preconditions
The <Steps> section contains a numbered list of concrete actions. Each step can:
- Invoke sub-skills using the
$<skill>syntax - Call low-level tools like
omx explore,delegate, orstate_write - Request user input via
AskUserQuestion
Keep each step atomic—performing exactly one action or one tool call—to improve traceability and simplify the verification loop for architect and critic agents.
<Tool_Usage> (Optional)
Document required external dependencies, binaries, or low-level tools in this optional section. This transparency allows the orchestrator to warn if dependencies are missing before execution begins, preventing runtime surprises.
Step-by-Step: Creating a hello-world Skill
Create the directory structure:
mkdir -p ./.codex/skills/hello-world
Create ./.codex/skills/hello-world/SKILL.md with the following content:
---
name: hello-world
description: Print a friendly greeting; optionally persist it to a file.
argument-hint: "[name] [--output <path>]"
---
<Purpose>
Provide a quick, reusable way to say hello from the command line.
</Purpose>
<Use_When>
- User types `/hello-world` or mentions "say hello".
- Helpful in tutorials or when a placeholder message is needed.
</Use_When>
<Do_Not_Use_When>
- When the user needs a complex templating engine – use `/template` instead.
</Do_Not_Use_When>
<Why_This_Exists>
A tiny example for newcomers showing the required sections and how to use arguments.
</Why_This_Exists>
<Execution_Policy>
- Run synchronously – no background jobs.
- Validate arguments before proceeding.
- If `--output` is provided, ensure the target directory exists (create it if necessary).
- All errors are reported with a `✗ Error:` prefix.
</Execution_Policy>
<Steps>
1. **Parse arguments** – split the command line on spaces.
- `name` = first token (default `"world"`).
- If the token `--output` appears, the following token is `outputPath`.
2. **Generate greeting** – `greeting = "Hello, ${name}!"`.
3. **Print greeting** – output to the console (`println(greeting)`).
4. **Optional file write** – if `outputPath` is set:
- Ensure the directory exists: `mkdir -p $(dirname outputPath)`.
- Write the greeting to the file: `echo "${greeting}" > "${outputPath}"`.
- Report success: `✓ Wrote greeting to ${outputPath}`.
5. **Finish** – return a success message to the runtime.
</Steps>
<Tool_Usage>
- `delegate(role="executor", tier="LOW", task="write greeting file")` – used in step 4 when `--output` is present.
- `AskUserQuestion` – not needed; arguments are supplied directly.
</Tool_Usage>
Invoke the skill:
/hello-world Alice --output ./greeting.txt
The runtime parses the YAML front-matter, validates all mandatory sections, executes the five steps sequentially, prints Hello, Alice!, and writes the same text to ./greeting.txt while reporting ✓ Wrote greeting to ./greeting.txt.
Validation and Runtime Guarantees
Before executing any skill, oh-my-codex performs mandatory checks defined in the validation layer:
- Section completeness: Ensures
<Purpose>,<Use_When>,<Do_Not_Use_When>,<Why_This_Exists>,<Execution_Policy>, and<Steps>exist - YAML integrity: Verifies front-matter is syntactically correct
- Trigger uniqueness: Confirms no other skill claims the same invocation triggers
If validation fails, the runtime aborts with a ✗ Error: message indicating which section is missing or malformed, and the skill does not appear in /skill list output.
Best Practices for Production Skills
When writing complex skills for the oh-my-codex ecosystem, follow these guidelines derived from the source analysis:
- Keep steps atomic: Each
<Step>should perform exactly one action or tool call. This improves traceability and simplifies the verification loop for the architect/critic agents. - Use explicit triggers: Define clear, comma-separated keywords in
<Use_When>to minimize false positives from the dispatcher. - Limit hard-coded paths: Prefer relative paths anchored to the skill directory to ensure portability across machines and CI pipelines.
- Document dependencies: List required binaries or npm packages in
<Execution_Policy>so the orchestrator can pre-check availability. - Provide fallback messages: Use the
✗ Error:prefix for destructive actions to force user confirmation before irreversible changes.
Reference: Built-in Skill Templates
Study these canonical implementations in the Yeachan-Heo/oh-my-codex repository to model advanced patterns:
skills/skill/SKILL.md: The official template defining required sections and front-matter structure.skills/plan/SKILL.md: A complex example showing multi-step planning, consensus loops, and advanced tool usage patterns.skills/ralph/SKILL.md: Demonstrates persistence, background execution, and verification loops for long-running tasks.skills/worker/SKILL.md: Shows how meta-skills delegate work to other agents using parallelism.AGENTS.md(root): Defines the overall orchestration model, execution policies, and safety constraints that every skill must obey according to the repository's agent contract.
Summary
- Skills are self-contained
SKILL.mdfiles living under./.codex/skills/<skill-name>/(local) or./skills/<skill-name>/(global). - The format combines YAML front-matter with XML-style markdown sections (
<Purpose>,<Steps>, etc.) that the engine extracts using regex markers. - The execution engine in
src/agent/parses these sections sequentially, invoking sub-skills ($<skill>) or tools (delegate,state_write) as specified in the<Steps>list. - Validation logic in
src/skill/validator.tsensures mandatory sections exist, YAML is valid, and triggers are unique before runtime. - Reference
skills/skill/SKILL.mdfor the base template andskills/plan/SKILL.mdfor complex real-world patterns involving consensus and delegation.
Frequently Asked Questions
Where should I place my custom SKILL.md file?
Create a directory under ./.codex/skills/<skill-name>/ for project-local skills or ./skills/<skill-name>/ for global installation. Place the SKILL.md file inside this directory. The runtime discovers skills by scanning these paths and validates them using the logic in src/skill/validator.ts before making them available via the /<skill-name> command.
What happens if I forget a mandatory section like or ?
The validation engine rejects the skill during load time and reports a ✗ Error: message indicating which required section is missing. The skill will not appear in /skill list output and cannot be invoked until you add the missing section and the YAML front-matter passes syntax validation.
Can I execute arbitrary code inside a SKILL.md file?
No. The SKILL.md format is pure markdown interpreted by the engine in src/agent/—it never executes embedded code directly. You describe actions declaratively in <Steps> using tool calls like delegate or omx explore, or invoke other skills using the $<skill> syntax. This design ensures safety and portability across different environments.
How do I pass arguments to my custom skill?
Declare an argument-hint in the YAML front-matter to document the expected format. Inside <Steps>, describe how to parse the command line (e.g., splitting on spaces or parsing flags like --output). The runtime passes the raw argument string after the command name (/<skill-name> <arguments>), and your step logic handles tokenization and validation according to the rules defined in your <Execution_Policy>.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →