# How the Codex Plugin Collects Git Repository Context for Reviews

> Discover how the Codex plugin collects git repository context for reviews. It uses a three-stage pipeline to gather diff data and untracked files, creating a structured JSON payload for the language model.

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

---

**The Codex plugin collects git repository context through a three-stage pipeline in `plugins/codex/scripts/lib/git.mjs`: resolving the review target, gathering raw diff data with size limits, and enriching with untracked files to produce a structured JSON payload for the language model.**

When you run `codex review`, the `openai/codex-plugin-cc` repository needs to feed the Codex language model a complete yet concise snapshot of your changes. This **review context** is built by the `collectReviewContext` function and follows a predictable pipeline from detection to delivery. Understanding how this works helps you interpret review behavior, debug missing files, or tune performance for large repositories.

## The Three Stages of Context Collection

The `collectReviewContext` routine in `plugins/codex/scripts/lib/git.mjs` breaks the work into modular stages that each handle a specific concern.

### Stage 1: Resolve the Review Target with `resolveReviewTarget`

The plugin first determines **what** to diff. The `resolveReviewTarget(cwd, options)` function (starting at line 135 in `git.mjs`) inspects repository state and returns a target descriptor:

- **Dirty working tree**: If `git status --porcelain` shows uncommitted changes, it prepares a working-tree diff.
- **Clean state**: Falls back to a branch-range diff using the default branch (`git symbolic-ref refs/remotes/origin/HEAD`).
- **Explicit overrides**: Respects `options.base`, `options.head`, or `options.scope` when provided.

The function ensures the current directory is a Git repository via `ensureGitRepository` (line 80) before proceeding.

### Stage 2: Gather Raw Diff Data

With the target resolved, the plugin executes `git diff` commands (around lines 320-350 in `git.mjs`):

- Uses `--binary` to preserve file renames and binary changes.
- Runs `git diff --shortstat` for a human-readable summary.
- Applies `maxInlineDiffBytes` (default 256 KB) to prevent oversized payloads.

When the diff exceeds this limit, the function switches to a **lightweight context** containing only filenames and short-stat rather than full patch text.

### Stage 3: Enrich with Untracked Files and File Contents

The final enrichment step (lines 380-420 in `git.mjs`) handles edge cases:

- **Untracked files**: Discovered via `git ls-files --others --exclude-standard`, then read via `fs.readFile` and added to `context.files` with path and content.
- **Symlink safety**: Broken symlinks are skipped without crashing (verified in `tests/git.test.mjs`).
- **Size pruning**: Individual file reads respect the same size limits as diffs.

The resulting context object follows the schema defined in [`plugins/codex/schemas/review-output.schema.json`](https://github.com/openai/codex-plugin-cc/blob/main/plugins/codex/schemas/review-output.schema.json):

```json
{
  "base": "origin/main",
  "head": "HEAD",
  "diff": "…patch text…",
  "files": [
    { "path": "src/app.js", "content": "…" }
  ],
  "stats": "3 files changed, 45 insertions(+), 12 deletions(-)"
}

```

## Practical Example: Using the Git Utilities Directly

The `codex-companion.mjs` script (line 409) demonstrates the standard integration pattern. You can also use these utilities in custom workflows:

```javascript
import {
  ensureGitRepository,
  resolveReviewTarget,
  collectReviewContext,
} from "./lib/git.mjs";

// Validate repository presence
await ensureGitRepository(process.cwd());

// Auto-detect target (dirty working tree vs. branch range)
const target = resolveReviewTarget(process.cwd());

// Build context with custom size limits
const reviewContext = await collectReviewContext(process.cwd(), target, {
  maxInlineDiffBytes: 200 * 1024, // 200 KB limit
});

// Submit to Codex
await codex.submitReview(reviewContext);

```

## Key Source Files and Their Roles

| File | Purpose | Critical Functions |
|------|---------|-------------------|
| `plugins/codex/scripts/lib/git.mjs` | Core Git operations | `ensureGitRepository`, `resolveReviewTarget`, `collectReviewContext` |
| `plugins/codex/scripts/codex-companion.mjs` | CLI orchestration | Calls `collectReviewContext` at line 409 |
| [`plugins/codex/schemas/review-output.schema.json`](https://github.com/openai/codex-plugin-cc/blob/main/plugins/codex/schemas/review-output.schema.json) | Payload validation | Defines context object shape |
| `tests/git.test.mjs` | Behavior verification | Tests dirty repos, untracked directories, broken symlinks |
| `tests/commands.test.mjs` | CLI integration | Verifies `git diff --shortstat` output format |

## Summary

- **Target resolution** uses `resolveReviewTarget` to choose between working-tree and branch-range diffs based on repository state and explicit options.
- **Diff collection** runs `git diff --binary` with configurable size limits via `maxInlineDiffBytes`, falling back to lightweight context when exceeded.
- **Content enrichment** adds untracked files through `git ls-files --others` and `fs.readFile`, safely handling symlinks and size constraints.
- **Final packaging** produces a JSON payload conforming to [`review-output.schema.json`](https://github.com/openai/codex-plugin-cc/blob/main/review-output.schema.json) with `base`, `head`, `diff`, `files`, and `stats` fields.

## Frequently Asked Questions

### How does the plugin decide between reviewing unstaged changes or comparing branches?

The `resolveReviewTarget` function runs `git status --porcelain` first. If output exists (uncommitted changes), it targets the working tree. Otherwise it uses the default remote branch for a branch-range comparison. You can override this with `options.base`, `options.head`, or `options.scope`.

### What happens when a repository has very large diffs?

When `collectReviewContext` encounters a diff larger than `maxInlineDiffBytes` (default 256 KB), it truncates the patch text and returns a **lightweight context** containing only file paths and `git diff --shortstat` output. This prevents token limit exhaustion in the language model.

### Are untracked files included in reviews?

Yes. The plugin runs `git ls-files --others --exclude-standard` to find untracked files, reads their contents up to the size limit, and includes them in the `files` array with path and content. Broken symlinks are detected and skipped to prevent crashes.

### Can I use the git utilities outside the standard CLI workflow?

Yes. The module exports `ensureGitRepository`, `resolveReviewTarget`, and `collectReviewContext` from `plugins/codex/scripts/lib/git.mjs`. Import these in custom scripts to build review contexts with your own configuration, then submit via `codex.submitReview(context)`.