How ponytail-activate.js Initializes Ponytail on Session Start: Inside the Claude Hook Lifecycle

The ponytail-activate.js hook initializes Ponytail by determining the target mode from configuration, persisting an activation flag to the Claude config directory, and injecting mode-specific instructions into the invisible SessionStart context.

The ponytail-activate.js script serves as the automatic entry point for the Ponytail system in Claude Code sessions. Located in the DietrichGebert/ponytail repository, this SessionStart hook ensures that every new Claude session begins with the appropriate behavioral ruleset active, eliminating the need for manual configuration on each launch.

The Three-Phase Initialization Process

When a Claude Code session begins, ponytail-activate.js executes automatically and proceeds through three distinct logical phases to bootstrap the system.

Phase 1: Determining the Target Mode

The hook first resolves which operational mode should govern the session. It calls getDefaultMode from the configuration layer to retrieve the user’s preferred setting.

If the returned mode is "off", the hook performs an early exit sequence. It clears any previously stored mode state, writes a minimal "off" output, and terminates immediately. This ensures Ponytail remains dormant when explicitly disabled, preventing any interference with standard Claude behavior.

// Simplified logic from lines 24-31
const mode = getDefaultMode();
if (mode === 'off') {
  clearMode();  // Remove any existing activation
  writeHookOutput('SessionStart', 'off', '');
  return;
}

Phase 2: Activating the Mode

For active modes (lite, full, ultra, etc.), the hook proceeds to establish the runtime environment. It calls setMode(mode), which writes a flag file named .ponytail-active to the Claude configuration directory ($CLAUDE_CONFIG_DIR).

Simultaneously, the hook generates the behavioral instructions specific to the selected intensity level by invoking getPonytailInstructions(mode) at line 42. These instructions constitute the hidden SessionStart context that Claude uses to constrain agent behavior for every subsequent turn in the conversation.

// Core activation sequence (line 36, 42)
setMode(mode);  // Creates $CLAUDE_CONFIG_DIR/.ponytail-active
const instructions = getPonytailInstructions(mode);

Phase 3: Optional Status-Line Nudging

For non-Copilot/Codex sessions, the hook performs an optional user experience enhancement between lines 47 and 85. It inspects the user’s settings.json to detect whether a status-line configuration already exists.

If no status-line is configured and the user has not previously declined this suggestion (tracked via the .ponytail-statusline-nudged flag file), the hook creates the tracker file and appends a setup message to the output. This message includes a ready-to-copy snippet that adds a statusLine command pointing to either ponytail-statusline.sh or ponytail-statusline.ps1 depending on the platform. If the installation path contains unsafe shell characters that could break command substitution, the hook emits a fallback message with manual instructions instead.

Core Implementation Details

Flag File Management

The activation state persists across sessions through a filesystem marker. The setMode function (provided by hooks/ponytail-runtime.js) creates .ponytail-active in $CLAUDE_CONFIG_DIR, while clearMode removes it during deactivation or when the mode is set to "off". This flag serves as the source of truth for other Ponytail components that need to verify whether the system is active between sessions.

Instruction Injection

The final operation at line 93 sends the assembled payload back to Claude:

writeHookOutput('SessionStart', mode, output);

This output remains invisible to the user but drives Ponytail’s behavior for the entire session. The output variable contains either the pure JSON instructions (for standard activation) or the instructions concatenated with the status-line setup hint (when nudging occurs).

Code Architecture and Dependencies

The activation hook relies on a modular architecture split across three supporting files:

  • hooks/ponytail-config.js – Resolves configuration values, determines the Claude directory path, and performs safety checks on file locations.
  • hooks/ponytail-runtime.js – Provides the runtime helpers setMode, clearMode, and writeHookOutput that abstract filesystem and hook protocol operations.
  • hooks/ponytail-instructions.js – Generates the JSON-based instruction sets filtered by intensity level (lite, full, ultra), ensuring the agent receives only the rules relevant to the selected mode.

Practical Usage Examples

Automatic Session Initialization

Under normal operation, users do not invoke the hook manually. The script runs automatically when Claude starts a new session:

// No manual intervention required
// The hook executes automatically on SessionStart, writes .ponytail-active,
// and injects the appropriate ruleset into the context window

Programmatic Testing

For integration testing or development purposes, you can simulate the activation flow programmatically:

const { getDefaultMode, setMode, writeHookOutput } = require('./hooks/ponytail-runtime');
const { getPonytailInstructions } = require('./hooks/ponytail-instructions');

function activatePonytailForTest(mode = 'full') {
  setMode(mode);                                      // writes .ponytail-active
  const instructions = getPonytailInstructions(mode);
  writeHookOutput('SessionStart', mode, instructions);
}

activatePonytailForTest(); // Defaults to the configured mode

Summary

  • Three-phase initialization: ponytail-activate.js determines the target mode via getDefaultMode, persists state through setMode writing to $CLAUDE_CONFIG_DIR/.ponytail-active, and generates instructions via getPonytailInstructions.
  • Early exit handling: When the mode is "off", the hook clears stored state and exits without writing activation flags or instructions.
  • Optional UX nudging: The hook inspects settings.json and creates .ponytail-statusline-nudged to offer one-time status-line setup assistance.
  • Final delivery: writeHookOutput at line 93 transmits the invisible SessionStart payload that constrains agent behavior for the session duration.
  • Modular dependencies: The script delegates configuration, runtime operations, and instruction generation to ponytail-config.js, ponytail-runtime.js, and ponytail-instructions.js respectively.

Frequently Asked Questions

What triggers ponytail-activate.js to execute?

The script runs automatically as a SessionStart hook whenever Claude Code initializes a new conversation session. It does not require manual invocation; the Claude agent executes it based on the hook configuration, making it the effective entry point for all Ponytail functionality.

Where does Ponytail store its activation state between sessions?

The system persists activation state in a flag file named .ponytail-active located in the Claude configuration directory ($CLAUDE_CONFIG_DIR). The setMode function creates this file during activation, while clearMode removes it when deactivating or when the user sets the mode to "off".

How does the script handle disabled or "off" configurations?

When getDefaultMode returns "off", the hook immediately calls clearMode to remove any existing activation flag, writes a minimal empty output via writeHookOutput, and exits early without generating instructions. This ensures Ponytail imposes zero overhead or behavioral changes when disabled.

What is the purpose of the status-line nudging feature?

The status-line nudging inspects the user’s settings.json during activation to detect missing status-line configurations. If absent and the user hasn't been previously notified (tracked by .ponytail-statusline-nudged), the hook provides a one-time message containing copy-paste ready commands to enable visual Ponytail status indicators in the Claude interface.

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 →