Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,13 @@ paths, tool installation, subscription, or credentials as a consumer default.
`$skill-creator` when those workflows are available.
- Keep every skill focused on one recognizable goal. Put essential procedure in
`SKILL.md` and detailed variants in directly linked `references/` files.
- Keep `agents/openai.yaml` aligned with its skill as UI and invocation
metadata; do not treat that file as a custom execution agent definition.
- Keep `agents/openai.yaml` aligned with its skill. It is the harness-facing
sidecar covering `interface` presentation, `dependencies.tools` MCP
declarations, and `policy` (`allow_implicit_invocation`, product
restrictions); do not treat that file as a custom execution agent definition.
A declared MCP dependency is metadata only — it neither installs nor
authenticates a server, so the capability check, fallback, and credential
handling stay in the skill.
- Package a custom agent only when current official Codex documentation defines
the target discovery and packaging contract. Otherwise use a focused skill or
normal Codex task coordination.
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ Dogfoods the marketplace by providing skills to:
- validate catalogs, manifests, skills, and portable path contracts; and
- translate Claude Code or Cursor plugins into Codex-native packages.

`codex-operations` provides portable skills to:
### `codex-operations`

Provides portable skills to:

- coordinate multi-task, multi-agent, and long-running Codex work; and
- find evidence-backed opportunities for reusable skills from bounded local
Expand Down
67 changes: 53 additions & 14 deletions docs/CODEX-CAPABILITY-CHEAT-SHEET.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,23 @@

<!-- markdownlint-disable MD013 -->

Quick reference for choosing and explicitly invoking Codex skills. This is a
user-facing snapshot, verified on 2026-08-05 against the live official docs and
the installed Codex CLI. Availability can vary by release, plan, workspace,
platform, and installed plugins.
Quick reference for choosing and explicitly invoking Codex skills. Availability
can vary by release, plan, workspace, platform, and installed plugins.

This page mixes two kinds of claim, and they carry different verification
dates. Do not read one date as covering the other.

| Claim | Basis | Last verified |
| --- | --- | --- |
| Invocation grammar and CLI syntax | Codex CLI source (`openai/codex`, `main`) | 2026-08-30 |
| Built-in system skill roster | Codex CLI source: skills embedded in the binary | 2026-08-30 |
| Bundled and runtime plugin roster, and the `latex` example | One operator's installed environment | 2026-08-05, **not re-verified since** |

The bundled and runtime plugin table below is an environment snapshot, not an
entitlement list. It was captured from one account on one platform and cannot
be re-verified from source, because that roster is served at run time. Treat it
as an illustration of the naming pattern and confirm the live set with
`/plugins` or `codex plugin list --available --json`.

## The short version

Expand All @@ -22,10 +35,18 @@ matters. In Codex CLI, `/skills` browses skills and `/plugins` browses plugins.
After installing a plugin, start a new task or CLI session so its skills are
discovered.

The namespace is not cosmetic. Codex qualifies a skill's name at load time with
the name from the nearest plugin manifest above it, so a skill named `search`
inside a plugin named `sample` is loaded as `sample:search`. A `$` mention is
matched against that qualified name, so the bare `$search` form does not
resolve for a plugin-provided skill. Built-in system skills sit outside any
plugin manifest, so they keep the bare `$skill-name` form.

## Built-in system skills

These are the user-facing system skills available in the verified Codex
environment. They are skills, not plugins.
These skills are embedded in the Codex CLI binary and unpacked into
`CODEX_HOME/skills/.system` on startup; no plugin install is needed. They are
skills, not plugins.

| Capability | Natural-language request | Explicit Codex request |
| --- | --- | --- |
Expand All @@ -34,16 +55,22 @@ environment. They are skills, not plugins.
| Plugin creation | `Create a Codex plugin for this reusable workflow.` | `$plugin-creator Create a Codex plugin for this reusable workflow.` |
| Skill creation | `Turn this repeated release checklist into a skill.` | `$skill-creator Turn this repeated release checklist into a skill.` |
| Skill installation | `Install the skill from openai/skills.` | `$skill-installer Install the skill from openai/skills.` |
| Delegated code review | `Review my uncommitted changes against the base branch.` | `$review-agent Review my uncommitted changes against the base branch.` |

`$review-agent` is written for delegation: it performs a read-only, defect-first
review and returns findings without editing files, committing, or posting review
comments.

`$imagegen` is the important special case: it is built-in image generation,
not an image-generation marketplace plugin. Attach or identify reference images
and state what must change and what must remain fixed when editing.

## Official bundled and runtime plugins

The following plugins were installed and enabled in the verified environment.
Use the exact namespaced skill identifier shown below when invoking one
explicitly.
The following plugins were installed and enabled in one operator's environment
on 2026-08-05, and that roster has not been re-verified since. Use the exact
namespaced skill identifier shown below when invoking one explicitly, and treat
the rows themselves as an example rather than as your own entitlements.

| Plugin capability | Natural-language request | Explicit Codex request |
| --- | --- | --- |
Expand Down Expand Up @@ -76,14 +103,23 @@ codex plugin list --available --json
codex plugin marketplace list --json
```

At verification time, the official bundled marketplace also offered the
uninstalled `latex` plugin. Install it before using skills such as
`$latex:latex-doctor` or `$latex:latex-compile`:
`--available` widens the listing to uninstalled marketplace plugins and is only
accepted together with `--json`; `codex plugin list --available` on its own is
rejected.

On 2026-08-05 the official bundled marketplace also offered the uninstalled
`latex` plugin, and that has not been re-checked since. Where such a plugin is
offered, install it before using its skills, for example `$latex:latex-doctor`
or `$latex:latex-compile`:

```powershell
codex plugin add latex@openai-bundled
```

`openai-bundled` is the configured name of the official bundled marketplace.
`codex plugin add` accepts either `<plugin>@<marketplace>` or a bare
`<plugin>` with `--marketplace <marketplace>`; the two forms are equivalent.

Partner connectors, Codex Security, and other OpenAI-curated entries are
plugins, not built-in system skills. Installation, authentication, policy, and
surface availability determine whether their skills and tools can run.
Expand All @@ -110,8 +146,11 @@ codex plugin list --available --json
codex plugin marketplace list --json
```

When this snapshot changes, update the tables and the verification date. Keep
the full dynamic plugin directory out of the repository.
When this snapshot changes, update the affected table and only the verification
date that covers it. The two dates at the top of this page move independently:
re-reading the CLI source does not re-verify anyone's plugin roster, and
re-capturing a roster does not re-verify the CLI grammar. Keep the full dynamic
plugin directory out of the repository.

## Official pointers

Expand Down
7 changes: 5 additions & 2 deletions docs/MIGRATION-PLAYBOOK.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,11 @@ to preserve the source file shape.
## 6. Rebuild natively

Use `$plugin-creator` for the target package and `$skill-creator` for each
skill. Use the installed `$migrate-plugin` component map as a checklist, then
override it when current official documentation differs.
skill; those are built-in system skills, so they take the bare `$name` form. Use
the installed `$plugin-ops:migrate-plugin` component map as a checklist, then
override it when current official documentation differs. Skills that ship inside
a plugin are loaded under that plugin's namespace, so they are invoked as
`$plugin-name:skill-name`.

During implementation:

Expand Down
1 change: 1 addition & 0 deletions docs/OFFICIAL-DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Read the smallest complete set that covers the affected surface.
| Built-in image generation and `$imagegen` invocation | [Image generation](https://learn.chatgpt.com/docs/image-generation) |
| Plugin boundaries and component model | [Plugin architecture](https://developers.openai.com/plugins/concepts/plugins) |
| Skill format, triggers, resources, and tests | [Build skills](https://developers.openai.com/plugins/build/skills) |
| Skill loading, distribution, and the `agents/openai.yaml` keys `interface`, `policy`, and `dependencies` | [Build skills for Codex](https://learn.chatgpt.com/docs/build-skills) |
Comment thread
kyle-sexton marked this conversation as resolved.
| MCP tools, authentication, and server behavior | [Build an MCP server](https://developers.openai.com/plugins/build/mcp-server) |
| Optional MCP-backed UI | [Add optional UI](https://developers.openai.com/plugins/build/chatgpt-ui) |
| Manifests, paths, marketplaces, and packaging | [Package plugins and marketplaces](https://developers.openai.com/plugins/build/plugins) |
Expand Down
27 changes: 20 additions & 7 deletions docs/PLUGIN-PHILOSOPHY.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,23 @@ policy system when a current native surface can express the requirement. When a
native gap is real, the change MUST document the missing capability and isolate
the workaround behind a replaceable adapter.

`agents/openai.yaml` is skill presentation and invocation metadata, not a
custom execution agent. Keep it synchronized with its `SKILL.md`. Package or
migrate a custom agent only when current official Codex documentation defines
the discovery and packaging contract; otherwise express the cohesive workflow
as a skill or use normal task coordination.
`agents/openai.yaml` is the skill's harness-facing sidecar, not a custom
execution agent. It carries exactly three concerns: `interface` presentation
(display name, short description, icons, brand color, default prompt),
`dependencies.tools` declarations of the MCP tools the skill expects, and
`policy` (`allow_implicit_invocation`, product restrictions). Keep all three
synchronized with the owning `SKILL.md`.

A `dependencies.tools` entry is a declaration, not a connection: it names an
MCP dependency for discovery and presentation and does not install,
authenticate, or start a server. It is therefore subject to the same
outbound-port rules as any other integration — declare only what the skill
actually consumes, keep the capability check and fallback in the skill, and
never place a credential or a private endpoint in the sidecar.

Package or migrate a custom agent only when current official Codex
documentation defines the discovery and packaging contract; otherwise express
the cohesive workflow as a skill or use normal task coordination.

## Ports and adapters

Expand Down Expand Up @@ -123,8 +135,9 @@ Configuration SHOULD flow through native surfaces in this order:

Defaults MUST be quiet, safe, reversible, and non-blocking when a safe choice
exists. Required questions MUST be limited to material choices that cannot be
derived from authorized context. Optional integrations MUST be capability-
detected and MUST have either a useful fallback or a clear unsupported result.
derived from authorized context. Optional integrations MUST be
capability-detected and MUST have either a useful fallback or a clear
unsupported result.

Extension points MUST describe their input, output, error, and trust boundary.
Do not expose an entire tool or environment when a smaller port is sufficient.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"node": ">=20"
},
"scripts": {
"test": "node --test tests/documentation-contract.test.mjs tests/codex-operations.test.mjs tests/scheduled-tasks-plugin.test.mjs tests/humanize-plugin.test.mjs tests/codex-operations-plugin.test.mjs tests/plugin-ops-plugin.test.mjs plugins/plugin-ops/skills/verify-plugin/scripts/validate-marketplace.test.mjs",
"test": "node --test tests/test-harness.test.mjs tests/documentation-contract.test.mjs tests/codex-operations.test.mjs tests/scheduled-tasks-plugin.test.mjs tests/humanize-plugin.test.mjs tests/codex-operations-plugin.test.mjs tests/plugin-ops-plugin.test.mjs plugins/plugin-ops/skills/verify-plugin/scripts/validate-marketplace.test.mjs",
"validate": "node plugins/plugin-ops/skills/verify-plugin/scripts/validate-marketplace.mjs ."
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
interface:
display_name: "Coordinate Codex Work"
short_description: "Direct multi-task and long-running Codex work."
default_prompt: "Use $coordinate-codex-work to coordinate this work across Codex tasks and agents."
policy:
allow_implicit_invocation: true
default_prompt: "Use $codex-operations:coordinate-codex-work to coordinate this work across Codex tasks and agents."
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
interface:
display_name: "Find Skill Candidates"
short_description: "Find reusable skill ideas from recent sessions."
default_prompt: "Use $find-skill-candidates to review recent Codex sessions for reusable skill opportunities."
default_prompt: "Use $codex-operations:find-skill-candidates to review recent Codex sessions for reusable skill opportunities."
policy:
allow_implicit_invocation: false
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
#!/usr/bin/env python3
"""Collect bounded, redacted evidence from recent Codex session JSONL files."""
"""Collect bounded, redacted evidence from recent Codex session JSONL files.

Requires Python 3.11 or newer: this script uses ``datetime.UTC``, which was
added in 3.11.
"""

from __future__ import annotations

import argparse
import datetime as dt
import json
import math
import os
import re
import sys
Expand All @@ -19,12 +24,12 @@
MAX_TEXT_CHARS_PER_RECORD = 2000

SKILL_PATTERN = re.compile(r"\$[a-z0-9][a-z0-9-]{1,63}\b")
SKILL_WORD_PATTERN = re.compile(
r"\b(skill|skills|SKILL\.md|agents[/\\]skills)\b", re.IGNORECASE
)
SKILL_WORD_PATTERN = re.compile(r"\bskills?\b", re.IGNORECASE)
# Friction words carry difficulty; bare frequency words ("often", "repeated")
# belong to WORKFLOW_PATTERN so a record cannot count toward both summaries.
FRICTION_PATTERN = re.compile(
r"\b(failed|error|blocked|confusing|unclear|struggl(?:e|ed|ing)|"
r"workaround|manual|again|repeated|often|candidate|missed trigger|"
r"workaround|manual|again|candidate|missed trigger|"
r"more helpful|not useful|doesn't trigger|did not trigger)\b",
re.IGNORECASE,
)
Expand Down Expand Up @@ -125,8 +130,14 @@ def parse_args(argv: Sequence[str] | None = None) -> argparse.Namespace:
args = parser.parse_args(argv)
if args.hours <= 0:
parser.error("--hours must be greater than zero")
if not math.isfinite(args.hours):
parser.error("--hours must be a finite number")
if args.max_excerpts < 0:
parser.error("--max-excerpts must be zero or greater")
try:
args.since = dt.datetime.now(dt.UTC) - dt.timedelta(hours=args.hours)
except (OverflowError, ValueError):
parser.error("--hours is too large to form a lookback window")
args.skills_dir = unique_paths(args.skills_dir or default_skill_roots())
return args

Expand All @@ -146,7 +157,7 @@ def parse_timestamp(value: Any) -> dt.datetime | None:
return parsed.astimezone(dt.UTC)


def iter_candidate_files(root: Path, since: dt.datetime) -> Iterable[Path]:
def iter_candidate_files(root: Path, since: dt.datetime) -> list[Path]:
if not root.exists():
return []
cutoff = since.timestamp()
Expand All @@ -162,12 +173,15 @@ def iter_candidate_files(root: Path, since: dt.datetime) -> Iterable[Path]:

def safe_text(value: Any) -> str:
chunks: list[str] = []
joined_length = 0

def walk(node: Any) -> None:
if len(" ".join(chunks)) >= MAX_TEXT_CHARS_PER_RECORD:
nonlocal joined_length
if joined_length >= MAX_TEXT_CHARS_PER_RECORD:
return
if isinstance(node, str):
if node and not node.startswith("data:image/"):
joined_length += len(node) + (1 if chunks else 0)
chunks.append(node)
return
if isinstance(node, list):
Expand Down Expand Up @@ -241,18 +255,13 @@ def read_skill_metadata(skill_roots: Iterable[Path]) -> list[tuple[str, str]]:
return sorted(skills.items())


def markdown_escape(text: str) -> str:
return text.replace("|", "\\|")


def main(argv: Sequence[str] | None = None) -> int:
reconfigure = getattr(sys.stdout, "reconfigure", None)
if reconfigure is not None:
reconfigure(encoding="utf-8", errors="replace")
args = parse_args(argv)
now = dt.datetime.now(dt.UTC)
since = now - dt.timedelta(hours=args.hours)
files = list(iter_candidate_files(args.sessions_dir, since))
since = args.since
files = iter_candidate_files(args.sessions_dir, since)

scanned_records = 0
included_records = 0
Expand Down Expand Up @@ -301,7 +310,7 @@ def main(argv: Sequence[str] | None = None) -> int:
matches = {
match
for match in SKILL_PATTERN.findall(text)
if match.lower() not in IGNORED_DOLLAR_NAMES
if match not in IGNORED_DOLLAR_NAMES
}
for match in matches:
skill_mentions[match] += 1
Expand Down Expand Up @@ -368,11 +377,12 @@ def main(argv: Sequence[str] | None = None) -> int:
print(f"- Friction-related records: {signal_counts['friction']}")
print(f"- Reusable-workflow records: {signal_counts['workflow']}")
if skill_mentions:
ranked_mentions = sorted(
skill_mentions.items(), key=lambda item: (-item[1], item[0])
)[:20]
print(
"- Skill mentions: "
+ ", ".join(
f"`{name}` ({count})" for name, count in skill_mentions.most_common(20)
)
+ ", ".join(f"`{name}` ({count})" for name, count in ranked_mentions)
)
else:
print("- Skill mentions: none")
Expand All @@ -391,10 +401,7 @@ def main(argv: Sequence[str] | None = None) -> int:
print("## Bounded Redacted Excerpts")
if excerpts:
for timestamp, session, labels, excerpt in excerpts:
print(
f"- `{timestamp}` `{session}` [{labels}] "
f"{markdown_escape(excerpt)}"
)
print(f"- `{timestamp}` `{session}` [{labels}] {excerpt}")
else:
print("- No relevant excerpts found.")

Expand Down
2 changes: 1 addition & 1 deletion plugins/humanize/skills/humanize/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
interface:
display_name: "Humanize"
short_description: "Revise prose for natural, context-aware voice"
default_prompt: "Use $humanize to revise this writing while preserving its meaning, evidence, and voice."
default_prompt: "Use $humanize:humanize to revise this writing while preserving its meaning, evidence, and voice."
9 changes: 7 additions & 2 deletions plugins/plugin-ops/skills/install-marketplace/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,21 @@ marketplace source and installing a plugin from that source.
```

Use `--ref` only when the user wants a pinned branch, tag, or commit. Use
`--sparse` only for Git sources.
`--sparse` only for Git sources; it may be repeated to select more than one
path.
6. Verify discovery with `codex plugin marketplace list` and `codex plugin list`.
7. Install only the requested plugin:

```text
codex plugin add <plugin>@<marketplace>
```

`codex plugin add <plugin> --marketplace <marketplace>` selects the same
plugin. Prefer the `@` form so the source is visible in the command itself.

8. Ask the user to start a new task so newly installed skills and tools are
loaded.
loaded. A plugin's skills are then invoked as `$<plugin>:<skill>`, because
Codex qualifies a skill name with the name of the plugin that owns it.

## Guardrails

Expand Down
Loading