# How to Create a Codex Plugin from Scratch: A Complete Guide to Scaffolding, Manifests, and Marketplace Registration

> Learn to create a Codex plugin from scratch using the basic plugin scaffold script. This guide covers scaffolding, manifests, and marketplace registration for your AI application.

- Repository: [OpenAI/plugins](https://github.com/openai/plugins)
- Tags: how-to-guide
- Published: 2026-06-28

---

**Use the [`create_basic_plugin.py`](https://github.com/openai/plugins/blob/main/create_basic_plugin.py) scaffold script in `openai/plugins` to generate a complete plugin directory with a [`plugin.json`](https://github.com/openai/plugins/blob/main/plugin.json) manifest, optional component folders, and automatic marketplace registration in a single command.**

Creating a custom Codex plugin requires more than just writing code—you need a properly structured directory, a validated manifest file, and an entry in the marketplace registry. The `openai/plugins` repository provides a dedicated **plugin-creator skill** that automates this entire workflow. This guide walks you through generating a complete plugin skeleton, understanding the [`plugin.json`](https://github.com/openai/plugins/blob/main/plugin.json) schema, and making your plugin discoverable in the Codex UI.

## What the Scaffold Script Generates

The plugin scaffolding system lives in `.agents/skills/plugin-creator/` and centers on [`scripts/create_basic_plugin.py`](https://github.com/openai/plugins/blob/main/scripts/create_basic_plugin.py). This script performs three core functions: it normalizes your plugin name, creates the directory structure, and writes a placeholder manifest.

When you run the script, it executes the `normalize_plugin_name()` function to convert your input to lower-case kebab-case (e.g., `MyPlugin` becomes `my-plugin`). The `validate_plugin_name()` helper enforces a maximum length of 64 characters. These functions ensure your plugin identifier follows Codex naming conventions.

The script creates the plugin root folder and writes the manifest to [`.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main/.codex-plugin/plugin.json). By default, this produces a minimal structure containing only the manifest file. You can extend this with optional component directories using flags.

### Optional Component Flags

The scaffold script supports five boolean flags that create empty directories or stub JSON files:

- **`--with-skills`** – Creates a `skills/` directory for agent capabilities
- **`--with-hooks`** – Creates a `hooks/` directory for lifecycle hooks  
- **`--with-assets`** – Creates an `assets/` directory for UI resources
- **`--with-mcp`** – Generates [`.mcp.json`](https://github.com/openai/plugins/blob/main/.mcp.json) with `{"mcpServers": {}}` stub
- **`--with-apps`** – Generates [`.app.json`](https://github.com/openai/plugins/blob/main/.app.json) with `{"apps": {}}` stub

These flags give you a ready-to-extend skeleton without manual directory creation.

## Understanding the plugin.json Manifest

The generated manifest at `<plugin-root>/.codex-plugin/plugin.json` follows the schema defined in [`references/plugin-json-spec.md`](https://github.com/openai/plugins/blob/main/references/plugin-json-spec.md). This file contains two critical sections: top-level metadata and an `interface` block.

**Top-level metadata** includes fields like `name`, `version`, and `author`. These identify your plugin in the Codex system.

**The `interface` block** drives how your plugin appears in the Codex app UI. It controls display properties, entry points, and integration hooks. The spec file documents valid values for each field, including type constraints and required vs. optional status.

When you edit the manifest, reference the specification to ensure compatibility with the Codex runtime. Invalid manifests will fail validation checks.

## Registering Your Plugin in the Marketplace

The `--with-marketplace` flag automates marketplace registration, eliminating manual JSON editing. When enabled, the script updates a [`marketplace.json`](https://github.com/openai/plugins/blob/main/marketplace.json) file with your plugin's entry.

### Marketplace Entry Structure

Each marketplace entry contains:

- **`name`** – The normalized plugin identifier
- **`source`** – Object with `{"source": "local", "path": "./plugins/<name>"}` pointing to the plugin directory
- **`policy`** – Object with `installation` and `authentication` settings
- **`category`** – Display category for the Codex UI marketplace view

### Policy Configuration Flags

Three additional flags control the marketplace entry:

- **`--install-policy`** – Sets `AVAILABLE`, `HIDDEN`, or `DISABLED`
- **`--auth-policy`** – Sets `ON_INSTALL`, `ON_USE`, or `NONE`  
- **`--category`** – Assigns a display category like "Productivity" or "Development"

The default marketplace path is `~/.agents/plugins/marketplace.json`. Override this with `--marketplace-path` to use a repository-local file instead.

The marketplace itself has a top-level `interface.displayName` field that belongs to the marketplace, not individual plugins. New marketplace files are seeded with a placeholder display name and an empty `plugins` array as outlined in lines 13-20 of the spec.

## Step-by-Step: Creating Your First Codex Plugin

### 1. Scaffold a Basic Plugin

Run the scaffold script with your desired plugin name:

```bash
python3 .agents/skills/plugin-creator/scripts/create_basic_plugin.py my-plugin

```

This creates:
- `~/plugins/my-plugin/.codex-plugin/plugin.json` – Placeholder manifest with kebab-cased name
- `~/plugins/my-plugin/` – Root directory ready for your code

### 2. Add Component Directories

Generate a full-featured skeleton with all optional components:

```bash
python3 .agents/skills/plugin-creator/scripts/create_basic_plugin.py \
  my-plugin \
  --with-skills \
  --with-hooks \
  --with-assets \
  --with-mcp \
  --with-apps

```

This produces the structure:

```

my-plugin/
├─ .codex-plugin/
│  └─ plugin.json
├─ skills/
├─ hooks/
├─ assets/
├─ .mcp.json
└─ .app.json

```

### 3. Register with Marketplace Integration

Complete the setup with marketplace registration and policy settings:

```bash
python3 .agents/skills/plugin-creator/scripts/create_basic_plugin.py \
  my-plugin \
  --with-marketplace \
  --install-policy AVAILABLE \
  --auth-policy ON_INSTALL \
  --category Productivity

```

The script appends this entry to your marketplace file:

```json
{
  "name": "my-plugin",
  "source": { "source": "local", "path": "./plugins/my-plugin" },
  "policy": { "installation": "AVAILABLE", "authentication": "ON_INSTALL" },
  "category": "Productivity"
}

```

### 4. Validate Your Plugin

Before deployment, verify your JSON schemas using the validation helper:

```bash
python3 .agents/skills/plugin-creator/scripts/quick_validate.py .agents/skills/plugin-creator

```

This script checks the validity of your manifest and marketplace entries against the specification.

## Key Source Files in openai/plugins

| Path | Purpose |
|------|---------|
| [`.agents/skills/plugin-creator/scripts/create_basic_plugin.py`](https://github.com/openai/plugins/blob/main/.agents/skills/plugin-creator/scripts/create_basic_plugin.py) | Main scaffold script with `normalize_plugin_name()` and `validate_plugin_name()` functions |
| [`.agents/skills/plugin-creator/references/plugin-json-spec.md`](https://github.com/openai/plugins/blob/main/.agents/skills/plugin-creator/references/plugin-json-spec.md) | Complete JSON schema for [`plugin.json`](https://github.com/openai/plugins/blob/main/plugin.json) and marketplace entries |
| [`.agents/skills/plugin-creator/SKILL.md`](https://github.com/openai/plugins/blob/main/.agents/skills/plugin-creator/SKILL.md) | Usage documentation and flag descriptions |
| [`.agents/skills/plugin-creator/scripts/quick_validate.py`](https://github.com/openai/plugins/blob/main/.agents/skills/plugin-creator/scripts/quick_validate.py) | JSON validation helper for scaffolded files |
| [`.agents/plugins/marketplace.json`](https://github.com/openai/plugins/blob/main/.agents/plugins/marketplace.json) | Example marketplace showing entry format and ordering |

## Summary

- **Scaffold generation** – Use [`create_basic_plugin.py`](https://github.com/openai/plugins/blob/main/create_basic_plugin.py) to create a standardized plugin directory with normalized naming and automatic manifest creation.
- **Manifest structure** – The [`plugin.json`](https://github.com/openai/plugins/blob/main/plugin.json) at [`.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main/.codex-plugin/plugin.json) combines metadata and UI interface definitions per the spec in [`references/plugin-json-spec.md`](https://github.com/openai/plugins/blob/main/references/plugin-json-spec.md).
- **Component options** – Flags like `--with-skills` and `--with-mcp` generate directory stubs and configuration files for extended functionality.
- **Marketplace registration** – The `--with-marketplace` flag automatically creates valid marketplace entries with configurable installation and authentication policies.
- **Validation** – Run [`quick_validate.py`](https://github.com/openai/plugins/blob/main/quick_validate.py) to catch JSON schema errors before deployment.

## Frequently Asked Questions

### What is the maximum length for a Codex plugin name?

Plugin names must be **64 characters or fewer**. The `validate_plugin_name()` function in [`create_basic_plugin.py`](https://github.com/openai/plugins/blob/main/create_basic_plugin.py) enforces this limit, and `normalize_plugin_name()` converts your input to lower-case kebab-case to ensure compatibility.

### What does the [`plugin.json`](https://github.com/openai/plugins/blob/main/plugin.json) interface block control?

The `interface` block in your manifest **drives the UI presentation inside the Codex app**. It defines how your plugin appears to users, including display properties and integration hooks. The complete schema is documented in [`references/plugin-json-spec.md`](https://github.com/openai/plugins/blob/main/references/plugin-json-spec.md).

### Can I register a plugin in a custom marketplace location?

Yes. While the default marketplace path is `~/.agents/plugins/marketplace.json`, you can specify an alternative location using the **`--marketplace-path`** flag. This is useful for repository-local development or team-shared plugin registries.

### What is the difference between installation and authentication policies?

**Installation policy** (`--install-policy`) controls whether the plugin appears in the marketplace (`AVAILABLE`), is hidden (`HIDDEN`), or disabled (`DISABLED`). **Authentication policy** (`--auth-policy`) determines when the user must authenticate: at installation (`ON_INSTALL`), at first use (`ON_USE`), or never (`NONE`).