# What Does ponytail-runtime.js Do in Ponytail? Core Runtime and Mode Management

> Discover what ponytail-runtime.js does in Ponytail. This module manages environment detection, mode tracking, and hook output for VS Code Copilot, Codex, Qoder, and Claude.

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

---

**The [`ponytail-runtime.js`](https://github.com/DietrichGebert/ponytail/blob/main/ponytail-runtime.js) module serves as Ponytail's central runtime helper, managing environment detection, persistent mode tracking, and formatted hook output across VS Code Copilot, Codex, Qoder, and native Claude environments.**

The [`ponytail-runtime.js`](https://github.com/DietrichGebert/ponytail/blob/main/ponytail-runtime.js) file is the backbone of the Ponytail project (DietrichGebert/ponytail), enabling seamless integration with multiple AI coding assistants through a unified API. This core runtime module determines the active host environment, persists operational modes between sessions, and standardizes communication protocols for hook events. Understanding how [`ponytail-runtime.js`](https://github.com/DietrichGebert/ponytail/blob/main/ponytail-runtime.js) functions is essential for developers extending Ponytail or debugging its behavior across different IDE plugins.

## Detecting the Host Environment

Ponytail supports multiple AI assistant plugins, and [`ponytail-runtime.js`](https://github.com/DietrichGebert/ponytail/blob/main/ponytail-runtime.js) identifies the active host by inspecting specific environment variables. In [`hooks/ponytail-runtime.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-runtime.js) (lines 19-23), the module checks for `COPILOT_PLUGIN_DATA`, `CLAUDE_PLUGIN_ROOT`, `PLUGIN_DATA`, and `QODER_SESSION_ID` to determine whether it is running inside **VS Code Copilot**, **Codex**, **Qoder**, or native Claude.

```js
const isCopilot = Boolean(process.env.COPILOT_PLUGIN_DATA) ||
  isVsCodeCopilotRoot(process.env.CLAUDE_PLUGIN_ROOT);
const isCodex = !isCopilot && Boolean(process.env.PLUGIN_DATA);
const isQoder = !isCopilot && !isCodex && Boolean(process.env.QODER_SESSION_ID);

```

This detection logic ensures that subsequent operations use the correct file paths and output formats for the specific environment.

## Persisting the Current Ponytail Mode

The runtime enables Ponytail to maintain state between process invocations by writing the active mode to a hidden file named `.ponytail-active`. Located in [`hooks/ponytail-runtime.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-runtime.js) (lines 33-49), the **mode management functions** handle three critical operations: `setMode()`, `readMode()`, and `clearMode()`.

The storage location varies by environment:

- **VS Code Copilot**: `process.env.COPILOT_PLUGIN_DATA` or the default Claude directory
- **Codex**: `process.env.PLUGIN_DATA`
- **Qoder**: `~/.qoder`

```js
function setMode(mode) {
  fs.mkdirSync(path.dirname(statePath), { recursive: true });
  fs.writeFileSync(statePath, mode);
}
function clearMode() { try { fs.unlinkSync(statePath); } catch (e) {} }
function readMode() {
  try { return fs.readFileSync(statePath, 'utf8').trim() || null; }
  catch (e) { return null; }
}

```

These functions provide a consistent, environment-agnostic API for activating debug or test modes, reading the current state on startup, and clearing the state when Ponytail is disabled.

## Emitting Environment-Specific Hook Output

When Ponytail-related events occur—such as `SessionStart`, `SubagentStart`, or `UserPromptSubmit`—the `writeHookOutput()` function formats JSON payloads tailored to the host plugin's expectations. This logic, found in [`hooks/ponytail-runtime.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-runtime.js) (lines 51-90), ensures that **Copilot** receives `additionalContext` objects, while **Codex** receives `systemMessage` prefixes with optional `hookSpecificOutput` blocks.

```js
function writeHookOutput(event, mode, context = '') {
  if (isCopilot) {
    process.stdout.write(JSON.stringify(
      event === 'SessionStart' && context ? { additionalContext: context } : {}));
    return;
  }
  if (isCodex) {
    const output = { systemMessage: `PONYTAIL:${mode.toUpperCase()}` };
    if (context) {
      output.hookSpecificOutput = { hookEventName: event, additionalContext: context };
    }
    process.stdout.write(JSON.stringify(output));
    return;
  }
  // Qoder and Native Claude handling omitted for brevity …
}

```

**Qoder** and **native Claude** receive similar but distinct formats, with Claude requiring special handling for `SubagentStart` events to guarantee the correct JSON shape for sub-agent communication.

## Practical Implementation Examples

Developers can import [`ponytail-runtime.js`](https://github.com/DietrichGebert/ponytail/blob/main/ponytail-runtime.js) into custom scripts to interact with Ponytail's state machine directly.

Activating a mode and notifying the host:

```js
// example.js
const { setMode, writeHookOutput } = require('./hooks/ponytail-runtime');

// Turn Ponytail on in “debug” mode
setMode('debug');

// Notify the host that a new session has started, passing extra context
writeHookOutput('SessionStart', 'debug', 'Running debug session for feature X');

```

Reading the active mode inside another hook:

```js
// some-other-hook.js
const { readMode, isCopilot } = require('./hooks/ponytail-runtime');

const current = readMode();
if (current) {
  console.log(`Ponytail is active in ${current} mode`);
  if (isCopilot) {
    // Copilot‑specific handling …
  }
}

```

Clearing the state when the user disables Ponytail:

```js
const { clearMode } = require('./hooks/ponytail-runtime');
clearMode();   // Removes .ponytail-active, signalling “off”

```

## Integration with the Ponytail Ecosystem

The [`ponytail-runtime.js`](https://github.com/DietrichGebert/ponytail/blob/main/ponytail-runtime.js) module does not operate in isolation. It relies on companion files within the `hooks/` directory to provide a complete mode-tracking solution:

- **[`hooks/ponytail-config.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-config.js)**: Provides helper functions like `getClaudeDir` and `getConfigDir` used to locate state files across environments.
- **[`hooks/ponytail-mode-tracker.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-mode-tracker.js)**: Listens for IDE events and invokes `setMode()` or `clearMode()` accordingly.
- **[`hooks/ponytail-activate.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-activate.js)**: Serves as the entry point that initializes Ponytail and wires the runtime into the host environment.
- **[`hooks/ponytail-instructions.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-instructions.js)**: Supplies instruction templates that may be injected via `writeHookOutput()`.

Together, these components enable Ponytail to maintain a **consistent operational state** regardless of which AI assistant plugin is hosting the session.

## Summary

- **Environment Detection**: [`ponytail-runtime.js`](https://github.com/DietrichGebert/ponytail/blob/main/ponytail-runtime.js) inspects environment variables like `COPILOT_PLUGIN_DATA` and `QODER_SESSION_ID` to identify the active AI assistant plugin.
- **Mode Persistence**: The module provides `setMode()`, `readMode()`, and `clearMode()` functions to manage the `.ponytail-active` state file across VS Code Copilot, Codex, and Qoder environments.
- **Standardized Output**: The `writeHookOutput()` function formats event-specific JSON payloads for `SessionStart`, `SubagentStart`, and other hook events according to each plugin's requirements.
- **Cross-Platform API**: Located at [`hooks/ponytail-runtime.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-runtime.js), this file offers a unified interface for mode management that abstracts away environment-specific implementation details.

## Frequently Asked Questions

### What is the primary purpose of ponytail-runtime.js in the Ponytail project?

The [`ponytail-runtime.js`](https://github.com/DietrichGebert/ponytail/blob/main/ponytail-runtime.js) file serves as the central runtime helper that enables Ponytail's mode-tracking and hook output logic across different AI-assistant environments. It abstracts environment detection, state persistence, and communication protocols into a single module that other hooks can import and use consistently.

### How does ponytail-runtime.js detect which AI assistant plugin is active?

The module checks for environment-specific variables in the following priority: `COPILOT_PLUGIN_DATA` or `CLAUDE_PLUGIN_ROOT` for VS Code Copilot, `PLUGIN_DATA` for Codex, and `QODER_SESSION_ID` for Qoder. Boolean checks on these variables determine the active host and configure subsequent file paths and output formats accordingly.

### Where is the Ponytail mode state stored on disk?

The active mode is written to a hidden file named `.ponytail-active` located in environment-specific directories: the Copilot plugin data directory (or default Claude directory) for VS Code Copilot, the `PLUGIN_DATA` directory for Codex, and `~/.qoder` for Qoder. The `setMode()` function creates these directories recursively if they do not exist.

### Can I use ponytail-runtime.js functions in my own custom hooks?

Yes, you can require [`hooks/ponytail-runtime.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-runtime.js) in custom scripts to access `setMode()`, `readMode()`, `clearMode()`, and `writeHookOutput()`. This allows custom hooks to read the current operational mode, activate specific modes like debug or test, and emit properly formatted JSON output recognized by the host AI assistant plugin.