# How to Troubleshoot Agent Reach Channels Showing as 'broken' in Doctor Output

> Troubleshoot Agent Reach channels showing as broken in doctor output. Fix stale Python virtual environments or missing interpreters by reinstalling the tool with uv or pipx.

- Repository: [Pnant/Agent-Reach](https://github.com/Panniantong/Agent-Reach)
- Tags: how-to-guide
- Published: 2026-06-26

---

**Agent Reach marks channels as "broken" when the underlying CLI executable exists on your `$PATH` but fails to run, typically due to stale Python virtual environment shims or missing interpreters, which you can fix by reinstalling the tool with `uv` or `pipx`.**

The `python -m agent_reach.cli doctor` command performs a comprehensive health check of all platform channels in the **Panniantong/Agent-Reach** repository. When channels appear as **"broken"** in the output, it indicates a specific failure mode where the backend command is discovered but cannot execute properly. Understanding how the doctor probe mechanism works enables you to diagnose and resolve these issues quickly.

## How the Doctor Command Detects Broken Channels

The doctor engine orchestrates health checks through three core components that classify backend status.

### The Doctor Engine

In [`agent_reach/doctor.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/doctor.py), the `check_all()` function (lines 12-35) iterates over every channel object, invokes each channel's `check()` method, catches any exceptions, and aggregates results into a status dictionary. This function handles the formatting you see in the terminal output.

### The Probe Utility

The actual execution logic lives in [`agent_reach/probe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/probe.py). The `probe_command()` function (lines 47-78) runs candidate commands using `cmd *args` and classifies outcomes into five categories: **missing**, **broken**, **timeout**, **error**, or **ok**. A status of `"broken"` specifically indicates that `shutil.which()` found the executable, but the subprocess failed to start—usually because the shebang points to a non-existent Python interpreter.

### Channel Base Class

Each channel inherits from the `Channel` class in [`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py) (lines 29-70). This base class provides the default `check()` method and the `ordered_backends()` helper that respects user configuration overrides. When you run the doctor, each channel's `check()` method calls `probe_command()` for every backend in its priority list.

## Common Root Causes of "broken" Status

When `probe_command()` returns `"broken"`, the underlying cause is almost always one of these scenarios:

1. **Stale Virtual Environment Shims** – The executable was installed via `pipx` or a virtual environment, and the system Python was upgraded or removed, leaving a broken shebang line.
2. **Permission Issues** – The file exists but lacks executable permissions.
3. **Corrupted Installation** – The CLI package is partially uninstalled or has missing dependencies.

Note that `"missing"` (command not found) and `"broken"` (command found but broken) are distinct states. The doctor marks channels as **"broken"** only for the latter.

## Step-by-Step Troubleshooting Guide

### Run the Doctor with Verbose Interpretation

Start by examining the full output to identify which specific backend is failing:

```bash
python -m agent_reach.cli doctor

```

Look for lines containing `[red][X][/red]` or the text **"命令存在但无法执行"** (command exists but cannot execute). The hint following this message is generated by `reinstall_hint()` in [`probe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/probe.py) (lines 38-44).

### Validate CLI Executables Manually

Verify that the command is actually executable:

```bash
which twitter-cli
ls -l $(which twitter-cli)

```

If the file points to a Python interpreter that no longer exists (common with `~/.local/pipx/venvs/` paths), you have confirmed the stale shim issue.

### Check the Active Backend

You can inspect which backend Agent Reach will use at runtime by checking the `active_backend` attribute:

```python
from agent_reach.channels import get_all_channels

for ch in get_all_channels():
    print(f"{ch.name}: {ch.active_backend}")

```

This helps confirm whether the doctor is failing on your preferred backend or a fallback.

### Override the Broken Backend

If one backend is broken but another works, bypass the broken one immediately via configuration. Create or edit `~/.agent-reach/config.yaml`:

```yaml
twitter_backend: OpenCLI
reddit_backend: OpenCLI

```

Or use environment variables:

```bash
export TWITTER_BACKEND=OpenCLI
export REDDIT_BACKEND=OpenCLI

```

Agent Reach reads these values through the `Config` class in [`agent_reach/config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/config.py).

### Fix Configuration File Permissions

The doctor warns if [`config.yaml`](https://github.com/Panniantong/Agent-Reach/blob/main/config.yaml) is world-readable (lines 15-23 of [`doctor.py`](https://github.com/Panniantong/Agent-Reach/blob/main/doctor.py)). While this doesn't cause "broken" channels, it is a security risk:

```bash
chmod 600 ~/.agent-reach/config.yaml

```

## Specific Fixes for Common Broken Channels

### Fixing Twitter CLI (twitter-cli)

When the doctor reports `twitter-cli 命令存在但无法执行`, reinstall using modern Python tooling:

```bash

# Using uv (recommended)

uv tool install --force twitter-cli

# Using pipx

pipx reinstall twitter-cli

```

### Fixing Reddit CLI (rdt-cli)

The `rdt-cli` tool often breaks after system Python upgrades. Uninstall the broken version and reinstall from the specific git commit:

```bash
pipx uninstall rdt-cli
pipx install --force 'git+https://github.com/public-clis/rdt-cli.git@5e4fb3720d5c174e976cd425ccc3b879d52cac66'

```

### Resolving Timeout Issues

If the doctor reports `timeout` rather than `broken`, the backend is installed but hanging (often due to network or authentication delays). Increase the timeout by editing the `timeout=` argument in the channel file (e.g., [`agent_reach/channels/twitter.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/twitter.py) lines 19-53), or run the backend manually to see detailed logs:

```bash
twitter status
opencli twitter search article -f yaml

```

### Handling Non-Zero Exit Codes (error status)

When `probe_command()` returns `"error"`, the backend runs but exits with a non-zero code (e.g., "not_authenticated"). This requires channel-specific authentication steps—exporting required environment variables, running a login command, or using the browser-based OpenCLI workflow.

## Code Examples

### Running the Doctor and Parsing Output

```bash
python -m agent_reach.cli doctor

```

Example broken output for Twitter:

```

  [red][X][/red]  Twitter/X — twitter-cli 命令存在但无法执行。
                重新安装即可修复：
                  uv tool install --force twitter-cli
                或：pipx reinstall twitter-cli

```

### Programmatic Channel Inspection

Re-run checks programmatically to test fixes without reloading the CLI:

```python
from agent_reach.channels import get_all_channels
from agent_reach.config import Config

cfg = Config.load()
for ch in get_all_channels():
    status, msg = ch.check(cfg)
    print(f"{ch.name}: {status}")
    if "broken" in msg:
        print(f"  Hint: {msg}")

```

### Reinstalling from Source

For the Reddit channel specifically, use the fixed git source:

```bash
pipx install --force 'git+https://github.com/public-clis/rdt-cli.git@5e4fb3720d5c174e976cd425ccc3b879d52cac66'

```

## Summary

- **"Broken" status** means the executable exists on `$PATH` but cannot run, usually due to stale Python shims.
- The doctor uses `probe_command()` in [`agent_reach/probe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/probe.py) to classify backend health, while `check_all()` in [`agent_reach/doctor.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/doctor.py) aggregates results.
- **Quick fix**: Reinstall broken CLIs using `uv tool install --force` or `pipx reinstall` to regenerate proper shebang lines.
- **Workaround**: Override broken backends via `~/.agent-reach/config.yaml` or environment variables like `TWITTER_BACKEND`.
- **Distinguish errors**: `"broken"` (execution failure), `"missing"` (not installed), `"timeout"` (hangs), and `"error"` (runs but exits non-zero) require different remediation steps.

## Frequently Asked Questions

### Why does the doctor say "broken" instead of "missing"?

The doctor distinguishes between these states using `shutil.which()` and subprocess execution. **"Missing"** means `which()` returned `None` (command not found). **"Broken"** means `which()` found the file, but executing it raised a `FileNotFoundError` or `OSError` (typically a broken symlink or stale shebang), placing it in the `status == "broken"` category in [`probe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/probe.py).

### How do I switch to a working backend without fixing the broken one?

Set the backend preference in your configuration file. Agent Reach checks `ordered_backends()` in [`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py), which respects user overrides before falling back to defaults. Add `twitter_backend: OpenCLI` to `~/.agent-reach/config.yaml` or export `TWITTER_BACKEND=OpenCLI` to skip the broken `twitter-cli` executable entirely.

### What is the difference between "timeout" and "broken"?

**"Broken"** occurs during process creation—the executable cannot start. **"Timeout"** means the process started but did not complete within the allotted time (default varies by channel). Timeouts indicate network issues, authentication prompts, or slow APIs, whereas broken indicates local installation corruption. Fix timeouts by checking network connectivity or increasing the `timeout=` parameter in the channel's `check()` method.

### Where does Agent Reach store its configuration and doctor hints?

Configuration lives in `~/.agent-reach/config.yaml`, loaded by [`agent_reach/config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/config.py). The doctor hints (like reinstall suggestions) are generated in [`agent_reach/probe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/probe.py) by the `reinstall_hint()` function (lines 38-44), which detects the package manager used originally (pipx, uv, etc.) and suggests the appropriate reinstall command.