Difference Between .app.json and .codex-plugin/plugin.json in OpenAI Plugins

The .codex-plugin/plugin.json file provides the full declarative UI metadata and identity for OpenAI plugins, while .app.json supplies the runtime backend app ID mapping used for request routing.

In the OpenAI Plugins repository, each plugin follows a strict two-file configuration pattern that separates user-facing metadata from backend identifiers. Understanding the difference between .app.json and .codex-plugin/plugin.json is essential for developers building plugins for the Codex platform.

What is .codex-plugin/plugin.json?

This file lives in the .codex-plugin/ directory within each plugin folder (e.g., plugins/fyxer/.codex-plugin/plugin.json). It serves as the declarative manifest that Codex consumes to render the plugin in the marketplace and UI.

Declarative Metadata Structure

The file defines top-level identity fields including name, version, description, author, repository, license, and keywords. Crucially, it contains an apps field that points to the companion .app.json file, establishing the link between UI description and runtime configuration. According to the source in plugins/fyxer/.codex-plugin/plugin.json, this field uses a relative path like "./.app.json".

The Interface Object

The heart of plugin.json is the interface object. This contains UI-specific data such as displayName, shortDescription, longDescription, websiteURL, privacyPolicyURL, termsOfServiceURL, and icon paths (composerIcon, logo). This structure tells the platform exactly how the plugin should appear to users, including default prompts and branding assets.

What is .app.json?

Located at the plugin root (e.g., plugins/fyxer/.app.json), this file provides the runtime-only mapping between the plugin's logical name and its backend-assigned identifier.

Runtime App Identifier

The structure follows { "apps": { "<plugin-name>": { "id": "<app-id>" } } }. For example, in plugins/fyxer/.app.json, the mapping contains "id": "asdk_app_696e3c8854748191a6006dd80660ad35". This UUID-like string is opaque to the UI and used exclusively by the plugin host to route requests to the correct backend endpoints.

Backend Integration

Unlike plugin.json, .app.json contains no presentation logic. It is read by the plugin host during initialization to resolve the concrete app ID. This file may be regenerated automatically when the app is registered, making it a purely operational configuration rather than a source of truth for plugin metadata.

Key Differences Between the Configuration Files

  • .codex-plugin/plugin.json: Defines what the plugin is and how it should be presented. Contains UI metadata, descriptions, icons, and user-facing configuration consumed by Codex.
  • .app.json: Defines how the plugin is identified for backend operations. Contains only the runtime app ID used for request routing and service discovery.

The separation enables frontend teams to modify UI copy and icons without touching backend identifiers, while platform engineers can rotate or update app IDs without affecting the user experience.

Practical Implementation Examples

Minimal plugin.json Configuration

{
  "name": "example-plugin",
  "version": "1.0.0",
  "description": "A simple example plugin.",
  "author": { "name": "Example Inc", "url": "https://example.com" },
  "apps": "./.app.json",
  "interface": {
    "displayName": "Example Plugin",
    "shortDescription": "Shows the structural split.",
    "longDescription": "This plugin demonstrates the separation of UI metadata from runtime IDs.",
    "websiteURL": "https://example.com",
    "composerIcon": "./assets/icon.png",
    "logo": "./assets/logo.png"
  }
}

Minimal .app.json Configuration

{
  "apps": {
    "example-plugin": {
      "id": "asdk_app_1234567890abcdef"
    }
  }
}

Accessing the Runtime ID in Node.js

const fs = require('fs');
const path = require('path');

const appConfig = JSON.parse(
  fs.readFileSync(path.join(__dirname, '.app.json'), 'utf8')
);

const pluginId = appConfig.apps['example-plugin'].id;
console.log(`Runtime app ID: ${pluginId}`);

Summary

Frequently Asked Questions

Can I modify .app.json manually?

While technically possible, manual edits to .app.json are discouraged because this file is typically auto-generated when the plugin is registered with the backend. The id field contains backend-assigned identifiers that may change during re-registration or environment switches.

What happens if the apps field in plugin.json points to the wrong file?

Codex will fail to resolve the plugin's runtime configuration, causing the plugin to be unavailable for invocation. The apps field must correctly reference the relative path to .app.json (e.g., "./.app.json") to maintain the link between UI metadata and backend identity.

Why are these configurations split into two files?

The separation follows the architectural principle of dividing presentation from implementation. By isolating UI metadata in .codex-plugin/plugin.json and runtime IDs in .app.json, teams can update marketplace descriptions and icons without redeploying backend services, and vice versa.

Where can I find real-world examples of these files?

Reference the OpenAI Plugins repository at openai/plugins. The plugins/fyxer/ and plugins/demandbase/ directories contain complete implementations showing the relationship between .codex-plugin/plugin.json and .app.json.

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 →