# How Ponytail Handles Subagent Scoping: Regex-Based Filtering in hooks/ponytail-subagent.js

> Discover how Ponytail handles subagent scoping using regex-based filtering in hooks/ponytail-subagent.js. Learn to control which child processes receive rule-sets efficiently.

- Repository: [DietrichGebert/ponytail](https://github.com/DietrichGebert/ponytail)
- Tags: internals
- Published: 2026-09-08

---

**Ponytail filters which child processes receive injected rule-sets by comparing the `PONYTAIL_AGENT_TYPE` environment variable against a configurable regex matcher defined in [`hooks/ponytail-subagent.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-subagent.js).**

The DietrichGebert/ponytail repository implements a hierarchical agent architecture where parent agents spawn sub-agents as child processes. To prevent blanket application of constraints across every subprocess, Ponytail provides a granular scoping mechanism that inspects environment variables at spawn time to determine rule-set inheritance.

## The Scoping Implementation in hooks/ponytail-subagent.js

All subagent scoping logic resides in the hook script [`hooks/ponytail-subagent.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-subagent.js). This script executes for every subprocess created while Ponytail mode is active, implementing a conditional injection strategy that respects explicit agent type declarations.

### Execution Flow and Environment Inspection

The hook operates through a six-step validation process:

1. **Hook Activation**: The script triggers for each new subprocess spawned under active Ponytail supervision.
2. **Type Extraction**: It reads the `PONYTAIL_AGENT_TYPE` environment variable from the child process context.
3. **Regex Evaluation**: The type value is tested against the `PONYTAIL_SUBAGENT_MATCHER` regular expression.
4. **Match Verification**: Only sub-agents whose type matches the regex receive the injected parent rule-set.
5. **Rule Injection**: Upon match confirmation, the parent’s configuration is written into the child’s environment variables.
6. **Fallback Handling**: If the matcher is unset, the hook bypasses filtering and injects rules into every sub-agent.

### Default Matcher Behavior

The default configuration in [`hooks/ponytail-subagent.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-subagent.js) uses the regex `^general$`, restricting rule injection to agents that explicitly declare `PONYTAIL_AGENT_TYPE=general`. This prevents unintended constraint inheritance in specialized sub-agents that do not identify as general-purpose workers.

## Configuring Subagent Scoping Patterns

You control subagent scoping through two environment variables: `PONYTAIL_SUBAGENT_MATCHER` for the parent’s filtering criteria, and `PONYTAIL_AGENT_TYPE` for the child’s self-identification.

### Targeted Injection by Agent Type

To limit rule propagation to specific agent families, export a targeted regex before invoking the parent agent:

```bash
export PONYTAIL_SUBAGENT_MATCHER='^node$'

ponytail run my-script.js

```

When the child process sets `PONYTAIL_AGENT_TYPE=node`, the hook in [`hooks/ponytail-subagent.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-subagent.js) detects the match and injects the parent’s rule-set. Non-matching types receive no injection.

### Universal Injection for Backward Compatibility

For workflows requiring legacy behavior or simple scripts without type declarations, unset the matcher to restore universal injection:

```bash
unset PONYTAIL_SUBAGENT_MATCHER

ponytail run complex-workflow.sh

```

This configuration forces [`hooks/ponytail-subagent.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-subagent.js) to inject the rule-set into every spawned sub-agent regardless of `PONYTAIL_AGENT_TYPE` values.

## Validation and Testing

The scoping mechanism is validated by the test suite in [`tests/hooks.test.js`](https://github.com/DietrichGebert/ponytail/blob/main/tests/hooks.test.js). These tests verify that `PONYTAIL_SUBAGENT_MATCHER` correctly prevents rule-set leakage to non-matching agent types while confirming that the fallback "inject-into-all" behavior functions when the matcher is undefined. The test file specifically covers edge cases including empty matchers, partial regex matches, and multiple nested subagent spawning scenarios.

## Summary

- **[`hooks/ponytail-subagent.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-subagent.js)** implements the core scoping logic that filters rule-set injection based on environment variables.
- **`PONYTAIL_SUBAGENT_MATCHER`** accepts a regular expression that determines which sub-agent types receive the parent configuration.
- **Default regex `^general$`** restricts injection to agents explicitly typed as "general" unless configured otherwise.
- **Unset matcher fallback** triggers historic behavior, injecting rules into every sub-agent for backward compatibility.
- **[`tests/hooks.test.js`](https://github.com/DietrichGebert/ponytail/blob/main/tests/hooks.test.js)** provides comprehensive validation of matcher behavior and injection boundaries.

## Frequently Asked Questions

### What file contains the subagent scoping logic in Ponytail?

The scoping implementation resides in [`hooks/ponytail-subagent.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-subagent.js) within the DietrichGebert/ponytail repository. This hook script executes for every subprocess spawned under Ponytail supervision and evaluates `PONYTAIL_AGENT_TYPE` against the configured regex matcher to determine injection eligibility.

### What is the default regex pattern for subagent matching?

The default `PONYTAIL_SUBAGENT_MATCHER` value is `^general$`, meaning only sub-agents that explicitly set `PONYTAIL_AGENT_TYPE=general` receive the injected rule-set. This conservative default prevents accidental constraint application to specialized or untyped child processes.

### How do I force Ponytail to inject rules into every sub-agent?

Unset or empty the `PONYTAIL_SUBAGENT_MATCHER` environment variable before running the parent agent. When this variable is missing or empty, [`hooks/ponytail-subagent.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-subagent.js) falls back to the historic behavior and injects the parent rule-set into every spawned sub-agent regardless of their declared type.

### Can a sub-agent opt out of receiving the parent's rule-set?

Yes. A sub-agent opts out by setting a `PONYTAIL_AGENT_TYPE` value that does not match the parent’s `PONYTAIL_SUBAGENT_MATCHER` regex. For example, if the matcher is `^python$`, a sub-agent setting `PONYTAIL_AGENT_TYPE=shell` will not receive the injected constraints.