How Modly Resolves Python Executable Paths from Virtual Environments and System Python

Modly resolves Python executable paths by prioritizing user-specified arguments, then virtual environments in the API directory or extension folders, and finally falling back to the system Python interpreter that launched the CLI.

The lightningpixel/modly repository implements a robust, platform-aware mechanism to resolve Python executable paths across different operating systems and deployment contexts. When starting the API server or spawning isolated extension processes, Modly must locate the correct interpreter—whether it resides in a dedicated virtual environment or the system Python installation.

Resolving Python Paths for the API Server

When executing CLI commands such as modly-cli serve, Modly determines the appropriate Python interpreter through a cascading priority system defined in tools/modly-cli/agent.py.

Priority Order for CLI Commands

The _default_python function (lines 86-96) implements a four-tier fallback strategy:

  1. User-specified path: If the --python argument is provided, Modly expands and resolves that path immediately using Path(args.python).expanduser().resolve().

  2. API directory virtual environment: Modly searches for a venv inside the API directory at api/.venv, checking Scripts/python.exe on Windows or bin/python on POSIX systems.

  3. User-wide fallback (Windows only): On Windows systems, Modly checks %APPDATA%/Modly/dependencies/venv/Scripts/python.exe for a global fallback environment.

  4. System Python: As a final resort, Modly uses sys.executable—the interpreter that launched the CLI process.

The first existing file from this candidate list is returned. If none exist, the CLI raises a ModlyCliError to prevent execution with an invalid interpreter.

The _default_python Implementation

The resolution logic is implemented in tools/modly-cli/agent.py:


# From tools/modly-cli/agent.py

candidates = [
    api_dir / ".venv" / "Scripts" / "python.exe",
    api_dir / ".venv" / "bin" / "python",
    # Windows AppData fallback only

    Path(os.environ.get("APPDATA", "")) / "Modly" / "dependencies" / "venv" / "Scripts" / "python.exe",
    Path(sys.executable),
]

Modly iterates through these candidates and returns the first path where path.exists() returns True.

Isolated Extension Virtual Environments

For extension subprocesses, Modly uses a separate resolution strategy that enforces strict isolation. Each extension runs in its own dedicated virtual environment, and the system verifies this environment exists before spawning the subprocess.

The _venv_python Helper Function

Located in api/services/extension_process.py (lines 30-35), the _venv_python function constructs platform-specific paths to extension interpreters:


# From api/services/extension_process.py

def _venv_python(ext_dir: Path) -> Path:
    if sys.platform == "win32":
        return ext_dir / "venv" / "Scripts" / "python.exe"
    return ext_dir / "venv" / "bin" / "python"

This helper returns the appropriate path based on the host operating system, ensuring compatibility across Windows and POSIX environments.

Validation and Error Handling

When ExtensionProcess._start initializes, it validates the interpreter path before creating the subprocess:

python = _venv_python(self.ext_dir)
if not python.exists():
    raise RuntimeError(f"[{self.MODEL_ID}] venv not found at {python}. Run the extension's setup.py first.")

Unlike the CLI resolution, extension startup does not fall back to system Python. If the extension-specific virtual environment is missing, Modly raises a clear RuntimeError directing the user to run the extension's setup.py.

Platform-Specific Path Conventions

Modly handles platform differences automatically by checking sys.platform during path construction:

  • Windows: Uses Scripts/python.exe structure
  • POSIX (Linux/macOS): Uses bin/python structure

This convention applies consistently across both the API server resolution in _default_python and the extension resolution in _venv_python, ensuring cross-platform compatibility without manual configuration.

Practical Code Examples

Starting the API Server with a Custom Interpreter

You can explicitly specify a Python interpreter when starting the server:


# Explicitly specify a Python interpreter

modly serve --python /opt/conda/envs/modly/bin/python

If omitted, Modly internally executes the resolution logic:


# Inside tools/modly-cli/agent.py

python = Path(args.python).expanduser().resolve() if getattr(args, "python", None) else _default_python(api_dir)

Running an Extension Process

When Modly spawns an extension, it uses the isolated venv path:


# In api/services/extension_process.py

python = _venv_python(self.ext_dir)   # resolves to ext_dir/venv/.../python

subprocess.Popen([str(python), str(_RUNNER_PATH)], ...)

The extension's api/runner.py entrypoint receives execution through this specific interpreter path, maintaining complete isolation from the host Python environment.

Summary

  • Modly uses distinct resolution strategies for CLI server commands versus extension subprocesses.
  • The CLI prioritizes: user-specified --python, API directory venv, Windows AppData venv, then sys.executable.
  • Extensions require dedicated virtual environments and do not fall back to system Python if the venv is missing.
  • Platform-specific path construction handles both Windows (Scripts/python.exe) and POSIX (bin/python) conventions automatically.
  • Key implementation files are tools/modly-cli/agent.py for CLI resolution and api/services/extension_process.py for extension isolation.

Frequently Asked Questions

What happens if no virtual environment is found when starting the Modly server?

If Modly cannot locate a virtual environment in the API directory or the Windows AppData fallback, it uses sys.executable—the Python interpreter that launched the CLI process. This ensures the server can still start using the system Python, though running within a dedicated virtual environment is recommended for dependency isolation.

How do I specify a custom Python interpreter for the Modly server?

Pass the --python argument followed by the absolute path to your preferred interpreter. Modly immediately uses this path after expanding user variables and resolving symlinks via Path(args.python).expanduser().resolve(), bypassing the automatic venv detection entirely.

Where does Modly look for extension virtual environments?

Modly expects extension virtual environments to reside at {extension_directory}/venv/. On Windows, it looks for venv/Scripts/python.exe; on POSIX systems, it looks for venv/bin/python. This path is constructed by the _venv_python helper function in api/services/extension_process.py, which raises a RuntimeError if the directory does not exist.

Does Modly support both Windows and Linux Python paths?

Yes. Modly automatically detects the operating system using sys.platform checks. For Windows platforms, it uses Scripts/python.exe paths; for Linux, macOS, and other POSIX systems, it uses bin/python paths. This logic is applied consistently across both the CLI server resolution and extension subprocess management.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →