# How Ponytail Activates on Session Start: Hermes Plugin Lifecycle Explained

> Understand how Ponytail activates on session start by exploring the Hermes plugin lifecycle. Learn how it injects instructional context into model requests.

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

---

**Ponytail automatically activates when the `register()` function binds a pre-LLM hook to the Hermes context, injecting instructional context into the first model request of every session.**

Ponytail is a Hermes plugin that enhances LLM-agent interactions by automatically prepending contextual instructions at the start of each conversation. Understanding how Ponytail activates on session start requires examining its registration mechanism and hook architecture in the DietrichGebert/ponytail repository. When properly initialized, the plugin intercepts the first LLM call to insert mode-specific guidance without requiring manual intervention.

## The Activation Process on Session Start

The activation sequence begins when `ponytail.register(ctx)` is invoked with a valid Hermes context object. According to the source code in [`__init__.py`](https://github.com/DietrichGebert/ponytail/blob/main/__init__.py) (lines 95-106), this function registers three critical components with the Hermes framework:

- A **pre-LLM-call hook** (`_pre_llm_call`) via `ctx.register_hook("pre_llm_call", _pre_llm_call)`
- A **gateway-dispatch rewrite hook** (`rewrite_gateway_command`) via `ctx.register_hook("pre_gateway_dispatch", rewrite_gateway_command)`
- **Slash commands** including `/ponytail`, `/ponytail-review`, and others for runtime configuration

## Hook Execution and Context Injection

As soon as a session issues its first LLM request, Hermes invokes every registered `pre_llm_call` hook. Ponytail’s `_pre_llm_call` handler executes `build_injected_context` (implemented in [`__init__.py`](https://github.com/DietrichGebert/ponytail/blob/main/__init__.py), lines 25-33 and 105-112) to construct the mode-filtered instructional text.

The hook returns a dictionary in the format `{ "context": <text> }`, which Hermes automatically injects as a prefix to the model’s prompt. This injection happens transparently before the LLM processes the user's actual query.

## Mode Resolution Hierarchy

The content injected on session start depends on the active **mode**, resolved in the following priority order:

1. **Explicit argument** passed directly to `build_injected_context`
2. **Environment variable** `PONYTAIL_DEFAULT_MODE` (normalized via `_normalize_config_mode`)
3. **Configuration file** at `~/.config/ponytail/config.json` (if present)
4. **Hard-coded fallback** `DEFAULT_MODE = "full"`

When no other configuration exists, the first LLM call receives a prefix such as:

```

PONYTAIL MODE ACTIVE — level: full

<filtered skill description …>

```

Subsequent calls in the same session reuse this context unless the user changes modes via slash commands.

## Practical Implementation Examples

### Registering Ponytail with a Hermes Instance

```python
from hermes import Hermes
import ponytail

# Create a Hermes context (or obtain one from your app)

ctx = Hermes()

# Wire Ponytail into the session

ponytail.register(ctx)

# From now on every new session will receive Ponytail’s injected context

# on the very first LLM call.

```

### Changing the Mode During a Session

```python

# User enters the slash command in the chat UI

#   /ponytail lite

# Hermes routes the command to Ponytail’s `_handle_mode_command`,

# which updates the global `_current_mode`.

# The next LLM turn will see:

#   PONYTAIL MODE ACTIVE — level: lite

```

### Examining the Injected Context

```python
from ponytail import build_injected_context

# Assuming default mode (full)

print(build_injected_context())

# => 

# PONYTAIL MODE ACTIVE — level: full

#

# <skill body filtered for “full” mode>

```

## Key Source Files

Understanding Ponytail's activation mechanism requires familiarity with these components:

- **[`__init__.py`](https://github.com/DietrichGebert/ponytail/blob/main/__init__.py)**: Core plugin implementation containing mode handling, context building, and hook registration logic
- **[`skills/ponytail/SKILL.md`](https://github.com/DietrichGebert/ponytail/blob/main/skills/ponytail/SKILL.md)**: Full-mode skill description injected during activation
- **[`skills/ponytail-review/SKILL.md`](https://github.com/DietrichGebert/ponytail/blob/main/skills/ponytail-review/SKILL.md)**: Alternative skill content for "review" mode (activated via `PONYTAIL_DEFAULT_MODE=review`)
- **[`README.md`](https://github.com/DietrichGebert/ponytail/blob/main/README.md)**: Repository overview and initialization instructions

## Summary

- Ponytail activates on session start by registering a `pre_llm_call` hook through `ponytail.register(ctx)` that intercepts the first LLM request
- The hook builds mode-filtered context via `build_injected_context` (lines 25-33 and 105-112 in [`__init__.py`](https://github.com/DietrichGebert/ponytail/blob/main/__init__.py)) and returns it in a dictionary format for Hermes injection
- Mode selection follows a strict hierarchy: explicit argument, environment variable `PONYTAIL_DEFAULT_MODE`, config file at `~/.config/ponytail/config.json`, then falls back to `DEFAULT_MODE = "full"`
- Slash commands like `/ponytail` allow runtime mode changes that affect subsequent LLM turns by updating the global `_current_mode` variable
- The registration logic resides in [`__init__.py`](https://github.com/DietrichGebert/ponytail/blob/main/__init__.py) (lines 95-106), which binds the plugin to the Hermes lifecycle

## Frequently Asked Questions

### What triggers Ponytail to start working in a new session?

Ponytail activates when Hermes invokes the registered `_pre_llm_call` hook during the first LLM request of a session. This hook, registered via `ctx.register_hook("pre_llm_call", _pre_llm_call)` in [`__init__.py`](https://github.com/DietrichGebert/ponytail/blob/main/__init__.py) (lines 95-106), executes automatically without requiring manual activation commands, ensuring the context is injected before the model processes any user input.

### How do I configure Ponytail to use a specific mode on startup?

Set the environment variable `PONYTAIL_DEFAULT_MODE` to your preferred mode (e.g., `full` or `review`) before starting the session, or create a JSON config file at `~/.config/ponytail/config.json` specifying the default mode. If neither exists, Ponytail defaults to `DEFAULT_MODE = "full"` as defined in the source code and processed by the `_normalize_config_mode` function.

### Can I change Ponytail's behavior after a session has started?

Yes. Users can issue slash commands such as `/ponytail lite` or `/ponytail review` during an active session. Hermes routes these commands to `_handle_mode_command`, which updates the global `_current_mode` variable, causing subsequent LLM calls to receive the newly configured context prefix.

### Where does the injected context text come from?

The injected content originates from skill definition files located in the `skills/` directory. For `full` mode, Ponytail loads [`skills/ponytail/SKILL.md`](https://github.com/DietrichGebert/ponytail/blob/main/skills/ponytail/SKILL.md). For `review` mode, it loads [`skills/ponytail-review/SKILL.md`](https://github.com/DietrichGebert/ponytail/blob/main/skills/ponytail-review/SKILL.md). The `build_injected_context` function filters these files based on the current mode before injection into the LLM prompt.