How to Extend Ponytail's Functionality: 3 Proven Methods for OpenCode Plugin Development

You can extend Ponytail by adding new slash commands in the command/ directory, creating custom skill markdown files in skills/ponytail/, or modifying the instruction builder in hooks/ponytail-instructions.js to inject project-specific logic.

Ponytail is an OpenCode plugin that injects "lazy senior-dev" guidelines into AI-assisted coding sessions by persisting modes (off, lite, full, ultra, review) and appending instructions to the system prompt. Because the codebase isolates command registration, skill management, and instruction generation into distinct modules, you can safely extend Ponytail's functionality without disrupting the core workflow. All extension points reside in predictable file paths like hooks/ponytail-instructions.js and the command/ directory.

Understanding Ponytail's Extension Architecture

Before extending, understand that Ponytail uses three isolated components that minimize coupling:

  • Command registration: The ponytail.mjs entry point scans command/*.md files (lines 59-64) to auto-register slash commands.
  • Instruction generation: The getPonytailInstructions function in hooks/ponytail-instructions.js reads SKILL.md and filters content by mode.
  • Configuration persistence: hooks/ponytail-config.js handles mode state in ~/.config/opencode/.ponytail-active.

This separation lets you extend functionality at any layer without touching the others.

Method 1: Add Custom Slash Commands

Declaring New Commands

Create a markdown file in the command/ directory following the front-matter schema:

---
name: ponytail-debug
description: Show the current Ponytail mode and config paths for troubleshooting.
argument-hint: ""
---

The plugin automatically discovers this because ponytail.mjs scans the command directory at startup (lines 59-64).

Implementing Command Handlers

Add execution logic in ponytail.mjs within the command.execute.before hook:

'command.execute.before': async (input) => {
  if (input.command === 'ponytail-debug') {
    const mode = readMode();
    const cfg = getConfigPath();
    client && client.app && client.app.log({
      body: { service: 'ponytail', level: 'info',
              message: `mode=${mode}, config=${cfg}` }
    });
  }
  // existing /ponytail handling …
},

Now /ponytail-debug is available and reports internal state without leaving the chat.

Method 2: Create Custom Skill Files

Ponytail's instruction builder reads markdown from skills/ponytail/ and filters content based on mode labels. Create skills/ponytail/custom-rules.md:

---
name: custom-rules
description: Extra guidelines that apply only in "ultra" mode.
---

# Custom Rules (ultra only)

- **ultra**: "Never write more than 5 lines of code for any function."
- **ultra**: "Prefer `Array.at(-1)` over manual indexing."

Because ponytail.mjs adds the skills directory to the runtime's search paths (lines 68-70), this file loads automatically. The filterSkillBodyForMode function (lines 22-27 in hooks/ponytail-instructions.js) includes these bullets only when the active mode is ultra.

Method 3: Hook Into the Instruction Builder

To programmatically modify generated instructions, edit hooks/ponytail-instructions.js. The getPonytailInstructions function builds the final prompt text. You can prepend project-specific headers:

function getPonytailInstructions(mode) {
  const configuredMode = normalizePersistedMode(mode) || DEFAULT_MODE;
  const effectiveMode = normalizeMode(configuredMode) || DEFAULT_MODE;

  const base = (() => {
    try {
      return filterSkillBodyForMode(
        fs.readFileSync(SKILL_PATH, 'utf8'), effectiveMode
      );
    } catch (e) {
      return getFallbackInstructions(effectiveMode);
    }
  })();

  // Custom extension for full mode
  if (effectiveMode === 'full') {
    const header = '🚀 Project "MyApp" – full-mode guidelines\n\n';
    return 'PONYTAIL MODE ACTIVE — level: full\n\n' + header + base;
  }

  return 'PONYTAIL MODE ACTIVE — level: ' + effectiveMode + '\n\n' + base;
}

This ensures every system prompt in full mode includes your custom banner before the standard guidelines.

Summary

  • Add slash commands by creating .md files in command/ and handling them in ponytail.mjs via the command.execute.before hook.
  • Create custom skills by adding markdown files to skills/ponytail/ with mode-specific bullets; filterSkillBodyForMode automatically filters by bolded mode labels.
  • Modify instruction generation by extending getPonytailInstructions in hooks/ponytail-instructions.js to inject custom text based on the active mode.

Frequently Asked Questions

Where does Ponytail store the active mode configuration?

Ponytail persists the active mode in a per-user state file located at ~/.config/opencode/.ponytail-active, managed by hooks/ponytail-config.js through the writeDefaultMode and readMode utilities.

Can I add commands without modifying ponytail.mjs?

No, while command declarations are auto-scanned from command/*.md files, you must still add execution handlers in ponytail.mjs within the command.execute.before hook to define what happens when users invoke the command.

How does Ponytail filter which skill rules appear in each mode?

The filterSkillBodyForMode function in hooks/ponytail-instructions.js scans for bolded mode labels (e.g., **ultra**) at the start of list items and includes only the rules matching the current active mode.

What happens if the SKILL.md file is missing?

If SKILL.md cannot be read, getPonytailInstructions returns a static fallback via getFallbackInstructions(effectiveMode), ensuring the plugin continues functioning even when skill files are unavailable.

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 →