PTENES
MODULE 3.2

🎯 Skills in Codex and the openai.yaml sidecar

The peculiarity of openai.yaml, the hidden description limit, the lack of backtick-bang, and why $skill instead of /skill.

7
Topics
35
Minutes
Inter.
Level
Practical
Type

🎯What you get here

Understand exactly what changes in a skill when porting from Claude to Codex β€” where it goes, what needs adapting, and how the openai.yaml sidecar solves the MCP deps + branding problem.

Detailed content

1

πŸ“¦ Skill in Codex β€” .agents/skills/ not .codex/skills/

This is the first thing that causes confusion. People coming from Claude think: ".claude/skills/ in Claude β†’ .codex/skills/ in Codex". Wrong. Skill lives in .agents/skills/.

Why .agents/ and not .codex/

.agents/ is the convention used by the open spec Agent Skills (agentskills.io). Any tool that follows the spec reads from there. Codex simply follows the convention instead of inventing its own path.

Result: your skill in .agents/skills/ works in Codex today, and will work in Cursor/Gemini/any compatible tool tomorrow, without moving the file.

Correct paths

~/.agents/skills/<nome>/             ← global (suas skills)
./.agents/skills/<nome>/             ← projeto (skills do repo)

# NÃO existe:
.codex/skills/                       ← Codex nΓ£o enxerga
.codex/agents/skills/                ← idem

⚠️Error symptom

"I added the skill, but $minha-skill doesn’t trigger." β†’ Check the PATH first. It’s probably in .codex/skills/. Move to .agents/skills/, refresh Codex and it works again.

Key concepts

.agents/skills/
Required path
Open spec
agentskills.io
Portability
Other tools read
Manual refresh
Plugins β†’ reload
2

πŸ“ SKILL.md β€” almost identical to Claude’s

The SKILL.md file itself is practically the same. That’s why the spec works: YAML frontmatter with name e description, Markdown body. These are the 4 things that always match.

SKILL.md in Codex

---
name: revisar-pr
description: Use when the user asks to review a PR or diff.
---

# Revisar PR

## Passo a passo

1. Identifica a PR
2. LΓͺ diff completo
3. Verifica bugs/edge cases/security
4. Retorna findings categorizados

βœ“ What ALWAYS works

  • β€’ Frontmatter name + description
  • β€’ Body in standard markdown
  • β€’ Folders scripts/, references/, assets/
  • β€’ Relative references (./references/x.md)
  • β€’ Headings, lists, code blocks

βœ— What it does NOT port

  • β€’ allowed-tools in frontmatter (ignored)
  • β€’ disable-model-invocation (ignored)
  • β€’ Backtick-bang `!cmd` (becomes text)
  • β€’ Description > 8KB (silently truncated)
  • β€’ model: opus in frontmatter (not respected)

πŸ’‘The 4 portable pillars

The Agent Skills spec defines exactly 4 things in common: file name (SKILL.md), the name and description fields, Markdown body, folder convention. Keep your skill aligned with these 4 pillars and it will move to the other runtime without friction.

Key concepts

4 pillars
Common spec
Plain Markdown
No custom extension
Directory conventions
scripts/refs/assets
No extras
Which become sidecars
3

πŸ“Ž The agents/openai.yaml sidecar

This is where the detail that makes Codex most distinctive lives: everything that is runtime-specific (branding for the UI, MCP server dependencies, behavior flags) goes in a separate file β€” agents/openai.yaml inside the skill folder.

Complete structure with sidecar

.agents/skills/minha-skill/
β”œβ”€β”€ SKILL.md                ← obrigatΓ³rio (spec)
β”œβ”€β”€ agents/
β”‚   └── openai.yaml         ← SIDECAR do Codex
β”œβ”€β”€ scripts/
β”œβ”€β”€ references/
└── assets/

openai.yaml example

# Branding pra UI do Codex
branding:
  display_name: "Revisar PR"
  icon: "πŸ”"
  category: "code-review"

# MCP servers requeridos pela skill
mcp_servers:
  - name: github
    command: npx
    args: ["-y", "@modelcontextprotocol/server-github"]
    env:
      GITHUB_TOKEN: "${GITHUB_TOKEN}"

# Flags de comportamento
hidden: false
require_confirmation: true
🎨

Branding

Display name, icon, category. It appears in the UI. Without these, it looks generic.

πŸ”Œ

MCP deps

Skill declares the MCPs it needs. Installation is turnkey.

πŸŽ›οΈ

Flags

Hidden, require_confirmation, etc. Behavior per skill.

It’s optional

Without openai.yaml the skill works. You only lose refinements: no icon in the UI, generic branding, and MCP dependencies must be installed manually outside the skill. With a sidecar, the experience is polished.

Key concepts

Sidecar pattern
Separate metadata
Opt-in
Skill runs without
Turnkey MCP
Declares a dependency
UI branding
Icon, name
4

πŸ“ The hidden description limit (~8K)

Codex has a undocumented limit of about 8,000 characters for the description when indexed in the catalog. Above that, the description is truncated β€” and your skill loses the triggers at the end.

🚨The dangerous scenario

  1. You create a Claude skill with a long description (15KB)β€”it works well there
  2. Direct entry point to Codex
  3. Codex truncates at ~8K. The triggers at the end disappear.
  4. Skill seems to work (it still triggers on some prompts), but misses some cases
  5. You never find out because there’s no errorβ€”it’s silent

Front-loading technique

Put the most important triggers and examples in the first 1–2KB. The rest can come later (and can be cut without a fuss).

// CERTO β€” triggers no topo
description: |
  Use when reviewing PRs.
  Triggers: "revisa PR", "review pull request", "code review".
  Examples: "revisa PR #123", "review da branch atual".

  More context (pode ser truncado): ...

// ERRADO β€” triggers no fim
description: |
  This skill specializes in deep technical code review with focus on
  correctness, security, and edge cases. It analyzes pull requests
  by reading the full diff and ... [muito mais texto] ...
  Triggers: "revisa PR" ← truncado, nunca alcanΓ§a

🦜Polyskill anticipates

The polyskill Codex adapter automatically front-loads the content: it takes the triggers from the portable description and moves them to the top when generating output for Codex. You don't have to think about it.

Key concepts

~8K limit
Undocumented
Silent truncation
No errors
Front-loading
Triggers at the top
Automatic polyskill
Resolve at build time
5

🚫 No native backtick-bang β€” how to work around it

Codex doesn’t interpret `!cmd` (backtick-bang) as shell execution before the prompt. A skill that depends on this to inject dynamic context (git status, current log, branch) needs adaptation.

πŸ”· Claude (original)

Branch: `!git branch --show-current`

Último commit:
`!git log -1 --oneline`

Com base no acima, sugira...

The command RUNS. The result is already in the prompt.

🟣 Codex (fallback prose)

Before you start, run:
- `git branch --show-current`
- `git log -1 --oneline`

Based on the results, suggest...

The agent RUNS the commands when it reads the skill.

Alternative: delegated script

If you just want idempotent, structured output, put the logic in a script:

# scripts/context.sh
#!/bin/bash
echo "Branch: $(git branch --show-current)"
echo "Commit: $(git log -1 --oneline)"

# SKILL.md
Antes de comeΓ§ar, rode `./scripts/context.sh` e leia o output.

🦜Polyskill when porting

When you import a Claude skill with backtick-bang, the polyskill Codex adapter automatically rewrites as fallback prose. It’s not magicβ€”it’s simple and it works. You trade a little elegance for portability.

Key concepts

No build-time injection
Codex doesn’t have
Fallback prose
"Run X and analyze"
Delegated script
Logic in sh
Polyskill rewrites
Automatic on import
6

πŸ”Œ MCP servers in Codex

Same MCP spec. Same server runs. Only the declaration changes β€” TOML instead of JSON, inside the config.toml or in the sidecar openai.yaml of the skill (when MCP is a specific dependency).

πŸ”· Claude (.mcp.json)

{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@mcp/github"],
      "env": {
        "TOKEN": "$GH_TOKEN"
      }
    }
  }
}

🟣 Codex (config.toml)

[mcp_servers.github]
command = "npx"
args = ["-y", "@mcp/github"]

[mcp_servers.github.env]
TOKEN = "${GH_TOKEN}"

Where to declare β€” config.toml Γ— sidecar

🌍
config.toml (global or project): MCP that applies to ALL skills/agents. Github, database, etc.
πŸ“¦
openai.yaml (skill sidecar): MCP that ONLY that skill needs. Keeps the skill self-contained β€” install it alongside.

Key concepts

Same MCP spec
Shared server
JSON β†’ TOML
Only the syntax changes
Global vs. skill
config.toml Γ— sidecar
Self-contained
Sidecar installs MCP
7

$ Skill invocation $skill β€” not /skill

Codex uses the dollar sign for explicit skill invocation, leaving slash for built-in commands. $nome-skill instead of /nome-skill. A small detail that catches you on day one.

πŸ”· Claude Code

/review             ← skill OU slash command
/plan               ← built-in
/output-style x     ← built-in

Everything is a slash command. No separation.

🟣 Codex

$review            ← skill
/help              ← built-in (Codex)
/model             ← built-in (Codex)

Separation: $ for skills, / for built-ins.

πŸ’‘Autocomplete helps

Type $ and Codex suggests the available skills. Even if you forget it’s a dollar sign, not a slash, autocomplete quickly corrects it.

Key concepts

$ = skill
Invocation sigil
/ = built-in
Reserved
kebab-case
Skill Name
Autocomplete
Lists skills

🎯Module summary

βœ“
Skill in .agents/skills/ β€” not .codex/skills/. Convention from the open spec.
βœ“
SKILL.md practically the same as Claude β€” 4 shared pillars; extras become sidecars.
βœ“
openai.yaml = branding + MCP + flags β€” opt-in, but it makes a difference in the experience.
βœ“
Hidden ~8K description limit β€” manual front-loading or polyskill solves it.
βœ“
No backtick-bang β€” use fallback prose or a delegated script.
βœ“
MCP in TOML β€” global in config.toml, per skill in openai.yaml.
βœ“
$skill, not /skill β€” / is reserved for Codex built-ins.

Next track:

T4 β€” Converting your project (prompt template + checklist + 5 pitfalls)