How to Add a New Platform Channel for an Unsupported Website to Agent Reach
Adding a new platform channel to Agent Reach requires creating a Python subclass in agent_reach/channels/, implementing URL detection and health-check logic, and registering the class in the channel registry.
Agent Reach treats every supported platform as a channel—a thin wrapper that routes calls to upstream CLI tools or APIs. If you need to add support for a website that is not yet covered, you will extend the base architecture without modifying core upstream logic. This guide walks through the exact implementation pattern used in the Panniantong/Agent-Reach repository.
Understanding the Channel Architecture
Agent Reach channels follow a backend-agnostic pattern. Each channel declares a list of potential backends (such as platform-specific CLIs or generic OpenCLI), then probes them at runtime to find the first functional option. The base class in agent_reach/channels/base.py provides the abstract Channel class and the ordered_backends() helper method, while the global registry in agent_reach/channels/__init__.py exposes all channels via the ALL_CHANNELS list.
Key architectural constraints to remember:
- Tier classification: Set
tier = 0for zero-config channels,tier = 1for channels requiring a free API key, andtier = 2for channels needing complex setup. - Backend delegation: Keep operational methods (
read(),search(),transcribe()) thin—they should only route to the selected backend rather than implementing platform logic directly. - Health-check priority: The
check()method iterates throughself.ordered_backends()and selects the first backend reporting"ok"or"warn"status.
Step-by-Step Implementation Guide
Step 1: Create a Channel Subclass
Create a new file in agent_reach/channels/ (e.g., mysite.py). Subclass Channel from agent_reach/channels/base.py and declare the mandatory class attributes:
from agent_reach.channels.base import Channel
class MySiteChannel(Channel):
name = "mysite" # Short identifier used in CLI and config files
description = "MySite – read and search content"
backends = ["mytool-cli", "OpenCLI"] # Ordered candidate backends
tier = 1 # Requires free API key
Step 2: Implement URL Detection with can_handle
Implement the can_handle(self, url: str) -> bool method to recognize URLs belonging to your platform. Use urllib.parse.urlparse to inspect the network location:
from urllib.parse import urlparse
def can_handle(self, url: str) -> bool:
"""Return True for URLs that belong to MySite."""
netloc = urlparse(url).netloc.lower()
return "mysite.com" in netloc or "mys.site" in netloc
Step 3: Configure Backend Health Checks
Override check(self, config=None) to probe each backend candidate. Follow the two-stage pattern used by existing multi-backend channels like Twitter or Reddit in agent_reach/channels/twitter.py:
- Iterate over
self.ordered_backends(config). - Probe each candidate using
agent_reach.probe.probe_commandorshutil.whichcombined withsubprocess.run. - Collect
(backend, status, message)tuples. - Set
self.active_backendto the first backend with"ok"or"warn"status.
import shutil
from agent_reach.probe import probe_command
def check(self, config=None):
"""Probe backends and pick the first usable one."""
self.active_backend = None
findings = []
for backend in self.ordered_backends(config):
if backend == "mytool-cli":
if not shutil.which("mytool-cli"):
continue
probe = probe_command("mytool-cli", ["--version"], package="mytool-cli")
if probe.ok:
findings.append((backend, "ok", "mytool-cli ready"))
else:
findings.append((backend, "warn", "installed but may need config"))
continue
if backend == "OpenCLI":
from agent_reach.backends import opencli_status
st = opencli_status()
if not st.installed:
continue
status = "error" if st.broken else ("ok" if st.ready else "warn")
findings.append((backend, status, st.hint))
continue
# Select best candidate
for wanted in ("ok", "warn"):
for backend, status, msg in findings:
if status == wanted:
self.active_backend = backend
return status, msg
return "off", "mytool-cli not installed. Install with `pip install mytool-cli`"
Step 4: Register the Channel
Import the new class in agent_reach/channels/__init__.py and append an instance to the ALL_CHANNELS list. This makes the channel discoverable via get_all_channels() and get_channel(name):
from .mysite import MySiteChannel # Add this import
ALL_CHANNELS: List[Channel] = [
# ... existing channels ...
MySiteChannel(), # Add the instance
]
Step 5: Add Tests and Documentation
Write unit tests in tests/test_channels.py verifying can_handle URL matching and check status reporting. Use the same monkey-patching style as the existing TwitterChannel test suite:
def test_mysite_can_handle():
ch = MySiteChannel()
assert ch.can_handle("https://www.mysite.com/article/123")
assert not ch.can_handle("https://github.com/user/repo")
def test_mysite_check_off_when_missing(monkeypatch):
monkeypatch.setattr(shutil, "which", lambda _: None)
ch = MySiteChannel()
status, msg = ch.check()
assert status == "off"
assert "mytool-cli not installed" in msg
Update docs/install.md to include the new channel name in the Supported channel names table.
Complete Working Example
Here is the full implementation for a fictional MySite channel following the Agent Reach patterns:
agent_reach/channels/mysite.py
# -*- coding: utf-8 -*-
"""MySite – example of adding a new platform channel."""
from urllib.parse import urlparse
import shutil
from agent_reach.probe import probe_command
from .base import Channel
class MySiteChannel(Channel):
"""Channel for the fictional MySite platform."""
name = "mysite"
description = "MySite – read and search content"
backends = ["mytool-cli", "OpenCLI"]
tier = 1
def can_handle(self, url: str) -> bool:
"""Return True for URLs that belong to MySite."""
netloc = urlparse(url).netloc.lower()
return "mysite.com" in netloc or "mys.site" in netloc
def check(self, config=None):
"""Probe backends and pick the first usable one."""
self.active_backend = None
findings = []
for backend in self.ordered_backends(config):
if backend == "mytool-cli":
if not shutil.which("mytool-cli"):
continue
probe = probe_command("mytool-cli", ["--version"], package="mytool-cli")
if probe.status == "missing":
continue
if probe.ok:
findings.append((backend, "ok", "mytool-cli ready"))
else:
findings.append((backend, "warn", "mytool-cli installed but may need config"))
continue
if backend == "OpenCLI":
from agent_reach.backends import opencli_status
st = opencli_status()
if not st.installed:
continue
if st.broken:
findings.append((backend, "error", st.hint))
elif st.ready:
findings.append((backend, "ok", st.hint))
else:
findings.append((backend, "warn", st.hint))
continue
for wanted in ("ok", "warn"):
for backend, status, msg in findings:
if status == wanted:
self.active_backend = backend
return status, msg
return "off", "mytool-cli not installed. Install with `pip install mytool-cli`"
Key Files and Reference Architecture
When adding a new platform channel, reference these source files in the Panniantong/Agent-Reach repository:
agent_reach/channels/base.py– Provides the abstractChannelclass and theordered_backends()helper.agent_reach/channels/__init__.py– Contains theALL_CHANNELSlist used for CLI discovery and thedoctorcommand.agent_reach/channels/twitter.py– Demonstrates the canonical multi-backend probing pattern with fallback logic.agent_reach/probe.py– Implementsprobe_commandfor classifying executable states (missing, broken, ready).tests/test_channels.py– Houses canonical tests forcan_handleandcheckmethod validation.docs/install.md– Documentation file requiring updates when new channels are added.
Summary
- Create a subclass of
Channelinagent_reach/channels/withname,description,backends, andtierattributes. - Implement
can_handle()to filter URLs usingurllib.parse.urlparsenetwork location matching. - Implement
check()to iterate throughself.ordered_backends(), probe each withprobe_commandorshutil.which, and setself.active_backendto the first healthy candidate. - Register the channel by importing the class and adding an instance to
ALL_CHANNELSinagent_reach/channels/__init__.py. - Test thoroughly using monkey-patching to simulate missing or broken backends, and update
docs/install.mdto reflect the new supported platform.
Frequently Asked Questions
What is the minimum code required to add a new platform channel?
You need a Python file in agent_reach/channels/ containing a class that inherits from Channel (from agent_reach.channels.base), defines the four mandatory attributes (name, description, backends, tier), implements can_handle() for URL detection, implements check() for backend health validation, and is registered in agent_reach/channels/__init__.py. Without registration in ALL_CHANNELS, the CLI will not discover your channel.
How does Agent Reach choose which backend to use for a channel?
The check() method iterates over the backends list in order, probing each candidate using agent_reach.probe.probe_command or similar utilities. It selects the first backend reporting "ok" or "warn" status and assigns it to self.active_backend. If no backends pass the health check, the channel reports "off" and provides installation hints to the user.
What do the tier values (0, 1, 2) represent in Agent Reach channels?
Tier 0 indicates a zero-config channel that works immediately after installation. Tier 1 requires a free API key or simple authentication. Tier 2 requires complex setup, paid credentials, or additional infrastructure. These values help the doctor command prioritize troubleshooting messages and guide users through configuration requirements.
Can I add operational methods like read() or search() to my custom channel?
Yes, you can implement optional methods such as read(self, url), search(self, query), or transcribe(self, ...) depending on the platform's capabilities. Keep these methods thin—they should delegate to the active backend via subprocess.run or library calls rather than implementing platform-specific parsing logic directly, maintaining the channel's role as a routing layer.
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 →