How to Scope Ponytail’s Sub-Agent Injection to Specific Agent Types
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.
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 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, 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, 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):
export PONYTAIL_SUBAGENT_MATCHER="explore|general"
ponytail run mytask
Restrict injection to exactly the "general" agent type using anchors:
export PONYTAIL_SUBAGENT_MATCHER="^general$"
ponytail run mytask
Restore default behavior and inject into all sub-agents:
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– Implements the injection hook, handlesPONYTAIL_SUBAGENT_MATCHERparsing, and executes the evaluation pipeline (lines 19-71).hooks/ponytail-instructions.js– Supplies the instruction payload that gets injected when the hook determines a match exists.hooks/ponytail-config.js– Provides mode-handling utilities used by the sub-agent hook to determine whether Ponytail is active.
Summary
- Use
PONYTAIL_SUBAGENT_MATCHERto limit injection to specificagent_typevalues 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, with supporting utilities inhooks/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, 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".
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 →