How to Structure Plugin Commands in Codex: The Skill-Script Architecture

Codex plugins expose commands through Python skill scripts that use argparse sub-parsers to map each top-level sub-command to a concrete operation, registered via a plugin.json manifest in the .codex-plugin/ directory.

To structure plugin commands in Codex, you implement a skill-script interface within the openai/plugins repository. Each skill acts as a self-contained CLI program—typically a Python script—that exposes discrete operations via sub-commands, while the plugin manifest wires these capabilities to the Codex runtime for automatic discovery.

How to Structure Plugin Commands Using argparse

According to the openai/plugins source code, the standard pattern for defining commands relies on Python’s argparse module with a root parser and dedicated sub-parsers. Each sub-parser corresponds to a distinct command that users invoke through the Codex UI or the codex CLI.

The implementation follows three steps:

  1. Create a root parser to consume global options (e.g., --session).
  2. Add sub-parsers via add_subparsers(dest="command", required=True), where each call to add_parser() registers a named command.
  3. Dispatch based on args.command to execute the matching logic block.

The Zotero skill demonstrates this pattern in plugins/zotero/skills/zotero/scripts/zotero.py (lines 730–762). The script initializes a root ArgumentParser, attaches sub-parsers for status, enable, and disable, then routes execution based on the parsed sub-command.

import argparse

parser = argparse.ArgumentParser(description="Zotero CLI")
subcommands = parser.add_subparsers(dest="command", required=True)

# Define individual commands

subcommands.add_parser("status", help="Show Zotero local API readiness")
subcommands.add_parser("enable", help="Enable Zotero's local Desktop API")
subcommands.add_parser("disable", help="Disable Zotero's local Desktop API")

args = parser.parse_args()

# Dispatch to handler

if args.command == "status":
    check_status()
elif args.command == "enable":
    enable_api()

When a user runs codex zotero status, Codex invokes the skill script with the status argument, and args.command equals "status", triggering the corresponding handler.

Registering Structured Commands in the Plugin Manifest

Commands remain invisible to Codex until you register them via the plugin manifest located at .codex-plugin/plugin.json. This JSON file declares the skills/ directory containing your scripts, allowing Codex to scan and load each skill as a command entry point.

The manifest for the Zoom plugin in plugins/zoom/.codex-plugin/plugin.json illustrates the required structure:

{
  "name": "zoom",
  "version": "1.0.2",
  "skills": "./skills/",
  "interface": {
    "displayName": "Zoom",
    "defaultPrompt": [
      "Search my recent Zoom meetings for the discussion about pricing."
    ]
  }
}
  • The skills field points to the directory containing skill subfolders.
  • Each skill folder contains a scripts/ directory with executable Python files.
  • When a user issues a command like /plan-zoom-product, Codex routes the request to the appropriate script under plugins/zoom/skills/.

Handling JSON Command Payloads in Codex

For interactive or web-based plugins—such as those integrating the Zoom Video SDK—commands transmit as JSON messages over a bridge rather than CLI arguments. This pattern decouples the frontend interface from the skill logic.

As shown in plugins/zoom/skills/video-sdk/web/examples/command-channel.md, the payload structure includes a command field for dispatch and a text field for data:

{
  "command": "update-overlay",
  "text": "Q&A Time"
}

The receiving skill extracts the command value and forwards it to the corresponding handler. On the client side, you send these payloads via the SDK’s message channel:

zoomSdk.postMessage({ command: "update-overlay", text: "Live Q&A" });

Mapping Codex Tool Names to Native Calls

When skills reference high-level Codex tool names such as Task, TodoWrite, or Read, they invoke aliases for native Codex CLI capabilities. The mapping reference in plugins/superpowers/skills/using-superpowers/references/codex-tools.md defines how these abstract names translate to concrete runtime calls like spawn_agent or update_plan.

This abstraction layer ensures that skills remain portable across different Codex environments while still accessing advanced agent orchestration features. You do not implement these tools directly in your skill script; instead, you reference them by name, and the Codex runtime resolves them according to the mapping specification.

Summary

  • Use argparse sub-parsers to declare each command as a distinct sub-command under a root parser, following the pattern in plugins/zotero/skills/zotero/scripts/zotero.py.
  • Register the skill directory in .codex-plugin/plugin.json using the skills field so Codex can discover and load your commands.
  • Dispatch logic based on the args.command value to route execution to the correct operation.
  • Use JSON payloads for web or interactive SDK integrations, extracting the command field to trigger handlers.
  • Reference Codex tool names (e.g., Task, Read) according to codex-tools.md to leverage native agent capabilities without hard-coding CLI calls.

Frequently Asked Questions

What file structure is required to register plugin commands in Codex?

You must place a plugin.json file inside a .codex-plugin/ directory at the root of your plugin folder. This manifest must specify a skills path pointing to a directory containing skill subfolders, each with a scripts/ directory holding executable Python files. Codex scans this structure to discover available commands.

How does Codex route a user command to the correct skill script?

Codex parses the user’s input to identify the plugin namespace and command name. It then locates the corresponding Python script within the registered skills/ directory, invokes it with the remaining arguments, and relies on the script’s internal argparse logic to route to the specific sub-command handler defined by args.command.

Can plugin commands accept complex command-line arguments?

Yes. Because skills are standard Python scripts using argparse, you can define positional arguments, optional flags, and sub-command-specific parameters using standard add_argument() calls on the sub-parser objects. Codex passes all arguments following the command name directly to the skill script.

What is the difference between skill commands and Codex tool names like Task or TodoWrite?

Skill commands are custom operations defined in your plugin’s Python scripts (e.g., status, enable) that perform domain-specific logic. Codex tool names are reserved aliases (e.g., Task, TodoWrite, Read) that map to native Codex runtime capabilities such as spawning sub-agents or updating plans. Skills invoke these tools by name, and the runtime translates them into concrete system calls according to the codex-tools.md reference.

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 →