# How Agent Reach Multi-Backend Routing Works: Complete Guide to Override the Default Backend

> Understand Agent Reach multi-backend routing. Learn how ordered backends prioritize overrides and discover the default backend to activate the first working connection.

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

---

**Agent Reach uses an ordered `backends` list per channel with `ordered_backends()` to prioritize user overrides before probing each candidate, making the first working backend active.**

Agent Reach treats every platform—YouTube, Twitter, Reddit—as a **channel** that binds to one or more **backends** (e.g., `yt-dlp`, `OpenCLI`, `rdt-cli`). The routing intelligence lives in the abstract base class `Channel` at [[`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py)](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py), and every concrete channel inherits this multi-backend selection logic.

## How Channels Declare Available Backends

Each channel defines an ordered list `backends` where the first element is the **preferred backend** and subsequent items serve as fallbacks.

**Single-backend channel:**

```python
class YouTubeChannel(Channel):
    backends = ["yt-dlp"]

```

**Multi-backend channels:**

```python
class RedditChannel(Channel):
    backends = ["OpenCLI", "rdt-cli"]

```

```python
class TwitterChannel(Channel):
    backends = ["twitter-cli", "OpenCLI", "bird CLI (legacy)"]

```

These declarations appear in their respective channel files: [[`youtube.py`](https://github.com/Panniantong/Agent-Reach/blob/main/youtube.py)](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/youtube.py), [[`reddit.py`](https://github.com/Panniantong/Agent-Reach/blob/main/reddit.py)](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/reddit.py), and [[`twitter.py`](https://github.com/Panniantong/Agent-Reach/blob/main/twitter.py)](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/twitter.py).

## The `ordered_backends()` Method: How Prioritization Works

The core routing method `Channel.ordered_backends(config=None)` builds the probe sequence by respecting user overrides while preserving fallback safety.

### Algorithm steps:

1. Copy the channel's `self.backends` list.
2. Check for override in `config` (key: `<channel>_backend`) or environment variable (`<CHANNEL>_BACKEND`).
3. If the override matches or prefixes an existing backend, move it to index 0.
4. Ignore unknown overrides to prevent breaking fallback chains.

```python
def ordered_backends(self, config=None) -> List[str]:
    """Candidate backends in probe order, honoring the user override."""
    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

```

*Source:* [[`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py)](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py)

## Backend Probing and Selection in `check()`

Concrete channels implement `check(self, config=None)` following a common probe pattern:

1. Reset `self.active_backend = None`.
2. Iterate through `self.ordered_backends(config)`.
3. Call channel-specific validation helpers (e.g., `_check_opencli`, `_check_twitter_cli`).
4. Collect `(backend, status, message)` tuples in `findings`.
5. Return first `"ok"` result; if none, return first `"warn"` result.
6. Aggregate `"error"`/`"broken"` results only if no viable backend exists.

```python
for backend in self.ordered_backends(config):
    if backend == "OpenCLI":
        result = self._check_opencli()
    elif backend == "twitter-cli":
        result = self._check_twitter_cli(config)
    ...
    if result is None:
        continue                     # backend not installed -> skip

    findings.append((backend, *result))

```

### Channel-specific behaviors:

- **YouTube**: Directly sets `self.active_backend = "yt-dlp"` after successful probe.
- **Reddit**: Sets `self.active_backend` only when status equals `"ok"` (see probe loop in [[`reddit.py`](https://github.com/Panniantong/Agent-Reach/blob/main/reddit.py)](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/reddit.py)).
- **Twitter**: Same two-stage pattern with `twitter-cli`, `OpenCLI`, and legacy `bird CLI` priority (see [[`twitter.py`](https://github.com/Panniantong/Agent-Reach/blob/main/twitter.py)](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/twitter.py)).

## How to Override the Default Backend

Agent Reach provides two override mechanisms that feed into `ordered_backends()`:

| Override source | Syntax | Example |
|---------------|--------|---------|
| **Configuration file** (`~/.agent-reach/config.yaml`) | `<channel>_backend` | `twitter_backend: OpenCLI` |
| **Environment variable** | Uppercase `<CHANNEL>_BACKEND` | `export REDDIT_BACKEND=rdt-cli` |

### Configuration file example:

```yaml

# ~/.agent-reach/config.yaml

youtube_backend: yt-dlp
twitter_backend: OpenCLI
reddit_backend: rdt-cli

```

### Environment variable example:

```bash
export TWITTER_BACKEND=twitter-cli
export REDDIT_BACKEND=OpenCLI

```

**Critical behavior:** Overrides are **prefix-safe**. The name `twitter` would match `twitter-cli` and move it to the front. However, a non-matching override like `twitter_backend: nonexistent` is silently ignored—preserving the original `backends` order rather than breaking the channel with a dead backend search.

## Tracking the Active Backend

After `check()` completes successfully, the winning backend name is stored in `Channel.active_backend`. This attribute:

- Is reset to `None` at the start of every `check()` call to prevent stale state.
- Appears in `agent_reach.doctor.check_all` reports for operational visibility.
- Can be inspected programmatically to verify which backend actually served the request.

```python
channel = TwitterChannel()
channel.check(config)  # probes in order, selects first viable backend

print(channel.active_backend)  # e.g., "OpenCLI"

```

## Summary

- **Backend declaration**: Channels define ordered `backends` lists; position 0 is the default preference.
- **Override injection**: `ordered_backends()` checks `<channel>_backend` config key or `<CHANNEL>_BACKEND` env var to reprioritize.
- **Safe fallback**: Unknown overrides are ignored; partial matches work via prefix check.
- **Probe execution**: `check()` iterates candidates, validates each, and selects `"ok"` > `"warn"` > fail.
- **State tracking**: `active_backend` reflects the selected backend and resets per health check.

## Frequently Asked Questions

### How do I force Agent Reach to use a specific backend for Twitter?

Set either `twitter_backend: OpenCLI` in `~/.agent-reach/config.yaml` or run `export TWITTER_BACKEND=OpenCLI` before execution. The `ordered_backends()` method will move `OpenCLI` to the front of Twitter's probe list.

### What happens if my backend override is misspelled?

Agent Reach ignores unrecognized overrides entirely. The original `backends` list order is preserved, allowing normal fallback behavior rather than failing with a missing backend error.

### Can I use partial backend names in overrides?

Yes. The `ordered_backends()` method matches prefixes, so `twitter_backend: twitter` successfully prioritizes `twitter-cli` while still allowing full name specificity when multiple backends share a prefix.

### Why does `active_backend` reset during each health check?

The `check()` method explicitly sets `self.active_backend = None` at entry to prevent stale backend state from previous invocations. This ensures accurate reporting of which backend actually passed the current probe cycle.