# How Ponytail Handles Mode Switching and Deactivation Commands

> Learn how Ponytail handles mode switching and deactivation commands. Discover the core files responsible for command parsing, natural language processing, and configuration management.

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

---

**Ponytail processes mode switches and deactivation commands through two core files: [`hooks/ponytail-mode-tracker.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-mode-tracker.js) parses `/ponytail` commands and natural language deactivation phrases, while [`hooks/ponytail-config.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-config.js) manages default mode persistence and command detection utilities.**

The DietrichGebert/ponytail repository implements a hook-based architecture that intercepts user prompts to dynamically adjust runtime behavior. Understanding how Ponytail mode switching and deactivation commands function requires examining the interaction between the mode tracker hook and configuration utilities.

## Understanding Ponytail's Mode Switching Architecture

### The Core Hook System ([`ponytail-mode-tracker.js`](https://github.com/DietrichGebert/ponytail/blob/main/ponytail-mode-tracker.js))

The primary logic for Ponytail mode switching resides in [`hooks/ponytail-mode-tracker.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-mode-tracker.js). This file handles incoming JSON prompts, parses command syntax, and manages state transitions between **lite**, **full**, **ultra**, and **off** states. When a prompt arrives, the hook lower-cases the input string and checks for command prefixes at lines 23-54.

### Configuration Utilities ([`ponytail-config.js`](https://github.com/DietrichGebert/ponytail/blob/main/ponytail-config.js))

Supporting the mode tracker, [`hooks/ponytail-config.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-config.js) provides essential helper functions including `writeDefaultMode()` for persisting user preferences and `isDeactivationCommand()` for detecting natural language shutdown requests. These utilities abstract file I/O operations and string normalization logic away from the main hook flow.

## How Mode Switching Works in Ponytail

### Command Syntax and Runtime Modes

Ponytail recognizes explicit command syntax when prompts begin with `/ponytail`. The parser supports several variants:

- **`/ponytail lite|full|ultra`** – Immediately switches the current session to the requested runtime mode by calling `setMode(mode)` at lines 65-66
- **`/ponytail off`** – Deactivates Ponytail for the current session using `clearMode()` at lines 77-81
- **`/ponytail`** (no arguments) – Returns a status report without modifying the active mode
- **Any other text after `/ponytail`** – Falls back to the configured default mode

When `setMode()` executes successfully, the hook emits a "mode changed" confirmation message via `writeHookOutput()`.

### Persisting Default Modes Across Sessions

Users can permanently store their preferred mode using the `default` subcommand. When the hook detects `/ponytail default <mode>` at lines 38-44, it invokes `writeDefaultMode()` to persist the selection (valid options: `off`, `lite`, `full`, `ultra`) to configuration storage. Future sessions automatically initialize to this default unless overridden by an explicit runtime command.

### Special Handling for Qoder Client

The repository includes client-specific logic for "Qoder" at lines 70-76. Rather than emitting separate status messages, mode change confirmations are folded directly into the ruleset output for this client. This ensures the Qoder interface receives consolidated feedback without additional hook writes cluttering the response stream.

## Deactivation Commands and Flow

### Explicit Off Commands (`/ponytail off`)

The most direct method for disabling Ponytail involves sending `/ponytail off`. This command triggers `clearMode()` and emits the standardized "PONYTAIL MODE OFF" message at lines 77-81. This immediate deactivation takes precedence over other operations and signals the system to skip subsequent rule injections.

### Natural Language Deactivation Phrases

Beyond explicit commands, Ponytail supports conversational deactivation through `isDeactivationCommand()` at lines 40-43 of [`ponytail-config.js`](https://github.com/DietrichGebert/ponytail/blob/main/ponytail-config.js). This helper recognizes two specific phrases:

- **"stop ponytail"**
- **"normal mode"**

The detection is **case-insensitive**, automatically **trimmed**, and **ignores punctuation**. When the mode tracker identifies these phrases at lines 84-89—and no mode switch has already occurred—it executes `clearMode()` and emits the same "off" confirmation used for explicit commands.

### Deactivation Impact on Rule Injection

Post-deactivation behavior varies by client. For standard clients, the off state simply prevents mode-specific processing. However, for the Qoder client, deactivation carries specific consequences at lines 95-96: the hook explicitly skips automatic ruleset injection following a shutdown command, ensuring clean deactivation without residual rule output.

## Implementation Flow and Code Examples

The complete processing flow follows this sequence:

1. Incoming prompt JSON is parsed and the `prompt` field is lower-cased
2. If the text begins with `/ponytail`, parse the command and potentially persist defaults via `writeDefaultMode()`
3. For runtime modes (`lite`, `full`, `ultra`), invoke `setMode()` and emit confirmation
4. For `off`, invoke `clearMode()` and emit "PONYTAIL MODE OFF"
5. If no command prefix exists but `isDeactivationCommand()` returns true, clear mode and emit off message
6. For Qoder clients, inject the full ruleset unless deactivation just occurred (lines 95-96)

```javascript
// Switch to full mode for the current session
{ "prompt": "/ponytail full" }

// Persist ultra as the default for all future sessions
{ "prompt": "/ponytail default ultra" }

// Turn Ponytail off via explicit command
{ "prompt": "/ponytail off" }

// Natural language deactivation phrase
{ "prompt": "stop ponytail" }

// Alternative deactivation phrase (punctuation ignored)
{ "prompt": "Normal mode!" }

```

## Summary

- **Dual-file architecture**: Mode switching logic splits between [`hooks/ponytail-mode-tracker.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-mode-tracker.js) (orchestration) and [`hooks/ponytail-config.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-config.js) (utilities).
- **Command flexibility**: Supports both explicit `/ponytail <mode>` syntax and conversational phrases like "stop ponytail".
- **Persistent defaults**: The `default` subcommand writes preferences via `writeDefaultMode()` for automatic future session initialization.
- **Clean deactivation**: Both `/ponytail off` and natural language triggers execute `clearMode()` and suppress subsequent rule injection for Qoder clients.

## Frequently Asked Questions

### How does Ponytail detect deactivation commands in natural language?

Ponytail uses the `isDeactivationCommand()` helper in [`hooks/ponytail-config.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-config.js) (lines 40-43) to identify the exact strings "stop ponytail" or "normal mode". The function normalizes input by converting to lowercase, trimming whitespace, and stripping punctuation before comparison, allowing flexible phrasing like "Stop Ponytail!" or "normal mode..." to trigger deactivation.

### What happens when I set a default mode versus a runtime mode?

Setting a default mode via `/ponytail default ultra` calls `writeDefaultMode()` to permanently store the preference for future sessions, while runtime commands like `/ponytail ultra` call `setMode()` to temporarily change the active session without persisting the selection. The default only applies when no explicit mode command is issued.

### Why does the Qoder client handle mode changes differently?

According to the source at lines 70-76 and 95-96 of [`ponytail-mode-tracker.js`](https://github.com/DietrichGebert/ponytail/blob/main/ponytail-mode-tracker.js), the Qoder client receives mode confirmations embedded within ruleset output rather than separate hook messages. Additionally, Qoder skips automatic ruleset injection entirely after deactivation to prevent conflicting instructions, ensuring the client receives clean "off" state signaling.

### Can I deactivate Ponytail without using the `/ponytail` prefix?

Yes. The hook checks for deactivation phrases independently of command prefixes at lines 84-89. If your prompt contains "stop ponytail" or "normal mode" (case-insensitive) and no mode switch has already occurred, `clearMode()` executes and emits "PONYTAIL MODE OFF" regardless of whether you used the `/ponytail` syntax.