How to Define Skills in an OpenAI Plugin Structure: A Complete Guide

To define a skill in an OpenAI plugin structure, create a dedicated directory under plugins/<plugin-name>/skills/ containing a SKILL.md file with YAML front matter, an agents/openai.yaml UI specification, and optional helper scripts that implement the runtime logic.

OpenAI plugins are organized as collections of reusable capabilities called skills, each residing in the openai/plugins repository. Learning how to define skills in an OpenAI plugin structure enables you to extend Codex with custom tools that integrate seamlessly into the agentic workflow. Every skill follows a strict three-part architecture that separates metadata declaration from implementation logic.

The Three Core Components of an OpenAI Plugin Skill

Each skill lives in its own directory under plugins/<plugin-name>/skills/<skill-name>/ and requires three mandatory parts to function within the Codex ecosystem.

SKILL.md: Metadata and Documentation

The SKILL.md file serves as the canonical declaration of the skill's identity. It must begin with a YAML front-matter block that registers the skill with the system:

---
name: Zotero
description: Use Zotero Desktop to search your library and add citations
---

The name field becomes the skill identifier used in prompts (e.g., $Zotero), while the description appears in the plugin catalogue. Following the front matter, the markdown body contains usage guidelines, command references, workflow documentation, and safety policies. According to the source code in plugins/zotero/skills/zotero/SKILL.md, this file should remain self-contained so users understand capabilities without referencing external documentation.

agents/openai.yaml: UI and Prompt Configuration

The agents/openai.yaml file, located at plugins/<plugin-name>/skills/<skill-name>/agents/openai.yaml, defines how the skill appears in the UI and how the model interacts with it:

interface:
  display_name: "Zotero"
  short_description: "Search Zotero and add citations"
  icon_small: "./assets/icon.png"
  default_prompt: "Use $Zotero to search my Zotero library..."

This specification dictates which model to invoke, what system prompt to prepend to user queries, and which icons render in the interface. The default_prompt is automatically injected when the skill is selected, establishing the context for the LLM.

Helper Scripts and Assets: Runtime Implementation

The actual logic resides in executable helpers stored under plugins/<plugin-name>/skills/<skill-name>/scripts/. These scripts must use stdlib-only Python (no external dependencies) and are executed by Codex via the python3 command line. Static assets such as icons and images belong in the assets/ directory and are referenced relative to the skill root.

How Skills Are Wired Together

Understanding the runtime flow clarifies how the three components interact when a user invokes a capability:

  1. Registration – Codex loads the YAML front matter from SKILL.md to register the skill identifier and description.

  2. Prompt Construction – When selected, the system merges the default_prompt from agents/openai.yaml with the user's query, creating a contextualized instruction set for the model.

  3. Execution – The model identifies the need to call a helper script (e.g., python3 <plugin-root>/skills/zotero/scripts/zotero.py --json "query") and executes it via the command line.

  4. Response Parsing – The script outputs JSON or plain text, which the model receives and uses to render the final response to the user.

Creating a New Skill with the Plugin Creator

The repository provides a scaffolding tool to generate the complete directory structure. Run the following command from the repository root:

python3 .agents/skills/plugin-creator/scripts/create_basic_plugin.py \
    my-plugin \
    --path ./plugins \
    --marketplace-path ./.agents/plugins/marketplace.json \
    --with-skills --with-scripts --with-assets --with-marketplace

This generates:


plugins/my-plugin/
└─ skills/
   └─ my-skill/
       ├─ SKILL.md
       ├─ agents/
       │   └─ openai.yaml
       ├─ scripts/
       │   └─ my_script.py
       └─ assets/
           └─ icon.png

The generated SKILL.md includes template sections for "Fast starts", "Workflow", and "Output standards". Refer to .agents/skills/plugin-creator/SKILL.md for detailed scaffolding options.

Best Practices for Skill Definition

Follow these patterns established in the plugins/zotero and plugins/github/skills/yeet implementations:

  • Keep documentation self-contained – All commands, safety notes, and usage examples must reside in SKILL.md so users understand the skill without external references.

  • Expose JSON output – Helper scripts should implement a --json flag (as demonstrated in the Zotero skill) to return machine-readable data that Codex can parse reliably.

  • Declare safety guards – For write-heavy actions like commits or pushes, explicitly document required user confirmations in the "Write Safety" section, following the pattern in plugins/github/skills/yeet/SKILL.md.

  • Version-control assets – Store icons as PNG or SVG files under assets/ and reference them with relative paths in agents/openai.yaml.

Complete Example: Building an Echo Skill

Here is a minimal, functional skill that echoes user input back unchanged.

SKILL.md Definition

Create plugins/echo/skills/echo/SKILL.md:

---
name: echo
description: Return the supplied text unchanged – useful for quick tests.
---

# Echo

## Fast start

```bash
python3 <plugin-root>/skills/echo/scripts/echo.py "Hello world"

Workflow

  1. The model receives the user request.
  2. It injects the request into the default prompt (Use $echo …).
  3. The helper prints the payload as JSON:
python3 <plugin-root>/skills/echo/scripts/echo.py --json "Hello world"

# → {"result":"Hello world"}

Output standards

  • Always return a JSON object with a single result field.
  • No side‑effects; safe for any user context.

### Agent Configuration

Create [`plugins/echo/skills/echo/agents/openai.yaml`](https://github.com/openai/plugins/blob/main/plugins/echo/skills/echo/agents/openai.yaml):

```yaml
interface:
  display_name: "Echo"
  short_description: "Echo back whatever you give me"
  icon_small: "./assets/icon.png"
  icon_large: "./assets/icon.png"
  default_prompt: "Use $echo to repeat the user’s input exactly."

Helper Script Implementation

Create plugins/echo/skills/echo/scripts/echo.py:

#!/usr/bin/env python3
import json, sys

if "--json" in sys.argv:
    # Strip the flag and any leading option names

    text = " ".join(arg for arg in sys.argv[1:] if not arg.startswith("--"))
    print(json.dumps({"result": text}))
else:
    print(" ".join(sys.argv[1:]))

Runtime Flow

When a user requests "Please repeat the phrase 'quick brown fox'", Codex constructs the prompt:


Use $echo to repeat the user’s input exactly.

User: Please repeat the phrase 'quick brown fox'.

Codex executes the helper and receives {"result":"quick brown fox"}, then renders the final response:


quick brown fox

Summary

  • Three files are mandatory: SKILL.md (with YAML front matter), agents/openai.yaml, and the optional but typical helper scripts under scripts/.
  • Directory structure matters: Skills must reside at plugins/<plugin-name>/skills/<skill-name>/ to be discovered by the Codex runtime.
  • Use stdlib-only Python: Helper scripts run via python3 command line and cannot rely on external packages.
  • JSON output preferred: Implement --json flags for reliable machine-readable communication between scripts and the model.
  • Safety documentation is critical: Document write-operation safeguards explicitly in SKILL.md, as shown in the GitHub yeet skill.

Frequently Asked Questions

What is the mandatory file structure for an OpenAI plugin skill?

Every skill requires a SKILL.md file (containing YAML front matter with name and description fields) and an agents/openai.yaml file (containing the interface configuration). These must reside in plugins/<plugin-name>/skills/<skill-name>/. Helper scripts are optional but typically placed in a scripts/ subdirectory.

How does the SKILL.md front matter connect to the Codex runtime?

The first three lines of SKILL.md contain a YAML block that Codex reads during skill discovery to register the identifier. The name field becomes the invocation token (e.g., $Zotero), while the description populates the plugin catalogue UI. This registration happens before any code execution occurs.

Can skills depend on external Python packages?

No. Helper scripts must be stdlib-only and execute via the system's python3 binary without external dependencies. As implemented in the openai/plugins repository, scripts like zotero.py rely solely on standard library modules to ensure portability and security.

How do I add safety guards to prevent destructive operations?

Document safety requirements in the "Write Safety" section of SKILL.md, explicitly stating required user confirmations (e.g., "Never push without confirming scope"). For write-heavy skills like the GitHub yeet skill, include policy notes that Codex can reference to ensure destructive actions receive explicit user approval before execution.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →