UserPromptSubmit Hook in Ponytail: Mode Management and Command Parsing
The UserPromptSubmit hook in the Ponytail repository intercepts every user prompt to parse JSON input, detect /ponytail commands, manage session-scoped modes, persist default configurations, and emit structured status messages back to the terminal UI.
The UserPromptSubmit hook serves as the central command processor for the DietrichGebert/ponytail project, enabling real-time control of AI assistance levels directly from the terminal interface. Implemented in hooks/ponytail-mode-tracker.js, this Node.js script executes on every prompt submission to interpret directives, maintain state across sessions, and communicate configuration changes to the host environment.
Parsing Incoming Prompts and Detecting Commands
The hook initiates by reading raw JSON from standard input and normalizing the data for processing.
JSON Input Processing
At lines 17–19 of hooks/ponytail-mode-tracker.js, the hook reads the entire stdin stream, strips potential UTF-8 byte order marks (BOM), and parses the JSON payload to extract the prompt field. This ensures compatibility with various terminal emulators that may prepend invisible characters to the input stream.
Command Pattern Recognition
The hook employs a strict regex pattern /^[/@$]ponytail/ (lines 23–27) to identify valid Ponytail commands. This pattern accepts three command prefixes:
/ponytail– Standard command syntax@ponytail– Alternative prefix for specific shells$ponytail– Additional variant for compatibility
When matched, the hook tokenizes the remaining string to determine the requested operation, distinguishing between mode switches (lite, full, ultra, off), default configuration updates, and status queries.
Managing Ponytail Modes and Persistence
The UserPromptSubmit hook maintains two distinct configuration layers: temporary session states and persistent default settings.
Session-Scoped Mode Switching
When a user submits commands like /ponytail ultra or /ponytail lite, the hook invokes setMode() from hooks/ponytail-runtime.js (lines 64–68). This writes a flag file to disk, allowing subsequent prompts to reference the current operating mode. The available modes include:
- lite – Minimal AI assistance
- full – Standard assistance level
- ultra – Maximum context awareness
- off – Complete deactivation
Persisting Default Configurations
For cross-session persistence, the hook processes /ponytail default <mode> commands by calling writeDefaultMode() (lines 69–75), which stores the preference in hooks/ponytail-config.js. This ensures new terminal sessions initialize with the user's preferred baseline rather than requiring manual activation each time.
Graceful Deactivation
The hook monitors for deactivation commands (e.g., /stop ponytail) at lines 84–89. Upon detection, it invokes clearMode() to remove the session flag file and emits a termination status, ensuring clean state removal without residual configuration artifacts.
Communicating with the Host UI
The UserPromptSubmit hook operates as a bidirectional interface between the user and the terminal UI (TUI), requiring structured output for visual feedback.
JSON Status Emission
After processing any command, the hook calls writeHookOutput('UserPromptSubmit', …) (lines 71–75) to emit a single JSON object to stdout. This payload includes:
hook: The identifier string "UserPromptSubmit"mode: The active or changed mode statemessage: A human-readable status description (e.g., "PONYTAIL MODE CHANGED — level: ultra")
Host applications like Claude, Codex, or Qoder parse this output to display real-time status indicators within the terminal interface.
Handling Platform-Specific Edge Cases
The hook includes specialized logic for environments with non-standard lifecycle events or shell behaviors.
Qoder Session Initialization
Because Qoder lacks a native SessionStart event, the hook implements a fallback initialization routine (lines 91–112). On every prompt, it checks whether the mode state has been initialized; if not, it loads the default configuration from disk. Additionally, when running under Qoder, the hook prepends the full Ponytail ruleset (generated via hooks/ponytail-instructions.js) to every prompt payload, ensuring consistent behavior despite the missing session boundary event.
Windows Shell Robustness
To prevent hung processes in PowerShell environments, lines 29–31 implement a timeout safeguard. If the surrounding wrapper swallows the EOF signal or stdin becomes unresponsive, the hook force-exits after a predefined interval, guaranteeing the terminal session remains responsive even under error conditions.
Usage Examples
The following examples demonstrate typical interactions with the UserPromptSubmit hook from the repository root:
# Activate ultra mode for the current session
echo '{"prompt":"@ponytail ultra"}' | node hooks/ponytail-mode-tracker.js
# → {"hook":"UserPromptSubmit","mode":"ultra","message":"PONYTAIL MODE CHANGED — level: ultra"}
# Set the default mode to lite (persists across sessions)
echo '{"prompt":"@ponytail default lite"}' | node hooks/ponytail-mode-tracker.js
# → {"hook":"UserPromptSubmit","mode":"lite","message":"PONYTAIL DEFAULT SET — new sessions start in lite."}
# Query the current mode without arguments
echo '{"prompt":"@ponytail"}' | node hooks/ponytail-mode-tracker.js
# → {"hook":"UserPromptSubmit","mode":"lite","message":"PONYTAIL MODE ACTIVE — level: lite"}
# Deactivate Ponytail
echo '{"prompt":"@ponytail off"}' | node hooks/ponytail-mode-tracker.js
# → {"hook":"UserPromptSubmit","mode":"off","message":"PONYTAIL MODE OFF"}
Summary
The UserPromptSubmit hook in hooks/ponytail-mode-tracker.js provides the following core functionality:
- JSON Input Parsing: Reads stdin, removes UTF-8 BOM artifacts, and extracts the prompt text
- Command Detection: Identifies
/ponytail,@ponytail, and$ponytaildirectives via regex matching - Mode Management: Switches between
lite,full,ultra, andoffstates usingsetMode()andclearMode() - Configuration Persistence: Saves default modes via
writeDefaultMode()inhooks/ponytail-config.js - Status Reporting: Emits structured JSON responses through
writeHookOutput()for host UI consumption - Platform Adaptation: Handles Qoder's missing
SessionStartevent and prevents Windows PowerShell hangs through timeout safeguards
Frequently Asked Questions
How does the UserPromptSubmit hook detect Ponytail commands?
The hook uses the regex pattern /^[/@$]ponytail/ defined at lines 23–27 of hooks/ponytail-mode-tracker.js to scan the incoming prompt text. This pattern accommodates three distinct command prefixes (/, @, and $) to ensure compatibility across different terminal emulators and shell configurations.
What is the difference between session modes and default modes in Ponytail?
Session modes (activated via /ponytail lite, /ponytail ultra, etc.) apply only to the current terminal session and are stored temporarily via setMode(). Default modes (set via /ponytail default <mode>) persist across sessions through writeDefaultMode() in the configuration file, automatically applying to new terminal instances until explicitly changed.
Why does the hook require special handling for Qoder environments?
Qoder lacks the standard SessionStart lifecycle event that other host UIs provide, meaning the hook cannot rely on initialization hooks to load rulesets. As implemented in lines 91–112, the UserPromptSubmit hook detects Qoder runtime contexts and proactively injects the full Ponytail instructions on every prompt while maintaining mode state across the session through local flag files.
How does the UserPromptSubmit hook prevent hanging in Windows PowerShell?
The hook implements a timeout mechanism at lines 29–31 that forces process termination if standard input becomes unresponsive or if the PowerShell wrapper fails to transmit the EOF signal. This safeguard ensures the terminal remains interactive even when the surrounding shell environment exhibits irregular stream handling behaviors.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →