# How to Load and Interpolate Prompt Templates in the OpenAI Codex Plugin

> Learn how the OpenAI Codex plugin loads prompt templates from files and interpolates {{PLACEHOLDER}} tokens with runtime values using loadPromptTemplate and interpolateTemplate utilities.

- Repository: [OpenAI/codex-plugin-cc](https://github.com/openai/codex-plugin-cc)
- Tags: how-to-guide
- Published: 2026-08-01

---

**The Codex plugin loads Markdown prompt templates from `plugins/codex/prompts/` and replaces `{{PLACEHOLDER}}` tokens with runtime values using the `loadPromptTemplate` and `interpolateTemplate` utilities.**

The openai/codex-plugin-cc repository separates prompt content from application logic by storing templates as external Markdown files. This article explains how the `prompts.mjs` utility module handles prompt interpolation and template loading, enabling dynamic injection of context-specific values into static template files at runtime.

## The Prompt Utility Module

All template operations are centralized in `plugins/codex/scripts/lib/prompts.mjs`. This module exports two primary functions that form a complete pipeline for rendering final prompt strings from external files.

### Loading Templates from the Filesystem

The `loadPromptTemplate(rootDir, name)` function constructs a file path to `plugins/codex/prompts/<name>.md` and reads the content synchronously as UTF-8 text. According to the source code at lines 4-7, this function resolves the template path relative to the repository root.

```javascript
// plugins/codex/scripts/lib/prompts.mjs
export function loadPromptTemplate(rootDir, name) {
  const templatePath = path.join(rootDir, "plugins/codex/prompts", `${name}.md`);
  return fs.readFileSync(templatePath, "utf-8");
}

```

### Interpolating Template Variables

The `interpolateTemplate(template, variables)` function handles the actual prompt interpolation by scanning for tokens in the format `{{UPPERCASE_NAME}}`. For each match, it looks up the token name in the supplied `variables` object, substituting the value or an empty string if the key is missing. This implementation appears at lines 9-13 of the utility module.

```javascript
// plugins/codex/scripts/lib/prompts.mjs
export function interpolateTemplate(template, variables) {
  return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
    return variables[key] || "";
  });
}

```

## Real-World Usage Examples

The Codex plugin utilizes this template system across multiple workflows, ensuring consistent prompt rendering for review gates and adversarial analysis.

### Stop-Review Gate Hook

In `plugins/codex/scripts/stop-review-gate-hook.mjs`, the `buildStopReviewPrompt` function demonstrates the complete pattern. It loads the `stop-review-gate` template and injects the previous Claude response into the `{{CLAUDE_RESPONSE_BLOCK}}` placeholder.

```javascript
// plugins/codex/scripts/stop-review-gate-hook.mjs
import { loadPromptTemplate, interpolateTemplate } from "./lib/prompts.mjs";
import path from "node:path";

const ROOT_DIR = path.resolve(import.meta.url, "..", "..");
const template = loadPromptTemplate(ROOT_DIR, "stop-review-gate");

// Insert the previous Claude response (if any)
const prompt = interpolateTemplate(template, {
  CLAUDE_RESPONSE_BLOCK: previousClaudeMessage
});

console.log(prompt);   // Fully‑rendered prompt ready for the Codex task

```

### Adversarial Review Generation

The codex companion script utilizes multiple placeholders for complex prompt interpolation. Located in `plugins/codex/scripts/codex-companion.mjs` at lines 41-49, the `buildAdversarialReviewPrompt` function maps context values to template variables including `REVIEW_KIND`, `TARGET_LABEL`, and `USER_FOCUS`.

```javascript
// plugins/codex/scripts/codex-companion.mjs
import { loadPromptTemplate, interpolateTemplate } from "./lib/prompts.mjs";

function buildAdversarialReviewPrompt(context, focusText) {
  const template = loadPromptTemplate(ROOT_DIR, "adversarial-review");
  return interpolateTemplate(template, {
    REVIEW_KIND: "Adversarial Review",
    TARGET_LABEL: context.target.label,
    USER_FOCUS: focusText || "No extra focus provided.",
    REVIEW_COLLECTION_GUIDANCE: context.collectionGuidance,
    REVIEW_INPUT: context.content
  });
}

```

## Template Syntax and File Organization

Prompt templates follow a strict organizational convention. All template files reside under `plugins/codex/prompts/` with the `.md` extension. Placeholders use double curly braces with uppercase snake_case naming, such as `{{CLAUDE_RESPONSE_BLOCK}}` or `{{REVIEW_KIND}}`.

For example, [`stop-review-gate.md`](https://github.com/openai/codex-plugin-cc/blob/main/stop-review-gate.md) contains the token `{{CLAUDE_RESPONSE_BLOCK}}`, which the interpolation engine replaces with the actual previous message content at runtime. This convention ensures that static prompt instructions remain editable in version-controlled Markdown while runtime data injects safely and deterministically.

## Summary

- **Separation of concerns**: Prompt text lives in `plugins/codex/prompts/` as Markdown files, decoupled from JavaScript logic in `plugins/codex/scripts/`.
- **Two-function API**: `loadPromptTemplate()` reads files from disk using synchronous UTF-8 encoding; `interpolateTemplate()` replaces `{{TOKENS}}` with values from a variables object.
- **Consistent usage**: Both the stop-review gate and adversarial review workflows reuse the same utility module, ensuring uniform prompt rendering across the codebase.
- **Safe defaults**: Missing variables render as empty strings rather than throwing runtime errors, providing graceful degradation.

## Frequently Asked Questions

### Where are prompt templates stored in the Codex plugin?

Prompt templates are stored as Markdown files in the `plugins/codex/prompts/` directory. Each template uses the `.md` extension and is referenced by name (without extension) when calling `loadPromptTemplate(rootDir, name)`.

### What happens if a template variable is missing during interpolation?

If a placeholder like `{{MISSING_KEY}}` cannot be found in the variables object, the `interpolateTemplate` function substitutes an empty string. This prevents runtime errors while allowing optional template sections to remain in the prompt structure.

### Can I use nested objects in the variables parameter?

The current implementation in `plugins/codex/scripts/lib/prompts.mjs` performs a simple key lookup on the variables object. It does not support nested property access—only direct key-value pairs where the key matches the placeholder name exactly.

### How do I add a new prompt template to the system?

Create a new Markdown file in `plugins/codex/prompts/` containing your template text and `{{PLACEHOLDER}}` tokens. Import the utility functions from `plugins/codex/scripts/lib/prompts.mjs`, then call `loadPromptTemplate(rootDir, "your-filename-without-extension")` followed by `interpolateTemplate()` with your data object to render the final prompt.