# Understanding probe_command in Agent-Reach: How It Checks Channel Availability

> Learn how Agent-Reach uses probe_command to check essential channel availability. Understand the five states that ensure your tools are ready for optimal performance.

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

---

**`probe_command` is a lightweight health-checking utility that executes CLI commands and classifies the results into five distinct states—ok, missing, broken, timeout, or error—to determine if external tools required by Agent-Reach channels are available and functional.**

The `probe_command` function serves as the foundation for dependency validation in the **Agent-Reach** framework, providing a standardized mechanism to verify that command-line tools are installed, executable, and responsive before channels attempt to use them. Implemented in [`agent_reach/probe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/probe.py), this utility enables consistent health reporting across all platform integrations.

## What Is probe_command?

`probe_command` is a Python function that wraps subprocess execution to test whether a given binary responds correctly to a lightweight probe, typically a version or status flag. According to the implementation in [`agent_reach/probe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/probe.py) (lines 47-76), the function returns a **`ProbeResult`** dataclass that encapsulates the execution status, captured output, and diagnostic hints.

### The Five Status States

The function categorizes every probe attempt into one of five specific statuses:

- **`ok`** – The command executed successfully with exit code 0.
- **`missing`** – The executable is not found on `PATH` (detected via `shutil.which` returning `None`).
- **`broken`** – The executable exists but cannot be run, typically indicating a stale virtual environment or missing interpreter (triggered by `FileNotFoundError`, `OSError`, or exit codes 126/127).
- **`timeout`** – The command did not complete within the supplied timeout duration (`subprocess.TimeoutExpired`).
- **`error`** – Any other non-zero exit code that does not indicate a broken installation.

### The ProbeResult Dataclass

The **`ProbeResult`** class (defined in [`agent_reach/probe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/probe.py), lines 27-36) stores three key attributes:

1. **`status`** – The string classification (`ok`, `missing`, `broken`, `timeout`, or `error`).
2. **`output`** – The combined `stdout` and `stderr` from the command execution.
3. **`hint`** – An optional message suggesting corrective actions (e.g., reinstall instructions for broken statuses).

For convenience, the dataclass provides an **`ok`** property that returns `True` only when the status is `"ok"`, allowing for simple conditional checks like `if probe.ok:`.

## How probe_command Checks CLI Availability

The core logic follows a four-step pipeline to determine the availability state of a command-line tool.

### Step 1: Binary Location

First, the function attempts to locate the executable using **`shutil.which(cmd)`**. If this returns `None`, the function immediately returns `ProbeResult("missing")` without attempting execution.

### Step 2: Command Execution

If the binary is found, the function invokes a private helper **`_run_once`** that executes `[path, *args]` via **`subprocess.run`**. This execution uses a configurable timeout and a UTF-8 environment provided by [`agent_reach/utils/process.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/utils/process.py) to ensure consistent output encoding.

### Step 3: Result Classification

The function translates subprocess exceptions and return codes into semantic statuses:

- **`FileNotFoundError`** or **`OSError`** during execution → `broken` (with a reinstall hint).
- **`TimeoutExpired`** → `timeout`.
- Exit codes **126** or **127** → `broken` (indicating command-not-found or permission issues at the shell level).
- Exit code **0** → `ok` (output is captured).
- Any other non-zero exit code → `error`.

### Step 4: Retry Logic

If the `retries` parameter is greater than 0, the command is re-executed until a non-transient result (`ok`, `missing`, or `broken`) is observed. Transient failures like timeouts or certain errors trigger the retry mechanism before returning the final `ProbeResult`.

## Channel Integration and Availability Reporting

Channels in Agent-Reach utilize `probe_command` within their health-check lifecycle to report precise availability states to users.

### The Base Channel Contract

Each channel implements a **`check()`** method defined in the base class at [`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py) (lines 19-46). This method calls `probe_command` on the underlying CLI binary and maps the returned status to a channel availability statement.

### Mapping Probe Status to Channel States

The probe's status directly drives the channel's availability reporting:

- **Missing** → The CLI is not installed; the channel reports an error stating the tool is not found.
- **Broken** → The CLI exists but cannot be executed; the channel returns an error including the `probe.hint` for reinstallation guidance.
- **Timeout / Error** → The CLI is present but misbehaving; the channel returns a warning indicating the tool is installed but potentially unusable.
- **OK** → The CLI is healthy; the channel proceeds with normal operations.

For example, the YouTube channel in [`agent_reach/channels/youtube.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/youtube.py) probes `yt-dlp` with:

```python
probe = probe_command("yt-dlp", ["--version"], timeout=10, package="yt-dlp")
if probe.status == "missing":
    return "error", "yt‑dlp 未安装"
if probe.status == "broken":
    return "error", f"yt‑dlp 已安装但无法执行\n{probe.hint}"
if not probe.ok:
    return "warn", f"yt‑dlp 探测失败（{probe.status}），运行 `yt‑dlp status` 查看详情"

```

## Implementation Examples

### Basic Health Check

```python
from agent_reach.probe import probe_command

# Simple health check for a CLI tool

result = probe_command("gh", ["--version"])
print(result.status)   # ok | missing | broken | timeout | error

print(result.output)   # Version string if ok

print(result.hint)     # Reinstall suggestion for broken status

```

### Channel Check Implementation

```python
from agent_reach.probe import probe_command

def check(self):
    probe = probe_command("ffmpeg", ["-version"], timeout=5, package="ffmpeg")
    if probe.status == "missing":
        return "error", "ffmpeg 未安装"
    if probe.status == "broken":
        return "error", f"ffmpeg 已安装但无法执行\n{probe.hint}"
    if not probe.ok:
        return "warn", f"ffmpeg 探测失败（{probe.status}）"
    return "ok", "ffmpeg 可用"

```

## Summary

- **`probe_command`** in [`agent_reach/probe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/probe.py) provides a unified mechanism for testing CLI tool availability through subprocess execution.
- The function returns one of five statuses—**`ok`**, **`missing`**, **`broken`**, **`timeout`**, or **`error`**—based on `shutil.which` detection and subprocess exit codes.
- **`ProbeResult`** (lines 27-36) encapsulates the status, output, and hints, with an `ok` property for quick success verification.
- Channels implement **`check()`** methods (defined in [`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py)) that map probe results to user-facing availability messages.
- The system supports configurable **timeouts** and **retries** to handle transient failures and ensure accurate health reporting.

## Frequently Asked Questions

### What is the difference between "missing" and "broken" status in probe_command?

The **`missing`** status indicates that `shutil.which` could not locate the executable on the system `PATH`, meaning the tool is not installed. The **`broken`** status indicates that the executable was found but could not be executed, typically due to a stale virtual environment, missing interpreter, or permission issues (captured via `FileNotFoundError`, `OSError`, or exit codes 126/127).

### How does probe_command handle command timeouts?

When the subprocess execution exceeds the configurable `timeout` parameter, `subprocess.run` raises a `TimeoutExpired` exception. The `probe_command` function catches this exception and returns a `ProbeResult` with status **`timeout`**, allowing channels to distinguish between slow responses and complete failures.

### Can I customize the timeout for specific channel health checks?

Yes, the `timeout` parameter in `probe_command` accepts a numeric value in seconds. Individual channels can specify custom timeouts based on the expected response time of their underlying CLI tools; for example, the YouTube channel uses `timeout=10` for `yt-dlp` while other channels might use shorter durations for faster tools.

### What does the `ok` property on ProbeResult do?

The **`ok`** property is a convenience boolean that returns `True` only when the `status` field equals `"ok"`. This allows for clean conditional logic in channel implementations, such as `if probe.ok:` to immediately determine if the health check passed, rather than comparing string values manually.