# What Determines the Backend Preference Order in Agent Reach Channel Configuration?

> Understand how Agent Reach prioritizes backend channels. Discover the three-stage process: static priority, user configuration, and runtime health checks for optimal backend selection.

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

---

**Agent Reach determines the backend preference order through a three-stage resolution process: a static priority list defined in each channel's `backends` attribute, dynamic reordering via user configuration that moves preferred backends to the front, and runtime health checks that select the first available "ok" or "warn" status.**

Agent Reach is a multi-channel automation framework that abstracts platforms like YouTube, Twitter, and GitHub into configurable channels. Understanding what determines the backend preference order in Agent Reach channel configuration is essential for troubleshooting connectivity issues and optimizing CLI tool selection. The framework implements a deterministic resolution strategy that balances developer defaults with user overrides and runtime availability.

## Static Backend Declaration in Channel Classes

Each channel class defines its default priority through a class-level **`backends`** attribute. This ordered list represents the developers' preference, with the most desirable backend listed first.

For example, the Twitter channel in [`agent_reach/channels/twitter.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/twitter.py) (lines 11-13) declares:

```python
class TwitterChannel(Channel):
    backends = [
        "twitter-cli",      # Native CLI (preferred)

        "OpenCLI",          # Generic OpenCLI fallback

        "bird CLI"          # Legacy bird CLI

    ]

```

This static list serves as the foundation for all subsequent ordering decisions.

## Dynamic Reordering via User Configuration

Before probing candidates, the base `Channel` class executes **`ordered_backends()`** to apply user preferences. This method, implemented in [`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py) (lines 45-59), performs the following steps:

1. Copies the static `backends` list
2. Checks for a user override via the `<channel>_backend` configuration key or the `<CHANNEL>_BACKEND` environment variable
3. If the override matches a known backend (or prefix), moves that backend to the **front** of the candidate list
4. Preserves the relative order of all remaining backends

Unknown or malformed overrides are explicitly ignored, guaranteeing that stale configuration entries cannot hide functional backends. The mapping of feature keys to configuration entries is defined in [`agent_reach/config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/config.py) (lines 21-28) within **`FEATURE_REQUIREMENTS`**.

## Runtime Health Verification

After reordering, **`Channel.check()`** iterates through the candidate list to select the active backend. According to the implementation demonstrated in [`agent_reach/channels/twitter.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/twitter.py) (lines 19-48), the method uses a two-pass approach:

- **First pass**: Selects the first backend reporting an `"ok"` status
- **Second pass**: If no "ok" found, selects the first `"warn"` status
- **Final fallback**: Marks the channel unavailable if neither status is detected

The first backend that passes its health check becomes the channel's `active_backend` for that session.

## Configuration Sources and Override Mechanics

User preferences are loaded from `~/.agent-reach/config.yaml` or environment variables via the **`Config`** class. The override mechanism follows these rules:

- **Valid match**: The specified backend moves to position 0 in the probe order
- **Invalid/unknown**: The original static order is preserved without modification
- **Environment variables**: Automatically mapped to config keys (e.g., `TWITTER_BACKEND` becomes `twitter_backend`)

This design ensures that user intent takes precedence while maintaining system reliability.

## Practical Implementation Examples

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

# 1. Default behavior (no override)

cfg = Config()
tw = TwitterChannel()
tw.check(cfg)                 # probes: twitter-cli → OpenCLI → bird CLI

print(tw.active_backend)     # → "twitter-cli" (if installed)

# 2. User override to prioritize legacy backend

cfg.set("twitter_backend", "bird CLI (legacy)")
tw = TwitterChannel()
tw.check(cfg)
print(tw.active_backend)     # → "bird CLI (legacy)" (moved to front)

# 3. Invalid override ignored (falls back to static order)

cfg.set("twitter_backend", "nonexistent-cli")
tw = TwitterChannel()
tw.check(cfg)
print(tw.active_backend)     # → first working backend from static list

```

## Summary

- **Static ordering**: The `backends` class attribute in each channel defines the default priority, as seen in [`agent_reach/channels/twitter.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/twitter.py) (lines 11-13)
- **User override**: Configuration keys like `twitter_backend` or environment variables move matching backends to the front via `ordered_backends()` in [`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py) (lines 45-59)
- **Health validation**: `check()` selects the first backend with `"ok"` status, falling back to `"warn"`, as implemented in [`agent_reach/channels/twitter.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/twitter.py) (lines 19-48)
- **Safety mechanism**: Unknown overrides are ignored to prevent configuration errors from masking functional backends

## Frequently Asked Questions

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

Set the `<channel>_backend` configuration key in `~/.agent-reach/config.yaml` or export the `<CHANNEL>_BACKEND` environment variable. If the value matches a known backend in the channel's `backends` list (or matches a prefix), Agent Reach moves that backend to the front of the preference list before running health checks.

### What happens if I specify a backend that isn't installed?

The override is ignored and Agent Reach falls back to the static order defined in the channel's `backends` attribute. The framework validates overrides against known backends in [`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py) to ensure that configuration mistakes cannot hide functional alternatives.

### Where does Agent Reach load user configuration from?

The `Config` class reads from `~/.agent-reach/config.yaml` and environment variables, mapping them according to `FEATURE_REQUIREMENTS` in [`agent_reach/config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/config.py) (lines 21-28). These values are passed to `Channel.ordered_backends()` to determine the final probe sequence.

### Can the backend preference order change at runtime?

No, the order is determined once during channel initialization when `check()` calls `ordered_backends()`. However, the active backend selection depends on real-time health probe results, meaning the first backend in the ordered list that returns `"ok"` becomes the active choice for that session.