# How Ponytail Mode Is Tracked and Activated Using /ponytail Commands

> Discover how Ponytail mode is tracked and activated via /ponytail commands. Learn about the dual state machine using Python variables and Node.js flags for intensity levels.

- Repository: [DietrichGebert/ponytail](https://github.com/DietrichGebert/ponytail)
- Tags: how-to-guide
- Published: 2026-09-11

---

**Ponytail implements a two-layer state machine that combines in-process Python variables with persistent Node.js filesystem flags to track and activate lazy-senior-dev intensity levels through `/ponytail` slash commands.**

The DietrichGebert/ponytail repository uses a hybrid architecture spanning Hermes plugins and runtime hooks to manage session state. When you issue a `/ponytail` command, the system coordinates between ephemeral memory storage and disk-based persistence to ensure your selected mode—whether `lite`, `full`, `ultra`, or `off`—survives across conversation restarts and plugin reloads.

## Understanding the Two-Layer State Machine

Ponytail’s mode management relies on complementary tracking mechanisms that operate during active sessions and between restarts.

### In-Process Session Tracking

While a conversation session remains active, the Python Hermes plugin maintains the current intensity level in a module-level variable. In [`__init__.py`](https://github.com/DietrichGebert/ponytail/blob/main/__init__.py), the `_current_mode` variable is initialized to `None` at line 27:

```python

# __init__.py line 27

_current_mode = None

```

This variable stores the active mode only for the duration of the process lifecycle. When you issue a slash command, the `_handle_mode_command` function (lines 66‑78) updates this in-memory state after validating the requested intensity.

### Persistent Mode Storage

To survive process restarts, a Node.js *mode-tracker* hook writes state to a hidden flag file. The hook at [`hooks/ponytail-mode-tracker.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-mode-tracker.js) (lines 20‑82) parses user prompts and manages the `.ponytail-active` file through utility functions defined in [`hooks/ponytail-runtime.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-runtime.js).

The `setMode` function writes the mode string to disk:

```javascript
// hooks/ponytail-runtime.js lines 33-36
function setMode(mode) {
  fs.mkdirSync(path.dirname(FLAG_PATH), { recursive: true });
  fs.writeFileSync(FLAG_PATH, mode, 'utf8');
}

```

Conversely, `readMode` retrieves the persisted state:

```javascript
// hooks/ponytail-runtime.js lines 44-48
function readMode() {
  if (!fs.existsSync(FLAG_PATH)) return null;
  return fs.readFileSync(FLAG_PATH, 'utf8').trim();
}

```

## The /ponytail Command Activation Flow

The activation sequence involves four coordinated steps across the Python plugin and Node.js runtime environment.

### Step 1: Command Registration and Receipt

The Hermes plugin registers the `/ponytail` command during initialization. The `register()` function (lines 95‑108) binds the command to the `_handle_mode_command` callback:

```python

# __init__.py lines 95-108

def register():
    ctx = get_context()
    ctx.register_command(
        "ponytail",
        _handle_mode_command,
        description="Set Ponytail mode: lite, full, ultra, off, or default"
    )

```

When a user types `/ponytail ultra`, the gateway dispatches to this handler.

### Step 2: Parsing and Validation

The `_handle_mode_command` function strips the leading command, normalizes the argument, and validates it against supported modes (`lite`, `full`, `ultra`, `off`, `default`, `review`). Valid modes update `_current_mode`, while the `off` command clears the session state.

### Step 3: Runtime Hook Processing

Every user prompt passes through the *UserPromptSubmit* hook in [`hooks/ponytail-mode-tracker.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-mode-tracker.js) (lines 23‑50). This hook matches commands using the regex `/^[\/@$]ponytail/`:

```javascript
// hooks/ponytail-mode-tracker.js lines 23-50
const PONYTAIL_REGEX = /^[\/@$]ponytail\s*(.*)/i;
// ...
const match = prompt.match(PONYTAIL_REGEX);
if (match) {
  const subcommand = match[1].trim().toLowerCase();
  if (['lite', 'full', 'ultra'].includes(subcommand)) {
    setMode(subcommand);
  } else if (subcommand === 'off') {
    clearMode();
  }
}

```

This persists the mode to `.ponytail-active` so subsequent prompts and new sessions recognize the setting.

### Step 4: Session Start Activation

When a new session begins, [`hooks/ponytail-activate.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-activate.js) (lines 24‑33) executes during the *SessionStart* hook. It calls `readMode()` to retrieve the persisted flag, then injects the appropriate Ponytail ruleset into the conversation context. If the mode is `off`, the hook aborts early to skip injection.

## Default Mode Resolution

If no explicit mode is set, the system resolves defaults through a hierarchical cascade. The `_default_mode()` function (lines 52‑64) checks:

1. The `PONYTAIL_DEFAULT_MODE` environment variable
2. The `~/.config/ponytail/config.json` configuration file
3. The library constant `DEFAULT_MODE` (set to `"full"`)

```python

# __init__.py lines 52-64

def _default_mode():
    env_mode = os.getenv('PONYTAIL_DEFAULT_MODE')
    if env_mode in VALID_MODES:
        return env_mode
    config = load_user_config()
    if config.get('default_mode') in VALID_MODES:
        return config['default_mode']
    return DEFAULT_MODE  # "full"

```

## Summary

- **Two-layer architecture**: In-process `_current_mode` variables handle active sessions, while `.ponytail-active` files persist across restarts.
- **Command parsing**: The regex `/^[\/@$]ponytail/` identifies commands in the Node.js hook, while `_handle_mode_command` processes them in Python.
- **Persistence layer**: `setMode`, `clearMode`, and `readMode` in [`ponytail-runtime.js`](https://github.com/DietrichGebert/ponytail/blob/main/ponytail-runtime.js) manage the hidden flag file.
- **Session injection**: [`ponytail-activate.js`](https://github.com/DietrichGebert/ponytail/blob/main/ponytail-activate.js) reads the persisted mode on startup and filters the injected skill context accordingly.
- **Fallback chain**: Environment variables override config files, which override the built-in `"full"` default.

## Frequently Asked Questions

### What files are responsible for tracking Ponytail mode state?

The state is managed across four key files: [`__init__.py`](https://github.com/DietrichGebert/ponytail/blob/main/__init__.py) holds the in-process `_current_mode` variable; [`hooks/ponytail-mode-tracker.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-mode-tracker.js) parses commands and triggers updates; [`hooks/ponytail-runtime.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-runtime.js) provides the `setMode` and `readMode` utilities; and [`hooks/ponytail-activate.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-activate.js) reinstates the mode on new sessions.

### How does Ponytail handle mode changes during an active conversation?

When you type `/ponytail lite`, the Hermes plugin immediately updates `_current_mode` in Python memory. Simultaneously, the *UserPromptSubmit* hook invokes `setMode()` to write the change to `.ponytail-active`, ensuring the setting persists if the session restarts.

### Which regex pattern identifies valid /ponytail commands?

The runtime hook uses `/^[\/@$]ponytail/` to match commands starting with `/ponytail`, `@ponytail`, or `$ponytail`, allowing flexible invocation across different chat interfaces.

### What happens when no mode is explicitly configured?

The system calls `_default_mode()`, which checks the `PONYTAIL_DEFAULT_MODE` environment variable first, then `~/.config/ponytail/config.json`, and finally falls back to the `"full"` intensity level defined in the library constants.