How Ponytail Mode Is Tracked and Activated Using /ponytail Commands

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, the _current_mode variable is initialized to None at line 27:


# __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 (lines 20‑82) parses user prompts and manages the .ponytail-active file through utility functions defined in hooks/ponytail-runtime.js.

The setMode function writes the mode string to disk:

// 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:

// 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:


# __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 (lines 23‑50). This hook matches commands using the regex /^[\/@$]ponytail/:

// 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 (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")

# __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 manage the hidden flag file.
  • Session injection: 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 holds the in-process _current_mode variable; hooks/ponytail-mode-tracker.js parses commands and triggers updates; hooks/ponytail-runtime.js provides the setMode and readMode utilities; and 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →