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:
- Choose the target channel (e.g.,
twitter,youtube,reddit) located inagent_reach/channels/<channel>.py. - Define a backend identifier—a short lowercase string like
"mycli"that will appear in thebackendslist. - Insert the identifier into the channel's
backendslist, positioning it according to your preferred priority order. - Implement the probe method
_check_<backend>()inside the channel class. Useprobe_commandfromagent_reach/probe.pyfor simple binaries, or create a shared utility underagent_reach/backends/for complex multi-step checks (as demonstrated byagent_reach/backends/opencli.py). - Wire the probe into the
check()loop by adding anelif backend == "<identifier>":branch that assignsresult = self._check_<backend>(). - Return a standardized tuple
(status, message)where status is"ok","warn","error", or returnNoneto skip the candidate. The message should describe the backend's condition. - Run the test suite with
pytest tests/ -vto 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 abstractChannelclass, thebackendsattribute,ordered_backends(), and the genericcheck()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: Providesprobe_command(), which executes external binaries safely and classifies results asmissing,broken,ok, ortimeout, 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
backendsclass attribute in the concrete channel file. - Implement a
_check_<backend>()method that usesprobe_commandor custom logic to verify the external tool is installed and functional. - Return standard status tuples (
"ok","warn","error", orNone) so the channel'scheck()method can evaluate candidates against each other. - Wire the new probe into the
check()method's backend iteration with anelifbranch. - Users can force selection of your backend via the
<channel>_backendconfiguration key or<CHANNEL>_BACKENDenvironment variable, whichordered_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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →