# How to Add a New Platform Channel to Agent Reach: Implementing can_handle and check Methods

> Learn to add a new platform channel to Agent Reach by subclassing Channel, implementing can_handle and check methods to handle URLs and verify CLI tools, and registering your new channel.

- Repository: [Pnant/Agent-Reach](https://github.com/Panniantong/Agent-Reach)
- Tags: how-to-guide
- Published: 2026-06-07

---

**To add a new platform channel to Agent Reach, subclass the abstract `Channel` base class in [`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/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`](https://github.com/Panniantong/Agent-Reach/blob/main/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`](https://github.com/Panniantong/Agent-Reach/blob/main/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`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py), the `can_handle` method determines whether a specific channel instance should process a given URL:

```python
@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:

```python
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`](https://github.com/Panniantong/Agent-Reach/blob/main/gitlab.py), [`bitbucket.py`](https://github.com/Panniantong/Agent-Reach/blob/main/bitbucket.py)). The file must import the base class and define a concrete subclass:

```python

# 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:

```python
    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`](https://github.com/Panniantong/Agent-Reach/blob/main/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'`:

```python
    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`](https://github.com/Panniantong/Agent-Reach/blob/main/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`](https://github.com/Panniantong/Agent-Reach/blob/main/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:

```python

# 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:

```bash
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:

```python

# -*- 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 `Channel`** from [`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py) and define the required class attributes `name`, `description`, `backends`, and `tier`.
- **Implement `can_handle`** to inspect URLs and return `True` when the channel should assume responsibility for processing.
- **Implement `check`** to verify CLI availability and authentication, returning a status tuple `('ok'|'warn'|'off'|'error', message)`.
- **Register the channel** by importing and instantiating it in `ALL_CHANNELS` inside [`agent_reach/channels/__init__.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/__init__.py).
- **Validate** the integration using `python -m agent_reach.cli doctor` to 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`](https://github.com/Panniantong/Agent-Reach/blob/main/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`](https://github.com/Panniantong/Agent-Reach/blob/main/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.