# How to Define Ponytail Commands for Different AI Hosts: Claude, Gemini, and OpenCode

> Learn how to define Ponytail commands for AI hosts like Claude, Gemini, and OpenCode. Discover the dual-format adapter system and TOML/Markdown file generation.

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

---

**Ponytail commands are defined through a dual-format adapter system where command metadata is registered once in [`pi-extension/index.js`](https://github.com/DietrichGebert/ponytail/blob/main/pi-extension/index.js) and then emitted as TOML files for Claude/Gemini and Markdown files for OpenCode.**

The Ponytail repository (`DietrichGebert/ponytail`) implements a host-specific command catalog that adapts to the consumption requirements of multiple AI execution environments. Each supported host—Claude Code, Gemini CLI, and OpenCode—expects command metadata in distinct formats, necessitating a flexible definition strategy that maintains a single source of truth while generating compatible representations.

## Host-Specific Command Formats

Ponytail uses different file formats depending on the target AI host. The repository maintains parallel definitions to ensure compatibility across Claude, Gemini, and OpenCode environments.

### Claude and Gemini: TOML Definitions

Both **Claude Code** and **Gemini CLI** consume command definitions written in TOML format. These files reside in the `commands/` directory and share identical structure between the two hosts.

In [`commands/ponytail.toml`](https://github.com/DietrichGebert/ponytail/blob/main/commands/ponytail.toml), the command metadata follows this pattern:

```toml
description = "Switch ponytail intensity level (lite/full/ultra/off)"
prompt = "Switch to ponytail {{args}} mode. If no level specified, use full. \
Lazy senior dev mode, before any code: does it need to exist at all (YAGNI)? \
Does the standard library do it? A native platform feature? Can it be one line? \
Build the minimum that works."

```

The `{{args}}` placeholder allows dynamic argument injection when the command executes. Every sub-command receives its own TOML file in this directory, ensuring granular control over each operation's prompt engineering and description.

### OpenCode: Markdown Definitions

**OpenCode** requires a different approach, consuming command definitions as Markdown files located in the hidden `.opencode/command/` directory. These files wrap the same metadata in a host-specific structure.

The file [`.opencode/command/ponytail.md`](https://github.com/DietrichGebert/ponytail/blob/main/.opencode/command/ponytail.md) demonstrates the OpenCode format:

```markdown

# ponytail

Switch ponytail intensity level (lite/full/ultra/off).

> **Prompt**  
> Switch to ponytail {{args}} mode. If no level specified, use full.

```

While the semantic content mirrors the TOML version, the Markdown format uses header-based titles and blockquote sections to satisfy OpenCode's parsing expectations.

## The Registration and Adapter Generation Pipeline

The canonical definitions for all Ponytail commands originate in [`pi-extension/index.js`](https://github.com/DietrichGebert/ponytail/blob/main/pi-extension/index.js), where the **π-extension** registers each command using the `registerCommand` function.

```javascript
// pi-extension/index.js (excerpt)
registerCommand('ponytail', {
  description: 'Switch ponytail intensity level',
  prompt: 'Switch to ponytail {{args}} mode. If no level specified, use full.'
});

```

When the registration system executes, it triggers an adapter generation process that emits two representations for every registered command name:

- A **TOML file** under `commands/<name>.toml` for Claude and Gemini consumption
- A **Markdown file** under `.opencode/command/<name>.md` for OpenCode integration

This pipeline ensures that the source code remains the single source of truth while automatically producing the host-specific artifacts required by each execution environment.

## Validating Command Definitions Across Hosts

The repository enforces consistency through automated testing in [`tests/commands.test.js`](https://github.com/DietrichGebert/ponytail/blob/main/tests/commands.test.js). This test suite verifies that every registered command maintains parity across host formats.

Specifically, the tests validate that:

- Each command registered via `registerCommand()` has a corresponding `commands/<name>.toml` file
- Each registered command also has a matching `.opencode/command/<name>.md` file
- No orphaned definition files exist without matching registration entries

This strict validation prevents drift between the TOML and Markdown representations, ensuring that Claude, Gemini, and OpenCode users all interact with identical command functionality despite the different file formats.

## Complete Command Definition Examples

### TOML Structure for Claude/Gemini

When defining commands for Claude Code or Gemini CLI, include the description and prompt fields in the TOML format:

```toml

# commands/ponytail.toml

description = "Switch ponytail intensity level (lite/full/ultra/off)"
prompt = "Switch to ponytail {{args}} mode. If no level specified, use full. \
Lazy senior dev mode, before any code: does it need to exist at all (YAGNI)? \
Does the standard library do it? A native platform feature? Can it be one line? \
Build the minimum that works."

```

### Markdown Structure for OpenCode

For OpenCode hosts, structure the definition with a level-1 header and prompt blockquote:

```markdown
<!-- .opencode/command/ponytail.md -->

# ponytail

Switch ponytail intensity level (lite/full/ultra/off).

> **Prompt**  
> Switch to ponytail {{args}} mode. If no level specified, use full.

```

### Registration in the π-Extension

All definitions begin with JavaScript registration in the extension entry point:

```javascript
// pi-extension/index.js
registerCommand('ponytail', {
  description: 'Switch ponytail intensity level',
  prompt: 'Switch to ponytail {{args}} mode. If no level specified, use full.'
});

```

## Summary

- **Claude and Gemini** consume **TOML files** located in `commands/`, sharing identical format specifications.
- **OpenCode** requires **Markdown files** placed in `.opencode/command/` with specific header and blockquote conventions.
- The `registerCommand()` function in [`pi-extension/index.js`](https://github.com/DietrichGebert/ponytail/blob/main/pi-extension/index.js) serves as the **single source of truth** for all command metadata.
- An automated **adapter generation** process creates both TOML and Markdown representations from the canonical registration.
- [`tests/commands.test.js`](https://github.com/DietrichGebert/ponytail/blob/main/tests/commands.test.js) enforces **format parity**, ensuring every registered command exists in both host-specific formats.

## Frequently Asked Questions

### What file format does Claude use for Ponytail commands?

Claude Code consumes **TOML files** (`.toml` extension) stored in the `commands/` directory. These files contain `description` and `prompt` fields that define the command's behavior and user-facing explanation.

### How does OpenCode differ from Claude in command definitions?

OpenCode uses **Markdown files** (`.md` extension) placed in the `.opencode/command/` hidden directory instead of TOML. While the semantic content remains identical, OpenCode expects the command name as a level-1 header and the prompt wrapped in a blockquote section with a "Prompt" label.

### Where is the source of truth for Ponytail commands?

The **π-extension** ([`pi-extension/index.js`](https://github.com/DietrichGebert/ponytail/blob/main/pi-extension/index.js)) serves as the source of truth, where each command is registered via `registerCommand(name, metadata)`. This registration drives the generation of both TOML and Markdown adapter files, ensuring consistency across all supported hosts.

### How does Ponytail ensure consistency across host formats?

The repository uses [`tests/commands.test.js`](https://github.com/DietrichGebert/ponytail/blob/main/tests/commands.test.js) to enforce a strict contract: every command registered in the π-extension must have both a `commands/<name>.toml` file for Claude/Gemini and a `.opencode/command/<name>.md` file for OpenCode. Tests fail if either representation is missing or if definition files exist without corresponding registrations.