# How Ponytail Integrates with Hermes Agent: Plugin Architecture Explained

> Discover how Ponytail integrates with Hermes Agent via its plugin architecture. Learn how to register skills, hooks, and slash commands for enhanced LLM interactions.

- Repository: [DietrichGebert/ponytail](https://github.com/DietrichGebert/ponytail)
- Tags: architecture
- Published: 2026-09-13

---

**Ponytail integrates with Hermes Agent as a plugin that registers skills, hooks, and slash commands through a manifest-based architecture, automatically injecting context before each LLM call and intercepting gateway dispatches to rewrite commands.**

The DietrichGebert/ponytail repository provides a lightweight development guidance system that operates within the Hermes Agent ecosystem. Understanding how Ponytail integrates with Hermes Agent reveals a sophisticated plugin pattern that leverages declarative manifests and runtime hooks to modify LLM behavior without altering core agent code.

## The Plugin Manifest: Declaring Capabilities to Hermes

Hermes discovers Ponytail through the [`plugin.yaml`](https://github.com/DietrichGebert/ponytail/blob/main/plugin.yaml) manifest located in the repository root. This file declares the hooks, commands, and skills that Ponytail exposes to the Hermes runtime.

When Hermes loads the plugin, it reads this manifest to understand what capabilities Ponytail provides, including **pre-LLM call hooks**, **pre-gateway dispatch interceptors**, and a suite of `/ponytail-*` slash commands. This declarative approach allows Hermes to initialize the plugin without hardcoding Ponytail-specific logic into the agent core.

## Registering Skills and Hooks in the Hermes Context

The integration centers on the `register(ctx)` function defined in [`__init__.py`](https://github.com/DietrichGebert/ponytail/blob/main/__init__.py). When Hermes initializes the plugin, it invokes this function with a Hermes context object, triggering a three-phase registration process.

### Automatic Skill Discovery from the skills/ Directory

During registration, Ponytail iterates over the `skills/` directory and automatically registers every markdown-based skill with the Hermes context. According to the source code in [`__init__.py`](https://github.com/DietrichGebert/ponytail/blob/main/__init__.py) (lines 95-101), the plugin calls `ctx.register_skill` for each discovered skill file:

```python

# From __init__.py lines 95-101

for skill_file in skills_dir.glob("*.md"):
    skill_name = skill_file.stem
    with open(skill_file, "r") as f:
        skill_content = f.read()
    ctx.register_skill(skill_name, skill_content)

```

This pattern allows developers to add new capabilities simply by dropping markdown files into the `skills/` directory, without modifying the core plugin logic.

### The pre_llm_call Hook: Injecting Context

Ponytail registers the `pre_llm_call` hook to modify prompts before they reach the LLM. As implemented in [`__init__.py`](https://github.com/DietrichGebert/ponytail/blob/main/__init__.py) (lines 125-130), this hook injects a mode-filtered context string that informs the LLM about the current Ponytail mode:

```python

# Hook implementation from __init__.py lines 125-130

def pre_llm_call(session_id: str) -> dict:
    mode = _get_current_mode(session_id)
    context = f"PONYTAIL MODE ACTIVE — level: {mode}\n\n"
    return {"context": context}

```

The returned context string is prepended to the prompt sent to the LLM, ensuring that the "lazy senior developer" guidance is always active during the conversation.

### The pre_gateway_dispatch Hook: Rewriting Commands

The second core hook, `pre_gateway_dispatch`, intercepts slash-command text from gateways before processing. Located at lines 152-165 in [`__init__.py`](https://github.com/DietrichGebert/ponytail/blob/main/__init__.py), this function rewrites authorized `/ponytail-*` commands into normal agent prompts:

```python

# From __init__.py lines 152-165

def pre_gateway_dispatch(text: str, session_id: str) -> str:
    if text.startswith("/ponytail"):
        # Rewrite command into structured prompt

        return _rewrite_ponytail_command(text, session_id)
    return text

```

This interception allows users to trigger Ponytail functionality through intuitive slash commands while the Hermes core processes them as standard prompts.

## Runtime Mode Management and Slash Commands

Ponytail exposes several slash commands—including `/ponytail`, `/ponytail-review`, and `/ponytail-audit`—that allow users to change runtime modes or invoke specific skills directly.

The mode management system supports both configuration-time defaults and runtime toggling. The `_default_mode` variable sets the initial state, while the `_handle_mode_command` function (lines 166-176 in [`__init__.py`](https://github.com/DietrichGebert/ponytail/blob/main/__init__.py)) processes mode changes during conversations:

```python

# Mode command handling from __init__.py lines 166-176

def _handle_mode_command(args: list, session_id: str) -> str:
    new_mode = args[0] if args else "full"
    _current_mode[session_id] = new_mode
    return f"Ponytail mode set to {new_mode}."

```

Users can trigger this functionality directly in chat:

```text
/user> /ponytail lite

```

The system responds immediately, updating the internal `_current_mode` dictionary for that session and confirming the change.

## Summary

- **Manifest-based discovery**: Hermes loads Ponytail by reading [`plugin.yaml`](https://github.com/DietrichGebert/ponytail/blob/main/plugin.yaml), which declares available hooks, commands, and skills without requiring code changes to the agent core.
- **Automatic skill registration**: The plugin scans the `skills/` directory and registers markdown-based capabilities via `ctx.register_skill` during initialization (lines 95-101).
- **Dual-hook architecture**: `pre_llm_call` injects mode-specific context before each LLM turn (lines 125-130), while `pre_gateway_dispatch` intercepts and rewrites slash commands (lines 152-165).
- **Runtime flexibility**: Users control Ponytail behavior through slash commands like `/ponytail`, with mode persistence handled via `_handle_mode_command` (lines 166-176).

## Frequently Asked Questions

### How does Hermes discover the Ponytail plugin?

Hermes discovers Ponytail through the [`plugin.yaml`](https://github.com/DietrichGebert/ponytail/blob/main/plugin.yaml) manifest file in the repository root. This YAML file declares the plugin's hooks, commands, and entry points, allowing Hermes to load and initialize the integration automatically without manual configuration in the agent core.

### What happens when a user types a slash command like `/ponytail lite`?

When a user sends `/ponytail lite`, the `pre_gateway_dispatch` hook (lines 152-165 in [`__init__.py`](https://github.com/DietrichGebert/ponytail/blob/main/__init__.py)) intercepts the text before it reaches the LLM. The hook recognizes the `/ponytail` prefix, routes it to `_handle_mode_command` (lines 166-176), which updates the internal `_current_mode` for that session, and returns a confirmation message rather than processing it as a standard LLM prompt.

### Can I add custom skills to Ponytail without modifying the Python code?

Yes. Ponytail automatically discovers skills by scanning the `skills/` directory for markdown files during registration (lines 95-101). Adding a new [`SKILL.md`](https://github.com/DietrichGebert/ponytail/blob/main/SKILL.md) file to this directory automatically registers it with Hermes via `ctx.register_skill`, making the new capability available immediately without touching [`__init__.py`](https://github.com/DietrichGebert/ponytail/blob/main/__init__.py).

### What is the difference between the `pre_llm_call` and `pre_gateway_dispatch` hooks?

The `pre_llm_call` hook (lines 125-130) executes immediately before sending a prompt to the LLM, injecting Ponytail's mode-specific context strings to guide the model's behavior. In contrast, `pre_gateway_dispatch` (lines 152-165) runs earlier in the pipeline, intercepting raw user input from chat gateways to rewrite slash commands into standard prompts before they enter the conversation flow.