关于 byo-proxy
byo-proxy 是面向希望让其他技能使用自有 IPRoyal 代理账户的配置技能。它保存凭据和技能绑定,并提供构建代理 URL 的 Python 接口;自身不运行代理服务,也不拦截流量。
主要功能
- 01保存 IPRoyal 凭据
- 02为技能绑定代理设置
- 03构建轮换或粘性代理 URL
- 04登记专用 ISP 代理
- 05测试代理连通性
适用场景
- 01为爬虫配置特定国家的住宅 IP
- 02让技能绑定粘性会话或专用 IP
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ starchild-ai-agent/ official-skills --skill byo-proxy安装后在 Claude Code 中输入/byo-proxy确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
exports.pyreferences/iproyal-isp.mdiproyal.mdscripts/add_isp_proxy.pybind_skill.pylist_providers.pyonboard.pysetup_provider.pytest_proxy.py详细介绍
byo-proxy —— 自带代理
用户提供自己的代理账户(目前支持 IPRoyal);此技能负责存储
凭据、维护 skill → provider 绑定表,并提供一个简洁的 Python API,供其他技能选择使用。
此技能不会运行代理服务器,也不会拦截任何流量。
只有显式从 exports.py import 的其他技能才会因此改变行为。
与现有代理技能的边界
| 技能 | 功能 | 适用场景 |
|---|---|---|
sc-vpn | 内部 VPN 网关,支持 18 个固定国家,无需身份验证 | 在 Starchild 内访问受地理位置限制的请求时的最后手段 |
transparent-proxy-maintenance | 维护平台的计费代理插件 | 对 sc-proxy 进行运维 |
byo-proxy(本技能) | 管理用户自己的服务商密钥和每个技能的绑定 | 用户需要住宅 IP、付费账户、超出 sc-vpn 的 18 个国家的国家/地区粒度,或专用固定 IP |
支持的服务商
| 服务商 | 类型 | 端点 | IP 行为 | 身份验证 |
|---|---|---|---|---|
iproyal | 网关 | geo.iproyal.com:12321 | 轮换;每个会话的粘性 IP 最长 ≤ 7 天 | 账户用户名 + 密码 |
iproyal-isp | isp | 每个 IP 独立配置 host:port(例如 191.116.125.248:12323) | 专用,永不变更 | 每个代理各自的用户名 + 密码 |
两种“固定 IP”形式:
- 粘性会话(
iproyal+--session+--sticky)→ 最长 7 天使用同一个出口 IP, 之后可能因地址池轮换而变更。价格低廉(按 GB 计费)。 - 专用静态 IP(
iproyal-isp)→ 为你保留且永不变更的 IP。按 IP 计费,流量不限。这就是“永久固定 IP”。
如需添加更多服务商:在 PROVIDERS 中添加条目,并在
exports.py 中添加 URL 构建器。参见 references/iproyal.md(住宅代理)和
references/iproyal-isp.md(专用代理)。
存储
- 账户凭据(网关服务商)→
/data/workspace/.env(与polymarket、birdeye、coingecko使用相同的约定)。键:IPROYAL_USERNAME、IPROYAL_PASSWORD。 - 绑定 + ISP 代理清单 →
/data/workspace/.byo-proxy.json:
ISP 凭据按 IP 配置,因此存放在此处(以本地{ "bindings": { "web-crawler": { "provider": "iproyal", "country": "jp", "session": "crawler-jp", "sticky_minutes": 360 } }, "isp_proxies": { "jp-1": { "host": "191.116.125.248", "port": 12323, "socks_port": 12324, "username": "…", "password": "…", "label": "Tokyo ISP" } } }proxy_id为键),而不是.env中。两个文件只能通过脚本编辑;Agent 不应手动编辑。仅包含旧版绑定的文件会在下次保存时自动迁移。
用户工作流
SKILL=/data/workspace/skills/byo-proxy
# ── Residential gateway (rotating / sticky) ──────────────────────────────────
# 0. One-shot onboarding — prompts for creds only if missing, binds, live-tests:
python3 $SKILL/scripts/onboard.py web-crawler --provider iproyal --country jp
# 1. Register credentials (interactive — prompts for username/password)
python3 $SKILL/scripts/setup_provider.py iproyal
# 2. Bind a skill (long-term preference)
python3 $SKILL/scripts/bind_skill.py web-crawler --provider iproyal --country jp
# Pin one exit IP for up to 7 days (sticky needs a session id):
python3 $SKILL/scripts/bind_skill.py web-crawler --provider iproyal --country jp \
--session crawler-jp --sticky 360 # 6 hours
# ── Dedicated static IP (permanent) ─────────────────────────────────────────
# 3. Register a purchased ISP proxy (interactive if flags omitted), then bind:
python3 $SKILL/scripts/add_isp_proxy.py jp-1 \
--host 191.116.125.248 --port 12323 --socks-port 12324 \
--username <user> --password <pass> --label "Tokyo ISP"
python3 $SKILL/scripts/bind_skill.py web-crawler --provider iproyal-isp --proxy-id jp-1
# Or one-shot: python3 $SKILL/scripts/onboard.py web-crawler --provider iproyal-isp
# ── Inspect / verify / clean up ────────────────────────────────────────────
python3 $SKILL/scripts/list_providers.py # providers, ISP proxies, bindings
python3 $SKILL/scripts/test_proxy.py iproyal --country jp
python3 $SKILL/scripts/test_proxy.py iproyal-isp --proxy-id jp-1
python3 $SKILL/scripts/bind_skill.py web-crawler --unset
python3 $SKILL/scripts/add_isp_proxy.py --list
python3 $SKILL/scripts/add_isp_proxy.py --remove jp-1 [--force]
其他技能如何使用
有两种模式。配置错误时,两者都会引发 ProxyNotConfiguredError,绝不静默回退(代理用户正在排查地理位置或身份问题;静默改用直接连接会让排查困难得多)。
模式 A——显式、单次使用
import sys, requests
sys.path.insert(0, "/data/workspace/skills/byo-proxy")
from exports import get_proxy_url
p = get_proxy_url(provider="iproyal", country="jp") # rotating
p = get_proxy_url(provider="iproyal", country="jp",
session="crawler-jp", sticky_minutes=360) # sticky 6h
p = get_proxy_url(provider="iproyal-isp", proxy_id="jp-1") # dedicated IP
r = requests.get("https://example.com", proxies={"http": p, "https": p}, timeout=30)
模式 B——绑定后长期使用
适用于始终希望通过用户为其配置的代理路由的技能:
import sys, requests
sys.path.insert(0, "/data/workspace/skills/byo-proxy")
from exports import get_proxy_for_skill, ProxyNotConfiguredError
try:
p = get_proxy_for_skill("web-crawler") # caller declares its own name
except ProxyNotConfiguredError as e:
# The exception message IS a multi-line onboarding guide for the user —
# surface it verbatim. It includes the signup URL, pricing note, and the
# one-shot `onboard.py` command to fix the situation.
raise SystemExit(str(e))
r = requests.get(url, proxies={"http": p, "https": p}, timeout=30)
get_proxy_for_skill 与服务商无关:无论用户绑定的是轮换国家、粘性会话还是专用 ISP IP,它都会返回正确的 URL。即使用户已配置绑定,不 import 它的技能也不会受到影响。仅在选择使用时启用。
未配置技能的引导流程
当 get_proxy_for_skill("X") 因未为 X 配置任何内容而引发异常时,异常消息本身就是完整的引导脚本:包含注册 URL、定价、凭据位置,以及要运行的确切 onboard.py 命令。将此错误展示给用户的 Agent 会自然地引导他们完成注册和绑定,无需调用技能添加额外逻辑。
如果调用技能希望自行呈现引导 UI(而不是依赖错误消息),可以直接导入相同的文本:
from exports import onboarding_guide
print(onboarding_guide("web-crawler", provider="iproyal", country="jp"))
print(onboarding_guide("web-crawler", provider="iproyal-isp"))
公共 API(exports.py)
| 函数 | 返回值 | 引发的异常 |
|---|---|---|
get_proxy_url(provider, country=None, sticky_minutes=None, session=None, proxy_id=None) | str 代理 URL | 凭据/代理缺失时引发 ProxyNotConfiguredError;provider/country/参数错误时引发 ValueError |
get_proxy_for_skill(skill_name) | str 代理 URL | 未绑定、provider 不存在、凭据或 ISP 代理缺失时引发 ProxyNotConfiguredError(包含多行引导指南) |
onboarding_guide(skill_name, provider="iproyal", country="<cc>", proxy_id=None) | str 引导文本 | provider 错误时引发 ValueError |
list_providers() | list[dict] — {provider, kind, configured, …} + bound_skills | 不会 |
set_binding(skill_name, provider, country=None, sticky_minutes=None, session=None, proxy_id=None) | None | provider/country/参数错误或 ISP 代理未注册时引发 ValueError |
unset_binding(skill_name) | None | 不会 |
add_isp_proxy(proxy_id, host, port, username, password, socks_port=None, label=None) | None | id/host/port 错误时引发 ValueError |
remove_isp_proxy(proxy_id, force=False) | 仍绑定的技能组成的 list | 代理仍被绑定且未指定 force 时引发 ValueError |
list_isp_proxies() | list[dict] — {proxy_id, endpoint, socks_endpoint, label, bound_skills}(凭据已隐藏) | 不会 |
test_proxy(provider, country=None, proxy_id=None, timeout=15) | dict — {ok, exit_ip, geo_country, latency_ms} | ProxyNotConfiguredError / ValueError |
粘性时长范围:sticky_minutes ∈ 1..10080(7 天)。sticky_minutes 需要
session(IPRoyal 的 lifetime- 仅适用于 session-)。
仅针对单个请求 — 不设置全局代理
规则与 sc-vpn 相同:绝不要从此技能的 URL 执行 export HTTP_PROXY=...。
仅对特定请求传入 proxies=。设置全局环境变量会
影响无关技能(尤其是付费 API 的 sc-proxy 流量)。
故障排除
| 错误 | 原因 | 修复方法 |
|---|---|---|
Skill 'X' has no proxy binding | bindings 中没有 X 的条目 | python3 scripts/onboard.py X --provider iproyal --country <cc>(或 --provider iproyal-isp) |
... USERNAME / ... PASSWORD not found | 网关凭据从未保存(或已从 .env 中删除) | python3 scripts/setup_provider.py iproyal(或重新运行 onboard.py) |
ISP proxy 'X' is not registered | 绑定引用的 id 不存在于 .byo-proxy.json 中 | python3 scripts/add_isp_proxy.py X --host … --port … --username … --password … |
... bound to unknown provider | bindings 引用了已不存在的 provider | 重新绑定,或执行 bind_skill.py X --unset |
sticky_minutes requires a session id | 使用了 --sticky,但未使用 --session | 添加 --session <id>(IPRoyal 的 lifetime- 需要 session-) |
sticky_minutes must be between 1 and 10080 | 超出范围 | 最大值为 7 天 |
ValueError: Unknown country code 'XX' | 不在 IPRoyal 支持的列表中 | 请参阅 references/iproyal.md |
test_proxy 返回 ok=false | 凭据/主机错误、账户过期或网络问题 | 检查控制面板;对于 ISP,重新注册代理字符串 |
文件
byo-proxy/
├── SKILL.md
├── exports.py # public API for other skills
├── scripts/
│ ├── onboard.py # one-shot: register (if needed) + bind + test
│ ├── setup_provider.py # interactive gateway credential setup
│ ├── add_isp_proxy.py # register/list/remove dedicated ISP proxies
│ ├── list_providers.py # show providers + ISP proxies + bindings
│ ├── bind_skill.py # set/unset skill→provider binding
│ └── test_proxy.py # verify exit IP via ifconfig.co
└── references/
├── iproyal.md # residential gateway: params, sticky sessions
└── iproyal-isp.md # dedicated static IPs: per-IP endpoint + auth