How the Pi Extension Injects the Ruleset into the Agent Prompt in DietrichGebert/ponytail

The Pi Extension registers a before_agent_start event handler that prepends the active Ponytail mode's ruleset to the agent's system prompt immediately before the first LLM request is dispatched.

The DietrichGebert/ponytail repository provides a Pi Extension that transparently enforces coding standards by injecting a "lazy senior developer" ruleset into AI agent prompts. This injection mechanism operates at the runtime level, intercepting agent initialization to modify system prompts without requiring manual configuration changes. The extension supports multiple operational modes—lite, full, ultra, and review—each applying different subsets of the master rule set.

The Event Hook Mechanism (before_agent_start)

The injection logic resides in pi-extension/index.js and leverages the Pi runtime's event system. During extension initialization, the code registers an async handler for the before_agent_start event, which fires immediately before the agent sends its first request to the LLM.

pi.on("before_agent_start", async (event) => {
  if (!currentMode || currentMode === "off") return;
  // Guard a null/undefined event or a missing systemPrompt
  const base = event?.systemPrompt ? `${event.systemPrompt}\n\n` : "";
  return { systemPrompt: `${base}${getPonytailInstructions(currentMode)}` };
});

When triggered, the handler first validates that Ponytail is active (mode is not null, undefined, or "off"). It then preserves any existing system prompt content by storing it in the base variable, ensuring the ruleset appends rather than replaces prior instructions. The handler returns an object containing the merged systemPrompt string, which the Pi runtime uses to overwrite the original prompt before transmission.

Building the Mode-Specific Ruleset

The getPonytailInstructions function, defined in hooks/ponytail-instructions.js, constructs the actual content injected into the prompt. This function normalizes the active mode, distinguishes between independent and standard modes, and filters the master skill file accordingly.

function getPonytailInstructions(mode) {
  const configuredMode = normalizePersistedMode(mode) || DEFAULT_MODE;
  if (INDEPENDENT_MODES.has(configuredMode)) {
    return 'PONYTAIL MODE ACTIVE — level: ' + configuredMode +
           '. Behavior defined by /ponytail-' + configuredMode + ' skill.';
  }
  const effectiveMode = normalizeMode(configuredMode) || DEFAULT_MODE;
  try {
    return 'PONYTAIL MODE ACTIVE — level: ' + effectiveMode + '\n\n' +
           filterSkillBodyForMode(fs.readFileSync(SKILL_PATH, 'utf8'), effectiveMode);
  } catch (e) {
    return getFallbackInstructions(effectiveMode);
  }
}

Handling Independent Modes

For independent modes such as review (tracked in the INDEPENDENT_MODES Set), the function returns a minimal placeholder string rather than the full ruleset. This placeholder signals the active mode while delegating behavior definition to separate skill-specific handlers, preventing rule duplication in the system prompt.

Filtering the SKILL.md Source

Standard modes (lite, full, ultra) trigger a file read operation on skills/ponytail/SKILL.md. The filterSkillBodyForMode function parses the markdown content and extracts only the rules applicable to the requested mode level. The extension prepends a header line identifying the active mode, followed by two newlines, then the filtered rule set. If the file read fails, the system falls back to hard-coded instructions via getFallbackInstructions, ensuring the agent still receives behavioral constraints even when the skill file is missing or corrupted.

Prompt Composition Architecture

The Pi Extension employs a non-destructive concatenation strategy to preserve existing system context. The final prompt structure follows this pattern:


[Original System Prompt]

PONYTAIL MODE ACTIVE — level: [mode]

[Filtered Rules from SKILL.md]

This architecture ensures that personality definitions, role assignments, or safety guidelines set by other extensions or user configurations remain intact. The double newline separator (\n\n) visually distinguishes the original prompt from the injected Ponytail rules, improving token delineation for the LLM.

Configuration Dependencies

The injection pipeline relies on constants and utility functions exported from hooks/ponytail-config.js. This module provides:

  • DEFAULT_MODE: The fallback mode when none is specified
  • normalizeMode() and normalizePersistedMode(): Sanitization functions that validate mode strings against supported values
  • INDEPENDENT_MODES: A Set defining which modes bypass the full ruleset injection

These utilities ensure consistent mode resolution across the extension's event handlers and instruction generators.

Summary

  • The Pi Extension hooks into the before_agent_start event in pi-extension/index.js to intercept prompts immediately before LLM transmission.
  • getPonytailInstructions() in hooks/ponytail-instructions.js dynamically builds ruleset content by filtering skills/ponytail/SKILL.md based on the active mode.
  • Independent modes (like review) receive lightweight placeholders instead of the full markdown content.
  • The system preserves existing system prompts through string concatenation, appending Ponytail rules with clear visual separation.
  • Robust error handling ensures agents receive fallback instructions if the primary skill file is inaccessible.

Frequently Asked Questions

What event triggers the Pi Extension ruleset injection?

The before_agent_start event triggers the injection. This event fires automatically within the Pi runtime immediately before the agent dispatches its first request to the LLM, allowing the extension to modify the systemPrompt property before transmission.

Where does the Pi Extension store the master ruleset?

The master ruleset resides in skills/ponytail/SKILL.md. The extension reads this file synchronously at runtime and passes the content through filterSkillBodyForMode() to extract mode-specific instructions (lite, full, or ultra) before injecting them into the prompt.

How does the Pi Extension handle missing SKILL.md files?

If fs.readFileSync() throws an error (file missing or unreadable), the getPonytailInstructions() function catches the exception and returns getFallbackInstructions(effectiveMode). This fallback provides hard-coded behavioral guidelines ensuring the agent maintains Ponytail constraints even when the primary skill file is unavailable.

Can the Pi Extension work alongside existing system prompts?

Yes. The extension explicitly checks for event.systemPrompt and prepends the existing content with a newline separator. This non-destructive approach allows the Pi Extension to augment rather than replace prompts defined by other extensions, user settings, or default system messages.

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 →