How to Restrict Ponytail Injection to Specific Subagent Types

Set the PONYTAIL_SUBAGENT_MATCHER environment variable to a case-insensitive regular expression that matches the agent_type values you want to target.

Ponytail automatically injects its ruleset into every subagent process by default. To limit this behavior to specific subagent types, the DietrichGebert/ponytail repository provides a filtering mechanism that inspects the subagent's reported identity before proceeding with injection.

How Subagent Filtering Works

The injection logic resides in hooks/ponytail-subagent.js. This hook intercepts subagent initialization and conditionally injects rules based on the PONYTAIL_SUBAGENT_MATCHER environment variable.

Reading the Matcher Configuration

At startup (lines 8-12 and 34-36), the hook checks for process.env.PONYTAIL_SUBAGENT_MATCHER. If present, it compiles the value into a case-insensitive regular expression. Invalid regex patterns are safely caught and treated as "no matcher" (lines 31-39), causing the hook to fall back to default behavior and inject into all subagents.

Extracting agent_type from STDIN

The hook reads a JSON payload from stdin (lines 50-67) to extract the agent_type field reported by the subagent. The implementation accumulates data chunks from data events, parses the JSON, and extracts the type identifier to evaluate against your matcher.

Conditional Injection Logic

If a matcher is defined and the extracted agent_type fails the regex test, the hook exits immediately without injecting the ruleset (line 68). All other scenarios—missing matcher, unparsable payload, or successful match—proceed to injection (lines 46-47, 70-71) by calling the inject() function defined at lines 23-30.

Configuring PONYTAIL_SUBAGENT_MATCHER

Define the environment variable before launching Ponytail to control which subagent types receive the ruleset.

Match Multiple Agent Types

To inject only into agents whose type contains "general" or "explore":

export PONYTAIL_SUBAGENT_MATCHER="general|explore"
ponytail

The hook will inject the ruleset only when the subagent reports an agent_type matching the regex, such as "General-purpose" or "Explore".

Require Exact Matches

To enforce an exact, case-insensitive match for the literal type "general":

export PONYTAIL_SUBAGENT_MATCHER="^general$"
ponytail

The ^ and $ anchors ensure only subagents whose agent_type is exactly "general" receive the injection.

Restore Default Behavior

To disable filtering and inject into all subagents:

unset PONYTAIL_SUBAGENT_MATCHER
ponytail

When the variable is absent, the hook skips the matcher logic entirely, preserving Ponytail's original behavior of injecting every subagent.

Programmatic Configuration in Node.js

When spawning subagents programmatically, set the variable in the environment object:

const { spawn } = require('child_process');

process.env.PONYTAIL_SUBAGENT_MATCHER = 'assistant|coder';
const sub = spawn('node', ['my-subagent.js'], { env: process.env });

sub.stdout.pipe(process.stdout);
sub.stderr.pipe(process.stderr);

The environment variable propagates to the child process, and the hook conditionally injects based on the supplied regex.

Safety Mechanisms and Error Handling

The implementation includes defensive programming to prevent hook failures from breaking subagent spawning.

Invalid Regex Handling

If you provide a malformed regular expression in PONYTAIL_SUBAGENT_MATCHER, the hook catches the syntax error (lines 31-39) and treats the configuration as undefined. This prevents crashes and ensures subagents still launch, albeit with default injection behavior.

Timeout Protection

A 1-second timeout (lines 77-78) guarantees the hook never hangs indefinitely while waiting for stdin input or processing the matcher. If the timeout expires, the process exits safely without blocking the subagent initialization.

Summary

  • PONYTAIL_SUBAGENT_MATCHER controls which subagent types receive Ponytail's ruleset via regex matching against the agent_type field.
  • The filtering logic is implemented in hooks/ponytail-subagent.js (lines 8-71), which reads the matcher from environment variables and validates subagent payloads from stdin.
  • Matching is case-insensitive and occurs before the inject() function (lines 23-30) writes rules to the hook output.
  • Invalid regex patterns trigger a fallback to default behavior (lines 31-39), ensuring subagents always launch even with misconfiguration.
  • A 1-second timeout (lines 77-78) prevents the hook from hanging during stdin reads.

Frequently Asked Questions

What happens if the regex in PONYTAIL_SUBAGENT_MATCHER is invalid?

The hook wraps the regex compilation in a try-catch block (lines 31-39) according to the DietrichGebert/ponytail source code. Syntax errors are caught and treated as if no matcher was defined, causing the hook to fall back to injecting all subagents rather than crashing.

Is the agent_type matching case-sensitive?

No. The PONYTAIL_SUBAGENT_MATCHER is compiled into a RegExp with the case-insensitive flag (lines 34-36). This means a pattern of "general" will match "General", "GENERAL", or "general" equally.

Which subagents receive the injection if I don't set the environment variable?

All subagents receive the injection. When PONYTAIL_SUBAGENT_MATCHER is undefined, the hook skips the matcher validation logic (lines 46-47) and proceeds directly to inject() (lines 70-71), preserving Ponytail's default behavior of universal ruleset injection.

Can I use complex regex features like anchors or character classes?

Yes. The hook passes the environment variable directly to the JavaScript RegExp constructor (lines 34-36), so any valid JavaScript regular expression syntax is supported. You can use anchors (^, $), alternation (|), character classes ([a-z]), and other standard features to define precise matching rules.

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 →