How Ponytail Filters Instructions by Intensity Levels: A Deep Dive into the Three-Tier System

Ponytail filters instructions using a pure-JavaScript pipeline that extracts only content matching the requested intensity—lite, full, or ultra—from a master markdown skill file while preserving all mode-agnostic guidance.

The DietrichGebert/ponytail repository implements an intensity-aware instruction system that serves developers precisely calibrated guidance based on their selected mode. This article breaks down how the filtering mechanism works, from initial mode resolution through final instruction delivery.


Mode Resolution: From Request to Effective Intensity

Every instruction request begins with mode resolution in ponytail-mcp/instructions.js. The resolveMode() function normalizes user input, applies configured defaults, and ultimately falls back to "full" when no valid mode is detected.

// Resolve a user-provided mode string to an actual intensity
import { resolveMode } from "./ponytail-mcp/instructions.js";

const intensity = resolveMode("ultra"); // → "ultra"
const intensity2 = resolveMode("");     // falls back to default (e.g. "full")

This resolution step ensures that downstream components always receive one of three validated values: lite, full, or ultra.


Building Filtered Instructions: The Two-Stage Pipeline

Once resolved, the intensity flows through a two-stage pipeline that transforms raw skill content into mode-specific instructions.

Stage 1: Instruction Retrieval

The buildInstructions(requested) function forwards the resolved mode to getPonytailInstructions() in hooks/ponytail-instructions.js. This function reads the master skill file at skills/ponytail/SKILL.md and prepares it for filtering.

// Retrieve the filtered instructions for a given intensity
import { buildInstructions } from "./ponytail-mcp/instructions.js";

const instructions = await buildInstructions("lite");
console.log(instructions); // Only lite-specific rows/examples remain

Stage 2: Intensity-Aware Filtering

The core filtering logic resides in filterSkillBodyForMode(body, mode). This function performs three distinct operations:

  1. Strips front-matter — Removes YAML front-matter blocks (delimited by ---) that contain metadata rather than instructional content
  2. Filters intensity table rows — Keeps only table rows whose header matches the effective mode (pattern: | **lite** | …)
  3. Filters worked-example bullets — Retains only example bullets labeled for the current mode (pattern: - lite: "…")

All other content—general rule bullets, explanatory prose, mode-agnostic tables—passes through unchanged.

// Core filtering routine (simplified)
function filterSkillBodyForMode(body, mode) {
  const effective = normalizeMode(mode) || DEFAULT_MODE;
  return body
    .replace(/^---[\s\S]*?---\s*/, "")               // strip front‑matter
    .split(/\r?\n/)
    .filter(line => {
      // Keep a table row only if its header matches the effective mode
      const tbl = line.match(/^\|\s*\*\*(.+?)\*\*\s*\|/);
      if (tbl && normalizeMode(tbl[1].trim())) return normalizeMode(tbl[1].trim()) === effective;

      // Keep a worked‑example bullet only if its label matches the mode
      const ex = line.match(/^-\s*([^:]+):\s*"/);
      if (ex && normalizeMode(ex[1].trim())) return normalizeMode(ex[1].trim()) === effective;

      // Otherwise the line is mode‑agnostic → keep it
      return true;
    })
    .join("\n");
}

Fallback Handling When Skills Are Unavailable

If skills/ponytail/SKILL.md cannot be read, getFallbackInstructions() generates a minimal instruction set that ensures the system remains functional. This fallback provides basic guidance without intensity-specific tailoring, allowing graceful degradation when file system access fails.


Key Files in the Intensity Filtering System

File Role
ponytail-mcp/instructions.js Resolves the requested mode and builds the final instruction set via resolveMode() and buildInstructions()
hooks/ponytail-instructions.js Contains filterSkillBodyForMode(), getPonytailInstructions(), and getFallbackInstructions()
skills/ponytail/SKILL.md Master markdown source with intensity tables and worked examples
ponytail-mcp/test/instructions.test.js Unit tests verifying fallback behavior and resolution logic
pi-extension/test/helpers.test.js Edge case tests for filterSkillBodyForMode() including mode-named rule bullets

How Intensity Levels Map to Developer Workflows

Understanding how Ponytail filters instructions by intensity levels helps developers choose the right mode for their context:

  • lite — Minimal guidance, essential rules only; ideal for quick tasks or experienced users
  • full — Balanced instruction set with standard examples; default for general development
  • ultra — Comprehensive guidance with exhaustive examples; suited for complex or unfamiliar scenarios

The filtering system ensures that selecting /ponytail lite or /ponytail ultra delivers exactly the depth of instruction requested without manual configuration.


Summary

  • Mode resolution in ponytail-mcp/instructions.js validates and normalizes intensity requests, defaulting to "full"
  • Two-stage pipeline retrieves raw skill content then filters it based on the resolved intensity
  • filterSkillBodyForMode() strips front-matter and selectively retains table rows and worked examples matching the target mode
  • Pass-through preservation ensures all generic content remains available regardless of intensity selection
  • Fallback mechanism provides minimal instructions when the primary skill file is inaccessible
  • Test coverage in ponytail-mcp/test/instructions.test.js and pi-extension/test/helpers.test.js validates both resolution and filtering behavior

Frequently Asked Questions

What happens if I request an invalid intensity level?

resolveMode() normalizes the input and falls back to the configured default; if no default exists, it returns "full". Invalid values never propagate to the filtering stage.

Does filtering remove any content permanently?

No. The filterSkillBodyForMode() function creates a filtered view of the skill file contents. The original skills/ponytail/SKILL.md remains unchanged, and subsequent requests with different intensities generate fresh filtered outputs.

Can intensity levels be extended beyond lite, full, and ultra?

The current normalization logic in normalizeMode() recognizes only these three values. Extending the system would require updating the normalization function, the skill file markup conventions, and associated test suites.

How does Ponytail distinguish mode-specific table rows from regular tables?

Table rows are identified by the pattern | **{mode}** | where the mode name appears in bold within the first column. Regular table rows without this bold header pattern pass through unfiltered.

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 →