# How Ponytail Detects Different AI Agent Platforms: Environment Variables and Hook Loading

> Discover how Ponytail detects AI agent platforms like Copilot and Codex by examining environment variables and loading specific hook configurations.

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

---

**Ponytail detects the active AI agent platform by checking environment variables like `COPILOT_PLUGIN_DATA`, `CODX_PLUGIN_DATA`, and `CLAUDE_PLUGIN_DATA`, then loads platform-specific hook configurations to adapt its behavior accordingly.**

The open-source project `DietrichGebert/ponytail` implements a lightweight runtime detection system that identifies whether it is running under GitHub Copilot, OpenAI Codex, Anthropic Claude, or a generic instruction-only environment. This detection mechanism allows Ponytail to dynamically adjust its operational modes and hook sets based on the specific capabilities and constraints of each AI agent platform.

## Platform Detection via Environment Variables

Ponytail's detection logic centers on environment variables injected by each AI agent's plugin integration. When the runtime initializes in [`hooks/ponytail-runtime.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-runtime.js), it inspects `process.env` for platform-specific data directory pointers that indicate which agent is hosting the session.

### GitHub Copilot Detection

When running under GitHub Copilot, the runtime checks for the `COPILOT_PLUGIN_DATA` environment variable. This variable contains a path to a temporary directory where Copilot stores session-specific state files.

```javascript
// hooks/ponytail-runtime.js
if (env.COPILOT_PLUGIN_DATA) {
  return { name: 'copilot', dataDir: env.COPILOT_PLUGIN_DATA };
}

```

The existence of this variable triggers Copilot-specific behavior, including the loading of [`hooks/copilot-hooks.json`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/copilot-hooks.json) and verification of marker files within the data directory.

### OpenAI Codex Detection

For OpenAI Codex integration, Ponytail looks for the `CODX_PLUGIN_DATA` environment variable. This follows the same pattern as Copilot detection but directs the runtime to Codex-specific configuration files.

```javascript
if (env.CODX_PLUGIN_DATA) {
  return { name: 'codex', dataDir: env.CODX_PLUGIN_DATA };
}

```

When detected, the runtime imports hook configurations appropriate for the Codex execution environment.

### Anthropic Claude Detection

Anthropic Claude is identified through the `CLAUDE_PLUGIN_DATA` environment variable. The runtime treats this similarly to other platforms, using the provided data directory path to locate Claude-specific resources and configuration files.

```javascript
if (env.CLAUDE_PLUGIN_DATA) {
  return { name: 'claude', dataDir: env.CLAUDE_PLUGIN_DATA };
}

```

## Runtime Implementation in ponytail-runtime.js

The core detection logic resides in [`hooks/ponytail-runtime.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-runtime.js), which exports a `detectPlatform()` function that performs sequential checks against the environment. This function returns a platform descriptor object containing the platform name and data directory path, or falls back to a generic configuration.

```javascript
// hooks/ponytail-runtime.js (simplified)
function detectPlatform() {
  const env = process.env;

  if (env.COPILOT_PLUGIN_DATA) {
    return { name: 'copilot', dataDir: env.COPILOT_PLUGIN_DATA };
  }
  if (env.CODX_PLUGIN_DATA) {
    return { name: 'codex', dataDir: env.CODX_PLUGIN_DATA };
  }
  if (env.CLAUDE_PLUGIN_DATA) {
    return { name: 'claude', dataDir: env.CLAUDE_PLUGIN_DATA };
  }
  // Fallback – use instruction files only
  return { name: 'generic', dataDir: null };
}

```

After detection, the runtime uses the returned platform name to import the appropriate hook set from the corresponding JSON configuration files.

## Platform-Specific Hook Loading

Once Ponytail identifies the active platform, it dynamically loads hook configurations that define which capabilities and modes are available for that specific agent.

### Hook Configuration Files

Each supported platform has a dedicated configuration file in the `hooks/` directory:

- **[`hooks/copilot-hooks.json`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/copilot-hooks.json)** – Defines available hooks and modes for GitHub Copilot
- **[`hooks/claude-codex-hooks.json`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/claude-codex-hooks.json)** – Contains configuration for both Claude and Codex platforms
- **[`.github/plugin/plugin.json`](https://github.com/DietrichGebert/ponytail/blob/main/.github/plugin/plugin.json)** – Declares which hook files belong to which plugin

The runtime imports these files based on the `name` property returned by `detectPlatform()`, ensuring that only compatible hooks are activated for the current environment.

### Marker Files and Mode Detection

For platforms like Copilot, Ponytail performs additional validation by checking for marker files within the data directory. The runtime looks for `.ponytail-active` inside the `COPILOT_PLUGIN_DATA` directory to determine the current operational mode.

```javascript
function getCopilotMode(copilotDir) {
  const modePath = require('path').join(copilotDir, '.ponytail-active');
  try {
    return require('fs').readFileSync(modePath, 'utf8').trim();
  } catch (_) {
    return 'full'; // default mode
  }
}

```

This file stores values like `full` or `ultra`, allowing the platform to persist session preferences across invocations.

## Fallback Detection Strategy

When none of the platform-specific environment variables are defined, Ponytail enters a generic "instruction-only" mode. In this fallback state, the runtime relies on static instruction files rather than dynamic hook loading.

The fallback mechanism checks for:

- **[`AGENTS.md`](https://github.com/DietrichGebert/ponytail/blob/main/AGENTS.md)** – A generic instruction file read when no platform-specific environment is detected
- **[`.github/copilot-instructions.md`](https://github.com/DietrichGebert/ponytail/blob/main/.github/copilot-instructions.md)** – Used by the Copilot CLI and other agents that provide instruction files without plugin data directories

This design ensures Ponytail remains functional even when running in simplified environments or local CLI contexts where full plugin integration is unavailable.

## Summary

- **Environment variable inspection** is the primary detection method, with `COPILOT_PLUGIN_DATA`, `CODX_PLUGIN_DATA`, and `CLAUDE_PLUGIN_DATA` serving as platform identifiers.
- **[`hooks/ponytail-runtime.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-runtime.js)** contains the `detectPlatform()` function that implements the sequential checking logic and returns platform-specific configurations.
- **Hook configuration files** like [`hooks/copilot-hooks.json`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/copilot-hooks.json) and [`hooks/claude-codex-hooks.json`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/claude-codex-hooks.json) provide platform-specific behavior definitions that are loaded dynamically after detection.
- **Marker files** such as `.ponytail-active` within data directories enable fine-grained mode detection for supported platforms.
- **Fallback handling** through [`AGENTS.md`](https://github.com/DietrichGebert/ponytail/blob/main/AGENTS.md) and [`.github/copilot-instructions.md`](https://github.com/DietrichGebert/ponytail/blob/main/.github/copilot-instructions.md) ensures compatibility with instruction-only agent environments.

## Frequently Asked Questions

### How does Ponytail distinguish between Copilot and Codex when both might be present?

Ponytail checks environment variables in a specific priority order within `detectPlatform()`. Whichever variable is present first determines the active platform. Since each AI agent platform sets only its own specific variable during execution, conflicts are rare. If multiple variables were somehow present, the first match in the conditional chain (Copilot, then Codex, then Claude) would take precedence.

### What happens if none of the AI agent environment variables are set?

When `COPILOT_PLUGIN_DATA`, `CODX_PLUGIN_DATA`, and `CLAUDE_PLUGIN_DATA` are all undefined, `detectPlatform()` returns a generic configuration with `name: 'generic'` and `dataDir: null`. The runtime then falls back to reading static instruction files from [`AGENTS.md`](https://github.com/DietrichGebert/ponytail/blob/main/AGENTS.md) or [`.github/copilot-instructions.md`](https://github.com/DietrichGebert/ponytail/blob/main/.github/copilot-instructions.md), operating in a reduced functionality mode without dynamic hooks.

### Can new AI agent platforms be added to Ponytail without modifying the core code?

Yes, the architecture supports extensibility by following the established pattern. New platforms need only provide a unique `*_PLUGIN_DATA` environment variable and a corresponding hooks JSON file (e.g., [`hooks/newagent-hooks.json`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/newagent-hooks.json)). The detection logic in [`hooks/ponytail-runtime.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-runtime.js) would need a new conditional check, and the plugin manifest at [`.github/plugin/plugin.json`](https://github.com/DietrichGebert/ponytail/blob/main/.github/plugin/plugin.json) requires updating to register the new hook file.

### Where does Ponytail store the detected platform mode for GitHub Copilot?

When running under GitHub Copilot, Ponytail reads the current mode from a file named `.ponytail-active` located in the directory specified by the `COPILOT_PLUGIN_DATA` environment variable. The `getCopilotMode()` function in the runtime constructs this path using `path.join(copilotDir, '.ponytail-active')` and returns the file contents, defaulting to `'full'` if the file does not exist.