# How Agent Reach Selects Between bili-cli and OpenCLI Backends for Bilibili

> Agent Reach intelligently selects bili-cli or OpenCLI backends for Bilibili, prioritizing zero-login access and falling back to subtitle extraction or API search for seamless operation.

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

---

**Agent Reach automatically probes available tools to prioritize bili-cli for zero-login access, falling back to OpenCLI for subtitle extraction, and finally to the built-in search API if neither CLI tool is functional.**

Agent Reach treats each platform as a **channel** that abstracts multiple concrete **backends**—the actual tools that fetch data. For Bilibili, the system implements a deterministic selection strategy in [`agent_reach/channels/bilibili.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/bilibili.py) that evaluates availability, honors user configuration overrides, and maintains fallback chains to ensure reliable content retrieval.

## The Channel-Backend Architecture

In the Agent Reach codebase, the `BilibiliChannel` class defines its available backends as an ordered list:

```python
backends = ["bili-cli", "OpenCLI", "B站搜索 API"]

```

This declaration in [`agent_reach/channels/bilibili.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/bilibili.py) establishes the default preference order. The base class `Channel` in [`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py) provides the infrastructure for backend management, including the `ordered_backends()` method that handles user-specified overrides.

## Backend Selection Logic

When Agent Reach initializes a channel or explicitly calls `check()`, it executes a three-phase selection process:

### Ordered List Creation

The `Channel.ordered_backends()` method (lines 45-59 in [`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py)) reorders the candidate list based on configuration. If the user specifies `bilibili_backend` in a config file or sets the `BILIBILI_BACKEND` environment variable, that backend moves to the front of the list. The implementation ignores unknown values to prevent stale configurations from hiding working backends.

### Probing Each Backend in Order

The `BilibiliChannel.check()` method iterates through the ordered backends, calling dedicated probe methods for each:

**`bili-cli` probe**: The `_check_bili_cli` method (lines 82-95 in [`agent_reach/channels/bilibili.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/bilibili.py)) invokes `probe_command("bili", ["--version"], ...)` from [`agent_reach/probe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/probe.py). It returns `"ok"` if the command executes successfully, `"warn"` if it runs but reports issues, `"error"` if the binary is broken, or `None` if the command is missing entirely.

**`OpenCLI` probe**: The `_check_opencli` method imports `opencli_status` from [`agent_reach/backends/opencli.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/backends/opencli.py) (lines 80-118) and evaluates the `OpenCLIStatus` dataclass. It returns `"ok"` when the Chrome extension and daemon are functional, `"warn"` or `"error"` with diagnostic hints for partial failures, or `None` if the package is not installed.

**Search API probe**: The `_check_search_api` method performs a lightweight HTTP request to the Bilibili public search endpoint (`_SEARCH_API`). It returns `"ok"` if reachable, indicating that search functionality is available even when CLI tools are absent.

### Selecting the Active Backend

After probing, `BilibiliChannel.check()` (lines 47-71) scans the `findings` dictionary for the first `"ok"` status, then `"warn"`. The backend producing that status becomes `self.active_backend`. If all candidates fail, the method returns `"error"` or `"off"` with diagnostic information.

## User Override Mechanisms

Users can force a specific backend via configuration before the automatic selection runs:

```yaml

# config.yaml

bilibili_backend: OpenCLI

```

Or via environment variable:

```bash
export BILIBILI_BACKEND=OpenCLI
agent-reach read https://www.bilibili.com/video/BV1xx411c7kM

```

When either method is used, `Channel.ordered_backends()` moves the specified backend to the front of the evaluation list, ensuring it is probed first.

## Runtime Execution Flow

Once `check()` completes, the selected backend persists in `self.active_backend`. Subsequent calls to `read(url)` or `search(query)` dispatch to this backend without re-probing. For example, if `bili-cli` is selected, the channel executes `bili video info ...`; if `OpenCLI` is active, it invokes `opencli bilibili ...`.

Programmatic usage automatically handles this selection:

```python
from agent_reach.core import AgentReach

ar = AgentReach()

# Backend selection happens during initialization

content = ar.read("https://www.bilibili.com/video/BV1xx411c7kM")
print(content)  # Data fetched via the selected backend

```

## Summary

- **Agent Reach** implements a three-tier fallback system for Bilibili: **bili-cli** (preferred for zero-login access), **OpenCLI** (for subtitle extraction via Chrome extension), and the **built-in search API** (final fallback).
- The `BilibiliChannel.check()` method in [`agent_reach/channels/bilibili.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/bilibili.py) probes each backend in order, storing results in a `findings` dictionary before selecting the first functional candidate.
- Users override the default priority by setting `bilibili_backend` in configuration files or the `BILIBILI_BACKEND` environment variable, which `Channel.ordered_backends()` processes in [`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py).
- The **bili-cli** probe uses `probe_command()` to verify binary presence and version, while the **OpenCLI** probe checks the `OpenCLIStatus` dataclass for daemon and extension health.
- Once selected, the active backend persists for the channel's lifetime, ensuring consistent behavior across multiple `read()` or `search()` operations.

## Frequently Asked Questions

### What is the default priority order for Bilibili backends?

Agent Reach prioritizes **bili-cli** first because it provides zero-login access to video details, hot lists, and search functionality without requiring browser extensions. If bili-cli is unavailable or broken, the system falls back to **OpenCLI**, which offers subtitle extraction through a Chrome extension. Finally, if neither CLI tool is functional, the channel uses the **built-in Bilibili search API**, which provides limited search capabilities without external dependencies.

### How can I force Agent Reach to use a specific backend?

Set the `bilibili_backend` configuration key in your [`config.yaml`](https://github.com/Panniantong/Agent-Reach/blob/main/config.yaml) file, or export the `BILIBILI_BACKEND` environment variable with the desired backend name. According to the implementation in [`agent_reach/channels/base.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/channels/base.py), this value moves to the front of the evaluation list in `ordered_backends()`, ensuring the specified backend is probed first. Unknown values are ignored to prevent configuration errors from disabling functionality.

### What happens if all Bilibili backends fail the availability check?

If `bili-cli`, `OpenCLI`, and the search API all return failure statuses (either `"error"` or `None`), the `BilibiliChannel.check()` method returns an `"error"` or `"off"` status with diagnostic hints explaining why each backend failed. The channel will not set an `active_backend`, and subsequent `read()` or `search()` operations will fail until the underlying issue (missing binary, broken extension, or network connectivity) is resolved.

### How does Agent Reach verify if bili-cli is installed?

The `_check_bili_cli` method calls `probe_command("bili", ["--version"], ...)` from [`agent_reach/probe.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/probe.py). This executes the `bili --version` command in a subprocess. If the command returns a valid exit code and version string, the probe returns `"ok"`. If the command is not found in the system PATH, it returns `None`, causing the channel to skip this backend and proceed to the next candidate in the ordered list.