Risemi

How to install skills in Codex

Codex reads skills from .agents/skills in your repo and ~/.agents/skills in your home folder. How to install one, call it with $ and fix it when it hides.

6 min read · Updated November 8, 2026 · Risemi team

OpenAI Codex supports agent skills in the same SKILL.md format used by Claude Code, Cursor and others. A skill is a folder with a SKILL.md file: a name, a description, and instructions. Codex reads the name and description of every installed skill, and loads the full instructions when your task matches, or when you mention the skill by name.

This guide covers the Codex CLI and the Codex IDE extension. If skills are new to you, what agent skills are explains the idea in five minutes.

Where Codex looks for skills

Codex scans these locations:

ScopeFolderNotes
Repository.agents/skills/<skill-name>/In the current folder and every parent folder up to the repo root
User~/.agents/skills/<skill-name>/Available in every project
Admin/etc/codex/skills/Machine-wide, usually set by an administrator
SystemBundled with CodexIncludes skill-creator and skill-installer

The repository rule is useful in monorepos. If you start Codex in apps/api/, it reads apps/api/.agents/skills/, then apps/.agents/skills/, then the root .agents/skills/. So you can keep shared skills at the root and service-specific ones next to the code they describe.

One thing to watch: Codex does not merge skills that share a name. Give every skill a unique name.

Note that .agents/skills/ is the shared folder name. Cursor, Gemini CLI, GitHub Copilot and OpenCode read it too, so a skill you install for Codex at the repo level is often visible to teammates using those tools as well.

Step 1: Install the skill

Let Codex install it

Start Codex in your repository and paste one line:

Read https://risemi.io/p/tdd-red-green-loop/install.md and follow it to install the "tdd-red-green-loop" skill into this agent.

Replace the slug with the skill you want. Codex fetches the install guide and writes the folder to .agents/skills/<slug>/ (or to ~/.agents/skills/<slug>/ if you ask for a user-level install). Depending on your approval settings, it will ask before running commands or writing files outside the workspace. Free Risemi skills need a free account; paid ones need a one-time purchase or Risemi Pro.

Project: fresh `npm init -y` + `npm i -D vitest typescript` (Vitest 5.1.0, TypeScript strict). Every runner output below is pasted from the actual run.

Behaviour list (simplest first): 1. returns empty for blank input · 2. returns the address trimmed and lowercased when valid · 3. returns malformed when there is no @ · 4. returns malformed when there is more than one @ · 5. returns malformed when the domain has no dot · 6. returns too_long when the address is over 254 characters

Cycle 1: returns empty for blank input

```
[TDD] cycle 1/6  step RED  behaviour: returns empty for blank input
test:    src/validateEmail.test.ts > validateEmail > returns empty for blank input
ran:     npx vitest run src/validateEmail.test.ts -t "returns empty for blank input"
result:  FAIL  Error: Cannot find module './validateEmail' imported from <project>/src/validateEmail.test.ts
reason:  right (the unit under test does not exist yet: missing function, not a typo in the test)
changed: src/validateEmail.test.ts (+8, new file)
next:    minimum code in src/validateEmail.ts
```

```
[TDD] cycle 1/6  step GREEN  behaviour: returns empty for blank input
ran:     npx vitest run src/validateEmail.test.ts -t "returns empty for blank input" --reporter=verbose; npx vitest run src/validateEmail.test.ts
result:  PASS  Tests 1 passed (1)
changed: src/validateEmail.ts (+9, new file: result types + hard-coded `{ ok: false, error: 'empty' }`)
next:    refactor
```

Refactor: no refactor (hard-coded return is forced into the general version by cycle 2).

[Cycles 2–6 follow the same shape: each RED shows a real assertion mismatch such as `Tests 1 failed | 1 skipped (2)`, each GREEN the passing count, with refactors in cycles 5 and 6.]

Done

```
[TDD] DONE  cycles 6  tests added 6  suite PASS
ran:     npm test   (vitest run)   and   npx tsc -p .
result:  Test Files  1 passed (1) | Tests  6 passed (6); tsc exit 0
pre-existing failures: none (no tests existed)
found, not fixed: the 254 boundary itself (exactly 254 chars accepted) has no test; it passes today, so a test would be green on first run. 'a@.com' and 'a@b.' are accepted because the spec only asks for a dot in the domain.
```

No-fake-green check before every GREEN: no `.skip`/`.todo`, no assertion weakened, no test-only branch, nothing mocked.
SkillCodeFree
  • Antigravity
  • Claude Code
  • Codex
  • +3
Coding

Red-Green TDD Loop

Use it to make your coding agent build every change test-first: one failing test, the minimum code, a refactor, and a status block after each step.

0 installs
Free

Use the Risemi CLI

The command-line installer is shipping this week:

npx risemi login
npx risemi add tdd-red-green-loop --agent codex

Until it is on npm, use the line above or the ZIP.

Unzip it by hand

Download the ZIP from the product page and unzip it into the skills folder:

mkdir -p .agents/skills
unzip tdd-red-green-loop.zip -d .agents/skills/

Check that you ended up with .agents/skills/tdd-red-green-loop/SKILL.md and not an extra nested folder. For a user-level install, use ~/.agents/skills/ instead.

Codex's own installer

Codex ships a system skill called skill-installer. Typing $skill-installer followed by a skill name installs from OpenAI's curated list, and you can also ask it to fetch skills from other repositories. That route is handy for public skills; for Risemi products, use the install line or ZIP above.

Step 2: Restart if it does not appear

Codex detects skill changes automatically, so a new folder usually shows up without doing anything. If it does not, restart Codex: quit the CLI session and start it again, or reload the IDE window. Changes to Codex's config.toml always need a restart.

Step 3: Check that Codex sees it

In the Codex CLI or the IDE extension, run /skills. You get the list of available skills. You can also type $ in the composer: Codex suggests skills as you type their names. If yours is listed, it is installed.

Step 4: Use the skill

Implicitly. Describe the task. If it matches the skill's description, Codex can choose the skill by itself. With the test-first skill installed, "add rate limiting to the login endpoint" should start with a failing test.

Explicitly. Mention the skill with $, for example:

$tdd-red-green-loop add rate limiting to the login endpoint

Explicit mentions are the reliable option when you want a specific skill used, and they still work for skills that have implicit use turned off.

Optional: agents/openai.yaml

A skill folder can contain an optional agents/openai.yaml file with Codex-specific settings: a display name and icon for the app, tool dependencies, and an invocation policy. The setting you are most likely to need is:

policy:
  allow_implicit_invocation: false

With that set, Codex will not pick the skill on its own, but $skill-name still works. Use it for skills that take actions, like publishing or deploying, where you want to be the one who decides. Other agents ignore this file, so it does not break portability.

Turning a skill off

To disable a skill without deleting it, add an entry to ~/.codex/config.toml:

[[skills.config]]
name = "tdd-red-green-loop"
enabled = false

You can use path with the absolute path to the skill's SKILL.md instead of name. Restart Codex afterwards. To switch off the bundled system skills for one project, set enabled = false under [skills.bundled] in that project's .codex/config.toml (the project must be trusted).

Skills vs AGENTS.md

Codex also reads AGENTS.md files: a global one in ~/.codex and project ones from the repo root down to your current folder. AGENTS.md is loaded into every session, so keep it for short, always-true facts: build commands, test commands, conventions. Codex caps the combined size at 32 KiB, which is another reason not to stuff long procedures in there. A 150-line review checklist or debugging routine belongs in a skill, which costs only its description until it is used.

Troubleshooting

/skills does not list my skill

  • Confirm the path: .agents/skills/<name>/SKILL.md, exact capitals.
  • Make sure you started Codex inside the repository (or below the folder holding .agents/skills/). Codex walks up from where it starts, not down.
  • Check the frontmatter: it must start with --- on the first line and include both name and description, which Codex requires.
  • Check for a doubled folder from unzipping.
  • Restart Codex.

It is listed but never used automatically

The description is all Codex sees when deciding. Make it say what the skill does and when to use it, in words you would type in a request. Also check that agents/openai.yaml does not set allow_implicit_invocation: false, and that the skill is not disabled in config.toml. Our SKILL.md writing guide has examples of descriptions that trigger.

Two skills fight over the same name

Codex does not merge same-name skills. Rename one folder and its name field.

Next steps

See skills that run in Codex or filter the catalog by Codex. If you also use other agents, the Claude Code and Cursor guides cover their folders.

FAQ

Where do I put skills for Codex?

Put repository skills in `.agents/skills/<skill-name>/` and personal skills in `~/.agents/skills/<skill-name>/`. Codex reads `.agents/skills/` in the folder you start in and every parent up to the repo root.

How do I invoke a skill in Codex?

Mention it with `$` followed by the skill name, for example `$tdd-red-green-loop`, or run `/skills` to pick from the list. Codex can also choose a skill automatically when your task matches its description.

Do I need to restart Codex after installing a skill?

Usually not, since Codex detects skill changes automatically. If a new or updated skill does not show up, restart Codex. Changes to `config.toml` always need a restart.

Do skills work in the Codex IDE extension as well as the CLI?

Yes. OpenAI's documentation lists standalone skills as available in the Codex CLI, the IDE extension and the ChatGPT desktop app. Both the CLI and the IDE extension support `/skills` and `$` mentions.

Can I use the same skill in Codex and Claude Code?

Yes, the `SKILL.md` format is shared. Codex reads `.agents/skills/` and Claude Code reads `.claude/skills/`, so for a team using both, keep a copy in each folder or let the Risemi installer place it for each agent.

Project: fresh `npm init -y` + `npm i -D vitest typescript` (Vitest 5.1.0, TypeScript strict). Every runner output below is pasted from the actual run.

Behaviour list (simplest first): 1. returns empty for blank input · 2. returns the address trimmed and lowercased when valid · 3. returns malformed when there is no @ · 4. returns malformed when there is more than one @ · 5. returns malformed when the domain has no dot · 6. returns too_long when the address is over 254 characters

Cycle 1: returns empty for blank input

```
[TDD] cycle 1/6  step RED  behaviour: returns empty for blank input
test:    src/validateEmail.test.ts > validateEmail > returns empty for blank input
ran:     npx vitest run src/validateEmail.test.ts -t "returns empty for blank input"
result:  FAIL  Error: Cannot find module './validateEmail' imported from <project>/src/validateEmail.test.ts
reason:  right (the unit under test does not exist yet: missing function, not a typo in the test)
changed: src/validateEmail.test.ts (+8, new file)
next:    minimum code in src/validateEmail.ts
```

```
[TDD] cycle 1/6  step GREEN  behaviour: returns empty for blank input
ran:     npx vitest run src/validateEmail.test.ts -t "returns empty for blank input" --reporter=verbose; npx vitest run src/validateEmail.test.ts
result:  PASS  Tests 1 passed (1)
changed: src/validateEmail.ts (+9, new file: result types + hard-coded `{ ok: false, error: 'empty' }`)
next:    refactor
```

Refactor: no refactor (hard-coded return is forced into the general version by cycle 2).

[Cycles 2–6 follow the same shape: each RED shows a real assertion mismatch such as `Tests 1 failed | 1 skipped (2)`, each GREEN the passing count, with refactors in cycles 5 and 6.]

Done

```
[TDD] DONE  cycles 6  tests added 6  suite PASS
ran:     npm test   (vitest run)   and   npx tsc -p .
result:  Test Files  1 passed (1) | Tests  6 passed (6); tsc exit 0
pre-existing failures: none (no tests existed)
found, not fixed: the 254 boundary itself (exactly 254 chars accepted) has no test; it passes today, so a test would be green on first run. 'a@.com' and 'a@b.' are accepted because the spec only asks for a dot in the domain.
```

No-fake-green check before every GREEN: no `.skip`/`.todo`, no assertion weakened, no test-only branch, nothing mocked.
SkillCodeFree
  • Antigravity
  • Claude Code
  • Codex
  • +3
Coding

Red-Green TDD Loop

Use it to make your coding agent build every change test-first: one failing test, the minimum code, a refactor, and a status block after each step.

0 installs
Free
Phase 1: Root cause investigation
Full suite: FAIL test_expired_coupon_rejected_twice (tests/test_checkout.py:16) AssertionError: Coupon(code='OLD50', …expires_at=2020-01-01…) is not None.
In isolation the same test fails at a different line (17): AssertionError: 50.0 != 100.0. So the first lookup in a process is rejected and every later lookup is accepted; in the full suite the first lookup was done by test_expired_coupon_rejected. Cross-test pollution through module-level state.
Cache probe at the boundary: cache before [] → 1st None → cache after ['OLD50'] → 2nd Coupon(OLD50). Docstring says the cache was added in 3f2a1c9 "to cut DB reads": that is the regression point.
Trace (root-cause-tracing.md): apply_coupon → get_coupon → `if code in _CACHE: return _CACHE[code]`. get_coupon writes the coupon to _CACHE before the expiry check, and the cache-hit branch has no expiry check at all.

Phase 2: Pattern analysis
Working path: cache miss → _load → expiry check. Broken path: cache hit. Expiry depends on `now`, passed per call, so it cannot be a cached property; "don't cache expired coupons" alone would still serve a coupon cached while valid after it expires.

Phase 3: Hypothesis
"get_coupon returns cached coupons without re-checking expires_at against the caller's now; the cache was added around the lookup but the validity check stayed only on the miss path." Confirmed by the probe above.

Phase 4: Implementation
Failing test first: test_cached_coupon_rechecked_for_expiry (look up while valid, then after expiry) plus a setUp that clears the module cache. Before the fix: 5 tests, 2 failures, both for the expected reason.
Fix at the source: the cache stores the raw record; the expiry check runs on every lookup, cached or not.

    c = _CACHE.get(code)
    if c is None:
        c = _load(code)
        if c is None:
            return None
        _CACHE[code] = c
    if c.expires_at < now:
        return None
    return c

Verification: python3 -m unittest -v → Ran 5 tests … OK. The originally failing test in isolation, 3 runs: OK, OK, OK. Fix attempts: 1.
SkillCodePro
  • Claude Code
  • Codex
  • Copilot
  • +2
Coding

Systematic Debugging Loop

Stops your coding agent from guessing: root cause first, one hypothesis at a time, failing test before the fix.

0 installs
$9.99

More guides