# How to Scope Ponytail’s Sub-Agent Injection to Specific Agent Types

> Learn how to scope Ponytail's subagent injection to specific agent types. Set the PONYTAIL_SUBAGENT_MATCHER environment variable to target your agent types and inject the rule set precisely where you need it.

- Repository: [DietrichGebert/ponytail](https://github.com/DietrichGebert/ponytail)
- Tags: how-to-guide
- Published: 2026-09-04

---

**Set the `PONYTAIL_SUBAGENT_MATCHER` environment variable to a case-insensitive regular expression matching your target `agent_type` values, and Ponytail will inject its rule set only into sub-agents whose type satisfies that pattern.**

Ponytail automatically propagates its instruction set to every sub-agent spawned during task execution. Starting with issue #506, the project introduced granular control mechanisms that let you limit this behavior to specific agent families, allowing precise control over which sub-agent types receive the injection through configuration in [`hooks/ponytail-subagent.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-subagent.js).

## The PONYTAIL_SUBAGENT_MATCHER Environment Variable

The `PONYTAIL_SUBAGENT_MATCHER` environment variable acts as a runtime filter. When defined, Ponytail compiles its value as a case-insensitive regular expression and tests each incoming sub-agent’s `agent_type` against it before deciding whether to inject the rule set.

By default, the matcher is **unanchored**, meaning `"explore"` matches any `agent_type` containing that substring (e.g., `"code-explore"` or `"explorer"`). To enforce exact matches, use anchor metacharacters like `^` and `$`.

## How the Sub-Agent Hook Evaluates Agent Types

When a sub-agent starts, the [`ponytail-subagent.js`](https://github.com/DietrichGebert/ponytail/blob/main/ponytail-subagent.js) hook executes a four-stage evaluation process to determine whether injection should occur.

### Stage 1: Check Ponytail Mode

First, the hook verifies that Ponytail is active. In lines 19-21 of [`hooks/ponytail-subagent.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-subagent.js), the code checks the current mode; if the mode is absent or explicitly set to `off`, the hook exits immediately without reading any further input or attempting injection.

### Stage 2: Parse the Matcher Regex

If Ponytail is active, the hook attempts to compile the regex supplied in `PONYTAIL_SUBAGENT_MATCHER`. According to lines 34-36 of [`hooks/ponytail-subagent.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-subagent.js), the pattern is compiled with the `i` flag for case-insensitive matching. If the variable is undefined or contains an invalid pattern, the system defaults to the legacy "inject-all" behavior (lines 41-48).

### Stage 3: Match Against agent_type

When a valid matcher exists, the hook reads a JSON payload from `stdin` containing the sub-agent’s metadata (lines 50-71). If the `agent_type` field fails to satisfy the compiled regex, the hook exits silently without injecting anything. This allows you to scope Ponytail’s influence to specific agent families while leaving others untouched.

### Stage 4: Fail-Open Behavior

If the JSON payload is missing, malformed, or the read operation times out, the hook implements a **fail-open** strategy: it proceeds with injection rather than risking the omission of critical instructions. This safety mechanism ensures that I/O failures don't accidentally strip guidance from sub-agents.

## Practical Configuration Examples

Scope injection to agents whose type contains either "explore" or "general" (case-insensitive):

```bash
export PONYTAIL_SUBAGENT_MATCHER="explore|general"
ponytail run mytask

```

Restrict injection to exactly the "general" agent type using anchors:

```bash
export PONYTAIL_SUBAGENT_MATCHER="^general$"
ponytail run mytask

```

Restore default behavior and inject into all sub-agents:

```bash
unset PONYTAIL_SUBAGENT_MATCHER
ponytail run mytask

```

## Key Implementation Files

The sub-agent scoping logic spans three critical files in the `hooks/` directory:

- **[`hooks/ponytail-subagent.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-subagent.js)** – Implements the injection hook, handles `PONYTAIL_SUBAGENT_MATCHER` parsing, and executes the evaluation pipeline (lines 19-71).
- **[`hooks/ponytail-instructions.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-instructions.js)** – Supplies the instruction payload that gets injected when the hook determines a match exists.
- **[`hooks/ponytail-config.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-config.js)** – Provides mode-handling utilities used by the sub-agent hook to determine whether Ponytail is active.

## Summary

- **Use `PONYTAIL_SUBAGENT_MATCHER`** to limit injection to specific `agent_type` values using case-insensitive regex.
- **Anchoring matters**: Unanchored patterns match substrings; use `^` and `$` for exact type matching.
- **Mode check first**: The hook exits immediately if Ponytail is disabled or set to `off` (lines 19-21).
- **Fail-open design**: Malformed payloads or timeouts result in injection to prevent accidental guidance loss (lines 50-71).
- **Source location**: All logic resides in [`hooks/ponytail-subagent.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-subagent.js), with supporting utilities in [`hooks/ponytail-config.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-config.js).

## Frequently Asked Questions

### What happens if PONYTAIL_SUBAGENT_MATCHER is not set?

If the environment variable is undefined or contains an invalid regular expression, the hook defaults to injecting Ponytail’s rule set into **all** sub-agents, preserving backward compatibility with earlier versions.

### Is the regex case-sensitive?

No. As implemented in lines 34-36 of [`hooks/ponytail-subagent.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-subagent.js), the pattern is compiled with the `i` flag, making matching case-insensitive. Therefore, `"General"` and `"general"` both satisfy the matcher `"general"`.

### What happens if the sub-agent payload is malformed?

If the JSON payload from `stdin` is missing, malformed, or the read operation times out, the hook falls back to **injecting the rules** (fail-open behavior). This ensures that temporary I/O issues don't result in sub-agents running without Ponytail’s guidance.

### Can I use anchored regex patterns for exact matching?

Yes. While the default behavior uses unanchored substring matching, you can enforce exact matches using anchor metacharacters. For example, setting `PONYTAIL_SUBAGENT_MATCHER="^general$"` ensures only agents with the exact type `"general"` receive the injection, excluding subtypes like `"general-purpose"`.