How to Add a New Platform Channel to Agent Reach: Complete Developer Guide
To add a new platform channel to Agent Reach, subclass the Channel abstract base class from agent_reach/channels/base.py, implement the required can_handle() and check() methods, and register the instance in the ALL_CHANNELS list inside agent_reach/channels/__init__.py.
Agent Reach treats every supported internet platform as a Channel—a modular wrapper that enables the core routing logic to interact with specific sites. When you add a new platform channel to Agent Reach, you create a Python class that defines how the system identifies URLs, validates dependencies, and optionally extracts content. This architecture allows the doctor diagnostic tool and the CLI router to discover and interact with platforms dynamically.
Understanding the Channel Base Class and Tier System
Every channel inherits from the Channel class defined in agent_reach/channels/base.py. The base class establishes a contract that concrete implementations must fulfill to integrate with the routing system.
The architecture uses a tier system to categorize setup complexity:
- Tier 0 – Zero configuration required (e.g.,
WebChannelworks out-of-the-box) - Tier 1 – Requires a free API key or a simple binary installation
- Tier 2 – Needs extra setup such as authentication via cookies or complex configuration
The check method must return a tuple (status, message) where status is one of ok, warn, off, or error. The doctor module in agent_reach/doctor.py aggregates these results to inform users about the health of their environment.
Required Methods: can_handle and check
Every channel must implement two core methods:
can_handle(self, url: str) -> bool: ReturnsTrueif the channel recognizes and can process the given URLcheck(self, config=None) -> Tuple[str, str]: Validates that required upstream tools are installed and configured, returning a status code and human-readable message
Optional Content Methods: read and search
If your platform supports content extraction, implement:
read(self, url: str) -> str: Returns article text as plain Markdownsearch(self, query: str) -> List[str]: Returns a list of relevant URLs
Reference implementations exist in agent_reach/channels/youtube.py and agent_reach/channels/reddit.py.
Creating a New Platform Channel
Step 1: Implement the Channel Class
Create a new file in agent_reach/channels/ named after your platform (e.g., myplatform.py). Subclass Channel and define the required attributes and methods:
# agent_reach/channels/myplatform.py
"""MyPlatform — read and search via `mycli`."""
import shutil
import subprocess
from typing import List, Tuple
from .base import Channel
class MyPlatformChannel(Channel):
name = "myplatform"
description = "MyPlatform – articles and comments"
backends = ["mycli"]
tier = 1 # Requires a binary, no extra auth
def can_handle(self, url: str) -> bool:
from urllib.parse import urlparse
domain = urlparse(url).netloc.lower()
return "myplatform.com" in domain
def check(self, config=None) -> Tuple[str, str]:
binary = shutil.which("mycli")
if not binary:
return "off", "mycli not installed. Install with: pip install mycli"
try:
result = subprocess.run(
[binary, "--version"],
capture_output=True,
encoding="utf-8",
timeout=5
)
if result.returncode == 0:
return "ok", "mycli ready"
except Exception:
pass
return "warn", "mycli installed but not responding"
def read(self, url: str) -> str:
"""Return article text as plain Markdown."""
binary = shutil.which("mycli")
result = subprocess.run(
[binary, "read", url],
capture_output=True,
encoding="utf-8",
timeout=15
)
return result.stdout
def search(self, query: str) -> List[str]:
"""Search for content and return list of URLs."""
binary = shutil.which("mycli")
result = subprocess.run(
[binary, "search", query],
capture_output=True,
encoding="utf-8",
timeout=15
)
return [line.strip() for line in result.stdout.splitlines() if line.strip()]
Step 2: Register in ALL_CHANNELS
Import your class in agent_reach/channels/__init__.py and append an instance to the ALL_CHANNELS list. This registration makes the channel visible to the doctor check and the core router:
# agent_reach/channels/__init__.py
from typing import List
from .base import Channel
from .web import WebChannel
from .twitter import TwitterChannel
from .youtube import YouTubeChannel
from .myplatform import MyPlatformChannel # Add this import
ALL_CHANNELS: List[Channel] = [
WebChannel(),
TwitterChannel(),
YouTubeChannel(),
MyPlatformChannel(), # Add this instance
]
Testing Your Channel
Add tests to verify your implementation handles URLs correctly and responds appropriately when dependencies are missing. Create a dedicated test file following the pattern in tests/test_twitter_channel.py:
# tests/test_myplatform_channel.py
import pytest
from agent_reach.channels import get_channel
def test_myplatform_can_handle():
ch = get_channel("myplatform")
assert ch is not None
assert ch.can_handle("https://myplatform.com/article/123") is True
assert ch.can_handle("https://other-site.com/post/456") is False
def test_myplatform_check_off(monkeypatch):
# Force shutil.which to return None to simulate missing binary
monkeypatch.setattr("shutil.which", lambda x: None)
ch = get_channel("myplatform")
status, message = ch.check()
assert status == "off"
assert "not installed" in message
def test_myplatform_check_ok(monkeypatch):
# Mock successful binary detection
def mock_which(cmd):
if cmd == "mycli":
return "/usr/bin/mycli"
return None
def mock_run(*args, **kwargs):
class Result:
returncode = 0
stdout = "mycli v1.0.0"
stderr = ""
return Result()
monkeypatch.setattr("shutil.which", mock_which)
monkeypatch.setattr("subprocess.run", mock_run)
ch = get_channel("myplatform")
status, message = ch.check()
assert status == "ok"
Run the full test suite to ensure no regressions:
pytest tests/ -v
Updating CLI Documentation (Optional)
To display your channel in agent-reach --help output or the --list-platforms option, update agent_reach/cli.py where the platform listing logic reads from Channel.name and Channel.description attributes. Most CLI commands automatically discover channels through the ALL_CHANNELS registry, but explicit help text may need manual updates.
Summary
- Subclass
Channelfromagent_reach/channels/base.pyand setname,description,backends, andtierattributes - Implement
can_handle()to route URLs to your channel based on domain or pattern matching - Implement
check()to return(status, message)tuples that the doctor uses to report dependency health - Optionally implement
read()andsearch()to enable content extraction capabilities - Register the instance in
agent_reach/channels/__init__.pyby importing the class and adding it toALL_CHANNELS - Write tests in
tests/that verify URL handling and dependency checking behavior
Frequently Asked Questions
What is the minimum implementation required to add a new platform channel?
You must subclass Channel in a new file under agent_reach/channels/, implement can_handle(self, url) to identify your platform's URLs, and implement check(self, config) to return a status tuple. Then import and instantiate your class in agent_reach/channels/__init__.py, adding it to the ALL_CHANNELS list. The read and search methods are optional and only needed if your platform supports content extraction.
How does the tier system affect channel behavior?
The tier attribute (0, 1, or 2) categorizes setup complexity for documentation purposes but does not change runtime logic. Tier 0 channels require no configuration, Tier 1 channels need binaries or API keys, and Tier 2 channels require complex authentication. The doctor command in agent_reach/doctor.py reports these tiers to users when diagnosing their environment.
Why is my channel not appearing in the doctor check output?
The doctor only reports channels registered in ALL_CHANNELS inside agent_reach/channels/__init__.py. Verify that you imported your channel class and appended an instance to the list. Also ensure your check() method returns a valid status string (ok, warn, off, or error) rather than raising an exception, as uncaught errors prevent the doctor from aggregating results.
Can a single channel support multiple backends?
Yes. Set the backends attribute to a list of strings, such as ["yt-dlp", "youtube-api"], and implement check() to verify that at least one backend is available. The check method should return ok if any backend works, or cycle through alternatives to report specific missing dependencies. This pattern appears in the YouTube channel implementation where multiple extraction tools are supported.
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 →