How to Implement Read/Write/Interactive Capabilities in OpenAI Codex Plugins

To implement Read/Write/Interactive capabilities in plugins, declare the required permissions in the capabilities array of your .codex-plugin/plugin.json manifest and enforce them at runtime using the ensureCapability() function from @openai/plugin-runtime.

Implementing Read/Write/Interactive capabilities in plugins requires understanding the permission model defined in the openai/plugins repository. These three capability types control whether a Codex plugin can retrieve data, modify resources, or prompt users for additional input during execution.

Understanding the Three Capability Types

The Codex runtime recognizes three distinct permission levels that govern what actions a plugin can perform on external services.

Read Capability

The Read capability grants a plugin permission to retrieve data without mutating resources. This is the most restrictive permission level, suitable for operations like fetching calendar events, reading documents, or pulling analytics data. When you implement Read/Write/Interactive capabilities in plugins that only retrieve information, declare only ["Read"] in your manifest.

Write Capability

The Write capability allows a plugin to create, update, or delete resources on the target service. Any skill that adds spreadsheet rows, creates tickets, or uploads files requires this permission. The runtime strictly enforces that mutations cannot occur without an explicit Write declaration in the manifest.

Interactive Capability

The Interactive capability enables a plugin to prompt users for additional input during a session, such as requesting confirmation before a write operation or presenting UI widgets. This capability is required for any skill that needs user interaction beyond the initial prompt.

Declaring Capabilities in the Plugin Manifest

The capabilities array resides in the interface object of your .codex-plugin/plugin.json file. The Codex runtime parses this manifest to determine which operations a plugin may perform.

For example, the minimal-plugin fixture declares both Interactive and Write capabilities in plugins/plugin-eval/fixtures/minimal-plugin/.codex-plugin/plugin.json:

{
  "interface": {
    "capabilities": ["Interactive", "Write"]
  }
}

Production plugins follow similar patterns. The Twilio developer-kit plugin, located at plugins/twilio-developer-kit/.codex-plugin/plugin.json, lists Read and Write capabilities:

{
  "interface": {
    "capabilities": ["Read", "Write"]
  }
}

Enforcing Capabilities at Runtime

The Codex runtime automatically blocks any operation that exceeds the declared capabilities. To implement Read/Write/Interactive capabilities in plugins safely, use the ensureCapability() function to explicitly check permissions before executing sensitive operations.

Write Operations

Before creating or modifying resources, verify the Write capability:

// src/skills/updateRecord.ts
import { ensureCapability } from "@openai/plugin-runtime";

export async function updateRecord(id: string, payload: Record<string, any>) {
  // Runtime rejects this call if the plugin lacks Write
  await ensureCapability("Write");
  
  const result = await myServiceApi.put(`/records/${id}`, payload);
  return result;
}

Read Operations

For read-only operations, enforce the Read capability:

// src/skills/getRecord.ts
import { ensureCapability } from "@openai/plugin-runtime";

export async function getRecord(id: string) {
  await ensureCapability("Read");
  const data = await myServiceApi.get(`/records/${id}`);
  return data;
}

Interactive Workflows

When requiring user confirmation, check for the Interactive capability:

// src/skills/updateRecord.ts
import { ensureCapability } from "@openai/plugin-runtime";

export async function updateRecord(id: string, payload: Record<string, any>) {
  await ensureCapability("Write");
  
  // Optional interactive confirmation
  if (await ensureCapability("Interactive")) {
    const confirmed = await askUser(`Overwrite record ${id}?`);
    if (!confirmed) return { status: "cancelled" };
  }
  
  const result = await myServiceApi.put(`/records/${id}`, payload);
  return result;
}

Capability Design Best Practices

When you implement Read/Write/Interactive capabilities in plugins according to the openai/plugins source code, follow these principles:

  • Request minimal permissions: Only declare capabilities your plugin actually needs. The principle of least privilege reduces security risk and user friction.
  • Separate read and write skills: Design read-only skills that can be reused across plugins without requiring Write permissions.
  • Use Interactive sparingly: Mark Interactive only when skills truly require user input during execution, as unnecessary prompts increase friction.
  • Document capabilities: Include capability requirements in your skill's README, as demonstrated in plugins/zoom/skills/zoom-apps-sdk/SKILL.md, so downstream developers understand the permission model.

Summary

Frequently Asked Questions

What happens if a plugin attempts a write without the Write capability?

The Codex runtime blocks the operation and returns a "capability missing" error. The ensureCapability("Write") call will fail before your code executes the API request, preventing unauthorized mutations.

Can a plugin declare all three capabilities simultaneously?

Yes. You can declare "capabilities": ["Read", "Write", "Interactive"] in your manifest if your plugin requires all permission types. However, best practices recommend declaring only the minimal set needed for your specific use case.

Where is the capability enforcement logic implemented in the openai/plugins repository?

The enforcement logic is built into the core plugin framework within the generic plugin loader in plugins/**/.codex-plugin/. While the runtime handles checks automatically, the explicit ensureCapability() calls in your skills make the requirements transparent in logs and error messages.

How do I implement user confirmation prompts in a skill?

To create an interactive skill, first declare "Interactive" in your .codex-plugin/plugin.json capabilities array. Then use await ensureCapability("Interactive") in your skill code to verify you can prompt the user, followed by functions like askUser() to request confirmation or additional input.

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 →