Skip to content

feat(cli): add agent-reach route for URL to channel/backend/command - #614

Closed
AbdulrahmanAmer wants to merge 1 commit into
Panniantong:mainfrom
AbdulrahmanAmer:feat/route-command
Closed

feat(cli): add agent-reach route for URL to channel/backend/command#614
AbdulrahmanAmer wants to merge 1 commit into
Panniantong:mainfrom
AbdulrahmanAmer:feat/route-command

Conversation

@AbdulrahmanAmer

@AbdulrahmanAmer AbdulrahmanAmer commented Aug 13, 2026

Copy link
Copy Markdown

Follow-up to #613, separate branch so you can take them independently.

While I was in the channels code for the doctor change I hit something else. When my agent has a URL in hand, there's no way for it to ask which platform owns it and what to run. That mapping only exists as prose in SKILL.md plus the reference docs, so the agent has to read the skill and work it out. doctor --json tells it what's healthy, never what handles this particular link.

So, agent-reach route <url>, with --json for the agent:

$ agent-reach route https://www.xiaohongshu.com/explore/abc
URL      : https://www.xiaohongshu.com/explore/abc
渠道     : xiaohongshu — 小红书笔记
后端顺序 : OpenCLI、xiaohongshu-mcp、xhs-cli (xiaohongshu-cli)
命令     :
  [OpenCLI] opencli xiaohongshu note "https://www.xiaohongshu.com/explore/abc" -f yaml
  [xhs-cli (xiaohongshu-cli)] xhs read "https://www.xiaohongshu.com/explore/abc"
参考文档 : agent_reach/skill/references/social.md
提示     : 运行 `agent-reach doctor --json` 查看当前实际生效的后端

The part I'd most want your opinion on is where the commands come from. I did not want this thing guessing CLI flags, so there's a per-channel url_commands map and I only filled in backends where your own references show the tool taking a URL or ID: twitter-cli tweet URL_OR_ID, opencli xiaohongshu note NOTE_URL, xhs read NOTE_ID_OR_URL, yt-dlp, Jina Reader, feedparser. Bilibili, Reddit and V2EX read by id or keyword, so they print no command at all and send the agent to the reference doc. Printing something that looks right but doesn't run seemed worse than printing nothing.

Rest of it:

  • WebChannel.can_handle() is True for everything, so routing skips it while matching and only falls back to it. Otherwise where it sits in the registry would decide every answer.
  • if a channel's can_handle throws, it gets skipped rather than breaking routing for everything else. Same thing doctor already does with check().
  • no subprocess, no network, no writes, Config(read_only=True). It's meant to be cheap enough to call per URL. Two tests hold that line: one makes subprocess.run and Popen raise, one asserts the config dir never gets created.
  • goes through the existing ordered_backends(), so a <channel>_backend override moves the command to the front too and route agrees with doctor.

Also gave every channel a reference field so the routing table has a machine-readable pointer to the doc the agent should read next. There's a test that opens each one, so it fails if a reference doc gets renamed.

Documented in both SKILL.md and SKILL_en.md under the environment check section, since that's where an agent is already looking.

571 existing tests still pass, 41 new ones in tests/test_route.py: routing for all 15 channels, the fallback, bad input, {url} substitution and ordering, the override, plus consistency checks that no url_commands key names a backend that isn't declared and every template actually contains the placeholder.

An agent holding a URL had no programmatic way to ask which platform owns it
or what to run: that knowledge lived only in SKILL.md prose, so the agent had
to read the skill and its reference docs and infer the mapping. `route`
answers it in one call, in text or JSON.

Routing skips WebChannel while matching (its can_handle is True for every URL)
so a specific channel always wins over the fallback regardless of registry
order, and a channel whose matcher raises is skipped instead of breaking
routing for every other platform.

Commands come from a new per-channel `url_commands` map, populated only for
backends whose upstream CLI documents accepting a URL/ID in this repo's own
references. Backends that read by id/keyword (Bilibili, Reddit, V2EX) emit no
command and point at the reference doc instead — printing a plausible but
wrong invocation would be worse than printing none.

route is metadata-only: no subprocess, no network, no writes, so it is cheap
enough to call per URL. Tests pin all of that, including the no-subprocess and
no-disk-write guarantees.
@AbdulrahmanAmer AbdulrahmanAmer changed the title feat(cli): add agent-reach route — URL to channel, backend and command feat(cli): add agent-reach route for URL to channel/backend/command Aug 13, 2026
@AbdulrahmanAmer AbdulrahmanAmer closed this by deleting the head repository Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant