Codex.Plugins owns the local plugin authoring surface.

Use it when you want to create or maintain:

  • .codex-plugin/plugin.json
  • .agents/plugins/marketplace.json
  • minimal local plugin directory trees

This namespace is intentionally separate from Codex.AppServer.plugin_*. Authoring uses normal Elixir file IO and does not require a running Codex subprocess.

Core API

{:ok, manifest} =
  Codex.Plugins.new_manifest(
    name: "demo-plugin",
    skills: "./skills",
    interface: [display_name: "Demo Plugin"]
  )

:ok =
  Codex.Plugins.write_manifest(
    "/repo/plugins/demo-plugin/.codex-plugin/plugin.json",
    manifest,
    create_parents: true
  )

High-level scaffold:

{:ok, result} =
  Codex.Plugins.scaffold(
    cwd: "/repo/root",
    plugin_name: "demo-plugin",
    with_marketplace: true,
    skill: [name: "hello-world", description: "Greets the user"]
  )

result includes:

  • plugin_root
  • manifest_path
  • marketplace_path when requested
  • skill_paths

Validation Rules

Stable rules enforced locally:

  • manifest name must be a non-empty kebab-case identifier
  • manifest component paths such as skills, hooks, mcpServers, apps, and interface asset paths must start with ./
  • relative paths cannot escape with ..
  • interface.defaultPrompt accepts at most 3 prompts and each prompt must be 128 characters or fewer after whitespace normalization
  • writes are deterministic JSON with a trailing newline
  • scaffold does not generate mix.exs, .formatter.exs, build_support/*, or Dialyzer/PLT files in phase 1

Unknown forward-compatible keys are preserved in extra maps and survive read-modify-write flows where possible.

Scope Resolution

Repo scope:

  • plugin root defaults to <repo-root>/plugins/<plugin-name>
  • marketplace defaults to <repo-root>/.agents/plugins/marketplace.json

Personal scope:

  • plugin root defaults to ~/plugins/<plugin-name>
  • marketplace defaults to ~/.agents/plugins/marketplace.json

You can override either path explicitly with root: or marketplace_path:.

Authoring Versus Runtime

Normal authoring flows should stay local:

Runtime verification stays on app-server:

The SDK does not route normal local authoring through app-server fs/*.