# Channel Contract in Agent-Reach: The 4 Methods Platform Modules Must Implement

> Learn the 4 essential channel contract methods cant_handle, check, read, and search that Agent-Reach platform modules need for URL routing, health checks, and content retrieval.

- Repository: [Pnant/Agent-Reach](https://github.com/Panniantong/Agent-Reach)
- Tags: internals
- Published: 2026-07-12

---

**Platform modules in Agent-Reach must implement four core methods—`can_handle`, `check`, `read`, and `search`—to enable automatic URL routing, backend health diagnostics, and content retrieval across diverse internet services.**

Agent-Reach is a unified CLI framework for accessing content across disparate web platforms. The **channel contract** defines the strict interface that every platform module must fulfill, allowing the core engine in [`agent_reach/core.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/core.py) to route requests without knowing implementation details. This contract is enforced by the abstract `Channel` base class and concrete expectations for four critical operations.

## The Four-Method Channel Contract

The contract is anchored by the abstract `Channel` class in [`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py). Each concrete channel must inherit from this base and provide specific implementations for the following four methods to integrate with the routing and diagnostic systems.

### 1. can_handle(url) – Route Detection

The `can_handle` method determines whether a channel can process a specific URL. Defined as an abstract method in [`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py) (lines 40-44), it accepts a URL string and returns a boolean indicating ownership.

```python

# From agent_reach/channels/base.py

def can_handle(self, url: str) -> bool:
    """Return True if this channel handles the URL."""
    raise NotImplementedError

```

Concrete implementations perform pattern matching. For example, `TwitterChannel` checks for twitter.com domains, while `YouTubeChannel` identifies youtube.com and youtu.be links, allowing the router to dispatch URLs to the correct backend.

### 2. check(config) – Backend Health Verification

The `check` method probes available backends to verify installation and functionality. It returns a tuple of `(status, message)` where status is `"ok"`, `"warn"`, `"off"`, or `"error"`, and sets `self.active_backend` to the selected backend instance.

While [`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py) declares the abstract signature, concrete channels override this to probe specific tools. `TwitterChannel` in [`agent_reach/channels/twitter.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/twitter.py) (lines 19-52) checks for `twitter-cli`, and `YouTubeChannel` in [`agent_reach/channels/youtube.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/youtube.py) (lines 35-48) probes for `yt-dlp` availability.

```python
def check(self, config=None):
    """Verify backend and return (status, message) tuple."""
    # Implementation probes self.backends

    status, msg = self._probe_backends(config)
    self.active_backend = self._select_backend()
    return status, msg

```

### 3. read(url) – Content Retrieval

The `read` method fetches raw content for a given URL. Unlike `can_handle` and `check`, this method is not abstract in the base class, but channels supporting content retrieval must implement it. The generic fallback in [`agent_reach/channels/web.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/web.py) (lines 24-32) demonstrates a standard HTTP GET implementation that other channels can emulate.

```python

# From agent_reach/channels/web.py

def read(self, url: str) -> str:
    """Fetch raw HTML/content via HTTP."""
    import requests
    response = requests.get(url, timeout=10)
    response.raise_for_status()
    return response.text

```

### 4. search(query) – Platform Search

The `search` method executes platform-specific queries and returns a list of result objects. This enables the CLI to perform searches across YouTube, Twitter, and other indexed services. While the base class does not enforce this method, channels like `TwitterChannel` implement it to wrap API calls or CLI commands, returning structured data for the core engine to process.

```python
def search(self, query: str) -> List[Any]:
    """Search platform and return list of results."""
    # Platform-specific implementation

    pass

```

## How the Core Engine Uses the Contract

The [`agent_reach/core.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/core.py) router relies on `can_handle` to select the appropriate channel for a URL. Once selected, it invokes `check` to verify readiness before calling `read` for content retrieval or `search` for queries. Additionally, [`agent_reach/doctor.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/doctor.py) iterates through all registered channels, executing `check` to report system health and missing dependencies, utilizing the status tuples returned by each channel.

## Implementation Example: Creating a Custom Channel

Below is a complete implementation of a hypothetical `ExampleChannel` demonstrating all four required methods:

```python
from typing import List, Any, Tuple
from agent_reach.channels.base import Channel
from agent_reach.probe import probe_command

class ExampleChannel(Channel):
    name = "example"
    description = "Example platform module"
    backends = ["example-cli"]
    tier = 1

    def can_handle(self, url: str) -> bool:
        """Check if URL belongs to example.com domain."""
        return "example.com" in url.lower()

    def check(self, config=None) -> Tuple[str, str]:
        """Verify example-cli is installed and functional."""
        probe = probe_command("example-cli", ["--version"], 
                          package="example-cli")
        if probe.status == "missing":
            self.active_backend = None
            return "off", "example-cli not installed"
        self.active_backend = "example-cli"
        return "ok", "example-cli ready"

    def read(self, url: str) -> str:
        """Fetch content via HTTP GET."""
        import requests
        resp = requests.get(url, timeout=5)
        resp.raise_for_status()
        return resp.text

    def search(self, query: str) -> List[Any]:
        """Search platform using CLI."""
        import subprocess
        result = subprocess.run(
            ["example-cli", "search", query],
            capture_output=True, text=True
        )
        return result.stdout.splitlines()

```

## Summary

- **`can_handle`**: Returns `True` if the channel supports the provided URL, enabling automatic routing in [`agent_reach/core.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/core.py).
- **`check`**: Validates backend availability and configuration, returning status tuples used by [`agent_reach/doctor.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/doctor.py) for diagnostics.
- **`read`**: Retrieves raw content for URLs; required for fetch operations, implemented in [`agent_reach/channels/web.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/web.py) for HTTP-based platforms.
- **`search`**: Executes platform-specific queries, returning lists of results for channels supporting search capabilities.

## Frequently Asked Questions

### Is the read method mandatory for all channels?

No. While `can_handle` and `check` are mandatory for all channels, `read` is only required for channels that support content retrieval. Channels focused solely on search functionality or metadata extraction may omit `read` but must still inherit from the base `Channel` class in [`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py).

### What happens if can_handle returns False for all registered channels?

If no channel's `can_handle` method returns `True` for a given URL, the router in [`agent_reach/core.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/core.py) typically falls back to the generic `WebChannel` implemented in [`agent_reach/channels/web.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/web.py), which uses standard HTTP GET requests to retrieve content.

### How does the check method report configuration errors?

The `check` method returns a tuple of `(status, message)`. Status values include `"ok"` for healthy backends, `"warn"` for degraded but functional states, `"off"` for missing dependencies, and `"error"` for configuration failures. The [`agent_reach/doctor.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/doctor.py) module aggregates these reports to display system health diagnostics.

### Can I implement only search without read?

Yes. Channels may implement any subset of the optional methods. If your platform supports search API access but not direct content reading (or vice versa), you only need to implement the relevant methods. The core router dispatches calls based on the method signatures present, though you must still provide `can_handle` and `check` to satisfy the base contract.