# How Agent Reach Implements Backend Routing with Ordered Fallback Candidates

> Discover how Agent Reach implements backend routing using ordered fallback candidates. Learn to select healthy backends and preserve fallbacks for seamless operation.

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

---

**Agent Reach implements backend routing by scanning an ordered list of candidate backends, applying a user-configurable override, probing each candidate in sequence, and selecting the first healthy backend while preserving fallback options if higher-priority ones fail.**

Agent Reach is an open-source framework for automating browser-based interactions with web platforms. It treats every platform—Twitter, YouTube, Reddit, and others—as a **channel** that can be served by multiple backend tools. The routing logic is implemented in the abstract `Channel` base class and ensures that the first healthy backend from an ordered list is automatically selected, with automatic fallback to lower-priority candidates if primary ones are unavailable.

## Understanding the Ordered Backend List

Every concrete channel defines a `backends` class attribute that lists all supported backends in order of preference. This list acts as the source of truth for routing decisions.

In [`agent_reach/channels/twitter.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/twitter.py), the Twitter channel declares three possible backends:

```python

# agent_reach/channels/twitter.py

backends = ["twitter-cli", "OpenCLI", "bird CLI (legacy)"]

```

This declaration (line 12) establishes that `twitter-cli` is the preferred backend, followed by OpenCLI, with the legacy Bird CLI as the final fallback.

## User Overrides and the Ordered Backends Method

Users can force a specific backend by setting a configuration key in the format `<channel>_backend` or via an equivalent environment variable. The `Channel.ordered_backends()` method in [`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py) handles this logic while preserving the integrity of the fallback chain.

When an override is present, the method moves the matching backend to the front of the list without removing any other candidates. This ensures that an invalid or stale override does not hide working alternatives.

```python

# agent_reach/channels/base.py (lines 45-59)

def ordered_backends(self, config=None) -> List[str]:
    candidates = list(self.backends)
    override = config.get(f"{self.name}_backend") if config else None
    if override:
        for i, b in enumerate(candidates):
            if b == override or b.startswith(override):
                candidates.insert(0, candidates.pop(i))
                break
    return candidates

```

This implementation guarantees that:
- The returned list is always a permutation of the original `backends` list
- Unknown overrides do not cause runtime errors
- The fallback order is maintained for all non-overridden backends

## Health Probing and Selection Logic

Each channel's `check()` method iterates over the ordered backend list and executes lightweight health probes. The probing occurs in [`agent_reach/channels/twitter.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/twitter.py) (lines 29-48) and uses `agent_reach.probe.probe_command` to verify installation and usability.

The Twitter channel demonstrates the complete selection workflow:

```python

# agent_reach/channels/twitter.py (excerpt from lines 29-48)

for backend in self.ordered_backends(config):
    if backend == "twitter-cli":
        result = self._check_twitter_cli()
    elif backend == "OpenCLI":
        result = self._check_opencli()
    elif backend == "bird CLI (legacy)":
        result = self._check_bird()
    # ...

    if result is None:
        continue          # not installed → skip this candidate

    findings.append((backend, *result))

# Selection phase (lines 43-48)

for wanted in ("ok", "warn"):
    for backend, status, message in findings:
        if status == wanted:
            self.active_backend = backend
            return status, message

```

The selection algorithm prioritizes backends with status `"ok"` over those with status `"warn"`. If no backend reports `"ok"`, the first `"warn"`-status backend is selected. This two-tier system allows partial functionality (such as unauthenticated access) to serve as a fallback when full functionality is unavailable.

## Exposing the Selected Backend

After `check()` completes, the selected backend is stored in `self.active_backend`, defined in [`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py) (lines 37-38):

```python

# agent_reach/channels/base.py

#: Backend currently serving this channel; set by check(), None = unavailable.
active_backend: Optional[str] = None

```

Consumers throughout the codebase—including the CLI entry point and documentation generators—read this attribute to determine which binary to invoke. If no backend passes the health probe, `active_backend` remains `None`, signaling that the channel is unavailable.

## Practical Examples

### Listing Ordered Candidates with User Override

```python
from agent_reach.channels.twitter import TwitterChannel
from agent_reach.config import Config

cfg = Config()
cfg.update({"twitter_backend": "OpenCLI"})   # user forces OpenCLI preference

ch = TwitterChannel()
print(ch.ordered_backends(cfg))

# Output: ['OpenCLI', 'twitter-cli', 'bird CLI (legacy)']

```

### Running Health Checks and Inspecting Results

```python
status, msg = ch.check(cfg)   # probes in the overridden order

print(f"Chosen backend: {ch.active_backend}")   # e.g., 'OpenCLI'

print(status, msg)            # e.g., 'ok', 'OpenCLI 可用（复用浏览器登录态）...'

```

### Conditional Execution Based on Active Backend

```python
if ch.active_backend == "OpenCLI":
    # OpenCLI requires no extra wrapper

    run(["opencli", "twitter", "search", "python"])
elif ch.active_backend == "twitter-cli":
    # Standard twitter-cli invocation

    run(["twitter", "search", "python"])

```

## Key Implementation Files

| Component | File Path |
|-----------|-----------|
| Base channel logic and `ordered_backends()` | [`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py) |
| Concrete Twitter channel with probing | [`agent_reach/channels/twitter.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/twitter.py) |
| OpenCLI-specific backend utilities | [`agent_reach/backends/opencli.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/backends/opencli.py) |
| Contract tests for backend ordering | [`tests/test_channel_contracts.py`](https://github.com/Panniantong/Agent-Reach/blob/main/tests/test_channel_contracts.py) |
| CLI entry point displaying active backends | [`agent_reach/cli.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/cli.py) |

## Summary

- **Ordered Declaration**: Channels define `backends` as a priority-ordered list of candidate tools
- **User Override**: The `ordered_backends()` method moves user-specified backends to the front while preserving the complete fallback chain
- **Sequential Probing**: The `check()` method probes each candidate in order, collecting installation and health status
- **Tiered Selection**: Primary selection prefers `"ok"` status; `"warn"` status serves as secondary fallback
- **State Exposure**: The `active_backend` attribute exposes the winning backend for downstream consumption
- **Safety Guarantees**: Unit tests enforce that overrides produce valid permutations and never discard candidates

## Frequently Asked Questions

### How does Agent Reach handle a user-configured backend that is not installed?

Agent Reach moves the user-specified backend to the front of the candidate list via `ordered_backends()`, but the subsequent `check()` method probes every candidate sequentially. If the configured backend is not installed, the probe returns `None` and the iterator continues to the next candidate in the ordered list. This ensures that a missing or broken override does not prevent the channel from finding a working alternative.

### What happens if multiple backends are healthy?

The routing system selects the first healthy backend in the order returned by `ordered_backends()`. Since the list preserves the channel's declared preferences (with user overrides moved to the front), the highest-priority available backend is always chosen. The system does not load-balance between healthy backends; it deterministically selects the first match.

### Can a backend with warnings be selected if no "ok" backends exist?

Yes. The selection logic in `check()` iterates through statuses `("ok", "warn")`. If no backend reports `"ok"`, the method falls back to the first backend reporting `"warn"`. This allows partially functional backends—such as those requiring manual authentication or with limited API access—to serve the channel when fully functional options are unavailable.

### Where is the active backend stored after selection?

The `check()` method stores the selected backend name in the `active_backend` attribute of the channel instance, defined in [`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py) (lines 37-38). This attribute is typed as `Optional[str]` and remains `None` if no backend passes the health probe. Consumers including the CLI and automation scripts read this attribute to determine which binary to execute.