How to Use PONYTAIL_SUBAGENT_MATCHER to Scope Ruleset Injection in Ponytail

Set the PONYTAIL_SUBAGENT_MATCHER environment variable to a case‑insensitive regular expression to limit Ponytail’s ruleset injection to sub‑agents whose agent_type matches the pattern.

The Ponytail plugin injects instruction rulesets into sub‑agents spawned by AI hosts like Claude, Codex, and Qoder. By default, this injection applies to every sub‑agent unconditionally, but the PONYTAIL_SUBAGENT_MATCHER environment variable lets you restrict injection to specific agent types. This guide covers the matching implementation in hooks/ponytail-subagent.js and practical configuration examples for supported hosts.

How PONYTAIL_SUBAGENT_MATCHER Works

Regex Compilation and Validation

At startup, the hook reads process.env.PONYTAIL_SUBAGENT_MATCHER and compiles it with the case‑insensitive flag (i). In hooks/ponytail-subagent.js (lines 33‑38), the code attempts to instantiate a RegExp from the variable. If the pattern is malformed, the error is caught silently and the hook falls back to the default behavior: injecting into every sub‑agent.

Runtime Matching Logic

When the host spawns a sub‑agent, the hook receives a JSON payload via stdin containing the agent_type field (lines 60‑66). The logic follows these steps:

  • Parse the payload. If JSON parsing fails or the agent_type key is missing, the hook proceeds with injection (fail‑open) to avoid blocking the sub‑agent.
  • Test the regex. If agent_type exists and does not satisfy the compiled regex, the hook exits silently with process.exit(0) (lines 66‑70).
  • Inject the ruleset. If the regex matches, the inject() function is called, sending the SubagentStart payload containing Ponytail’s instructions.

Default Behavior When Unset

When PONYTAIL_SUBAGENT_MATCHER is unset or contains an invalid pattern, the hook skips the stdin read entirely and calls inject() synchronously (lines 45‑48). This preserves backward compatibility with Windows hosts and ensures the ruleset is always injected when no matcher is configured.

Configuration Examples

Bash Wrapper for Claude or Codex

Export the matcher before launching your AI host to restrict injection to agents with types containing "general" or "plan":

export PONYTAIL_SUBAGENT_MATCHER='general|plan'

# Launch the host—Ponytail will only inject into matching sub-agents

claude

Use anchors for exact matches. The pattern ^general$ matches only the agent type general, while general (unanchored) matches general‑purpose, general‑coding, etc.

Node.js Test Script

Validate your regex programmatically by simulating the hook’s stdin payload:

const { spawnSync } = require('child_process');
const path = require('path');

const env = {
  ...process.env,
  PONYTAIL_SUBAGENT_MATCHER: '^general$'  // Exact match only
};

const result = spawnSync(
  process.execPath,
  [path.join(__dirname, 'hooks', 'ponytail-subagent.js')],
  {
    env,
    input: JSON.stringify({ agent_type: 'general' }), // Matching payload
    encoding: 'utf8',
  }
);

console.log(result.stdout);   // → Contains SubagentStart JSON

Change agent_type to plan in the input to verify the hook exits silently for non‑matching types.

Qoder Hook Configuration

Add the environment variable to Qoder’s hook configuration in hooks/qoder-hooks.json:

{
  "UserPromptSubmit": {
    "command": "node $HOME/.qoder/plugins/ponytail/hooks/ponytail-subagent.js",
    "env": {
      "PONYTAIL_SUBAGENT_MATCHER": "explore|general"
    }
  }
}

With this configuration, Qoder spawns sub‑agents that receive Ponytail’s ruleset only if their agent_type contains "explore" or "general".

Regex Pattern Guidelines

The matcher is unanchored and case‑insensitive by design:

  • explore|general matches any agent_type that contains either substring regardless of case.
  • ^general$ forces an exact match, excluding variants like general‑coding.
  • Invalid regex patterns (e.g., unclosed parentheses) cause the hook to ignore the variable and inject everywhere, preventing accidental lockouts.

Because the implementation is fail‑open, missing agent_type fields in the platform payload result in unconditional injection. This ensures Ponytail’s instructions remain visible even if the host platform changes its message format.

Summary

  • Set PONYTAIL_SUBAGENT_MATCHER to a JavaScript‑compatible regular expression to filter which sub‑agents receive Ponytail’s ruleset.
  • Case‑insensitive matching is enforced automatically; anchoring (^ and $) is optional for exact matches.
  • Fail‑open behavior protects against misconfiguration: invalid regexes or missing agent_type fields result in unconditional injection.
  • Source location: The core logic resides in hooks/ponytail-subagent.js (lines 33‑70), with validation tests in tests/hooks.test.js.

Frequently Asked Questions

What happens if PONYTAIL_SUBAGENT_MATCHER is unset?

When the environment variable is undefined, the hook skips regex compilation and stdin processing entirely, injecting the ruleset into every sub‑agent synchronously. This matches the original Windows‑compatible behavior.

How do I match exact agent types only?

Use start‑of‑string (^) and end‑of‑string ($) anchors in your pattern. For example, ^general$ matches only the exact string general, whereas general (unanchored) also matches general‑purpose or my‑general‑agent.

What happens if the regex is malformed?

If PONYTAIL_SUBAGENT_MATCHER contains invalid syntax (e.g., [a-z), the hook catches the SyntaxError during RegExp construction and falls back to injecting into every sub‑agent. This prevents a bad regex from accidentally blocking all sub‑agent activity.

Does this work with all AI hosts?

Yes. The matcher operates inside hooks/ponytail-subagent.js, which is invoked by the host’s sub‑agent spawn hook. As long as the host conforms to the standard payload format (JSON with agent_type on stdin), the filtering works identically for Claude, Codex, Qoder, and other supported platforms.

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 →