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

> Extend Ponytail functionality with 3 proven methods. Add slash commands, create custom skills, or modify instructions for custom logic in your OpenCode plugin development.

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

---

**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`](https://github.com/DietrichGebert/ponytail/blob/main/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`](https://github.com/DietrichGebert/ponytail/blob/main/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`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-instructions.js) reads [`SKILL.md`](https://github.com/DietrichGebert/ponytail/blob/main/SKILL.md) and filters content by mode.
- **Configuration persistence**: [`hooks/ponytail-config.js`](https://github.com/DietrichGebert/ponytail/blob/main/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:

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

```js
'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`](https://github.com/DietrichGebert/ponytail/blob/main/skills/ponytail/custom-rules.md):

```markdown
---
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`](https://github.com/DietrichGebert/ponytail/blob/main/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`](https://github.com/DietrichGebert/ponytail/blob/main/hooks/ponytail-instructions.js). The `getPonytailInstructions` function builds the final prompt text. You can prepend project-specific headers:

```js
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`](https://github.com/DietrichGebert/ponytail/blob/main/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`](https://github.com/DietrichGebert/ponytail/blob/main/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`](https://github.com/DietrichGebert/ponytail/blob/main/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`](https://github.com/DietrichGebert/ponytail/blob/main/SKILL.md) cannot be read, `getPonytailInstructions` returns a static fallback via `getFallbackInstructions(effectiveMode)`, ensuring the plugin continues functioning even when skill files are unavailable.