# How the `probe` Command Validates Backend Availability Beyond `shutil.which` in Agent Reach

> Discover how Agent Reach's probe command validates backend availability using real execution checks, going beyond shutil.which to detect environment issues and timeouts.

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

---

**Agent Reach performs real execution health checks through [`agent_reach/probe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/probe.py), catching stale virtual environments, permission issues, and timeouts that simple path lookups miss.**

The `probe` command in Agent Reach distinguishes itself from basic availability checks by actually running target commands and classifying their runtime behavior. While `shutil.which` merely confirms that a binary exists on the system PATH, the `probe_command` function in [`agent_reach/probe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/probe.py) executes commands with real arguments to detect nuanced failure modes. This deeper validation powers the `doctor` diagnostic system, giving users actionable repair guidance when backends break.

## The Validation Pipeline in [`agent_reach/probe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/probe.py)

The `probe_command` function implements a seven-stage validation flow that transforms a simple existence check into a comprehensive health assessment.

### Stage 1: Existence Check with `shutil.which`

The probe begins with the standard path lookup. If `shutil.which` returns `None`, the function immediately returns `ProbeResult("missing")` without attempting execution.

```python

# agent_reach/probe.py, lines 67-70

if not cmd_path:
    return ProbeResult(
        status="missing",
        hint=f"{command} is not installed or not on PATH"
    )

```

This is the baseline behavior found in most tooling checks. The distinction comes in what happens when a path *is* found.

### Stage 2: Real Execution via `_run_once`

When a valid path exists, the helper function `_run_once` spawns the command through `subprocess.run`, defaulting to `--version` arguments:

```python

# agent_reach/probe.py, lines 92-105

def _run_once(cmd: List[str], timeout: int) -> Tuple[bool, str, str, int]:
    result = subprocess.run(
        cmd,
        capture_output=True,
        text=True,
        timeout=timeout,
        env=utf8_subprocess_env()  # From agent_reach/utils/process.py

    )
    return True, result.stdout, result.stderr, result.returncode

```

The `utf8_subprocess_env()` utility from [`agent_reach/utils/process.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/utils/process.py) ensures a clean environment, preventing locale-related encoding failures during probing.

### Stage 3: Shebang and Interpreter Detection

A classic failure case that `shutil.which` cannot catch: Python packages installed in virtual environments that become orphaned after interpreter upgrades. The probe catches `FileNotFoundError` and `OSError` exceptions to flag these as **"broken"**:

```python

# agent_reach/probe.py, lines 106-110

except (FileNotFoundError, OSError) as e:
    return ProbeResult(
        status="broken",
        hint=f"{command} exists but its interpreter is missing. Reinstall recommended."
    )

```

Without this check, users would see mysterious execution failures despite the binary appearing present.

### Stage 4: Timeout Detection

Unresponsive commands are classified separately from execution failures. A `subprocess.TimeoutExpired` exception triggers the **"timeout"** status:

```python

# agent_reach/probe.py, lines 111-112

except subprocess.TimeoutExpired:
    return ProbeResult(status="timeout", hint=f"{command} is not responding")

```

This distinguishes hung processes from fundamentally broken installations.

### Stage 5: Exit-Code Classification

The probe interprets universal exit codes from POSIX shells:

```python

# agent_reach/probe.py, lines 14-15

BROKEN_EXIT_CODES = {126, 127}  # Command found but not executable / command not found

# lines 114-115

if returncode in BROKEN_EXIT_CODES:
    return ProbeResult(status="broken", hint=f"{command} is not executable")

```

- **126**: Command found but not executable (permission denied)
- **127**: Command not found (often indicates broken symlink or PATH issue)

These codes signal "found but fundamentally broken" scenarios that mere path presence cannot reveal.

### Stage 6: General Error Reporting

Non-zero exit codes outside the broken set receive **"error"** status with captured output preserved for debugging:

```python

# agent_reach/probe.py, lines 118-120

if returncode != 0:
    return ProbeResult(
        status="error",
        output=f"stdout: {stdout}\nstderr: {stderr}"
    )

```

### Stage 7: Success Confirmation

Only zero exit codes yield **"ok"** status with command output:

```python

# agent_reach/probe.py, lines 120-121

return ProbeResult(status="ok", output=stdout.strip())

```

## Failure Mode Classification Summary

| Status | Detection Mechanism | Typical Cause |
|--------|---------------------|-------------|
| **missing** | `shutil.which` returns `None` | Binary not installed or not on PATH |
| **broken** | `FileNotFoundError`, `OSError`, or exit code 126/127 | Stale virtual environment, bad shebang, permission denied |
| **timeout** | `subprocess.TimeoutExpired` | Process hung or unresponsive |
| **error** | Non-zero exit code (other than 126/127) | Command-specific runtime failure |
| **ok** | Exit code 0 | Healthy, responsive backend |

## Practical Usage Examples

### Standalone Health Check

```python
from agent_reach.probe import probe_command

result = probe_command("yt-dlp", args=["--version"])
if result.ok:
    print("yt-dlp is available:", result.output)
elif result.status == "missing":
    print("yt-dlp is not installed.")
elif result.status == "broken":
    print("yt-dlp exists but cannot be executed:", result.hint)
elif result.status == "timeout":
    print("yt-dlp is unresponsive:", result.hint)
else:
    print("yt-dlp returned an error:", result.output)

```

### Channel Integration Pattern

Channels implement `check()` methods that delegate to `probe_command`, enabling unified diagnostics through [`agent_reach/doctor.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/doctor.py):

```python
from agent_reach.probe import probe_command
from agent_reach.channels.base import BaseChannel

class YoutubeChannel(BaseChannel):
    ...
    def check(self) -> None:
        probe = probe_command("yt-dlp")
        if not probe.ok:
            self.log.error(f"yt-dlp probe failed: {probe.status} – {probe.hint}")

```

The `doctor` module aggregates these checks across all registered channels, producing a comprehensive system health report.

## Key Source Files

- **[`agent_reach/probe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/probe.py)** — Core probing logic with existence, execution, and classification stages
- **[`agent_reach/doctor.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/doctor.py)** — Orchestrates health checks across all channels
- **`agent_reach/channels/*`** — Platform backends (YouTube, Reddit, etc.) implementing `check()` with `probe_command`
- **[`agent_reach/utils/process.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/utils/process.py)** — Subprocess environment utilities for clean command execution

## Summary

- **`shutil.which`** only verifies PATH presence; **`probe_command`** executes commands to validate actual runtime health
- The probe catches **broken interpreters**, **permission issues**, and **timeouts** through exception handling and exit-code analysis
- Channels integrate via `check()` methods, enabling `doctor` diagnostics to report precise failure modes with actionable repair hints
- Five distinct statuses (`missing`, `broken`, `timeout`, `error`, `ok`) provide granular visibility into backend state

## Frequently Asked Questions

### Why doesn't Agent Reach use just `shutil.which` like other tools?

`shutil.which` confirms that a file exists on PATH, but fails to detect common breakage modes: stale Python virtual environments with orphaned shebangs, permission-denied executables, and unresponsive hung processes. The `probe_command` function in [`agent_reach/probe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/probe.py) executes real commands to surface these issues with specific diagnostic messages.

### What exit codes does the probe treat as "broken"?

The probe classifies exit codes **126 and 127** as **"broken"** per POSIX conventions. Code 126 means "command found but not executable" (permissions), while 127 means "command not found" despite path presence (often broken symlinks). These are defined in `BROKEN_EXIT_CODES` at lines 14-15 of [`agent_reach/probe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/probe.py).

### How do channels report probe failures to users?

Channels call `probe_command` inside their `check()` methods, then log structured error messages including the probe `status` and `hint`. The [`agent_reach/doctor.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/doctor.py) module aggregates all channel checks into a unified diagnostic report, presenting actionable guidance for each failed backend.

### Can I customize the arguments passed during probing?

Yes. The `probe_command` function accepts an optional `args` parameter defaulting to `["--version"]`. Pass custom arguments for backends that don't support `--version` or require specific flags to validate functionality.