Understanding the Interface Section of plugin.json in OpenAI Plugins

The interface section in plugin.json serves as the contract between a plugin's metadata and the Codex runtime, controlling UI theming, capability declarations, and starter prompts while enabling the Composer to render plugin tiles and enforce security permissions.

The OpenAI Plugins repository defines the interface object within each plugin.json manifest as the single source of truth for how a plugin appears to users and what operations it advertises. This section bridges static plugin description with dynamic runtime behavior, driving everything from color schemes to capability gating.

What Is the Interface Section?

The interface object lives inside the plugin.json file located at plugins/<name>/.codex-plugin/plugin.json. It acts as the declarative contract that connects plugin metadata with both the Codex-Plugin runtime and the Composer UI components. According to the specification in .agents/skills/plugin-creator/references/plugin-json-spec.md, this section determines visual presentation, legal disclosures, and operational permissions.

Key Fields in the plugin.json Interface

Visual Branding and Icons

The branding fields control how the plugin appears in the Composer UI and Plugin Store:

  • brandColor and brandColorDark: Hex color values theming the plugin tile
  • composerIcon: Path to SVG/PNG assets displayed on the Composer toolbar
  • logo and logoDark: Larger assets shown in plugin detail views
  • screenshots: Paths to PNG/SVG assets displayed in the store carousel

Capability Declarations

The capabilities array declares what operations the plugin can perform. Valid values include Read, Write, and Interactive. The runtime validates all incoming requests against these flags in plugins/plugin-eval/src/evaluators/plugin.js, preventing write operations on plugins that only declare Read access.

Starter Prompts and Descriptions

  • defaultPrompt: An array of starter messages (maximum 3 prompts, each ≤128 characters) displayed when users create new conversations with the plugin
  • shortDescription and longDescription: Text rendered in store listings and Composer detail panes
  • category: Human-readable grouping (e.g., Communication, Productivity) for store organization
  • privacyPolicyURL, termsOfServiceURL, and websiteURL: Required legal endpoints displayed to end-users before installation

How the Runtime Consumes the Interface Section

Manifest Loading and Validation

When a plugin installs, the Codex runtime loads plugins/<name>/.codex-plugin/plugin.json and executes validation logic in plugins/plugin-eval/src/evaluators/plugin.js. This validator checks that required fields exist and enforces the defaultPrompt constraints:

// Validation logic mirrors this implementation
function validateDefaultPrompt(iface) {
  if (!Array.isArray(iface.defaultPrompt)) return false;
  if (iface.defaultPrompt.length > 3) return false;
  return iface.defaultPrompt.every(p => p.length <= 128);
}

Token Budget Estimation

The runtime uses defaultPrompt to reserve context window space. In plugins/plugin-eval/src/core/budget.js, the system concatenates the starter prompts and calls estimateTokenCount to calculate required allocations for new Composer conversations.

UI Rendering Pipeline

The Composer UI reads manifest.interface.* to:

  • Paint plugin tiles using brandColor and composerIcon
  • Display legal links and descriptions in detail views
  • Render defaultPrompt strings as clickable quick-start buttons

Capability Gating

Before executing any plugin action, the runtime checks manifest.interface.capabilities. A plugin declaring only "Read" receives an error when attempting write-oriented operations, enforcing the principle of least privilege.

Working with the Interface Section

Loading a Plugin Interface in JavaScript

import fs from 'fs';
import path from 'path';

function loadInterface(pluginName) {
  const manifestPath = path.join(
    __dirname,
    'plugins',
    pluginName,
    '.codex-plugin',
    'plugin.json'
  );
  const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
  return manifest.interface;
}

// Example usage
const zoomInterface = loadInterface('zoom');
console.log(zoomInterface.brandColor);     // → "#0B5CFF"
console.log(zoomInterface.capabilities);   // → ["Read", "Interactive"]

Enforcing defaultPrompt Constraints

function validateDefaultPrompt(iface) {
  if (!Array.isArray(iface.defaultPrompt)) return false;
  if (iface.defaultPrompt.length > 3) return false;
  return iface.defaultPrompt.every(p => p.length <= 128);
}

if (!validateDefaultPrompt(zoomInterface)) {
  throw new Error('defaultPrompt does not meet Codex requirements');
}

Rendering Starter Prompts in the UI

// React pseudo-code demonstrating Composer integration
function renderStarterPrompts(interface) {
  return interface.defaultPrompt.map((prompt, i) => (
    <button key={i} onClick={() => sendMessage(prompt)}>
      {prompt}
    </button>
  ));
}

Summary

  • The interface section in plugin.json controls both visual presentation and functional capabilities of OpenAI Plugins
  • Validation occurs in plugins/plugin-eval/src/evaluators/plugin.js, enforcing defaultPrompt limits (3 prompts max, 128 characters each) and verifying capability declarations
  • Token budgeting uses defaultPrompt content via plugins/plugin-eval/src/core/budget.js to manage context window allocation
  • Capability gating prevents unauthorized operations by matching runtime requests against declared capabilities (Read/Write/Interactive)
  • UI components consume brandColor, composerIcon, and description fields to render plugin tiles and detail views

Frequently Asked Questions

What happens if defaultPrompt exceeds 3 items or 128 characters?

The validator in plugins/plugin-eval/src/evaluators/plugin.js rejects the manifest during plugin installation. The runtime enforces these limits strictly to prevent token budget overflow and maintain UI consistency in the Composer's quick-start suggestions.

Can a plugin change its capabilities after installation?

No. The capabilities array is static and defined at build time in plugin.json. The runtime checks these flags before every operation, and modifying them requires repackaging and reinstalling the plugin with updated declarations.

Where does the Composer read the brand colors and icons?

The Composer UI reads manifest.interface.brandColor, manifest.interface.composerIcon, and related fields directly from the loaded manifest object. These values style the plugin tile in the toolbar and the detailed view in the Plugin Store.

How does the interface section relate to the rest of plugin.json?

While other sections of plugin.json define technical endpoints and authentication, the interface section specifically handles user-facing metadata. It remains the only portion read by both the UI rendering layer and the runtime security validator, making it the bridge between user experience and system enforcement.

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 →