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

Agent Reach performs real execution health checks through 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 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

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.


# 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:


# 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 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":


# 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:


# 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:


# 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:


# 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:


# 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

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:

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 — Core probing logic with existence, execution, and classification stages
  • 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 — 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 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.

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 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.

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 →