# Local vs Server Environment Detection in Agent Reach: How It Works

> Learn how Agent Reach detects local vs server environments using a multi-signal scoring system to automatically choose the right backend. Understand the core detection mechanism.

- Repository: [Pnant/Agent-Reach](https://github.com/Panniantong/Agent-Reach)
- Tags: internals
- Published: 2026-06-19

---

**Agent Reach distinguishes between local desktop and headless server environments using a multi-signal scoring system in [`agent_reach/cli.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/cli.py) to automatically select the appropriate backend for each platform.**

The **Agent Reach** repository (Panniantong/Agent-Reach) provides intelligent CLI automation for social media platforms, but it must adapt its behavior depending on whether it runs on a developer's laptop or a remote server. Understanding how local and server environment detection works in Agent Reach is crucial for debugging installation issues and predicting which backends the tool will provision.

## How Environment Detection Works

The core detection logic resides in the private helper `_detect_environment()` inside **[`agent_reach/cli.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/cli.py)** (lines 955–994). This function aggregates multiple OS-level indicators and returns either `"local"` or `"server"` based on a weighted scoring threshold.

```python
def _detect_environment():
    """Auto‑detect if running on local computer or server."""
    import os
    indicators = 0

    # 1️⃣ SSH session – typical for remote logins

    if os.environ.get("SSH_CONNECTION") or os.environ.get("SSH_CLIENT"):
        indicators += 2

    # 2️⃣ Docker / container environment

    if os.path.exists("/.dockerenv") or os.path.exists("/run/.containerenv"):
        indicators += 2

    # 3️⃣ Headless display (no X11/Wayland)

    if not os.environ.get("DISPLAY") and not os.environ.get("WAYLAND_DISPLAY"):
        indicators += 1

    # 4️⃣ Cloud‑VM identifiers (Amazon, Google, Azure, DigitalOcean, …)

    for cloud_file in ["/sys/hypervisor/uuid",
                       "/sys/class/dmi/id/product_name"]:
        if os.path.exists(cloud_file):
            try:
                with open(cloud_file) as f:
                    content = f.read().lower()
                if any(x in content
                       for x in ["amazon", "google", "microsoft",
                                 "digitalocean", "linode", "vultr", "hetzner"]):
                    indicators += 2
            except Exception:
                pass

    # 5️⃣ systemd‑detect‑virt (detects virtualisation)

    try:
        import subprocess
        result = subprocess.run(
            ["systemd-detect-virt"], capture_output=True,
            encoding="utf-8", errors="replace", timeout=3)
        if result.returncode == 0 and result.stdout.strip() != "none":
            indicators += 1
    except Exception:
        pass

    return "server" if indicators >= 2 else "local"

```

### Detection Signals and Scoring

The function checks five distinct signals, each assigned a weight reflecting its reliability:

- **SSH sessions** (`SSH_CONNECTION` or `SSH_CLIENT` environment variables): Adds **2** points — a strong indicator of remote server access.
- **Container environments** (`/.dockerenv` or `/run/.containerenv`): Adds **2** points — unambiguous proof of containerized deployment.
- **Headless display** (missing `DISPLAY` or `WAYLAND_DISPLAY`): Adds **1** point — suggests no GUI, but alone could indicate a minimal desktop setup.
- **Cloud VM identifiers** (reading `/sys/hypervisor/uuid` or `/sys/class/dmi/id/product_name` for Amazon, Google, Microsoft, DigitalOcean, etc.): Adds **2** points — confirms virtualized cloud infrastructure.
- **Virtualization detection** (`systemd-detect-virt` returning non-"none"): Adds **1** point — catches virtual machines not explicitly identified by cloud files.

## Platform-Specific Backend Selection

Agent Reach uses the environment string to choose between **graphical browser-based backends** (for local) and **headless CLI binaries** (for server).

| Platform | Local Environment | Server Environment |
|----------|-------------------|-------------------|
| **XiaoHongShu (xhs)** | Installs **OpenCLI**, reusing the user's existing Chrome session. | Recommends the **xiaohongshu-mcp** binary and provides QR-login guidance. |
| **Reddit** | Prefers **OpenCLI**; falls back to existing `rdt-cli` if present. | Installs **rdt-cli**, a pure-CLI backend that operates without UI requirements. |
| **Twitter** | Standard CLI operation; assumes graphical environment available. | Standard CLI operation, but requires manual headless configuration (e.g., proxies). |

### Reddit Installation Logic Example

The conditional routing is implemented in [`cli.py`](https://github.com/Panniantong/Agent-Reach/blob/main/cli.py) (lines 778–892). When installing Reddit dependencies, the code explicitly branches based on the detection result:

```python
def _install_reddit_deps():
    """Set up Reddit — desktop prefers OpenCLI, rdt-cli for servers/legacy."""
    if _detect_environment() != "server":
        _install_opencli_deps()
        print("  Reddit 走 OpenCLI（浏览器里登录过 reddit.com 即可用）")
        # ... optionally use rdt‑cli if already present ...

        return

    _install_rdt_cli()

```

### Why the Threshold Is Set to ≥2

The function returns `"server"` only when the indicator sum reaches **two or more**. This conservative threshold prevents false positives:

- **Strong signals** (SSH, containers, cloud VMs) each contribute 2 points, immediately triggering server mode.
- **Weak signals** (missing display, virtualization) contribute only 1 point, requiring combination with another signal to classify as server.

Therefore, a desktop workstation running without a GUI but without SSH or containerization remains classified as **local**, while a Docker container or EC2 instance is correctly identified as **server**.

## Practical Code Examples

You can invoke the detection directly from your Python code to verify the current environment:

```python

# Quick check from the CLI

>>> from agent_reach.cli import _detect_environment
>>> _detect_environment()
'local'   # on my laptop

```

For testing environment-specific logic, the test suite in **[`tests/test_cli.py`](https://github.com/Panniantong/Agent-Reach/blob/main/tests/test_cli.py)** (lines 88–100) demonstrates how to mock the detection function:

```python

# Simulating a server environment in a test (see tests/test_cli.py)

def test_install_reddit_deps_routes_by_environment(monkeypatch):
    monkeypatch.setattr(cli, "_detect_environment", lambda: "local")
    # ...assert OpenCLI path...

    monkeypatch.setattr(cli, "_detect_environment", lambda: "server")
    # ...assert rdt‑cli path...

```

## Summary

- **Local** environments trigger installation of **OpenCLI** and browser-based backends that require a graphical session.
- **Server** environments trigger installation of **headless binaries** like `rdt-cli` and `xiaohongshu-mcp` that function without UI dependencies.
- The detection logic in **[`agent_reach/cli.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/cli.py)** uses a weighted scoring system (≥2 points) checking SSH variables, container files, display environment variables, cloud VM metadata, and systemd virtualization.
- Key files involved include **[`agent_reach/cli.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/cli.py)** for detection logic, **[`tests/test_cli.py`](https://github.com/Panniantong/Agent-Reach/blob/main/tests/test_cli.py)** for validation, and **[`agent_reach/backends/opencli.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/backends/opencli.py)** for the desktop-only backend implementation.

## Frequently Asked Questions

### How does Agent Reach detect if it is running on a server?

Agent Reach checks five OS-level indicators in `_detect_environment()`: SSH environment variables, Docker/container files, display server variables (`DISPLAY`/`WAYLAND_DISPLAY`), cloud provider metadata in `/sys/`, and `systemd-detect-virt` output. Each indicator carries a weight of 1 or 2 points, and reaching a total of 2 or more points classifies the environment as `"server"`.

### Why does my headless desktop still show as "local"?

A single weak signal (such as missing `DISPLAY` or `WAYLAND_DISPLAY` variables) only adds 1 point to the score. The threshold requires **≥2 points** to trigger server mode. Since headless workstations typically lack SSH sessions, containers, or cloud VM signatures, they remain classified as local unless multiple indicators are present.

### What backends are installed on servers versus local machines?

On **local** machines, Agent Reach installs **OpenCLI** for Reddit and XiaoHongShu, which leverages the user's existing Chrome browser session. On **servers**, it installs pure CLI alternatives like **rdt-cli** for Reddit and **xiaohongshu-mcp** for XiaoHongShu, ensuring functionality without graphical dependencies.

### Can I override the environment detection manually?

While the source code in [`agent_reach/cli.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/cli.py) does not expose a public override flag, you can manipulate the underlying indicators (such as setting `SSH_CONNECTION` or creating `/.dockerenv`) to influence the scoring, or patch the `_detect_environment()` function in tests using `monkeypatch` as demonstrated in [`tests/test_cli.py`](https://github.com/Panniantong/Agent-Reach/blob/main/tests/test_cli.py).