# How to Add a New Backend to an Existing Agent Reach Channel

> Integrate a new backend into your Agent Reach channel. Learn to update the backends attribute, implement probe helpers, and extend the check method for seamless backend evaluation.

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

---

**Adding a new backend to an existing Agent Reach channel requires updating the `backends` attribute list, implementing a probe helper that returns status tuples, and extending the channel's `check()` method to evaluate the new backend during the selection loop.**

Agent Reach abstracts every platform (Twitter, Reddit, YouTube, etc.) as a channel class that inherits from `Channel` in [`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py). Each channel declares an ordered list of available backends, and the framework probes each one until it finds a working tool. By following the framework's probe-based architecture, you can integrate new CLI tools into existing channels without modifying the core routing logic.

## The Three-Step Process for Adding a New Backend

Agent Reach discovers and activates backends through a cascading health check. To add a new backend to an existing Agent Reach channel, you must modify the channel class definition, implement a verification helper, and wire that helper into the existing check loop.

### Step 1: Update the Channel's `backends` Attribute

Locate the channel class in its respective file (e.g., [`agent_reach/channels/twitter.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/twitter.py)). Identify the `backends` class attribute, which defines an ordered list of backend names. Insert your new backend identifier into this list according to your priority preference.

- **Prepend** the new backend to the list to give it highest priority
- **Append** it to serve as a fallback option

```python
class TwitterChannel(Channel):
    name = "twitter"
    description = "Twitter/X 推文"
    # New backend inserted before existing ones for higher priority

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

```

### Step 2: Implement a Probe Helper Method

Create a private method (conventionally named `_check_<backend_name>()`) that verifies the tool is installed, executable, and authenticated. Use `agent_reach.probe.probe_command` to normalize error handling for missing binaries, timeouts, and broken installations.

The probe must return:
- `None` if the backend is not installed or unavailable
- A tuple `(status, message)` where `status` is `"ok"`, `"warn"`, or `"error"`

```python
def _check_tweet_cli(self):
    """Probe tweet-cli – returns None if missing, otherwise (status, message)."""
    probe = probe_command(
        "tweet", ["status"], timeout=15, retries=1, package="tweet-cli"
    )
    if probe.status == "missing":
        return None                     # not installed

    if not probe.ok:
        return "error", "tweet-cli cannot execute – " + probe.hint
    # Assume tweet-cli prints "authenticated: true" on success

    if "authenticated: true" in probe.output:
        return "ok", "tweet-cli fully usable (search, read, timeline)."
    return "warn", "tweet-cli installed but not authenticated."

```

### Step 3: Extend the `check()` Method Logic

Modify the channel's `check()` method to call your new probe helper when iterating over `ordered_backends(config)`. Preserve the existing pattern: a `for` loop that gathers results, then selects the first backend reporting `"ok"` or `"warn"` status.

```python
def check(self, config=None):
    self.active_backend = None
    findings = []
    for backend in self.ordered_backends(config):
        if backend == "tweet-cli":
            result = self._check_tweet_cli()
        elif backend == "twitter-cli":
            result = self._check_twitter_cli()
        elif backend == "OpenCLI":
            result = self._check_opencli()
        elif backend == "bird CLI (legacy)":
            result = self._check_bird()
        else:
            continue
        if result is None:
            continue
        findings.append((backend, *result))

    # Keep the generic selection logic unchanged (first ok, then warn)

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

    return ("error", "\n".join(m for _, _, m in findings)) if findings else \
           ("warn", "No Twitter backend installed.")

```

## Complete Implementation Example: Integrating tweet-cli into TwitterChannel

Here is the complete implementation showing how to add a fictional `tweet-cli` backend to the existing `TwitterChannel` in [`agent_reach/channels/twitter.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/twitter.py):

```python
from agent_reach.channels.base import Channel
from agent_reach.probe import probe_command

class TwitterChannel(Channel):
    name = "twitter"
    description = "Twitter/X 推文"
    # New backend inserted before existing ones (higher priority)

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

    def _check_tweet_cli(self):
        """Probe tweet-cli – returns None if missing, otherwise (status, message)."""
        probe = probe_command(
            "tweet", ["status"], timeout=15, retries=1, package="tweet-cli"
        )
        if probe.status == "missing":
            return None                     # not installed

        if not probe.ok:
            return "error", "tweet-cli cannot execute – " + probe.hint
        # Assume tweet-cli prints "authenticated: true" on success

        if "authenticated: true" in probe.output:
            return "ok", "tweet-cli fully usable (search, read, timeline)."
        return "warn", "tweet-cli installed but not authenticated."

    def check(self, config=None):
        self.active_backend = None
        findings = []
        for backend in self.ordered_backends(config):
            if backend == "tweet-cli":
                result = self._check_tweet_cli()
            elif backend == "twitter-cli":
                result = self._check_twitter_cli()
            elif backend == "OpenCLI":
                result = self._check_opencli()
            elif backend == "bird CLI (legacy)":
                result = self._check_bird()
            else:
                continue
            if result is None:
                continue
            findings.append((backend, *result))

        # Keep the generic selection logic unchanged (first ok, then warn)

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

        return ("error", "\n".join(m for _, _, m in findings)) if findings else \
               ("warn", "No Twitter backend installed.")

```

## Backend Configuration and User Overrides

The base class method `ordered_backends()` in [`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py) automatically respects user preferences through configuration keys. Users can override the automatic selection by setting:

- A configuration key named `<channel>_backend` (e.g., `twitter_backend`)
- An environment variable named `<CHANNEL>_BACKEND` (e.g., `TWITTER_BACKEND`)

When present, these overrides move the specified backend to the front of the ordered list, ensuring it is probed first. This design allows fallback behavior without code duplication while giving users explicit control over tool selection.

## Summary

- **Agent Reach channels** inherit from `Channel` in [`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py) and declare available tools in an ordered `backends` list.
- **Probe helpers** use `probe_command` from [`agent_reach/probe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/probe.py) to normalize health checks, returning `None`, `("ok", msg)`, `("warn", msg)`, or `("error", msg)`.
- **The `check()` method** iterates through `ordered_backends(config)`, probes each backend, and activates the first one reporting `"ok"` or `"warn"` status.
- **User overrides** via configuration keys or environment variables allow runtime backend selection without modifying source code.

## Frequently Asked Questions

### What happens if the new backend is not installed?

If your probe helper returns `None` (typically when `probe.status == "missing"`), the framework skips that backend and continues to the next one in the `ordered_backends` list. The channel will only report an error if no backends return a valid status.

### How do I force a specific backend to be used?

Users can force a specific backend by setting a configuration key named `<channel>_backend` or an environment variable `<CHANNEL>_BACKEND`. According to the `ordered_backends()` implementation in [`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py), this moves the specified backend to the front of the priority list.

### What is the difference between "warn" and "error" probe statuses?

Return `"error"` when the backend binary exists but cannot execute properly (e.g., crashes or broken dependencies). Return `"warn"` when the tool is installed and runnable but lacks required authentication or optional features. The framework prefers `"ok"` backends, falls back to `"warn"` if no `"ok"` exists, and only shows `"error"` if no working backends are found.

### Can I create a channel that supports only the new backend?

Yes. Create a new class inheriting from `Channel`, set `backends = ["mycli"]`, and implement a single probe helper. The `check()` method can be simplified since it only needs to evaluate one backend, as shown in the `MyPlatformChannel` pattern in the Agent Reach codebase.