How to Add a New Platform Channel to Agent Reach: Implementing can_handle and check Methods
To add a new platform channel to Agent Reach, subclass the abstract Channel base class in agent_reach/channels/base.py, implement the can_handle method to identify platform-specific URLs and the check method to verify upstream CLI tools, then register the channel in agent_reach/channels/__init__.py to enable automatic discovery.
Agent Reach treats every supported platform as a modular channel that integrates with the core routing system. Adding support for a new platform—such as GitLab, Bitbucket, or a custom internal tool—requires implementing a concrete subclass that follows the contract defined in the source code. This guide provides the exact implementation pattern used in the Panniantong/Agent-Reach repository, including file paths and method signatures from the actual codebase.
Understand the Channel Base Class
The foundation of every platform integration is the abstract Channel class located in agent_reach/channels/base.py. This class defines the interface that the Agent Reach router uses to delegate URL processing and dependency validation.
The Abstract can_handle Method
As defined on lines 26-30 of agent_reach/channels/base.py, the can_handle method determines whether a specific channel instance should process a given URL:
@abstractmethod
def can_handle(self, url: str) -> bool:
"""Check if this channel can handle this URL."""
...
The router calls this method against all registered channels; the first channel returning True receives the task. Implementations typically parse the URL using urllib.parse.urlparse to inspect the netloc or path patterns.
The check Method
The check method, defined on lines 31-36 of the same file, verifies that external dependencies required by the channel are installed and functional:
def check(self, config=None) -> Tuple[str, str]:
"""
Check if this channel's upstream tool is available.
Returns (status, message) where status is 'ok'/'warn'/'off'/'error'.
"""
return "ok", f"{'、'.join(self.backends) if self.backends else '内置'}"
While the base class provides a default implementation that simply reports declared backends, serious channels should override this to execute actual health checks on CLI binaries or API credentials.
Step-by-Step Implementation
Follow these steps to create a production-ready channel that integrates seamlessly with the Agent Reach CLI and diagnostics.
1. Create the Channel File
Create a new Python module under agent_reach/channels/. Name the file after the platform slug (e.g., gitlab.py, bitbucket.py). The file must import the base class and define a concrete subclass:
# agent_reach/channels/gitlab.py
"""GitLab – read repositories and issues via the `glab` CLI."""
import shutil
import subprocess
from urllib.parse import urlparse
from .base import Channel
class GitLabChannel(Channel):
name = "gitlab"
description = "GitLab 仓库和 Issues"
backends = ["glab"] # Upstream CLI that Agent Reach will call
tier = 0 # No API key required, just the CLI
The class attributes name, description, backends, and tier are required. The backends list identifies the external tools the channel depends upon, while tier indicates whether API keys are required (tier 0 means CLI-only).
2. Implement can_handle for URL Detection
Override the abstract can_handle method to return True only for URLs belonging to your platform. This example inspects the domain:
def can_handle(self, url: str) -> bool:
"""Return True for URLs that point to gitlab.com."""
domain = urlparse(url).netloc.lower()
return "gitlab.com" in domain
This pattern mirrors the existing TwitterChannel implementation found in agent_reach/channels/twitter.py (lines 15-19), which checks for twitter.com or x.com domains.
3. Implement check for Dependency Verification
Override check to verify that the upstream CLI is installed and authenticated. The method must return a tuple of (status, message) where status is one of 'ok', 'warn', 'off', or 'error':
def check(self, config=None):
"""Verify that `glab` is installed and can authenticate."""
glab = shutil.which("glab")
if not glab:
return "off", (
"请先安装 glab CLI:\n"
" pip install glab\n"
"或者使用 uv:\n"
" uv tool install glab"
)
# Simple `glab auth status` probe
try:
result = subprocess.run(
[glab, "auth", "status"], capture_output=True,
encoding="utf-8", errors="replace", timeout=5
)
if result.returncode == 0:
return "ok", "glab 已安装并已登录"
else:
return "warn", "glab 已安装,但未登录。运行 `glab auth login` 配置凭据"
except Exception:
return "warn", "glab 已安装但无法运行 (可能缺少依赖或网络受限)"
This implementation follows the pattern established in agent_reach/channels/twitter.py (lines 20-36), which checks for the twurl or similar CLI tools before returning an operational status.
4. Register the Channel
Open agent_reach/channels/__init__.py and add your channel class to the ALL_CHANNELS registry (lines 28-45). Import the class and instantiate it in the list:
# agent_reach/channels/__init__.py
...
from .gitlab import GitLabChannel # <-- add this line
...
ALL_CHANNELS: List[Channel] = [
GitHubChannel(),
TwitterChannel(),
YouTubeChannel(),
...
GitLabChannel(), # <-- add this line
]
Registration is mandatory for the channel to appear in the doctor diagnostics and to be discoverable by the CLI routing logic.
5. Verify with the Doctor Command
After installing the required CLI tool (e.g., glab), run the built-in diagnostics to verify your implementation:
python -m agent_reach.cli doctor
You should see output similar to:
gitlab: ok – glab 已安装并已登录
If the CLI is missing, the doctor displays the installation hint defined in your check method's return value.
Complete Working Example
Here is the full implementation of a GitLab channel that follows Agent Reach conventions:
# -*- coding: utf-8 -*-
"""GitLab – read repositories and issues via the `glab` CLI."""
import shutil
import subprocess
from urllib.parse import urlparse
from .base import Channel
class GitLabChannel(Channel):
name = "gitlab"
description = "GitLab 仓库和 Issues"
backends = ["glab"]
tier = 0
def can_handle(self, url: str) -> bool:
"""Return True for URLs that point to gitlab.com."""
domain = urlparse(url).netloc.lower()
return "gitlab.com" in domain
def check(self, config=None):
"""Verify that `glab` is installed and can authenticate."""
glab = shutil.which("glab")
if not glab:
return "off", "请先安装 glab CLI:pip install glab"
try:
result = subprocess.run(
[glab, "auth", "status"], capture_output=True,
encoding="utf-8", errors="replace", timeout=5
)
if result.returncode == 0:
return "ok", "glab 已安装并已登录"
else:
return "warn", "glab 已安装,但未登录"
except Exception:
return "warn", "glab 已安装但无法运行"
Summary
- Subclass
Channelfromagent_reach/channels/base.pyand define the required class attributesname,description,backends, andtier. - Implement
can_handleto inspect URLs and returnTruewhen the channel should assume responsibility for processing. - Implement
checkto verify CLI availability and authentication, returning a status tuple('ok'|'warn'|'off'|'error', message). - Register the channel by importing and instantiating it in
ALL_CHANNELSinsideagent_reach/channels/__init__.py. - Validate the integration using
python -m agent_reach.cli doctorto ensure proper discovery and dependency reporting.
Frequently Asked Questions
What return values does the check method expect?
The check method must return a tuple of two strings: (status, message). According to the implementation in agent_reach/channels/base.py, the status string must be one of four values: 'ok' (fully operational), 'warn' (functional but with issues), 'off' (missing dependencies), or 'error' (critical failure). The message string provides human-readable details displayed by the doctor command.
How does Agent Reach discover new channels automatically?
Agent Reach uses an explicit registry pattern rather than automatic discovery. The ALL_CHANNELS list defined in agent_reach/channels/__init__.py (lines 28-45) contains instantiated channel objects. The CLI and core engine iterate over this list when routing URLs or running diagnostics. You must manually add your channel class to this list for it to be recognized.
Can a channel support multiple backends?
Yes. The backends class attribute accepts a list of strings, allowing a single channel to declare dependencies on multiple CLI tools or APIs. For example, a channel might require both glab and jq for advanced JSON processing. The default check implementation in the base class concatenates these names, but you should override check to verify each binary individually if multiple dependencies are critical.
What is the tier attribute used for?
The tier attribute is an integer that indicates the authentication complexity required by the channel. According to existing implementations in the repository, tier = 0 signifies that the channel operates using only local CLI tools without requiring API keys. Higher tier values indicate channels that require OAuth tokens, API keys, or other credentials. This attribute helps the doctor command prioritize which configuration instructions to display to the user.
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 →