# How the Codex Plugin Resolves State Directory Locations in openai/codex-plugin-cc

> Discover how the Codex plugin resolves state directory locations by hashing workspace roots and incorporating slugs, ensuring organized data storage.

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

---

**The Codex plugin derives a unique state directory by hashing the canonicalized workspace root path and combining it with a sanitized directory slug, storing files under `$CLAUDE_PLUGIN_DATA/state` or falling back to a temporary directory.**

The openai/codex-plugin-cc repository implements a deterministic file resolution system to persist runtime data across sessions. Understanding how the Codex plugin resolves state directory locations is essential for configuring persistent storage and avoiding collisions between multiple workspaces.

## Step-by-Step State Directory Resolution

The resolution logic lives in `plugins/codex/scripts/lib/state.mjs` and executes a six-step algorithm to ensure each workspace receives a collision-free storage location.

### Locating the Workspace Root

The process begins with `resolveWorkspaceRoot(cwd)` defined in `plugins/codex/scripts/lib/workspace.mjs` (lines 3–9). This function traverses up the directory tree from the supplied `cwd` until it identifies a Git repository root. If no Git repository is found, it falls back to the supplied `cwd` value.

### Canonicalizing the Path

To ensure stability, the discovered root passes through `fs.realpathSync.native` (lines 30–36 in `state.mjs`). This resolves any symbolic links, guaranteeing that the same physical directory always maps to the same state identifier regardless of access method.

### Generating the Directory Slug and Hash

The plugin creates a human-readable prefix by sanitizing the workspace basename, converting non-alphanumeric characters to hyphens (lines 38–40). It then computes a SHA-256 hash of the canonical path and retains the first 16 hexadecimal characters (lines 40–41). This hash ensures uniqueness even when two workspaces share identical names.

### Selecting the Base Directory via Environment Variable

The parent directory for state files depends on the `CLAUDE_PLUGIN_DATA` environment variable (lines 10–13). When defined, the plugin uses `$CLAUDE_PLUGIN_DATA/state` as the root. Otherwise, it falls back to `os.tmpdir()` under the subdirectory `codex-companion` (lines 41–43).

### Constructing the Final Path

The final state directory follows this pattern:

```text
<stateRoot>/<slug>-<hash>

```

As implemented in lines 42–44 of `state.mjs`, `<stateRoot>` is either the environment-based path or the temporary directory, resulting in paths like `/tmp/codex-companion/myproj-1a2b3c4d5e6f7g8h`.

## Helper Functions for State Access

Once `resolveStateDir` establishes the base directory, specialized helpers construct full paths for specific resources:

- **`resolveStateFile(cwd)`** – Returns the path to [`state.json`](https://github.com/openai/codex-plugin-cc/blob/main/state.json)
- **`resolveJobsDir(cwd)`** – Returns the jobs subdirectory
- **`resolveJobFile(cwd, jobId)`** – Returns the path for a specific job file
- **`resolveJobLogFile(cwd, jobId)`** – Returns the path for job-specific logs

These functions simply join filenames to the computed state directory.

## Implementation Examples

Locate the persistent state directory for the current process:

```javascript
import { resolveStateDir, resolveStateFile } from "./plugins/codex/scripts/lib/state.mjs";

const cwd = process.cwd();                     // any directory inside the workspace
const stateDir = resolveStateDir(cwd);          // e.g. /tmp/codex-companion/myproj-1a2b3c4d5e6f7g8h
const stateFile = resolveStateFile(cwd);        // e.g. /tmp/.../state.json

console.log("State directory:", stateDir);
console.log("State file:", stateFile);

```

Override the base location using the `CLAUDE_PLUGIN_DATA` environment variable:

```javascript
process.env.CLAUDE_PLUGIN_DATA = "/var/lib/codex-plugin";

import { resolveStateDir } from "./plugins/codex/scripts/lib/state.mjs";

const dir = resolveStateDir("/home/user/my-repo");
console.log(dir);
// → /var/lib/codex-plugin/state/my-repo-<hash>

```

Retrieve directories and paths for job-specific files:

```javascript
import { resolveJobsDir, resolveJobFile } from "./plugins/codex/scripts/lib/state.mjs";

const jobsDir = resolveJobsDir(cwd);
const jobId = "job-abc123";
const jobFile = resolveJobFile(cwd, jobId);

console.log("Jobs directory:", jobsDir);
console.log("Job file path:", jobFile);

```

## Summary

- The Codex plugin computes state directories by walking up to the Git root via `workspace.mjs` and canonicalizing paths with `fs.realpathSync.native` to handle symlinks.
- Directory names combine a sanitized slug with a 16-character SHA-256 hash of the canonical path, preventing collisions between identically named workspaces.
- The `CLAUDE_PLUGIN_DATA` environment variable overrides the default temporary directory (`os.tmpdir()/codex-companion`) as the storage root.
- Helper functions in `state.mjs` provide convenient accessors for [`state.json`](https://github.com/openai/codex-plugin-cc/blob/main/state.json), job directories, and log files.

## Frequently Asked Questions

### What happens if the workspace is not a Git repository?

If `resolveWorkspaceRoot` in `workspace.mjs` fails to locate a Git repository, it falls back to the `cwd` parameter provided to the function. The state directory is then derived from this fallback path, ensuring the plugin still functions outside of version-controlled projects.

### Can I customize where the Codex plugin stores its state files?

Yes. Set the `CLAUDE_PLUGIN_DATA` environment variable to your preferred base directory. The plugin automatically appends `/state` to this path and stores all persistent data there, bypassing the default temporary directory location.

### How does the plugin prevent state directory collisions between workspaces with the same name?

The plugin computes a SHA-256 hash of the canonicalized absolute path and appends the first 16 hexadecimal characters to the directory name. Since absolute paths are unique, this hash guarantees distinct state directories even for workspaces sharing identical basenames.

### Where are job-specific files stored within the state directory?

Job files reside in a `jobs` subdirectory within the computed state directory. The `resolveJobFile` and `resolveJobLogFile` functions in `plugins/codex/scripts/lib/state.mjs` generate specific paths by joining the job ID to this subdirectory, returning fully qualified paths for job data and logs.