How Ponytail Persists and Retrieves Active Mode State: A Complete Guide
Ponytail maintains active mode state in a runtime variable _current_mode for temporary session changes, while persisting defaults to config.json in the user configuration directory, reading values through the _default_mode() helper that checks environment variables before falling back to the JSON file.
The DietrichGebert/ponytail repository implements a dual-layer storage strategy for managing operational modes (off, lite, full, ultra, review). This architecture separates transient runtime adjustments from permanent user preferences, ensuring both immediate responsiveness and cross-session persistence.
Runtime Mode Storage
Ponytail stores transient mode changes in memory during the current process execution. This allows users to switch modes dynamically via the /ponytail command without affecting their saved defaults.
The _current_mode Variable
The global variable _current_mode holds the mode value set during the active session. According to the source code in __init__.py, this variable is accessed directly whenever Ponytail determines which contextual instructions to inject before LLM calls (source line 26-28).
When a user executes a command like /ponytail lite, the _handle_mode_command() function updates this variable. The value persists only until the process terminates, making it ideal for temporary workflow adjustments that should not survive application restarts.
Persistent Configuration Storage
For settings that survive process restarts, Ponytail writes to a JSON configuration file in the user's config directory.
config.json Location and Format
The persistent file resides at $XDG_CONFIG_HOME/ponytail/config.json on Linux systems, or ~/.config/ponytail/config.json on other platforms. The directory resolution logic lives in _config_dir() within __init__.py (source line 44-49).
The JSON structure contains a single "defaultMode" field:
{
"defaultMode": "lite"
}
This file is created on first run and updated when users invoke persistence commands, ensuring their preferred mode remains active across separate application launches.
How Ponytail Reads the Mode State
The system implements a cascading resolution strategy to determine the effective mode, prioritizing runtime changes over persistent configuration.
The Mode Resolution Priority
When preparing context injection (e.g., in _pre_llm_call), Ponytail evaluates the active mode using the following precedence:
- Runtime variable (
_current_mode): Set via the/ponytailcommand in the current session - Environment variable (
PONYTAIL_DEFAULT_MODE): System-level override for the default - Configuration file (
config.json): User-persisted preference in the XDG directory - Hardcoded fallback (
DEFAULT_MODE): Repository default when no other source exists
This logic ensures that temporary session changes always take precedence over saved settings, while environment variables allow system-wide overrides without modifying user files.
The _default_mode() Function Implementation
The helper function _default_mode() in __init__.py implements the cascading read logic for the default configuration (source line 52-60):
def _default_mode() -> str:
env_mode = _normalize_config_mode(os.environ.get("PONYTAIL_DEFAULT_MODE"))
if env_mode:
return env_mode
try:
data = json.loads((_config_dir() / "config.json").read_text(encoding="utf-8"))
file_mode = _normalize_config_mode(data.get("defaultMode"))
if file_mode:
return file_mode
except Exception:
pass
return DEFAULT_MODE
The function first normalizes the environment variable value, then attempts to parse the JSON configuration, and finally falls back to the built-in default if neither source yields a valid mode.
Context Injection Integration
Before each LLM call, Ponytail resolves the final mode using the expression found in __init__.py:
mode = _current_mode or _default_mode()
context = build_injected_context(mode)
This single line demonstrates how the system bridges volatile runtime state with persistent configuration, using Python's or operator to implement the fallback chain.
Working with Mode State Programmatically
You can interact with Ponytail's persistence layer directly in your own scripts.
Reading the Current Effective Mode
To determine which mode is currently active in your code:
from ponytail import _current_mode, _default_mode
def get_active_mode():
# Prefer the runtime override, otherwise use the persisted default
return _current_mode or _default_mode()
This mirrors the internal logic used by Ponytail's context injection system.
Changing the Mode at Runtime
To simulate a user changing modes programmatically:
# Simulate a user issuing "/ponytail lite"
from ponytail import _handle_mode_command
msg = _handle_mode_command("lite")
print(msg) # → "Ponytail mode set to lite."
Note that this only affects _current_mode and does not modify config.json.
Persisting a New Default Mode
To permanently save a mode preference across sessions:
import json
from ponytail import _config_dir
def set_default_mode(mode: str):
cfg_path = _config_dir() / "config.json"
cfg_path.parent.mkdir(parents=True, exist_ok=True)
cfg_path.write_text(json.dumps({"defaultMode": mode}), encoding="utf-8")
This creates or overwrites the configuration file in the user-specific directory, ensuring the setting persists after restarting the application.
Summary
Ponytail's mode state persistence relies on a two-tier architecture that balances flexibility with durability:
- Runtime storage uses the
_current_modevariable in__init__.pyfor temporary session changes set via the/ponytailcommand - Persistent storage writes to
config.jsonin the XDG-compliant user configuration directory (resolved by_config_dir()) - Resolution priority checks environment variables (
PONYTAIL_DEFAULT_MODE) before falling back to the JSON file - Effective mode calculation combines both layers using
mode = _current_mode or _default_mode()before context injection
Frequently Asked Questions
What happens if config.json doesn't exist?
If the configuration file is missing or unreadable, the _default_mode() function catches the exception and returns the hardcoded DEFAULT_MODE constant. The application continues functioning without persistent storage until the user explicitly saves a preference.
Can I override the mode without modifying the configuration file?
Yes. Set the PONYTAIL_DEFAULT_MODE environment variable to any valid mode (off, lite, full, ultra, review). The _default_mode() function checks this variable before attempting to read config.json, allowing system administrators to enforce defaults without touching user files.
Where exactly is the config.json file located on my system?
The _config_dir() function in __init__.py (source line 44-49) resolves the path using the XDG Base Directory specification. On Linux, this respects $XDG_CONFIG_HOME/ponytail/. On macOS and Windows, it defaults to ~/.config/ponytail/. You can verify the exact location by importing _config_dir() from the ponytail module and calling it directly.
How does Ponytail validate mode values?
Both _handle_mode_command() and _default_mode() utilize the _normalize_config_mode() helper to validate inputs. This function ensures only the five recognized modes (off, lite, full, ultra, review) are accepted, returning None for invalid values and triggering the fallback chain.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →