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

> Filter Ponytail skill bodies by mode using JavaScript. Learn to parse markdown content and extract sections for lite, full, or ultra modes with the filterSkillBodyForMode function.

- Repository: [DietrichGebert/ponytail](https://github.com/DietrichGebert/ponytail)
- Tags: how-to-guide
- Published: 2026-09-11

---

**Use the `filterSkillBodyForMode(body, mode)` function exported from [`hooks/ponytail-instructions.js`](https://github.com/DietrichGebert/ponytail/blob/main/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`](https://github.com/DietrichGebert/ponytail/blob/main/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:

```javascript
filterSkillBodyForMode(body, mode)

```

It accepts a raw markdown string (typically from [`skills/ponytail/SKILL.md`](https://github.com/DietrichGebert/ponytail/blob/main/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`](https://github.com/DietrichGebert/ponytail/blob/main/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`](https://github.com/DietrichGebert/ponytail/blob/main/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:

```javascript
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:

```javascript
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`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-instructions.js).

### Unit Testing Mode Filtering

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

```javascript
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

- **[`hooks/ponytail-instructions.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-instructions.js)** – Contains the core `filterSkillBodyForMode` implementation and line processing logic.
- **[`hooks/ponytail-config.js`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-config.js)** – Defines `normalizeMode` and `DEFAULT_MODE` constants used during filtering.
- **[`skills/ponytail/SKILL.md`](https://github.com/DietrichGebert/ponytail/blob/main/skills/ponytail/SKILL.md)** – Source markdown containing mode-specific tables and examples.
- **[`pi-extension/index.js`](https://github.com/DietrichGebert/ponytail/blob/main/pi-extension/index.js)** – Demonstrates export patterns for external consumption.
- **[`pi-extension/test/helpers.test.js`](https://github.com/DietrichGebert/ponytail/blob/main/pi-extension/test/helpers.test.js)** – Test suite validating filter behavior across all modes.

## Summary

- Use `filterSkillBodyForMode` from [`hooks/ponytail-instructions.js`](https://github.com/DietrichGebert/ponytail/blob/main/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`](https://github.com/DietrichGebert/ponytail/blob/main/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`](https://github.com/DietrichGebert/ponytail/blob/main/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.