How to Add a Custom Channel or Backend to Agent Reach: A Complete Developer Guide

To add a custom channel or backend to Agent Reach, subclass the abstract Channel base class in agent_reach/channels/, implement the can_handle() and check() methods, register the instance in ALL_CHANNELS, and optionally extend the backends list to support additional data retrieval tools.

Agent Reach discovers internet platforms through pluggable channel classes that live in the Panniantong/Agent-Reach repository. Whether you need to integrate a new social media site or extend an existing channel with alternative CLI tools, the framework provides a consistent architecture based on abstract base classes and a central registry. This guide walks through the exact file locations, method signatures, and code patterns required to integrate custom platforms.

Understanding the Channel Architecture

Agent Reach identifies platforms using three core components: the abstract base class, the channel registry, and contract tests.

The Channel Base Class

The file agent_reach/channels/base.py defines the abstract Channel class that enforces a consistent interface across all platforms. Every subclass must declare the class attributes name, description, backends, and tier, plus implement can_handle(url: str) -> bool to identify platform-specific URLs and check(config=None) -> Tuple[str, str] to probe available backends and set self.active_backend.

The Channel Registry

The agent_reach/channels/__init__.py file maintains ALL_CHANNELS, a list containing every channel instance. This registry powers the agent_reach.doctor diagnostic tool and public API functions like get_channel() and get_all_channels(). The registry automatically imports every channel file in the directory, making manual registration mandatory for new additions.

Contract Tests

The file tests/test_channel_contracts.py enforces mandatory attributes and methods. Any new channel must pass these assertions; otherwise, the agent-reach doctor command will raise an assertion error indicating which required property is missing.

Adding a New Custom Channel

Creating a custom channel follows four concrete steps: file creation, class implementation, registry registration, and contract validation.

Step 1: Create the Channel File

Create a new Python file at agent_reach/channels/<your_platform>.py. Import the base class and define your channel subclass with the required attributes.

Step 2: Implement Required Methods

Implement can_handle() to recognize your platform's URLs by inspecting the netloc or path. Implement check() to validate backend availability, set self.active_backend to the working backend name (or None for builtin channels), and return a tuple of (status, message).

For builtin channels that require no external tools, set backends = [] and return "ok" from check():


# agent_reach/channels/examplesite.py

from urllib.parse import urlparse
from .base import Channel

class ExampleSiteChannel(Channel):
    name = "examplesite"
    description = "ExampleSite – demo read-only platform"
    backends = []  # Builtin channel requires no external tools

    tier = 0       # Zero-config platform

    def can_handle(self, url: str) -> bool:
        return urlparse(url).netloc.lower().endswith("example.com")

    def check(self, config=None):
        self.active_backend = None
        return "ok", "built-in – no external tools required"

Step 3: Register in the Channel Registry

Import the new class in agent_reach/channels/__init__.py and append an instance to ALL_CHANNELS:


# agent_reach/channels/__init__.py

from .examplesite import ExampleSiteChannel

ALL_CHANNELS: List[Channel] = [
    # ... existing channels ...

    ExampleSiteChannel(),
]

Step 4: Validate with Contract Tests

Run the test suite to ensure your channel satisfies the contract:

pytest tests/test_channel_contracts.py -q

All assertions should pass, confirming that name, description, backends, tier, and active_backend are properly defined.

Adding a New Backend to an Existing Channel

Many platforms support multiple data retrieval methods. Extend existing channels by modifying the backends list and updating the probing logic in check().

Extending the Backends List

Append the new backend name to the channel's backends attribute, preserving order of preference (preferred first). The ordered_backends() method in the base class automatically respects user overrides from config files using the pattern <channel_name>_backend: <backend_name>.

Implementing Backend Probing

Update the check() method to probe the new backend before falling back to existing ones. Use probe_command() from agent_reach.probe to test CLI availability, and set self.active_backend to the first successful candidate.

Here is an example extending the YouTube channel with a hypothetical myyt CLI:


# agent_reach/channels/youtube.py

from agent_reach.probe import probe_command
from .base import Channel

class YouTubeChannel(Channel):
    name = "youtube"
    description = "YouTube videos and subtitles"
    backends = ["myyt", "yt-dlp"]  # New preferred backend first

    tier = 0

    def can_handle(self, url: str) -> bool:
        # Existing URL matching logic...

        return "youtube.com" in url or "youtu.be" in url

    def check(self, config=None):
        # Probe new backend first

        probe = probe_command("myyt", ["--version"], timeout=10, package="myyt")
        if probe.status == "ok":
            self.active_backend = "myyt"
            return "ok", "myyt CLI available"
        
        # Fallback to yt-dlp

        probe = probe_command("yt-dlp", ["--version"], timeout=10, package="yt-dlp")
        if probe.status != "ok":
            self.active_backend = None
            return "off", "yt-dlp not installed"
        
        self.active_backend = "yt-dlp"
        return "ok", "yt-dlp available"

Full Implementation Example: Multi-Backend Platform

For a complete real-world scenario, consider adding "FooTalk", a platform supporting both a native CLI and a generic browser-based backend:


# agent_reach/channels/footalk.py

from agent_reach.probe import probe_command
from agent_reach.backends import opencli_status, opencli_summary
from .base import Channel

class FooTalkChannel(Channel):
    name = "footalk"
    description = "FooTalk – micro-blogging platform"
    backends = ["footalk-cli", "opencli"]  # Native CLI preferred, fallback to OpenCLI

    tier = 1  # Requires login/key handled by CLI

    def can_handle(self, url: str) -> bool:
        from urllib.parse import urlparse
        return urlparse(url).netloc.lower().endswith("footalk.com")

    def check(self, config=None):
        # Try native CLI first

        probe = probe_command("footalk-cli", ["--version"], timeout=10, package="footalk-cli")
        if probe.status == "ok":
            self.active_backend = "footalk-cli"
            return "ok", "footalk-cli available"
        
        # Fallback to OpenCLI

        st = opencli_status()
        if st.ready:
            self.active_backend = "opencli"
            return "ok", opencli_summary(st)
        
        # Nothing available

        self.active_backend = None
        return "off", "Neither footalk-cli nor OpenCLI detected"

Register this channel in agent_reach/channels/__init__.py as shown previously. The agent-reach doctor command will now display the active backend, and agents can invoke the appropriate CLI directly.

Testing and Validation

After implementation, verify your integration:

  1. Run contract tests: pytest tests/test_channel_contracts.py -q ensures all required attributes exist.
  2. Check doctor output: agent-reach doctor should list your channel with the correct active backend.
  3. Test URL handling: Verify can_handle() returns True for your platform URLs and False for others.

Summary

  • Subclass Channel from agent_reach/channels/base.py and implement can_handle() for URL recognition and check() for backend probing.
  • Define required attributes: name, description, backends (ordered list), and tier (configuration complexity level).
  • Register the channel by importing the class in agent_reach/channels/__init__.py and appending an instance to ALL_CHANNELS.
  • Add new backends by extending the backends list and probing each candidate in check(), setting self.active_backend to the first successful option.
  • Validate using pytest tests/test_channel_contracts.py before running agent-reach doctor.

Frequently Asked Questions

What is the minimum required code to add a custom channel to Agent Reach?

At minimum, create a file in agent_reach/channels/, subclass Channel, define name, description, backends, and tier, implement can_handle() to return True for your platform URLs, and implement check() to set self.active_backend and return a status tuple. Finally, import and instantiate the class in agent_reach/channels/__init__.py and append it to ALL_CHANNELS.

How does Agent Reach choose which backend to use for a channel?

The check() method probes backends in order of preference and sets self.active_backend to the first successful candidate. Users can override this via ~/.agent-reach/config.yaml using the <channel_name>_backend key, which the ordered_backends() method respects when reordering the backends list.

Can I add a backend to an existing channel without modifying the original source files?

While you must edit the channel's Python file to add backend logic, you should extend the existing channel class in your fork or modify the existing one directly. There is currently no plugin system for backends independent of channel files; all backend logic must be registered within the channel's check() method and backends list.

What happens if my custom channel fails the contract tests?

The agent-reach doctor command will raise an assertion error indicating which required attribute or method is missing. Common failures include missing name, description, backends, or tier attributes, or failing to set active_backend in the check() method before returning.

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 →