How the Codex Plugin Determines Review Target: Working Tree vs Branch
The Codex plugin uses the resolveReviewTarget function in plugins/codex/scripts/lib/git.mjs to decide whether to review uncommitted working-tree changes or a branch diff, based on explicit flags (--base, --scope) and automatic detection of repository state.
Reviewing code with the OpenAI Codex companion plugin requires knowing exactly what changes you're targeting. The plugin intelligently switches between two modes: examining your working tree (unstaged, staged, and untracked changes) or comparing your current branch against a base reference (branch diff). This article explains the precise decision logic implemented in the openai/codex-plugin-cc source code.
The Core Decision Logic in resolveReviewTarget
The resolveReviewTarget function (lines 35-91 in plugins/codex/scripts/lib/git.mjs) implements a five-step priority flow. The plugin evaluates conditions in strict order and returns immediately when a match is found.
Priority Order for Target Selection
- Explicit
--baseflag — Branch mode with supplied reference - Explicit
--scope working-tree— Working-tree mode forced - Explicit
--scope branch— Branch mode with auto-detected default branch --scope auto+ dirty working tree — Working-tree mode (default behavior)--scope auto+ clean working tree — Branch mode with auto-detected default branch
Each step corresponds to specific source code blocks that set the mode, label, baseRef (when applicable), and explicit boolean on the returned target object.
The Resolved Target Object Structure
When resolveReviewTarget completes, it returns a JavaScript object with this shape:
{
mode: "working-tree" | "branch",
label: "...", // Human-readable description for CLI output
baseRef?: string, // Present only in branch mode
explicit: boolean // true if user forced via flag
}
This object feeds directly into executeReviewRun in plugins/codex/scripts/codex-companion.mjs (lines 58-78), which routes to either buildNativeReviewTarget or adversarial review prompt construction.
How the Plugin Detects Working Tree State
Before making automatic decisions, the plugin must determine if your repository has uncommitted changes. This happens via getWorkingTreeState (lines 22-33 in git.mjs).
The function executes Git commands to check for:
- Staged files (
git diff --cached --quiet) - Unstaged files (
git diff --quiet) - Untracked files (
git ls-files --others --exclude-standard)
If any check fails (returns non-zero), state.isDirty becomes true, triggering the working-tree path in auto mode.
Explicit Flags That Override Detection
The --base Flag (Highest Priority)
When you provide a specific reference, the plugin bypasses all other logic:
codex review --base develop
Code path: if (options.base) → returns branch target with baseRef: "develop" (lines 43-49).
The --scope Flag (Explicit Mode Selection)
| Flag Value | Behavior |
|---|---|
--scope working-tree |
Forces working-tree review regardless of repo state (lines 52-58) |
--scope branch |
Forces branch review against auto-detected default branch (lines 60-74) |
--scope auto |
Default. Delegates to working-tree state detection (lines 76-90) |
The Default Branch Detection Mechanism
When branch mode requires automatic base reference selection, detectDefaultBranch (lines 13-16 in git.mjs) attempts to find:
mainmastertrunk
If none exist, the function throws an error instructing the user to:
- Supply
--base <ref>explicitly, OR - Force
--scope working-tree
Practical Usage Examples
Review Current Uncommitted Changes (Auto-Detected)
# Inside a repo with staged, unstaged, or untracked files
codex review
The plugin detects state.isDirty === true and returns mode: "working-tree".
Force Working-Tree Review on Clean Repository
codex review --scope working-tree
Use this to review staged changes even when no other modifications exist.
Review Against Default Branch
codex review --scope branch
The plugin calls detectDefaultBranch, finds main (or master/trunk), and returns a branch target with that baseRef.
Review Against Specific Branch
codex review --base release/v2.0
Bypasses detection entirely; compares current HEAD against release/v2.0.
Explicit Auto Mode (Documented Default)
codex review --scope auto
Matches the behavior of running codex review without flags: dirty → working-tree, clean → branch.
Key Source Files and Their Roles
| File | Purpose |
|---|---|
plugins/codex/scripts/lib/git.mjs |
Implements resolveReviewTarget, getWorkingTreeState, and detectDefaultBranch |
plugins/codex/scripts/codex-companion.mjs |
Entry point for codex review; consumes target object and builds appropriate review |
plugins/codex/commands/review.md |
CLI documentation defining --scope and --base options |
Summary
resolveReviewTargetingit.mjsis the single source of truth for target determination.- Explicit flags win:
--baseoverrides everything;--scopeoverrides auto-detection. state.isDirtyfromgetWorkingTreeStatedrives the default behavior.- Branch mode requires a base reference: either supplied (
--base) or detected (main/master/trunk). - The returned target object (
mode,label,baseRef,explicit) determines which review path executes incodex-companion.mjs.
Frequently Asked Questions
What happens if I run codex review with no flags in a completely clean repository?
The plugin detects isDirty === false, enters the --scope auto clean-branch path, calls detectDefaultBranch to find your default branch (typically main), and performs a branch diff review comparing your current HEAD against that base. This effectively reviews all commits on your branch that aren't on main.
Can I review staged changes but ignore unstaged files?
Not directly through target resolution. The getWorkingTreeState function treats any staged, unstaged, or untracked files as "dirty," forcing working-tree mode. To review only staged changes, you could stash unstaged work, run codex review --scope working-tree, then unstash.
Why does the plugin fail with "cannot detect default branch"?
Your repository lacks the three standard default branch names (main, master, trunk). The detectDefaultBranch function throws this error (lines 13-16 in git.mjs) to prevent ambiguous branch comparisons. Resolve by passing --base <your-branch-name> explicitly or using --scope working-tree.
What's the difference between --scope branch and --base main?
--scope branch triggers branch mode but still runs detectDefaultBranch to find which reference to use. --base main explicitly sets the base reference, skipping detection entirely. Use --base when your default branch has a non-standard name or when comparing against a specific feature or release branch.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →