A Capability Is a Contract, Not a Command

Agent Reach’s most consequential design choice is not the number of platforms it mentions. It is the way it represents access: a channel describes a capability, orders several possible backends, and reports which one the environment can currently support. This chapter focuses on that contract because it explains how Agent Reach can adapt to changing tools without pretending to become a universal scraper. By the end, the important distinction is between a route that is named, a route that is preferred, and a route whose health has actually been established.

The Interface Between Request and Tool

When a user asks an AI agent to read a page, search a community, or summarize a video, the request contains more information than a URL. It implies an operation, a platform, an output, and a tolerance for delay or setup. Agent Reach does not turn all of those requests into one internal “fetch” operation. Instead, it represents each platform or capability as a Channel with a small set of responsibilities.

The first responsibility is identity. A channel has a name and a human-facing description, and it can decide whether it owns a URL. A YouTube address belongs to the YouTube channel; an X address belongs to the Twitter/X channel; a V2EX address belongs to the V2EX channel. A search-only capability such as Exa does not need to claim a URL at all. This looks simple, but it establishes an important boundary: the channel is the place where a request is classified before a backend is selected. Without that boundary, every calling agent would have to remember platform matching rules and choose tools independently.

The second responsibility is to describe candidate backends. A channel’s backends list is ordered. Its first entry is the preferred route, and the later entries are fallbacks. The list is not just documentation for a reader; the channel checks candidates in that order. A platform can therefore have a route policy without being locked to one implementation. The policy says, in effect, “try this access path first, keep these alternatives available, and expose the one that is actually usable.”

The third responsibility is health. A channel’s check method does not merely answer whether a package name appears somewhere on the machine. It returns a status and a message, and it sets active_backend to the backend that the check can support at that moment. If no usable candidate is established, the active backend is None. That makes health part of the contract rather than an unrelated diagnostic feature. A backend is not active because it is written in a README or because a command happens to be discoverable on PATH; it becomes active because the channel’s own check has enough evidence to say so.

The fourth responsibility is tiering. The repository distinguishes channels that can work with little or no configuration from those that need a free key, a login session, an MCP service, or a more involved environment. Tiering does not change what a channel can do, but it changes how a user should interpret its presence. A capability can be present in the registry and still require a deliberate setup decision. This prevents the architecture from confusing “supported by the project” with “ready on this computer.”

These responsibilities create a chain of ownership:

  • the AI agent owns the user’s request and decides what answer it is trying to produce;
  • the channel owns platform classification, candidate ordering, and the meaning of its health result;
  • configuration owns preferences and selected local state;
  • the upstream backend owns the actual request, parsing, authentication behavior, and output;
  • the platform owns the final response, access controls, and any changes to its interface.

The chain matters because no single component can honestly guarantee the whole result. Agent Reach can select a backend, but it cannot make a platform accept a request. An upstream CLI can return data, but it cannot decide whether that data answers the user’s question. A local credential can exist, but it may be expired or insufficient for a particular operation. The channel contract keeps those facts from being silently merged.

This is also why Agent Reach does not need to expose a large internal API for every content type. The project’s own core class is centered on health reporting. Its optional MCP server exposes a status tool rather than replacing the tools that read pages, search services, or retrieve media. The agent remains the caller of the upstream interface. That choice reduces one kind of coupling: Agent Reach does not have to normalize every external response into a permanent house format before the agent can use it.

But the choice has a cost. The calling agent still needs to understand what the selected upstream tool expects and what its output means. A skill document can provide that operational knowledge, but it cannot erase the differences between a YAML response from a browser bridge, a JSON response from a public API, a subtitle file, and a cleaned web document. Agent Reach standardizes the decision about where to look; it does not standardize the entire meaning of what comes back.

The boundary is easiest to see if we follow a single request rather than a component list. The agent first names an intended capability: perhaps it wants a discussion thread, not merely the home page of a platform. The channel supplies the platform-specific route policy. Configuration may promote a backend that fits the user’s environment. Doctor supplies evidence about what is installed, executable, connected, or deliberately unverified. The agent then invokes the selected upstream tool, whose request and response remain outside the channel abstraction. If the returned content is empty or the operation is unsupported, the agent must decide whether the route’s fallback preserves the original goal. No component can skip the meaning of the request and still select responsibly.

classDiagram class Agent class Channel class Backend class Configuration class Doctor Agent --> Channel : requests capability Channel --> Configuration : reads override Channel --> Doctor : exposes health result Channel --> Backend : selects candidate Doctor --> Backend : probes safely Agent --> Backend : invokes directly

This arrangement avoids two opposite mistakes. One is under-abstraction: every agent independently memorizes that a particular platform needs a particular CLI, browser session, or MCP entry. That repeats operational knowledge and makes a new installation fragile. The other is over-abstraction: a wrapper presents every source as if it had the same authentication, query language, response shape, and failure behavior. That makes the interface look tidy while hiding the conditions under which it breaks. Agent Reach occupies the middle position. It centralizes the route decision and the health vocabulary, but leaves the content operation visible.

The middle position also gives the project a place to record negative knowledge. A candidate list can say not only which backend is preferred, but which one should no longer be used for a particular platform or which one is retained only for existing installations. A health message can say that a service is configured but not live-tested. A tier can signal that a capability is available only after user involvement. These are not incidental annotations. They prevent an agent from converting an old command, an installed package, or a successful version check into a stronger claim than the system can support.

Why Order and Direct Invocation Matter

An ordered backend list turns change into a policy update. Suppose a platform begins rejecting requests from a previously reliable CLI. A tightly wrapped integration would need a new adapter, a migration path, and perhaps a new internal response schema. In Agent Reach’s model, the channel can promote another candidate while preserving the old one as a fallback when it remains useful. The important engineering work has not vanished—the replacement still needs to be installed, checked, and documented—but it is localized to route selection and the relevant channel boundary.

The Bilibili case shows why this policy must be specific to both platform and operation. The repository records that yt-dlp requests were receiving HTTP 412 under Bilibili’s risk controls. It therefore removes yt-dlp from that channel’s preferred path, while retaining yt-dlp as the YouTube backend. Bilibili’s bili-cli can cover search and video details without login, and OpenCLI can cover subtitles through a browser session. Those routes are related, but they are not interchangeable. A backend that handles video metadata may not handle subtitles; a browser-backed route may have an authentication requirement that a public search route does not.

The ordered list therefore expresses more than a ranking of tools. It encodes a set of assumptions:

  1. which operation is being served;
  2. which environment the route expects;
  3. what evidence counts as usable;
  4. what feature coverage the fallback preserves; and
  5. what the user must do when all candidates stop short.

That is why a fallback is not automatically equivalent to the preferred backend. The route can preserve the user’s broader goal while changing the available features, the login model, the response shape, or the risk of failure. A careful agent should not say “Bilibili works” when the evidence only establishes search, or “Twitter is ready” when credentials are stored for Doctor but have not been placed in the environment of the direct twitter process.

Agent Reach also allows a user to move a preferred backend to the front. A channel can honor a configuration key such as <channel>_backend, and the matching candidate is promoted without removing the remaining list. This is useful when the project’s default preference does not fit a user’s environment. A desktop user may prefer a browser-session route; a server operator may need a command-line or MCP route. The override changes preference, not reality. If the requested backend is unavailable, the other candidates remain visible to the selection logic. If the override names something unknown, it is ignored rather than allowed to hide a working path.

This behavior reveals a useful separation between policy and evidence. The ordered list is policy: it expresses what the project currently recommends. The check result is evidence: it reports what the environment can support. An override is another policy input. active_backend is the resulting claim, and the claim is meaningful only in the context of the check that produced it. Keeping these concepts separate prevents a stale configuration value from masquerading as a successful route.

The selection logic also needs to distinguish a fully usable candidate from one that is merely present but incomplete. The repository’s multi-backend channels collect candidate findings and prefer an ok result before falling back to a warn result when no candidate is fully usable. That ordering avoids a subtle failure: an installed but unconfigured preferred CLI should not block a later candidate that is genuinely usable. Conversely, a warning can still be valuable because it identifies the next fixable step. The system is not choosing between “truth” and “failure”; it is preserving the difference between evidence of readiness and evidence of a possible route.

The architecture is easiest to misunderstand when “direct invocation” sounds like a lack of abstraction. In fact, it is a deliberate abstraction boundary. Agent Reach abstracts the decision to select, install, inspect, and maintain a route. It leaves the actual operation to the upstream tool so that platform-specific behavior remains observable. If a Twitter command requires two explicit environment variables, that requirement belongs to the Twitter tool and its security boundary. If a Bilibili subtitle command needs a browser extension, that dependency should remain visible. If a public V2EX endpoint lacks full-text search, a wrapper that presents every channel as a generic search API would mislead the agent.

Direct invocation also changes the maintenance trade-off. Agent Reach can update its route policy, but it cannot freeze the upstream tools’ command syntax or release cadence. A user gains the ability to use familiar ecosystem tools, while retaining exposure to their changes. The project’s skill documentation is therefore part of the interface: it tells an agent which command group belongs to which backend and which retry chain applies when an operation fails. The documentation must stay aligned with the code and with the platform’s current behavior.

That last condition is visible in the project’s treatment of legacy backends. A tool may remain installed as a compatibility fallback even after the project stops recommending it for new users. The route policy must therefore carry maintenance context, not just a command name. An ordered backend contract is only as trustworthy as the evidence and maintenance process behind it: a candidate can be present, executable, and still be a poor default because its upstream is no longer maintained or because its feature coverage has narrowed.

The contract answers the question raised in the previous discussion: what can Agent Reach control if it does not perform the reading? It can control the representation of a capability, the order in which routes are considered, the evidence required before a route is called active, and the amount of setup exposed to the user. It cannot control the platform’s defenses, the upstream tool’s complete behavior, or the truth of content returned by a successful command. The next practical question follows naturally: how can the project check those routes without creating new side effects or claiming more readiness than it has observed?

References