# How Ponytail's Mode Resolution Order Works Across Restarts

> Understand Ponytail's mode resolution order across restarts. Learn how process memory, environment variables, and config files interact to persist settings after termination.

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

---

**Runtime mode commands in Ponytail are stored only in process memory and reset on restart, while environment variables and configuration files provide persistent mode settings that survive process termination.**

Ponytail, an LLM context injection tool developed by DietrichGebert, determines its active operating mode—`off`, `lite`, `full`, `ultra`, or `review`—through a strict priority resolution system. Understanding how Ponytail's mode resolution order interacts across restarts is essential for maintaining consistent LLM behavior between REPL sessions, server restarts, or container redeployments.

## The Four-Level Mode Resolution Hierarchy

Ponytail implements a cascading fallback mechanism defined in [`__init__.py`](https://github.com/DietrichGebert/ponytail/blob/main/__init__.py). The system evaluates four sources in descending priority order during each LLM call hook execution.

### 1. Runtime Commands (Process-Volatile)

The `/ponytail <mode>` slash command sets an in-process variable that takes immediate precedence over all other sources. When you execute `/ponytail ultra` in your session, the `_handle_mode_command` function (lines 67-78 in [`__init__.py`](https://github.com/DietrichGebert/ponytail/blob/main/__init__.py)) assigns the string `"ultra"` to the module-level variable `_current_mode`. This variable exists only in the current Python process's memory space. Because Ponytail does not write this state to disk, terminating the process—whether by closing a REPL, restarting a server, or rebuilding a container—permanently destroys this setting.

### 2. Environment Variables

When no runtime command has been issued in the current process, Ponytail falls back to the `PONYTAIL_DEFAULT_MODE` environment variable. The `_default_mode()` function (lines 52-55 in [`__init__.py`](https://github.com/DietrichGebert/ponytail/blob/main/__init__.py)) checks `os.environ.get("PONYTAIL_DEFAULT_MODE")` before examining any configuration files. Settings defined in your shell profile or container environment persist across restarts and take precedence over JSON configuration.

### 3. Configuration File

If the environment variable is undefined, Ponytail reads `$XDG_CONFIG_HOME/ponytail/config.json` (or `~/.config/ponytail/config.json` as a fallback). The same `_default_mode()` function parses this JSON file looking for the `defaultMode` key. A configuration entry like `{"defaultMode": "lite"}` survives process restarts but ranks below environment variables in the resolution order.

### 4. Hard-Coded Fallback

When no other source specifies a mode, Ponytail uses the `DEFAULT_MODE = "full"` constant defined at line 11 of [`__init__.py`](https://github.com/DietrichGebert/ponytail/blob/main/__init__.py). This ensures the tool always has a valid operational mode even without user configuration.

## Code Implementation of Mode Resolution

The resolution logic executes in the `_pre_llm_call` hook (lines 25-28 in [`__init__.py`](https://github.com/DietrichGebert/ponytail/blob/main/__init__.py)). Before each LLM inference, Ponytail executes:

```python
mode = _current_mode or _default_mode()
context = build_injected_context(mode)

```

This expression evaluates `_current_mode` first. If you have issued a runtime `/ponytail` command during this process lifetime, that value is used immediately. If `_current_mode` is `None`—either because you never set it or because the process restarted—the `or` operator triggers `_default_mode()` to evaluate the environment variable, configuration file, and fallback chain.

## Persistence Behavior Across Restarts

Runtime changes affect only the volatile `_current_mode` variable. When you restart your Python interpreter, this variable initializes to `None`, forcing the next LLM call to rebuild context using `_default_mode()`. This behavior ensures that accidental runtime switches do not persist unintentionally, but it requires explicit configuration for permanent mode changes.

To make a mode survive restarts, configure one of the persistent sources:

1. **Export an environment variable** in your shell startup file:

   ```bash
   export PONYTAIL_DEFAULT_MODE=ultra
   ```

2. **Create a configuration file** at `~/.config/ponytail/config.json`:

   ```json
   {
     "defaultMode": "full"
   }
   ```

The environment variable takes precedence over the configuration file, allowing temporary overrides without modifying persistent settings.

## Special Case: The Review Mode

The `review` pseudo-mode behaves differently from standard runtime modes. Defined in `CONFIG_MODES` rather than `RUNTIME_MODES`, `review` is only available through the configuration file or environment variable. If you attempt `/ponytail review` at runtime, the validator in `_handle_mode_command` rejects the input with the message "Usage: /ponytail [lite|full|ultra|off]". This design ensures that review mode—typically used for auditing or safety checks—cannot be accidentally activated or deactivated during an active session.

## Summary

- **Runtime commands** (`/ponytail <mode>`) modify `_current_mode` temporarily and reset to `None` on process termination.
- **Environment variables** (`PONYTAIL_DEFAULT_MODE`) persist across restarts and take precedence over configuration files.
- **Configuration files** (`~/.config/ponytail/config.json`) provide durable settings but rank below environment variables in the resolution order.
- **Hard-coded fallback** (`DEFAULT_MODE = "full"`) ensures operation when no user configuration exists.
- **Review mode** requires persistent configuration and cannot be toggled at runtime.

## Frequently Asked Questions

### Why doesn't my mode setting survive a Python REPL restart?

Runtime commands set the `_current_mode` variable in the active Python process only. Since Ponytail does not persist this variable to disk or external storage, restarting your REPL creates a fresh process where `_current_mode` initializes as `None`. To maintain settings across sessions, set the `PONYTAIL_DEFAULT_MODE` environment variable or create a [`config.json`](https://github.com/DietrichGebert/ponytail/blob/main/config.json) file.

### What is the difference between `RUNTIME_MODES` and `CONFIG_MODES`?

`RUNTIME_MODES` includes `off`, `lite`, `full`, and `ultra`—these can be switched dynamically using the `/ponytail` command. `CONFIG_MODES` includes `review` in addition to the runtime modes, but `review` can only be activated through the configuration file or environment variable, not via runtime commands.

### How do I permanently set Ponytail to `ultra` mode?

Add `export PONYTAIL_DEFAULT_MODE=ultra` to your shell profile (`.bashrc`, `.zshrc`, etc.), or create `~/.config/ponytail/config.json` containing `{"defaultMode": "ultra"}`. The environment variable method takes precedence if both are defined.

### Can I use different modes for different projects?

Yes. Since environment variables take precedence over global configuration files, you can set `PONYTAIL_DEFAULT_MODE` differently in various project directories using tools like `direnv` or project-specific container environments. Alternatively, start each Python session with a runtime `/ponytail <mode>` command, keeping in mind that this resets if the process restarts.