# How Ponytail Handles Configuration File Creation and Path Handling

> Learn how Ponytail handles configuration file creation and path handling across Linux, Windows, and POSIX systems. Discover its efficient directory specifications for user settings.

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

---

**Ponytail determines its configuration directory using the XDG Base Directory specification on Linux, falls back to `%APPDATA%` on Windows, and defaults to `~/.config/ponytail` on other POSIX systems, reading user settings from a manually created [`config.json`](https://github.com/DietrichGebert/ponytail/blob/main/config.json) file rather than auto-generating it.**

Ponytail is an open-source tool that stores user-specific runtime preferences in a JSON configuration file. Understanding how it approaches **configuration file creation and path handling** is essential for customizing the default mode across different operating systems. The implementation relies on private helper functions within [`__init__.py`](https://github.com/DietrichGebert/ponytail/blob/main/__init__.py) to resolve directory locations and parse settings without automatically writing files to disk.

## Configuration Directory Resolution Strategy

The private helper **`_config_dir()`** (defined in [`__init__.py`](https://github.com/DietrichGebert/ponytail/blob/main/__init__.py) lines 44-50) encapsulates the cross-platform directory detection logic. This function implements a hierarchical fallback strategy to locate the appropriate user-specific configuration folder based on environment variables and operating system detection.

### XDG Base Directory Support

On Linux and other systems following the XDG specification, Ponytail checks the **`XDG_CONFIG_HOME`** environment variable. If this variable is set, the function returns `"$XDG_CONFIG_HOME/ponytail"` as the configuration directory, ensuring compliance with modern Linux desktop conventions.

### Windows and POSIX Fallbacks

When `XDG_CONFIG_HOME` is unavailable, the code branches based on **`os.name`**. On Windows (where `os.name == "nt"`), Ponytail falls back to **`%APPDATA%`** or `%USERPROFILE%\AppData\Roaming` if `%APPDATA%` is missing, appending `ponytail` to the path. On all other platforms, it defaults to **`~/.config/ponytail`**, adhering to traditional POSIX conventions.

## Reading Configuration Settings Without Auto-Creation

Once the directory is determined, the **`_default_mode()`** function (lines 57-61 of [`__init__.py`](https://github.com/DietrichGebert/ponytail/blob/main/__init__.py)) attempts to read the [`config.json`](https://github.com/DietrichGebert/ponytail/blob/main/config.json) file. Unlike many applications, Ponytail **does not automatically create** this file; it expects users to manually create `$CONFIG_DIR/config.json` if they wish to override defaults.

### Parsing and Validating `defaultMode`

The function extracts the **`defaultMode`** key from the JSON object and passes it through **`_normalize_config_mode()`** (lines 37-42) for validation. This helper ensures the value matches one of the allowed modes: `"off"`, `"lite"`, `"full"`, `"ultra"`, or `"review"`.

### Graceful Degradation

If [`config.json`](https://github.com/DietrichGebert/ponytail/blob/main/config.json) is missing, unreadable, or contains malformed JSON, Ponytail silently catches the exception and falls back to the built-in constant **`DEFAULT_MODE = "full"`**. This robust error handling ensures the application starts successfully regardless of configuration file state.

## Implementing Ponytail's Configuration Logic

The following Python example replicates Ponytail's internal path resolution and configuration loading behavior:

```python
from pathlib import Path
import json
import os

def ponytail_config_dir() -> Path:
    """Mirrors Ponytail's internal _config_dir() logic."""
    if os.getenv("XDG_CONFIG_HOME"):
        return Path(os.getenv("XDG_CONFIG_HOME")) / "ponytail"
    if os.name == "nt":
        appdata = os.getenv("APPDATA", Path.home() / "AppData" / "Roaming")
        return Path(appdata) / "ponytail"
    return Path.home() / ".config" / "ponytail"

def load_default_mode() -> str:
    """Loads and validates the defaultMode from config.json."""
    config_path = ponytail_config_dir() / "config.json"
    try:
        data = json.loads(config_path.read_text(encoding="utf-8"))
        mode = data.get("defaultMode")
        if mode in {"off", "lite", "full", "ultra", "review"}:
            return mode
    except Exception:
        pass  # Missing or malformed file

    return "full"  # Built-in DEFAULT_MODE

print("Config directory:", ponytail_config_dir())
print("Effective mode:", load_default_mode())

```

To manually create the configuration file on Linux or macOS:

```bash
mkdir -p ~/.config/ponytail
cat > ~/.config/ponytail/config.json <<'EOF'
{
  "defaultMode": "lite"
}
EOF

```

## Summary

- **`_config_dir()`** implements cross-platform detection using `XDG_CONFIG_HOME`, Windows `%APPDATA%`, or `~/.config/ponytail` as fallback paths.
- Ponytail **never writes** [`config.json`](https://github.com/DietrichGebert/ponytail/blob/main/config.json) automatically; users must manually create the file to persist custom settings.
- **`_default_mode()`** parses the `defaultMode` key and validates values through **`_normalize_config_mode()`** before applying them.
- The application uses graceful degradation, falling back to **`DEFAULT_MODE = "full"`** when configuration files are missing or malformed.

## Frequently Asked Questions

### Where does Ponytail store its configuration file?

Ponytail stores its configuration file at `$XDG_CONFIG_HOME/ponytail/config.json` on Linux systems, `%APPDATA%\ponytail\config.json` on Windows, or `~/.config/ponytail/config.json` on macOS and other POSIX platforms. The `_config_dir()` function in [`__init__.py`](https://github.com/DietrichGebert/ponytail/blob/main/__init__.py) determines the exact path at runtime based on environment variables and operating system detection.

### Does Ponytail create the configuration file automatically?

No, Ponytail does not automatically create [`config.json`](https://github.com/DietrichGebert/ponytail/blob/main/config.json) during initialization. Users must manually create both the configuration directory and the JSON file if they want to override the default runtime mode. The codebase intentionally omits file creation logic, treating the configuration as optional and falling back to built-in constants when files are absent.

### What values are valid for the `defaultMode` setting?

The `defaultMode` key accepts one of five string values defined in the normalization logic: `"off"`, `"lite"`, `"full"`, `"ultra"`, or `"review"`. The **`_normalize_config_mode()`** function in [`__init__.py`](https://github.com/DietrichGebert/ponytail/blob/main/__init__.py) validates these entries, and any invalid or missing value triggers the fallback to `"full"`.

### How does Ponytail handle configuration file creation and path handling on Windows specifically?

On Windows, Ponytail checks for the `%APPDATA%` environment variable and uses `%USERPROFILE%\AppData\Roaming` as a secondary fallback if `%APPDATA%` is unavailable, appending `ponytail` to construct the final path. This Windows-specific logic resides in the `_config_dir()` function alongside the XDG and POSIX handling, ensuring consistent behavior across operating systems without requiring manual path configuration.