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

> Understand the structural difference between .codex-plugin/plugin.json and .app.json. Learn how OpenAI separates presentation and runtime configuration for plugins.

- Repository: [OpenAI/plugins](https://github.com/openai/plugins)
- Tags: deep-dive
- Published: 2026-06-11

---

**The [`.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main/.codex-plugin/plugin.json) file contains the full declarative UI metadata and interface specification that Codex consumes, while [`.app.json`](https://github.com/openai/plugins/blob/main/.app.json) contains only the backend runtime app ID mapping, creating a strict separation between presentation layer and runtime configuration.**

In the `openai/plugins` repository, each plugin directory contains two distinct JSON configuration files that serve different architectural purposes. Understanding the structural difference between [`.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main/.codex-plugin/plugin.json) and [`.app.json`](https://github.com/openai/plugins/blob/main/.app.json) is essential for developers building or debugging plugins within the OpenAI ecosystem.

## Understanding [`.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main/.codex-plugin/plugin.json)

Located at `plugins/<name>/.codex-plugin/plugin.json`, this file provides the comprehensive declarative description that Codex (ChatGPT) consumes to generate marketplace entries and render plugin information in the UI.

The structure includes top-level identity fields such as `name`, `version`, `description`, `author`, `repository`, and `license`. Crucially, the file contains an **`apps`** field that references the companion [`.app.json`](https://github.com/openai/plugins/blob/main/.app.json) file (e.g., `"apps": "./.app.json"`), establishing the link between UI metadata and runtime configuration.

The heart of this file is the **`interface`** object, which defines all presentation-layer properties:

- `displayName`: Human-readable plugin name shown to users
- `shortDescription` and `longDescription`: Marketing copy and detailed explanations
- `composerIcon` and `logo`: Paths to visual assets
- `websiteURL`, `privacyPolicyUrl`, `termsOfServiceUrl`: Legal and informational links

For example, in [`plugins/fyxer/.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main/plugins/fyxer/.codex-plugin/plugin.json), the interface object configures how the Fyxer plugin appears in the marketplace, while the `apps` field points to `"./.app.json"` to resolve the backend identifier.

## Understanding [`.app.json`](https://github.com/openai/plugins/blob/main/.app.json)

Located at the plugin root (e.g., [`plugins/fyxer/.app.json`](https://github.com/openai/plugins/blob/main/plugins/fyxer/.app.json)), this file serves a single, specific purpose: mapping the plugin's logical name to its backend-assigned runtime identifier.

The structure is minimal and flat:

```json
{
  "apps": {
    "fyxer": {
      "id": "asdk_app_696e3c8854748191a6006dd80660ad35"
    }
  }
}

```

The key `fyxer` matches the plugin name defined in [`plugin.json`](https://github.com/openai/plugins/blob/main/plugin.json), while the `id` value represents an opaque backend identifier used by the plugin host to route requests. This file is not consumed by the UI layer and is typically auto-generated during app registration rather than manually maintained. As seen in [`plugins/demandbase/.app.json`](https://github.com/openai/plugins/blob/main/plugins/demandbase/.app.json), this pattern remains consistent across the repository.

## Key Structural Differences

The architectural separation between these files can be summarized as follows:

- **Purpose**: [`plugin.json`](https://github.com/openai/plugins/blob/main/plugin.json) describes **what the plugin is** and **how it should be presented**; [`.app.json`](https://github.com/openai/plugins/blob/main/.app.json) describes **how the plugin is identified** for backend routing.
- **Content Scope**: [`plugin.json`](https://github.com/openai/plugins/blob/main/plugin.json) contains rich metadata including the `interface` object with display names, descriptions, and icon paths; [`.app.json`](https://github.com/openai/plugins/blob/main/.app.json) contains only the runtime `id` mapping under the `apps` key.
- **File Location**: [`plugin.json`](https://github.com/openai/plugins/blob/main/plugin.json) resides in the `.codex-plugin/` subdirectory; [`.app.json`](https://github.com/openai/plugins/blob/main/.app.json) sits at the plugin root directory.
- **Consumer**: Codex reads [`plugin.json`](https://github.com/openai/plugins/blob/main/plugin.json) to generate documentation and marketplace listings; the plugin host reads [`.app.json`](https://github.com/openai/plugins/blob/main/.app.json) to resolve endpoint routing.

## Practical Configuration Examples

### Complete [`plugin.json`](https://github.com/openai/plugins/blob/main/plugin.json) Structure

```json
{
  "name": "example-plugin",
  "version": "1.0.0",
  "description": "Demonstrates the split between UI metadata and runtime IDs.",
  "author": {
    "name": "Example Inc",
    "url": "https://example.com"
  },
  "apps": "./.app.json",
  "interface": {
    "displayName": "Example Plugin",
    "shortDescription": "Shows the structural split.",
    "longDescription": "This plugin demonstrates how UI presentation separates from backend identification.",
    "websiteURL": "https://example.com",
    "privacyPolicyUrl": "https://example.com/privacy",
    "termsOfServiceUrl": "https://example.com/tos",
    "composerIcon": "./assets/icon.png",
    "logo": "./assets/logo.png"
  }
}

```

### Corresponding [`.app.json`](https://github.com/openai/plugins/blob/main/.app.json) Structure

```json
{
  "apps": {
    "example-plugin": {
      "id": "asdk_app_1234567890abcdef1234567890abcdef"
    }
  }
}

```

### Accessing the Runtime ID Programmatically

When developing tooling around these configurations, you can read the mapping as follows:

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

const pluginName = 'example-plugin';
const appConfigPath = path.join(__dirname, '.app.json');
const appConfig = JSON.parse(fs.readFileSync(appConfigPath, 'utf8'));

const runtimeId = appConfig.apps[pluginName].id;
console.log(`Backend runtime ID: ${runtimeId}`);

```

## Summary

- **[`.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main/.codex-plugin/plugin.json)** contains the full declarative metadata including the `interface` object that defines UI presentation, icons, descriptions, and marketplace information for Codex consumption.
- **[`.app.json`](https://github.com/openai/plugins/blob/main/.app.json)** provides only the runtime app ID mapping used by the backend plugin host for request routing, containing a single `id` field under the plugin name key.
- The `apps` field in [`plugin.json`](https://github.com/openai/plugins/blob/main/plugin.json) creates a reference link to the [`.app.json`](https://github.com/openai/plugins/blob/main/.app.json) file, maintaining clean separation between presentation and runtime concerns.
- In the `openai/plugins` repository, examples like [`plugins/fyxer/.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main/plugins/fyxer/.codex-plugin/plugin.json) and [`plugins/fyxer/.app.json`](https://github.com/openai/plugins/blob/main/plugins/fyxer/.app.json) demonstrate this consistent architectural pattern across all plugin implementations.

## Frequently Asked Questions

### Can a plugin function without an [`.app.json`](https://github.com/openai/plugins/blob/main/.app.json) file?

No. While [`plugin.json`](https://github.com/openai/plugins/blob/main/plugin.json) defines the plugin's identity and UI presentation, the [`.app.json`](https://github.com/openai/plugins/blob/main/.app.json) file is required to provide the backend runtime `id` that the plugin host uses to route requests. Without this mapping, the system cannot resolve the plugin's endpoints, even though Codex could theoretically render the UI metadata from [`plugin.json`](https://github.com/openai/plugins/blob/main/plugin.json) alone.

### Is the app ID in [`.app.json`](https://github.com/openai/plugins/blob/main/.app.json) manually configurable?

Typically, no. According to the repository structure, the `id` value (e.g., `asdk_app_696e3c8854748191a6006dd80660ad35`) is assigned automatically by the backend when the app is registered. This file is generated as part of the deployment process and should not be manually edited, as doing so would break the routing between the plugin host and the actual backend service.

### Why doesn't [`plugin.json`](https://github.com/openai/plugins/blob/main/plugin.json) simply embed the app ID instead of referencing [`.app.json`](https://github.com/openai/plugins/blob/main/.app.json)?

This separation follows the architectural principle of decoupling presentation from runtime configuration. By keeping the environment-specific `id` in a separate file, [`plugin.json`](https://github.com/openai/plugins/blob/main/plugin.json) remains portable and can be shared or versioned independently of backend identifiers. This allows the same [`plugin.json`](https://github.com/openai/plugins/blob/main/plugin.json) to be used across different deployment stages where the runtime `id` would differ, while only the [`.app.json`](https://github.com/openai/plugins/blob/main/.app.json) file needs to change per environment.

### Where are these files located in the openai/plugins repository?

Each plugin follows the convention of placing [`plugin.json`](https://github.com/openai/plugins/blob/main/plugin.json) inside the `.codex-plugin/` subdirectory (e.g., [`plugins/demandbase/.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main/plugins/demandbase/.codex-plugin/plugin.json)) and [`.app.json`](https://github.com/openai/plugins/blob/main/.app.json) at the plugin root (e.g., [`plugins/demandbase/.app.json`](https://github.com/openai/plugins/blob/main/plugins/demandbase/.app.json)). This consistent file structure allows the Codex system to discover metadata and the plugin host to resolve runtime IDs using predictable paths.