How the SubagentStart Hook Injects the Ruleset into Subagents in Ponytail

The SubagentStart hook detects active Ponytail mode, retrieves the JSON ruleset from user configuration, and injects it into subagents by prepending it to the system prompt while simultaneously exposing it via the PONYTAIL_RULESET environment variable.

The Claude Code integration in the DietrichGebert/ponytail repository relies on the SubagentStart hook to enforce consistent safety policies across parent and child processes. When a new subagent spawns, this hook ensures the active ruleset is immediately available before any user instructions are processed. Understanding this injection mechanism is essential for developers extending Ponytail's behavior or debugging policy propagation failures.

Architecture of the SubagentStart Hook

Located in hooks/ponytail-subagent.js, the SubagentStart async function serves as the entry point for subagent initialization within Ponytail's hook system. It receives the subagent's payload object and modifies the execution context before the subagent begins processing tasks.

The Three-Phase Ruleset Injection Process

Phase 1: Detecting Ponytail Mode

The hook first determines whether Ponytail is active by calling isPonytailActive() from hooks/ponytail-mode-tracker.js. This function checks the global mode flag originally toggled by the activation sequence. If Ponytail mode is disabled, the hook returns the payload unmodified, bypassing injection entirely.

Phase 2: Loading the Active Ruleset

When mode detection succeeds, the hook invokes getActiveRuleset() from hooks/ponytail-config.js to retrieve the complete JSON configuration. This object contains safety rules, system prompts, and user-defined behavioral extensions that govern subagent operations.

Phase 3: Injecting into the Subagent Context

The hook performs dual injection to ensure redundant availability:

  • System Prompt Modification: It prepends the stringified ruleset JSON to payload.system, guaranteeing the subagent's language model receives the policies as part of its initial context.
  • Environment Variable Export: It stores the same JSON in process.env.PONYTAIL_RULESET, enabling programmatic access for runtime components.

Implementation in ponytail-subagent.js

// hooks/ponytail-subagent.js
import { isPonytailActive } from "./ponytail-mode-tracker.js";
import { getActiveRuleset } from "./ponytail-config.js";

export async function SubagentStart(payload) {
  // Skip injection if Ponytail mode is disabled
  if (!isPonytailActive()) {
    return payload;
  }

  // Retrieve the current safety and behavior rules
  const ruleset = getActiveRuleset();

  // Inject into system prompt for immediate LLM visibility
  payload.system = `${JSON.stringify(ruleset)}\n${payload.system}`;

  // Expose via environment for runtime consumption
  process.env.PONYTAIL_RULESET = JSON.stringify(ruleset);

  return payload;
}

Ruleset Consumption in the Subagent Runtime

Once injected, the Ponytail runtime consumes the ruleset through hooks/ponytail-runtime.js. This module checks process.env.PONYTAIL_RULESET during startup, parsing the JSON to initialize local safety constraints. Components that read directly from the system prompt can alternatively extract the ruleset from the initial payload content, ensuring the configuration survives across different runtime implementations.

Validation via the Test Suite

The injection logic is verified in tests/hooks.test.js, which confirms that the SubagentStart hook only modifies payloads when isPonytailActive() returns true. The test suite validates that the ruleset appears at the beginning of the system prompt string and that the PONYTAIL_RULESET environment variable contains valid JSON matching the configuration output.

Summary

  • The SubagentStart hook resides in hooks/ponytail-subagent.js and intercepts every subagent initialization
  • Injection occurs only when isPonytailActive() from ponytail-mode-tracker.js confirms Ponytail mode is enabled
  • The active ruleset is loaded via getActiveRuleset() from ponytail-config.js
  • Dual injection updates both payload.system and process.env.PONYTAIL_RULESET for redundancy
  • The ponytail-runtime.js module consumes these injected rules to enforce consistent safety policies

Frequently Asked Questions

What triggers the SubagentStart hook to inject the ruleset?

The hook executes automatically whenever Claude Code spawns a new subagent process. However, injection only occurs if isPonytailActive() returns true, indicating the user has explicitly enabled Ponytail mode in the current terminal session via the activation sequence.

Why does the hook use both the system prompt and environment variables for injection?

Dual injection ensures maximum compatibility across different runtime implementations. Updating payload.system guarantees the language model receives the policies immediately in its context window, while setting process.env.PONYTAIL_RULESET allows ponytail-runtime.js and other programmatic components to parse the JSON configuration directly without parsing the system prompt text.

How can I verify the ruleset was successfully injected into a subagent?

Inspect the PONYTAIL_RULESET environment variable in your subagent process, or examine the system prompt payload to confirm the JSON ruleset appears at the very beginning. The validation suite in tests/hooks.test.js provides automated assertions that verify both injection channels contain syntactically valid JSON matching the active configuration.

What happens if the ruleset configuration is missing or corrupted?

If getActiveRuleset() from ponytail-config.js fails to return valid JSON, the hook will still attempt to inject the returned value into both the system prompt and environment variable. However, downstream components like ponytail-runtime.js will throw parsing errors when attempting to read process.env.PONYTAIL_RULESET, potentially causing the subagent to fail initialization. Always validate your configuration file contains proper JSON before enabling Ponytail mode.

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 →