How the Codex Plugin Resolves the Workspace Root for State Storage and Job Tracking

The Codex plugin resolves the workspace root by first attempting to detect the Git repository root using git rev-parse --show-toplevel, and falls back to the current working directory if Git is unavailable or the current directory is not inside a Git repository.

The OpenAI Codex companion plugin requires a stable directory to persist internal state files and JSON logs for tracked jobs. Understanding how the Codex plugin resolves the workspace root is essential for debugging storage paths and ensuring job isolation across different repository structures.

Git-Based Workspace Detection

The entry point for workspace resolution is resolveWorkspaceRoot in plugins/codex/scripts/lib/workspace.mjs. This function implements a two-tier resolution strategy that prioritizes Git repository boundaries while providing a safe fallback.

The ensureGitRepository Helper

When the Codex plugin initializes, it attempts to anchor itself to the repository root via the ensureGitRepository function in plugins/codex/scripts/lib/git.mjs. This utility executes git rev-parse --show-toplevel to query Git for the absolute path of the top-level directory:

// git.mjs
export function ensureGitRepository(cwd) {
  const result = git(cwd, ["rev-parse", "--show-toplevel"]);
  if (result.status !== 0) {
    throw new Error("This command must run inside a Git repository.");
  }
  return result.stdout.trim();        // top-level path
}

If the Git command succeeds, the plugin uses this path as the canonical workspace root, ensuring that state files are stored relative to the repository boundary rather than the current working directory.

Fallback to Current Working Directory

If Git is not installed, not in the system PATH, or the current directory exists outside a Git repository, ensureGitRepository throws an error. The resolveWorkspaceRoot function catches this exception and falls back to the current working directory (cwd):

// workspace.mjs
export function resolveWorkspaceRoot(cwd) {
  try {
    return ensureGitRepository(cwd);   // ← Git-based root
  } catch {
    return cwd;                        // ← fallback to cwd
  }
}

This fallback ensures the plugin remains functional in non-Git environments, though state storage will be scoped to the invocation directory rather than a repository boundary.

State Directory Derivation

Once the workspace root is determined, the plugin derives isolated storage paths through resolveStateDir and related helpers in plugins/codex/scripts/lib/state.mjs. These functions import resolveWorkspaceRoot and perform additional transformations to create repository-scoped directories.

Canonicalization and Hashing

The state resolution process first obtains the workspace root, then canonicalizes it (resolving symlinks and relative paths) to create a deterministic identifier. According to the source code in plugins/codex/scripts/lib/state.mjs, the plugin constructs a hash-based subdirectory name that uniquely identifies the repository:

// state.mjs
import { resolveWorkspaceRoot } from "./workspace.mjs";

export function resolveStateDir(cwd) {
  const workspaceRoot = resolveWorkspaceRoot(cwd);
  // … canonicalise, slugify, hash …
  const stateRoot = process.env[PLUGIN_DATA_ENV] ? … : FALLBACK_STATE_ROOT_DIR;
  return path.join(stateRoot, `${slug}-${hash}`);
}

This hashing strategy ensures that each distinct repository receives its own isolated state folder, preventing collisions when multiple repositories exist on the same machine.

Environment Variable Overrides

The plugin respects the CLAUDE_PLUGIN_DATA environment variable (referenced internally as PLUGIN_DATA_ENV) to allow users to specify a custom base directory for state storage. When this variable is unset, the system falls back to /tmp/codex-companion as the root for state directories.

Job Tracking and Log File Resolution

The job tracking system in plugins/codex/scripts/lib/tracked-jobs.mjs relies entirely on the workspace root resolution chain. Functions such as resolveJobFile and resolveJobLogFile internally call resolveStateDir, which itself depends on resolveWorkspaceRoot.

This dependency chain ensures that every job's JSON metadata and log files are stored within the same repository-specific directory derived from the workspace root detection logic. When you create a tracked job, the plugin generates a unique job ID and places all associated files within the hashed state directory for the current workspace.

Practical Usage Example

To programmatically access the workspace root and state directories in your own scripts:

import { resolveWorkspaceRoot } from "./plugins/codex/scripts/lib/workspace.mjs";
import { resolveStateDir, resolveJobsDir } from "./plugins/codex/scripts/lib/state.mjs";

// 1️⃣ Get the workspace root (Git repo root or cwd)
const root = resolveWorkspaceRoot(process.cwd());
console.log("Workspace root:", root);

// 2️⃣ Compute where the plugin will store its state
const stateDir = resolveStateDir(process.cwd());
console.log("State directory:", stateDir);

// 3️⃣ Create a new tracked job and obtain its log file path
import { generateJobId, createJobLogFile } from "./plugins/codex/scripts/lib/tracked-jobs.mjs";

const jobId = generateJobId();
const logFile = createJobLogFile(stateDir, jobId, "My Example Job");
console.log(`Job ${jobId} log → ${logFile}`);

Summary

  • Git-first detection: The Codex plugin attempts to use git rev-parse --show-toplevel via ensureGitRepository to establish the workspace root, falling back to cwd only when Git is unavailable.
  • Repository isolation: State directories are created using canonicalized, hashed paths derived from the workspace root, ensuring each repository maintains separate storage.
  • Configurable storage: Set the CLAUDE_PLUGIN_DATA environment variable to override the default /tmp/codex-companion base path for state storage.
  • Job tracking dependency: All job logging and JSON state files resolve through the same workspace root chain, guaranteeing consistent file placement across the tracked-jobs.mjs module.

Frequently Asked Questions

What happens if I run the Codex plugin outside a Git repository?

If the current directory is not inside a Git repository or Git is not installed, ensureGitRepository throws an error that resolveWorkspaceRoot catches. The plugin then falls back to using the current working directory as the workspace root. State files will be stored relative to your invocation directory rather than a repository boundary.

Can I override where the Codex plugin stores its state files?

Yes. Set the CLAUDE_PLUGIN_DATA environment variable to specify a custom base directory for state storage. If this variable is undefined, the plugin defaults to /tmp/codex-companion and creates hashed subdirectories beneath it.

How does the plugin handle multiple repositories on the same machine?

The plugin canonicalizes the workspace root path and generates a deterministic hash to create unique subdirectory names under the state root. This ensures that each repository receives its own isolated state folder, preventing state collisions between different projects.

Where are job logs actually stored on disk?

Job logs and JSON metadata files are stored within the state directory derived from resolveStateDir. This directory is constructed by resolving the workspace root (Git repo or cwd), canonicalizing it, and appending a hash-based identifier to either the CLAUDE_PLUGIN_DATA location or /tmp/codex-companion.

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 →