Write an Agent Skill for ChatGPT and Codex
Write a skill with SKILL.md, scripts and references, load it in Codex, test when it triggers, and bundle it in a plugin so it also works in ChatGPT.
A skill is a folder of instructions (plus optional scripts and reference files) that teaches ChatGPT or Codex how to do one job your way: draft release notes, review a migration, prepare a weekly report. Skills follow the open Agent Skills standard, so a well-written skill can work across tools that support it.
The model doesn't read every skill all the time. It starts with each skill's name and description, and loads the full instructions only when it decides a skill fits the task. That makes the description the most important line you'll write.
This guide builds a release-notes skill, tests it in Codex, and packages it so it works in ChatGPT too.
Before you start#
- Codex installed (
npm install -g @openai/codex) and signed in, or the ChatGPT desktop app. - A task you repeat and already know how to do well. Skills capture a process; they don't invent one.
Tip: You don't have to write the files by hand. Run
$skill-creatorin Codex, or@skill-creatorin a ChatGPT Work chat, and describe the workflow. It asks when the skill should trigger and whether it needs scripts, then drafts the folder. The steps below explain what it produces, so you can review and edit it.
1. Create the skill folder#
A skill is a directory with a required SKILL.md and optional extras:
release-notes/
├── SKILL.md # required: front matter + instructions
├── scripts/ # optional: code the agent can run
├── references/ # optional: docs to read when needed
├── assets/ # optional: templates and other files
└── agents/
└── openai.yaml # optional: UI metadata, invocation policy, dependenciesWhere you put it decides where Codex finds it:
| Scope | Location | Use for |
|---|---|---|
| Repo | .agents/skills/ in the current folder, any parent folder, or the repo root | Skills for one project, checked into Git |
| User | $HOME/.agents/skills/ | Your personal skills, in every project |
| Admin | /etc/codex/skills/ | Machine-wide defaults |
| System | Bundled with Codex | Built-ins such as skill-creator |
For this guide, create it in a repository:
mkdir -p .agents/skills/release-notes/{scripts,references}Codex follows symlinked skill folders, so you can keep skills in one place and link them into several repos.
2. Write SKILL.md#
.agents/skills/release-notes/SKILL.md:
---
name: release-notes
description: Draft release notes from commits merged since the last Git tag. Use when the user asks for release notes, a changelog entry or a "what shipped" summary. Do not use for writing commit messages or PR descriptions.
---
Draft release notes for the changes since the most recent tag.
1. Run `scripts/changes_since_tag.sh` from the repository root. It prints the
last tag, then one line per commit since that tag.
2. If the script reports no tags, ask the user which commit to start from. Do
not guess.
3. Group the changes under these headings, in this order: Added, Changed,
Fixed, Removed. Skip empty headings.
4. Write each item as one sentence in plain language for users, not
developers. Drop pure refactors, test-only and CI-only changes.
5. Follow the tone and formatting rules in `references/style.md`.
6. End with the version range, for example `v1.4.0...HEAD`.
Never invent changes that aren't in the script output. If an item is unclear,
list it under "Needs review" instead of guessing what it does.The rules for the front matter:
nameanddescriptionare both required.- Front-load the description. Put the job and the trigger phrases first. When many skills are installed, Codex shortens descriptions to fit its budget, so the start must stand on its own.
- Say when not to use it. Boundaries stop the skill firing on nearby tasks.
For the body: write numbered, imperative steps with clear inputs and outputs. Say what to do when information is missing. Keep it to one job; split a skill when parts of it have different triggers.
3. Add a script and a reference file#
Use scripts/ when a step needs to be deterministic. Instructions are enough for most steps, so don't add code that the model could do reliably on its own.
.agents/skills/release-notes/scripts/changes_since_tag.sh:
#!/usr/bin/env bash
set -euo pipefail
last_tag=$(git describe --tags --abbrev=0 2>/dev/null || true)
if [ -z "$last_tag" ]; then
echo "NO_TAGS"
exit 0
fi
echo "LAST_TAG=$last_tag"
git log --no-merges --pretty=format:'%h %s' "$last_tag"..HEADchmod +x .agents/skills/release-notes/scripts/changes_since_tag.shUse references/ for longer material the agent should read only when it needs it, such as style guides, schemas and examples. SKILL.md stays short, and the reference loads only when the skill runs.
.agents/skills/release-notes/references/style.md:
# Release notes style
- Present tense: "Adds", "Fixes".
- No internal ticket numbers or author names.
- Link to docs pages when a feature has one.
- Maximum 12 items; group minor fixes as "Other fixes".4. Optional: agents/openai.yaml#
This file controls how the skill appears in the ChatGPT desktop app, whether the model may pick it on its own, and which MCP tools it depends on:
interface:
display_name: "Release notes"
short_description: "Draft release notes since the last tag"
policy:
allow_implicit_invocation: falseallow_implicit_invocation defaults to true. Set it to false for skills that should only run when you ask for them by name. If a skill relies on an MCP server, declare it under dependencies.tools with its type, value, transport and url, and still tell the model in SKILL.md which tools to call and in what order.
5. Run it in Codex#
Start Codex in the repository. New and changed skills are detected automatically; restart Codex if one doesn't show up.
There are two ways a skill runs:
- Explicitly: type
$release-notes, or run/skillsto pick it from a list. - Implicitly: ask "Write release notes for this version" and Codex should choose the skill from its description.
$release-notes for everything since the last tagCheck that Codex ran the script, used the headings, and followed the style file.
6. Test when it triggers#
Run a small set of prompts and record what happens for each:
| Prompt type | Example | Expected |
|---|---|---|
| Direct | "Draft release notes" | Skill runs |
| Indirect | "What shipped since v1.4?" | Skill runs |
| Missing input | Repo with no tags | Asks where to start |
| Negative | "Write a commit message for this diff" | Skill doesn't run |
| Edge case | Only CI changes since the tag | Says there's nothing user-facing |
If it fires at the wrong times, fix the description. If it fires correctly but the output is off, fix the instructions. Re-run the set after every change.
The Plugin Eval plugin can help run this kind of evaluation locally, with reports that explain token budgets.
7. Use the skill in ChatGPT#
Where a skill works depends on how you install it:
- Standalone skill folders work in the ChatGPT desktop app, the Codex CLI and the IDE extension. In the desktop app, open Skills in the sidebar to see skills from your projects.
- Skills bundled in a plugin also work in Chat and Work in ChatGPT on the web, desktop and mobile.
In ChatGPT, type @ to pick a skill explicitly, or just describe the task and let ChatGPT match it.
8. Bundle it in a plugin#
To share a skill, or use it on ChatGPT web and mobile, package it as a plugin. A skills-only plugin needs just a manifest and a skills/ folder:
release-notes-plugin/
├── plugin.json
└── skills/
└── release-notes/
├── SKILL.md
├── scripts/changes_since_tag.sh
└── references/style.md{
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
"name": "release-notes-plugin",
"version": "1.0.0",
"description": "Draft user-facing release notes from Git history."
}Portable plugins find skills in skills/ automatically. Add the plugin to a local marketplace to install it, or run $plugin-creator to scaffold the manifest and marketplace entry for you. A plugin can also bundle several related skills, or skills alongside an MCP server, the way the Google Drive plugin combines Drive, Docs, Sheets and Slides skills with its connector.
Publishing it to the directory is covered in Publish a ChatGPT plugin.
Troubleshooting#
| Problem | Fix |
|---|---|
| Skill doesn't appear | Check the folder location and that SKILL.md has both name and description. Restart Codex. |
| Never triggers implicitly | Put trigger phrases at the start of the description, and check allow_implicit_invocation. |
| Triggers too often | Add "Do not use for…" boundaries to the description. |
| Two skills with the same name | Codex doesn't merge them; both appear. Rename one. |
| Too many skills installed | The initial skill list is capped at about 2% of the context window, so descriptions get shortened and some skills may be left out. Disable ones you don't use. |
To turn a skill off without deleting it, add this to ~/.codex/config.toml and restart Codex:
[[skills.config]]
path = "/path/to/skill/SKILL.md"
enabled = falseNext steps#
- Browse skill-based plugins in the plugins directory, such as Superpowers.
- Install plugins in Codex: Use plugins and MCP servers in Codex.
- Give your skill live data with an MCP server: Build your first ChatGPT app.
