# How to Add a New Platform Channel to Agent Reach: A Complete Implementation Guide

> Learn how to add a new platform channel to Agent Reach with this complete implementation guide. Follow step-by-step instructions to extend Agent Reach's capabilities.

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

---

**To add a new platform channel in Agent Reach, create a Python module in `agent_reach/channels/` that inherits from the abstract `Channel` base class, implement the `can_handle()` and `check()` methods, and register the class in [`agent_reach/channels/__init__.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/__init__.py) for auto-discovery.**

Agent Reach's architecture treats every supported internet platform as a **channel**—a pluggable component that knows how to read, search, and interact with a specific service. Channels follow a consistent lifecycle defined in [[`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py)](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py), making it straightforward to extend the system with new platforms. This guide walks through the exact procedure used by existing channels like Twitter and YouTube.

---

## Understanding the Channel Base Class

Every channel inherits from `Channel`, which defines the contract that the core routing system expects.

### Core Metadata Properties

| Property | Purpose |
|----------|---------|
| `name` | Short identifier used in CLI arguments and configuration keys |
| `description` | Human-readable description displayed by diagnostics |
| `backends` | Ordered list of upstream command-line tools that can fulfill the channel |
| `tier` | Setup difficulty: `0` = zero-config, `1` = needs free API key, `2` = needs full user setup |
| `active_backend` | Set by `check()` to the first usable backend found |

### Key Inherited Methods

- **`ordered_backends(self, config)`** — Returns the backend list respecting user overrides from configuration or environment variables
- **`check(self, config)`** — Probes available backends and selects the first healthy one; default implementation marks channel as "built-in"

The [[`agent_reach/channels/twitter.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/twitter.py)](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/twitter.py) file demonstrates a production-ready override of `check()` with multi-backend probing logic.

---

## Step-by-Step Implementation Procedure

### Step 1: Create the Channel Module

Create a new file in the channels directory:

```bash
touch agent_reach/channels/myplatform.py

```

### Step 2: Import Required Dependencies

```python

# agent_reach/channels/myplatform.py

from .base import Channel
from agent_reach.probe import probe_command

```

The `probe_command` utility from [[`agent_reach/probe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/probe.py)](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/probe.py) runs health checks on external CLI tools and returns structured status information.

### Step 3: Define the Channel Class with Metadata

```python
class MyPlatformChannel(Channel):
    name = "myplatform"
    description = "MyPlatform – read and search content from myplatform.com"
    backends = ["myplatform-cli", "OpenCLI"]
    tier = 1  # Requires API key or authentication setup

```

### Step 4: Implement `can_handle()` for URL Routing

The core router in [[`agent_reach/core.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/core.py)](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/core.py) uses this method to dispatch URLs to the correct channel:

```python
    def can_handle(self, url: str) -> bool:
        from urllib.parse import urlparse
        
        domain = urlparse(url).netloc.lower()
        return "myplatform.com" in domain or "myp.com" in domain

```

### Step 5: Implement `check()` for Backend Discovery

This method probes each backend in priority order and selects the first usable one:

```python
    def check(self, config=None):
        """Probe backends and activate the first healthy one."""
        self.active_backend = None
        findings = []

        for backend in self.ordered_backends(config):
            if backend == "myplatform-cli":
                result = self._probe_myplatform_cli()
            elif backend == "OpenCLI":
                result = self._probe_opencli()
            else:
                continue

            if result is None:
                continue  # Backend not installed

            findings.append((backend, *result))

        # Prefer "ok", then "warn"

        for wanted in ("ok", "warn"):
            for backend, status, message in findings:
                if status == wanted:
                    self.active_backend = backend
                    return status, message

        if findings:
            return "error", "\n".join(msg for _, _, msg in findings)

        return "warn", (
            "MyPlatform CLI not installed. Install with:\n"
            "  pipx install myplatform-cli\n"
            "Or configure OpenCLI for browser-based access."
        )

```

### Step 6: Add Backend-Specific Probe Methods

```python
    def _probe_myplatform_cli(self):
        probe = probe_command(
            "myplatform",
            ["status"],
            timeout=15,
            retries=1,
            package="myplatform-cli"
        )
        if probe.status == "missing":
            return None
        if probe.status == "broken":
            return "error", f"CLI installed but failing.\n{probe.hint}"
        if probe.ok and "authenticated" in probe.output.lower():
            return "ok", "myplatform-cli ready (authenticated)"
        return "warn", "CLI installed but not authenticated; run: myplatform login"

```

### Step 7: (Optional) Implement Platform Operations

Add `read()`, `search()`, or other methods that delegate to the active backend:

```python
    def read(self, url: str) -> str:
        """Fetch content from a MyPlatform URL."""
        if self.active_backend == "myplatform-cli":
            return probe_command("myplatform", ["read", url]).output
        if self.active_backend == "OpenCLI":
            return probe_command("opencli", ["myplatform", "get", url]).output
        raise RuntimeError("No active backend for MyPlatform read operation")

    def search(self, query: str, limit: int = 10):
        """Search MyPlatform content."""
        if self.active_backend == "myplatform-cli":
            result = probe_command("myplatform", ["search", query, "--limit", str(limit)])
            return self._parse_search_results(result.output)
        # Add OpenCLI fallback as needed

        raise RuntimeError("Search requires myplatform-cli backend")

```

### Step 8: Register in Package Index

Edit [[`agent_reach/channels/__init__.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/__init__.py)](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/__init__.py) to enable auto-discovery:

```python
from .myplatform import MyPlatformChannel  # Add this line

```

### Step 9: Verify with Diagnostics

Run the built-in health checker:

```bash
python -m agent_reach.cli doctor

```

Expected output:

```

✔ MyPlatform (myplatform) – ok – myplatform-cli

```

---

## Complete Working Template

Copy this skeleton to start a new channel immediately:

```python

# agent_reach/channels/myplatform.py

"""MyPlatform channel implementation for Agent Reach."""

from .base import Channel
from agent_reach.probe import probe_command


class MyPlatformChannel(Channel):
    """Channel for myplatform.com content platform."""
    
    name = "myplatform"
    description = "MyPlatform – read and search myplatform.com content"
    backends = ["myplatform-cli", "OpenCLI"]
    tier = 1

    # ------------------------------------------------------------------

    # URL routing

    # ------------------------------------------------------------------

    def can_handle(self, url: str) -> bool:
        from urllib.parse import urlparse
        domain = urlparse(url).netloc.lower()
        return "myplatform.com" in domain

    # ------------------------------------------------------------------

    # Backend health checking and selection

    # ------------------------------------------------------------------

    def check(self, config=None):
        self.active_backend = None
        findings = []

        for backend in self.ordered_backends(config):
            result = self._probe_backend(backend, config)
            if result:
                findings.append((backend, *result))

        for wanted in ("ok", "warn"):
            for backend, status, message in findings:
                if status == wanted:
                    self.active_backend = backend
                    return status, message

        return self._format_failure(findings)

    def _probe_backend(self, backend, config):
        """Dispatch to appropriate probe method."""
        probes = {
            "myplatform-cli": self._probe_myplatform_cli,
            "OpenCLI": self._probe_opencli,
        }
        probe_fn = probes.get(backend)
        return probe_fn(config) if probe_fn else None

    def _probe_myplatform_cli(self, config):
        probe = probe_command(
            "myplatform", ["status"], 
            timeout=15, retries=1, package="myplatform-cli"
        )
        if probe.status == "missing":
            return None
        if probe.status == "broken":
            return "error", f"CLI broken: {probe.hint}"
        if probe.ok and "ready" in probe.output.lower():
            return "ok", "myplatform-cli ready"
        return "warn", "CLI installed but not ready; run: myplatform auth"

    def _probe_opencli(self, config):
        from agent_reach.backends import opencli_status
        st = opencli_status()
        if not st.installed:
            return None
        if st.broken:
            return "error", st.hint
        if st.ready:
            return "ok", "OpenCLI ready (browser session)"
        return "warn", st.hint

    def _format_failure(self, findings):
        if findings:
            return "error", "\n".join(m for _, _, m in findings)
        return "warn", "Install myplatform-cli: pipx install myplatform-cli"

    # ------------------------------------------------------------------

    # Platform operations

    # ------------------------------------------------------------------

    def read(self, url: str) -> str:
        if not self.active_backend:
            raise RuntimeError("Channel not checked or no backend available")
        if self.active_backend == "myplatform-cli":
            return probe_command("myplatform", ["read", url]).output
        if self.active_backend == "OpenCLI":
            return probe_command("opencli", ["myplatform", "get", url]).output
        raise RuntimeError(f"Unknown backend: {self.active_backend}")

```

---

## Using Your New Channel

Once registered, the channel integrates automatically:

```python
from agent_reach.core import AgentReach

ar = AgentReach()
url = "https://myplatform.com/article/abc123"

# Automatic channel selection via can_handle()

content = ar.read(url)
print(content)

# Or use the channel directly

from agent_reach.channels.myplatform import MyPlatformChannel
channel = MyPlatformChannel()
status, message = channel.check(ar.config)
print(f"MyPlatform status: {status} – {message}")

```

---

## Key Files Reference

| File | Purpose | Source |
|------|---------|--------|
| [`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py) | Abstract `Channel` class, `ordered_backends()`, default `check()` | [View source](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py) |
| [`agent_reach/channels/twitter.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/twitter.py) | Production example with multi-backend probing | [View source](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/twitter.py) |
| [`agent_reach/channels/__init__.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/__init__.py) | Channel registration for auto-discovery | [View source](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/__init__.py) |
| [`agent_reach/probe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/probe.py) | `probe_command()` utility for CLI health checks | [View source](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/probe.py) |
| [`agent_reach/core.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/core.py) | URL routing logic using `can_handle()` | [View source](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/core.py) |

---

## Summary

- **Inherit from `Channel`** in [`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py) to create a new platform integration
- **Define metadata** (`name`, `description`, `backends`, `tier`) for discovery and diagnostics
- **Implement `can_handle()`** so the router can dispatch URLs to your channel
- **Implement `check()`** to probe and select from available backends using `probe_command()`
- **Register in [`__init__.py`](https://github.com/Panniantong/Agent-Reach/blob/main/__init__.py)** for automatic discovery by `AgentReach` core
- **Verify with `python -m agent_reach.cli doctor`** before deploying

---

## Frequently Asked Questions

### What is the minimum code required to add a new platform channel?

You need a class inheriting from `Channel` with `name`, `description`, `backends`, `tier` defined, plus implementations of `can_handle()` and `check()`. The [[`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py)](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py) default `check()` works for built-in channels, but most real platforms need custom backend probing as shown in [[`agent_reach/channels/twitter.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/twitter.py)](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/twitter.py).

### How does Agent Reach choose which channel handles a URL?

The [`AgentReach`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/core.py) core iterates through all registered channels and calls `can_handle(url)` on each. The first channel returning `True` receives the operation. Implement `can_handle()` to parse URL hostnames or path patterns specific to your platform.

### What backend probing statuses does `probe_command()` return?

The utility in [[`agent_reach/probe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/probe.py)](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/probe.py) returns structured status: `missing` (command not found), `broken` (command fails), `timeout` (no response), `ok` (works as expected), plus `output` and `hint` fields for user guidance. Your `check()` method should map these to the channel-level statuses: `"ok"`, `"warn"`, or `"error"`.

### Can a channel support multiple backends with fallback?

Yes. List multiple backends in priority order: `backends = ["preferred-cli", "fallback-cli", "OpenCLI"]`. The `ordered_backends()` method respects user configuration overrides, and your `check()` implementation should probe each in sequence, selecting the first healthy option. This pattern is demonstrated in the Twitter channel's [`check()`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/twitter.py) method.