# Override Precedence for `VPHONE_ROOT`, `VPHONE_LIBRARY_ROOT`, and `VPHONE_VENV_DIR` in vphone-cli

> Understand vphone-cli environment variable precedence. Learn how VPHONE_LIBRARY_ROOT and VPHONE_VENV_DIR override VPHONE_ROOT for flexible path management. Get clear guidelines now.

- Repository: [Lakr/vphone-cli](https://github.com/Lakr233/vphone-cli)
- Tags: deep-dive
- Published: 2026-09-08

---

**In vphone-cli, `VPHONE_LIBRARY_ROOT` and `VPHONE_VENV_DIR` take precedence over `VPHONE_ROOT`, while `VPHONE_ROOT` only affects paths when the specific per-item variables are unset.**

The open-source virtualization tool `vphone-cli` stores per-user data under `~/.vphone/` by default, but three environment variables allow you to relocate specific directories. Understanding the override precedence for `VPHONE_ROOT`, `VPHONE_LIBRARY_ROOT`, and `VPHONE_VENV_DIR` ensures you can configure storage locations without unexpected conflicts when managing VM libraries and Python runtimes.

## The Hierarchy of Environment Variable Overrides

The precedence rules follow a specific cascade designed to allow fine-grained control without moving the entire data tree unnecessarily.

### Per-Item Overrides (Highest Priority)

`VPHONE_LIBRARY_ROOT` and `VPHONE_VENV_DIR` represent the highest level of override precedence. When either variable is defined, it wins regardless of whether `VPHONE_ROOT` is set.

- **`VPHONE_LIBRARY_ROOT`**: Redirects the VM library directory (default: `~/.vphone/VMs`)
- **`VPHONE_VENV_DIR`**: Redirects the auto-provisioned Python virtual environment (default: `~/.vphone/venv`)

### Root Override (Secondary Priority)

`VPHONE_ROOT` acts as a fallback that relocates the entire `~/.vphone` tree. It only takes effect when **both** `VPHONE_LIBRARY_ROOT` and `VPHONE_VENV_DIR` are undefined. When active, it moves the library, venv, and auxiliary caches (`ipsws/`, `tools/`, `debs/`) to the specified location.

### Default Locations (Base Case)

If none of the three environment variables are defined, vphone-cli uses the built-in defaults:

- Root: `~/.vphone/`
- Library: `~/.vphone/VMs/`
- Virtual Environment: `~/.vphone/venv/`

## Source Code Implementation

The override logic is hardcoded in the Swift source files of the `Lakr233/vphone-cli` repository.

### VM Library Resolution in [`VPhoneLibrary.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneLibrary.swift)

In [`sources/VPhoneCore/VPhoneLibrary.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/VPhoneCore/VPhoneLibrary.swift), the `defaultRoot()` method implements the precedence check:

```swift
public static func defaultRoot() -> URL {
    if let override = ProcessInfo.processInfo.environment["VPHONE_LIBRARY_ROOT"] {
        return URL(fileURLWithPath: override, isDirectory: true)
    }
    if let root = ProcessInfo.processInfo.environment["VPHONE_ROOT"] {
        return URL(fileURLWithPath: root, isDirectory: true)
            .appendingPathComponent("VMs", isDirectory: true)
    }
    return VPhoneResources.userDataRoot()
        .appendingPathComponent("VMs", isDirectory: true)
}

```

This function checks `VPHONE_LIBRARY_ROOT` first, then falls back to constructing a path from `VPHONE_ROOT`, and finally uses the default user data location.

### Python Virtual Environment Resolution in [`VPhoneResources.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneResources.swift)

In [`sources/VPhoneCore/VPhoneResources.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/VPhoneCore/VPhoneResources.swift), the `venvDirectory` property handles `VPHONE_VENV_DIR`:

```swift
public static var venvDirectory: URL {
    if let dir = ProcessInfo.processInfo.environment["VPHONE_VENV_DIR"], !dir.isEmpty {
        return URL(fileURLWithPath: dir, isDirectory: true)
    }
    let root = ProcessInfo.processInfo.environment["VPHONE_ROOT"]
        ?? FileManager.default.homeDirectoryForCurrentUser
            .appendingPathComponent(".vphone", isDirectory: true).path
    return URL(fileURLWithPath: root, isDirectory: true)
        .appendingPathComponent("venv", isDirectory: true)
}

```

Notice that `VPHONE_VENV_DIR` bypasses the root variable entirely, while the fallback chain uses `VPHONE_ROOT` before defaulting to `~/.vphone/`.

## Practical Configuration Examples

These shell examples demonstrate the precedence rules in action.

Redirect only the VM library while keeping other data in the default location:

```bash
export VPHONE_LIBRARY_ROOT=/data/vphone_lib
vphone-cli vm list  # Uses /data/vphone_lib despite VPHONE_ROOT being unset

```

Override the Python environment regardless of root settings:

```bash
export VPHONE_ROOT=/tmp/vphone_root
export VPHONE_VENV_DIR=/opt/vphone_venv
vphone-cli python-runtime  # Uses /opt/vphone_venv, not /tmp/vphone_root/venv

```

Move the entire tree using only `VPHONE_ROOT`:

```bash
export VPHONE_ROOT=/mnt/external/vphone
vphone-cli vm list  # Uses /mnt/external/vphone/VMs

vphone-cli python-runtime  # Uses /mnt/external/vphone/venv

```

## Summary

- **Per-item variables win**: `VPHONE_LIBRARY_ROOT` and `VPHONE_VENV_DIR` always take precedence over `VPHONE_ROOT`.
- **Root is a fallback**: `VPHONE_ROOT` only affects the library and venv locations when the specific overrides are absent.
- **Implementation clarity**: The precedence logic is explicitly coded in [`sources/VPhoneCore/VPhoneLibrary.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/VPhoneCore/VPhoneLibrary.swift) and [`sources/VPhoneCore/VPhoneResources.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/VPhoneCore/VPhoneResources.swift), ensuring consistent behavior across the CLI.

## Frequently Asked Questions

### What happens if I set both `VPHONE_ROOT` and `VPHONE_LIBRARY_ROOT`?

`VPHONE_LIBRARY_ROOT` takes precedence. The VM library will be stored at the location specified by `VPHONE_LIBRARY_ROOT`, while other directories (like `ipsws/`, `tools/`, and `venv/`) will respect `VPHONE_ROOT` or fall back to defaults.

### Can I use `VPHONE_ROOT` to move just the Python virtual environment?

No. To relocate only the Python virtual environment, you must set `VPHONE_VENV_DIR` explicitly. `VPHONE_ROOT` moves the venv only when `VPHONE_VENV_DIR` is undefined.

### Does vphone-cli create these directories automatically if they don't exist?

Yes. According to the source implementation in [`VPhoneLibrary.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneLibrary.swift) and [`VPhoneResources.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneResources.swift), the tool creates the necessary directory structure when initializing components, provided the parent paths exist and permissions allow.

### Are these environment variables supported on all platforms?

The variables are resolved using `ProcessInfo.processInfo.environment`, which works across macOS and Linux platforms where vphone-cli operates. The path construction uses `FileManager` APIs that handle platform-specific path separators correctly.