How to Troubleshoot Agent Reach Channels Showing as 'broken' in Doctor Output
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, 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. 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 (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:
- Stale Virtual Environment Shims – The executable was installed via
pipxor a virtual environment, and the system Python was upgraded or removed, leaving a broken shebang line. - Permission Issues – The file exists but lacks executable permissions.
- 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:
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 (lines 38-44).
Validate CLI Executables Manually
Verify that the command is actually executable:
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:
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:
twitter_backend: OpenCLI
reddit_backend: OpenCLI
Or use environment variables:
export TWITTER_BACKEND=OpenCLI
export REDDIT_BACKEND=OpenCLI
Agent Reach reads these values through the Config class in agent_reach/config.py.
Fix Configuration File Permissions
The doctor warns if config.yaml is world-readable (lines 15-23 of doctor.py). While this doesn't cause "broken" channels, it is a security risk:
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:
# 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:
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 lines 19-53), or run the backend manually to see detailed logs:
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
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:
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:
pipx install --force 'git+https://github.com/public-clis/rdt-cli.git@5e4fb3720d5c174e976cd425ccc3b879d52cac66'
Summary
- "Broken" status means the executable exists on
$PATHbut cannot run, usually due to stale Python shims. - The doctor uses
probe_command()inagent_reach/probe.pyto classify backend health, whilecheck_all()inagent_reach/doctor.pyaggregates results. - Quick fix: Reinstall broken CLIs using
uv tool install --forceorpipx reinstallto regenerate proper shebang lines. - Workaround: Override broken backends via
~/.agent-reach/config.yamlor environment variables likeTWITTER_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.
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, 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. The doctor hints (like reinstall suggestions) are generated in 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.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →