How to Add a Custom Backend to an Existing Channel in Agent-Reach

To add a custom backend to an existing channel in Agent-Reach, append the backend identifier to the channel's backends list, implement a private _check_<backend>() probe method that returns a status tuple, and wire it into the channel's check() loop so the channel can select it at runtime.

Agent-Reach treats every platform (YouTube, Twitter, Reddit) as a channel that delegates read, search, and check operations to external backends. When you need to integrate a new command-line tool or API client into an existing channel, you extend the channel's backend probing logic. This guide walks through the exact steps to add a custom backend to an existing channel using the source code from the Panniantong/Agent-Reach repository.

Understanding the Channel-Backend Architecture

The architecture relies on ordered backend lists and standardized health probes.

The Backends List

Every concrete channel declares an ordered list of backend identifiers in the backends class attribute. In agent_reach/channels/base.py (lines 34-35), the base Channel class defines this structure, and concrete implementations like TwitterChannel populate it with strings such as "twitter-cli", "OpenCLI", or "bird CLI (legacy)".

Backend Selection Logic

The ordered_backends(config) method in agent_reach/channels/base.py (lines 45-59) returns this list, moving any user-specified override (via <channel>_backend config or <CHANNEL>_BACKEND environment variable) to the front. The channel's check() method then loops through these candidates, calling private _check_<backend>() helpers to probe each one. The first backend returning "ok" or "warn" is stored in self.active_backend (lines 61-70).

Step-by-Step Implementation Guide

Follow these seven steps to integrate a new backend into an existing channel:

  1. Choose the target channel (e.g., twitter, youtube, reddit) located in agent_reach/channels/<channel>.py.
  2. Define a backend identifier—a short lowercase string like "mycli" that will appear in the backends list.
  3. Insert the identifier into the channel's backends list, positioning it according to your preferred priority order.
  4. Implement the probe method _check_<backend>() inside the channel class. Use probe_command from agent_reach/probe.py for simple binaries, or create a shared utility under agent_reach/backends/ for complex multi-step checks (as demonstrated by agent_reach/backends/opencli.py).
  5. Wire the probe into the check() loop by adding an elif backend == "<identifier>": branch that assigns result = self._check_<backend>().
  6. Return a standardized tuple (status, message) where status is "ok", "warn", "error", or return None to skip the candidate. The message should describe the backend's condition.
  7. Run the test suite with pytest tests/ -v to verify the new code does not break existing channel probes.

Practical Example: Extending the Twitter Channel

The following example adds a fictional "mycli" backend to the Twitter channel in agent_reach/channels/twitter.py. This demonstrates the complete pattern: updating the backends list, adding the probe helper, and wiring it into the selection loop.


# File: agent_reach/channels/twitter.py

class TwitterChannel(Channel):
    name = "twitter"
    description = "Twitter/X 推文"
    # Insert the new backend where you want it tried (after OpenCLI, before bird CLI)

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

    def check(self, config=None):
        self.active_backend = None
        findings = []

        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 == "mycli":
                result = self._check_mycli()          # ← new branch

            elif backend == "bird CLI (legacy)":
                result = self._check_bird()
            else:
                continue

            if result is None:
                continue
            findings.append((backend, *result))

        # ... existing selection logic ...

    # ----------------------------------------------------------------------

    # New probe helper for the custom backend

    # ----------------------------------------------------------------------

    def _check_mycli(self):
        """Probe the custom `mycli` tool."""
        from agent_reach.probe import probe_command

        probe = probe_command(
            "mycli", ["status"], timeout=10, package="mycli"
        )
        if probe.status == "missing":
            # Not installed – exclude from candidate list

            return None
        if probe.status == "broken":
            return "error", "mycli 命令存在但无法执行。" + probe.hint
        if probe.status == "timeout":
            return "error", "mycli 健康检查超时。" + probe.hint

        # Assume a healthy mycli prints "ready: true"

        if "ready: true" in probe.output.lower():
            return "ok", "mycli 可用(读取、搜索推文)"
        return "warn", "mycli 已安装但未准备好,请检查配置。"

The _check_mycli() method imports probe_command from agent_reach/probe.py and follows the same contract as _check_opencli() (lines 94-108 in twitter.py), returning status tuples that the base class logic consumes.

Key Source Files and Utilities

When you add a custom backend to an existing channel, you will work with these specific files:

  • agent_reach/channels/base.py (lines 34-70): Defines the abstract Channel class, the backends attribute, ordered_backends(), and the generic check() framework that evaluates probe results.
  • agent_reach/channels/twitter.py (lines 19-48): Concrete reference showing how _check_twitter_cli(), _check_opencli(), and _check_bird() integrate into the backend selection loop.
  • agent_reach/backends/opencli.py (lines 1-137): Illustrates complex backend validation with a dedicated module, useful when your custom backend requires sophisticated health checks beyond a simple command probe.
  • agent_reach/probe.py: Provides probe_command(), which executes external binaries safely and classifies results as missing, broken, ok, or timeout, handling exceptions and timeouts uniformly.

Summary

To successfully add a custom backend to an existing channel in Agent-Reach:

  • Append the backend identifier string to the channel's backends class attribute in the concrete channel file.
  • Implement a _check_<backend>() method that uses probe_command or custom logic to verify the external tool is installed and functional.
  • Return standard status tuples ("ok", "warn", "error", or None) so the channel's check() method can evaluate candidates against each other.
  • Wire the new probe into the check() method's backend iteration with an elif branch.
  • Users can force selection of your backend via the <channel>_backend configuration key or <CHANNEL>_BACKEND environment variable, which ordered_backends() automatically prioritizes without requiring code changes.

Frequently Asked Questions

What status values should my custom backend probe return?

Your _check_<backend>() method should return a two-element tuple (status, message). The status must be a string: "ok" indicates the backend is fully functional, "warn" indicates it is usable but degraded, "error" indicates a broken installation, and returning None excludes the backend from consideration. This contract matches the implementation in agent_reach/channels/base.py (lines 61-70).

Can I place my backend logic in a separate file instead of the channel class?

Yes. For complex backends requiring multiple helper functions or shared across channels, create a module under agent_reach/backends/ (similar to agent_reach/backends/opencli.py for the OpenCLI backend). Import your health check functions into the channel file and call them from the _check_<backend>() method to maintain clean separation of concerns.

How does Agent-Reach handle user-specified backend preferences?

The ordered_backends(config) method in agent_reach/channels/base.py (lines 45-59) checks for a configuration key matching <channel>_backend or an uppercase environment variable <CHANNEL>_BACKEND. When detected, it moves that identifier to index zero in the returned list, ensuring your custom backend is evaluated first regardless of its position in the default backends declaration.

Do I need to modify the base Channel class to add a custom backend?

No. You only need to modify the concrete channel file (e.g., agent_reach/channels/twitter.py). The base class in agent_reach/channels/base.py provides the generic probing framework and selection logic, while individual channels define their specific backends list and _check_* implementations. This design keeps custom backend logic scoped to the relevant platform.

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 →