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

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), 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:

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

Multi-backend channels:

class RedditChannel(Channel):
    backends = ["OpenCLI", "rdt-cli"]
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/agent_reach/channels/youtube.py), [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/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.
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)

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

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:


# ~/.agent-reach/config.yaml

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

Environment variable example:

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

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 →