How to Filter Ponytail Skill Bodies to a Specific Mode Using JavaScript

Use the filterSkillBodyForMode(body, mode) function exported from hooks/ponytail-instructions.js to parse raw markdown skill content and return only the sections matching your target intensity (lite, full, or ultra).

The DietrichGebert/ponytail repository implements a mode-based skill filtering system that allows developers to programmatically extract specific intensity levels from Ponytail skill bodies using JavaScript. When working with LLM instructions stored in skills/ponytail/SKILL.md, you often need to present only the relevant content for a specific operational mode rather than the entire skill definition. This guide explains the exact implementation details and practical integration patterns for this filtering mechanism.

Core Filtering Architecture

The filtering system operates as a pure function pipeline that processes raw markdown strings without side effects. When you filter Ponytail skill bodies to a specific mode using JavaScript, the filterSkillBodyForMode function executes four distinct transformation steps to isolate mode-specific content while preserving generic instructional text.

The function signature is straightforward:

filterSkillBodyForMode(body, mode)

It accepts a raw markdown string (typically from skills/ponytail/SKILL.md) and a mode identifier, then returns a filtered markdown string containing only the relevant sections.

Step-by-Step Filtering Logic

The implementation in hooks/ponytail-instructions.js processes content through a rigorous normalization and parsing pipeline.

Mode Normalization and Defaults

Before processing begins, the function calls normalizeMode from hooks/ponytail-config.js (line 6) to resolve mode aliases to canonical values (lite, full, ultra). If an invalid mode is specified, the system falls back to DEFAULT_MODE to ensure predictable behavior.

Stripping YAML Front-Matter

Leading metadata blocks are removed using the regex /^---[\s\S]*?---\s*/ implemented at line 13. This ensures that YAML configuration headers do not contaminate the instructional text presented to the LLM.

Processing Intensity Table Rows

The filter detects mode-specific table rows using the pattern /^\|\s*\*\*(.+?)\*\*\s*\|/ (line 22). When a row starts with a bold cell containing a mode label (e.g., | **lite** |), the label is extracted, normalized, and retained only if it matches the effective mode. Unmatched intensity rows are discarded.

Handling Worked Examples

For quoted examples following the pattern - lite: "...", the regex /^-\s*([^:]+):\s*"/ (line 32) identifies the mode prefix. Lines are kept only when the extracted label aligns with the active mode, ensuring worked examples match the requested intensity level.

Preserving Generic Rules

Any line not matching table-row or example patterns passes through unchanged. This guarantees that universal instructions remain available regardless of the selected mode, as implemented in the filter callback spanning lines 21–38.

Practical Implementation Examples

Direct Node.js Script Usage

For standalone scripts or custom tooling, require the filter function directly and process skill files:

const fs = require('fs');
const { filterSkillBodyForMode } = require('./hooks/ponytail-instructions.js');

const raw = fs.readFileSync('skills/ponytail/SKILL.md', 'utf8');
const mode = 'ultra';                     // could be 'lite', 'full', or 'ultra'
const filtered = filterSkillBodyForMode(raw, mode);

console.log(filtered);

This approach gives you complete control over file I/O and mode selection.

Pi Extension Integration

When working within the Ponytail Pi extension ecosystem, use the higher-level helper that wraps the filter:

const { getPonytailInstructions } = require('./hooks/ponytail-instructions.js');

(async () => {
  const instructions = await getPonytailInstructions('lite');
  console.log(instructions);   // full instructions with only lite‑mode content
})();

This pattern handles async loading and automatically applies the filtering logic from hooks/ponytail-instructions.js.

Unit Testing Mode Filtering

Validate that your filtering logic correctly isolates mode-specific content:

const { filterSkillBodyForMode } = require('./hooks/ponytail-instructions.js');
const assert = require('assert');

const body = `
- Full: keep this rule.
- Lite: "example for lite"
- ultra: "example for ultra"
`;

assert.ok(filterSkillBodyForMode(body, 'ultra').includes('ultra:"'));
assert.ok(!filterSkillBodyForMode(body, 'ultra').includes('Lite:'));

This test verifies that the function correctly includes ultra-mode examples while excluding lite-mode content.

Key Source Files

Summary

  • Use filterSkillBodyForMode from hooks/ponytail-instructions.js to transform raw skill markdown into mode-specific content.
  • The function supports three canonical modes: lite, full, and ultra, with automatic fallback to DEFAULT_MODE for invalid inputs.
  • Content filtering preserves generic rules while extracting mode-specific tables (detected via /^\|\s*\*\*(.+?)\*\*\s*\|/) and worked examples (detected via /^-\s*([^:]+):\s*"/).
  • The implementation deliberately maintains purity, accepting strings and returning strings to maximize reusability across hooks, extensions, and test suites.

Frequently Asked Questions

Where is the main filtering logic implemented?

The core implementation resides in hooks/ponytail-instructions.js, specifically within the filterSkillBodyForMode function spanning lines 21–40. This file handles mode normalization, front-matter stripping, and line-by-line content filtering.

How does the system handle invalid or unspecified modes?

The filter delegates mode validation to normalizeMode in hooks/ponytail-config.js. If the requested mode does not match canonical values (lite, full, ultra), the system automatically falls back to DEFAULT_MODE, ensuring the skill body always returns valid instructional content.

Can I use the Ponytail skill filter outside of the Pi extension?

Yes. The filterSkillBodyForMode function is designed as a pure utility that accepts a markdown string and mode identifier, returning a filtered string. This makes it suitable for Node.js scripts, CI/CD pipelines, custom LLM integrations, or any JavaScript context requiring mode-specific content extraction.

What happens to instructional content that does not specify a mode?

Any line that does not match the intensity table pattern (| **mode** |) or the worked example pattern (- mode: "...") passes through the filter unchanged. This ensures that universal guidelines, formatting instructions, and generic rules remain available regardless of which mode is active.

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 →