# How Prompt Interpolation Works in the OpenAI Codex Plugin

> Understand how OpenAI Codex plugin interpolates prompts by loading Markdown templates and substituting {{PLACEHOLDER}} tokens with runtime values via strict uppercase regex.

- Repository: [OpenAI/codex-plugin-cc](https://github.com/openai/codex-plugin-cc)
- Tags: deep-dive
- Published: 2026-07-08

---

**The OpenAI Codex plugin interpolates prompts by loading Markdown templates from disk and substituting `{{PLACEHOLDER}}` tokens with runtime values using a strict uppercase regex pattern.**

The `openai/codex-plugin-cc` repository implements a template-based prompt system that separates static wording from dynamic data. Understanding how prompt interpolation works in the Codex plugin is essential for customizing AI behavior or adding new review workflows. The system relies on two core utility functions defined in `plugins/codex/scripts/lib/prompts.mjs` that transform template files into executable instructions.

## The Three-Stage Interpolation Pipeline

The interpolation process follows a distinct pipeline: file loading, variable substitution, and prompt consumption. Each stage isolates specific concerns to maintain clean separation between prompt content and application logic.

### Loading Markdown Templates from Disk

The `loadPromptTemplate(rootDir, name)` function handles file I/O by reading templates from the `plugins/codex/prompts/` directory. It constructs the file path by appending `.md` to the provided name parameter and returns the raw text content.

This approach keeps all prompt wording in version-controlled Markdown files rather than embedding strings directly in JavaScript source code, making prompts easier to audit and modify without touching business logic.

### Substituting Placeholders at Runtime

The `interpolateTemplate(template, variables)` function performs the actual string replacement using the regular expression `/\{\{([A-Z_]+)\}\}/g`. This pattern matches only placeholders written in uppercase letters and underscores, ensuring strict naming conventions.

For each match found, the function checks the `variables` object for a corresponding key. If the key exists, the `{{PLACEHOLDER}}` token is replaced with the value; if missing, the plugin substitutes an empty string to prevent `undefined` values from leaking into prompts sent to the Codex model.

### Consuming the Interpolated Prompt

After interpolation completes, the resulting string is passed directly to the Codex runtime. In `stop-review-gate-hook.mjs`, the interpolated prompt is fed to `spawnSync` for execution, while `codex-companion.mjs` uses the output for adversarial review workflows.

## Practical Implementation Examples

### Manual Template Loading and Interpolation

To manually interpolate a prompt, import the utilities from the prompts module and provide your variable map:

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

const template = loadPromptTemplate("/path/to/repo", "my-custom-prompt"); // loads my-custom-prompt.md
const prompt = interpolateTemplate(template, {
  USER_NAME: "Alice",
  TASK_DESCRIPTION: "Refactor the authentication flow",
});
// `prompt` now contains the fully-filled text ready for Codex.

```

### Adding New Prompt Templates

Creating a new prompt requires placing a Markdown file in the correct directory and calling the interpolation functions.

First, create [`plugins/codex/prompts/my-custom-prompt.md`](https://github.com/openai/codex-plugin-cc/blob/main/plugins/codex/prompts/my-custom-prompt.md) with uppercase placeholders:

```markdown
Hello {{USER_NAME}},

Please perform the following task:
{{TASK_DESCRIPTION}}

Thanks!

```

Then load and interpolate it in your script:

```javascript
const template = loadPromptTemplate(ROOT_DIR, "my-custom-prompt");
const prompt = interpolateTemplate(template, {
  USER_NAME: "Bob",
  TASK_DESCRIPTION: "Update the API documentation",
});

```

## Real-World Usage in the Codebase

The plugin demonstrates this pattern in two primary execution contexts:

**Stop-review gate implementation** (`stop-review-gate-hook.mjs`, lines 48-56): Loads the `stop-review-gate` template and injects the `CLAUDE_RESPONSE_BLOCK` variable to construct the final prompt.

**Adversarial review workflow** (`codex-companion.mjs`, lines 41-49): Loads the `adversarial-review` template with multiple variables including `REVIEW_KIND`, `TARGET_LABEL`, `USER_FOCUS`, `REVIEW_COLLECTION_GUIDANCE`, and `REVIEW_INPUT`.

## Summary

- **Template Loading**: The `loadPromptTemplate` function reads Markdown files from `plugins/codex/prompts/` by resolving the filename against the provided root directory.
- **Variable Substitution**: The `interpolateTemplate` function uses the regex `/\{\{([A-Z_]+)\}\}/g` to replace `{{PLACEHOLDER}}` tokens with values from a variables object, substituting empty strings for missing keys to prevent undefined leakage.
- **Runtime Integration**: Interpolated strings are passed directly to Codex execution contexts in `stop-review-gate-hook.mjs` and `codex-companion.mjs` without additional processing.
- **Naming Convention**: Placeholders must use uppercase letters and underscores exclusively to match the interpolation regex.

## Frequently Asked Questions

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

If the `variables` object passed to `interpolateTemplate` lacks a key matching the placeholder name, the function replaces the `{{PLACEHOLDER}}` token with an empty string. This safety mechanism prevents `undefined` or `null` values from appearing in the final prompt sent to the Codex model.

### Can I use lowercase letters in placeholder names?

No. The regular expression `/\{\{([A-Z_]+)\}\}/g` explicitly matches only uppercase letters (A-Z) and underscores. Placeholders like `{{user_name}}` will not be replaced; you must use `{{USER_NAME}}` format instead according to the source code implementation.

### Where should I store new prompt templates?

Store all new Markdown templates in the `plugins/codex/prompts/` directory relative to your repository root. The `loadPromptTemplate` function automatically prepends this path and appends the `.md` extension when resolving file locations, as implemented in `plugins/codex/scripts/lib/prompts.mjs` lines 4-7.

### How does the plugin prevent template injection vulnerabilities?

The interpolation system treats all substituted values as literal strings and does not evaluate the template content as code. Additionally, the plugin substitutes empty strings for any missing variables, preventing accidental leakage of undefined values or internal object representations into the prompt context.