# Where Ponytail Stores Its Active Mode Flag for Persistence

> Discover where Ponytail stores its active mode flag for persistence. Learn about the .ponytail-active file in environment-specific config directories like ~/.claude and ~/.qoder.

- Repository: [DietrichGebert/ponytail](https://github.com/DietrichGebert/ponytail)
- Tags: internals
- Published: 2026-09-09

---

**Ponytail persists its active mode flag in a hidden file named `.ponytail-active` located inside environment-specific configuration directories such as `~/.claude`, `~/.qoder`, or the path specified by `PLUGIN_DATA`.**

The open-source tool **Ponytail** (DietrichGebert/ponytail) maintains its operational state across process restarts by writing the current mode to a simple text file. Understanding exactly where this active mode flag resides—and how the runtime resolves its location—is critical for debugging, manual configuration resets, or integrating with custom environments.

## The `.ponytail-active` State File

Ponytail uses a single hidden file named **`.ponytail-active`** to store the current mode as a plain-text string.

When present, the file contains values such as `full`, `lite`, or `ultra`. If the file is missing, Ponytail interprets this as the **off** state and behaves accordingly.

### Environment-Specific Storage Locations

The directory containing the active mode flag is determined at runtime based on the detected environment:

- **Native Claude**: Defaults to the Claude configuration directory, resolved via `getClaudeDir()` (typically `$HOME/.claude`)
- **VS Code Copilot**: Uses `process.env.COPILOT_PLUGIN_DATA` if available, otherwise falls back to `getClaudeDir()`
- **Codex**: Uses `process.env.PLUGIN_DATA` directly
- **Qoder**: Creates and uses a dedicated directory at `path.join(os.homedir(), '.qoder')`

This logic results in default paths such as `~/.claude/.ponytail-active` for standard Claude usage or `~/.qoder/.ponytail-active` when running under Qoder.

## Runtime Resolution Logic in [`ponytail-runtime.js`](https://github.com/DietrichGebert/ponytail/blob/main/ponytail-runtime.js)

The core implementation for resolving, reading, and writing the active mode flag lives in **[`hooks/ponytail-runtime.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-runtime.js)**.

### Directory Selection Algorithm

Lines 24-30 determine the target directory by checking environment flags in priority order:

```javascript
let stateDir = getClaudeDir();
if (isCodex) stateDir = process.env.PLUGIN_DATA;
if (isCopilot) stateDir = process.env.COPILOT_PLUGIN_DATA || getClaudeDir();
if (isQoder) stateDir = path.join(os.homedir(), '.qoder');

```

The filename constant is defined at line 6:

```javascript
const STATE_FILE = '.ponytail-active';

```

And the complete persistence path is assembled at line 31:

```javascript
const statePath = path.join(stateDir, STATE_FILE);

```

## Managing the Active Mode Flag

The runtime exposes three helper functions to interact with the state file, implemented in lines 33-49:

- **`setMode(mode)`**: Creates the target directory if it does not exist, then writes the mode string to `.ponytail-active`
- **`readMode()`**: Reads the file and returns the trimmed mode string, or `null` if the file is absent
- **`clearMode()`**: Deletes the flag file, effectively setting the active mode to off

### Practical Code Example

```javascript
const { readMode, setMode, clearMode } = require('./hooks/ponytail-runtime');

// Persist the mode as "ultra"
setMode('ultra');

// Later, or in a separate process, retrieve the persisted active mode
const current = readMode();
console.log('Current Ponytail mode:', current); // "ultra"

// Reset the mode (turn Ponytail off)
clearMode();
console.log('Mode after clear:', readMode()); // null

```

## Related Components Supporting Persistence

Several files in the DietrichGebert/ponytail repository interact with the active mode flag:

| File | Purpose |
|------|---------|
| [`hooks/ponytail-runtime.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-runtime.js) | Defines `STATE_FILE`, implements directory resolution (lines 24-30), and provides `setMode()`, `readMode()`, and `clearMode()` |
| [`hooks/ponytail-config.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-config.js) | Supplies `getClaudeDir()` and `getConfigDir()` helpers used to locate default configuration directories |
| [`scripts/uninstall.js`](https://github.com/DietrichGebert/ponytail/blob/main/scripts/uninstall.js) | Removes the flag file during cleanup via `removeIfExists(path.join(getClaudeDir(), '.ponytail-active'))` |
| [`tests/hooks.test.js`](https://github.com/DietrichGebert/ponytail/blob/main/tests/hooks.test.js) | Validates flag creation, cross-process persistence, and proper cleanup across supported plugin environments |

## Summary

- Ponytail stores its active mode flag in a hidden file named `.ponytail-active` inside environment-specific directories.
- **Native Claude** environments default to `~/.claude/.ponytail-active`, while **Qoder** uses `~/.qoder/.ponytail-active`, and **Codex** respects the `PLUGIN_DATA` environment variable.
- The resolution and I/O logic is centralized in **[`hooks/ponytail-runtime.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-runtime.js)**, specifically at lines 6 (constant definition), 24-30 (directory selection), and 33-49 (helper functions).
- The `setMode()`, `readMode()`, and `clearMode()` functions provide a complete API for state management.
- The uninstall script at [`scripts/uninstall.js`](https://github.com/DietrichGebert/ponytail/blob/main/scripts/uninstall.js) explicitly targets this file to ensure clean removal.

## Frequently Asked Questions

### What happens if I manually delete the `.ponytail-active` file?

If you manually remove the file, Ponytail treats this as an "off" state. The next call to `readMode()` returns `null`, and the tool behaves as if no mode is active until `setMode()` recreates the file with a new value.

### Can I change the location where the active mode flag is stored?

The storage location is hardcoded in [`hooks/ponytail-runtime.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-runtime.js) relative to environment variables and the `getClaudeDir()` helper. To use a custom location, you must modify the `stateDir` assignment logic in lines 24-30, or set the appropriate environment variables (`PLUGIN_DATA`, `COPILOT_PLUGIN_DATA`, or `QODER_SESSION_ID`) before launching Ponytail.

### Why does Ponytail use a text file for persistence instead of a database or registry?

According to the source code in [`hooks/ponytail-runtime.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-runtime.js), Ponytail uses a simple text file to ensure portability across Claude, Copilot, Codex, and Qoder environments without external dependencies. A single hidden file works identically across macOS, Linux, and Windows file systems and requires no administrative privileges or complex setup.

### How do I completely reset Ponytail to its default state?

To fully reset Ponytail, invoke `clearMode()` from [`hooks/ponytail-runtime.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-runtime.js) or manually delete the `.ponytail-active` file from your configuration directory (typically `~/.claude/.ponytail-active` or `~/.qoder/.ponytail-active`). The [`scripts/uninstall.js`](https://github.com/DietrichGebert/ponytail/blob/main/scripts/uninstall.js) script also performs this cleanup automatically during removal.