Stores durable facts in a categorized, plain-markdown vault on disk, alongside your agent's built-in memory.
Coding
skillhub-publish-skill
Try it把本地 Skill 打包并发布到 SkillHub(腾讯 skillhub.cn)与 ClawHub,覆盖预检、发布、状态回读与竞品对标全链路,并在上传被拒时用二分/ddmin 脚本把「服务端 WAF 拦内容(566)」与「包结构/字段问题」精确区分开。当用户说「发布技能到市场」「上架 skill」「SkillHub 提交失败」「Failed to fetch」「566」「上传 zip 报错」「技能审核状态」「版本号被拒」时使用。也讲清「入库成功 ≠ 已公开」——用 `mine` 的 `reviewStatus`、重发探测 `409 VERSION_EXISTS`、`/versions/<v>/signature` 三个探针判断版本到底走到哪一步。
What it does
发布一个技能实际要同步三个地方:**GitHub**(源码)、**SkillHub**(腾讯主市场)、**ClawHub**(海外市场)。 本技能覆盖全链路,并在任何一步被拒时给出**可定位根因**的判定,而不是猜。
The skill document
SkillHub / ClawHub 技能发布
发布一个技能实际要同步三个地方:GitHub(源码)、SkillHub(腾讯主市场)、ClawHub(海外市场)。 本技能覆盖全链路,并在任何一步被拒时给出可定位根因的判定,而不是猜。
铁律:报错先分类,别乱猜
上传失败的报错只有四类,每类的对策完全不同,先看报错文案归位:
| 报错文案 | 类别 | 对策 |
|---|---|---|
不支持的文件类型: xxx | 包内容 | 用 scripts/publish.py 发(它按白名单自动过滤) |
字段格式校验 类 | 包内容 | 跑 scripts/preflight.py 查 frontmatter |
slug 已被占用 / 409 / 500 | slug 冲突 | publish.py 会自动追加后缀重试并回写 SKILL.md |
提交失败 / Failed to fetch / net::ERR_FAILED 566 / CORS 报错 | 服务端 WAF 拦内容 | 跑 scripts/waf_bisect.py 定位,改内容,别改结构 |
不要把第四类当成网络/代理/浏览器扩展问题。判据是客观的:用本机脚本向发布端点 POST 同一份 multipart,
401 就说明请求已到达应用层(正常,只差登录态),566 才是被 WAF 拦。
这一条是本技能与其他发布类技能的核心差别。其他工具只处理 400/409/429, 遇到 566 会误导你去「检查元数据与文件类型」——方向完全错了。
铁律二:查不到 ≠ 不存在
判断「某个技能有没有」「上架了没有」之前,先确认你用的接口能看到什么范围。 公开接口天然过滤掉未公开、审核中、已下架的条目 —— 拿它当「是否存在」的判据会得到假阴性。
| 想知道什么 | 用哪个 | 别用哪个 |
|---|---|---|
| 这个技能公开发布了吗 | status (公开搜索) | — |
| 我到底发过哪些(含测试残留) | mine(我的后台) | ❌ 公开搜索查不到 |
| 某个 slug 归谁 | status / 看 namespace.handle | — |
之前踩过的具体坑:用公开搜索查自家测试探针,搜不到就判定「已被平台自动清理」,
实际 18 个条目里 12 个探针都还挂在「我的 Skills」里。清点自己发了什么,永远用 mine。
标准工作流
Step 1 预检(不联网,可做卡点)
python scripts/preflight.py # 人读报告
python scripts/preflight.py --json # Agent 解析
三级输出:ERROR(会被拒,必须修)/ WARN(能过审但影响质量)/ INFO(发布操作提醒)。 存在 ERROR 时退出码为 1,可直接接发布脚本卡点。
覆盖:frontmatter 缺字段与非法值、位图与独立 LICENSE 拒收、包结构与白名单、密钥泄漏、安全红线、 占位符残留、WAF 命中特征(本脚本独有)。
Step 2 确认元数据
python scripts/publish.py validate
缺 slug / version / displayName 会明确列出。补进 SKILL.md frontmatter——这些字段不影响 skill 本地运行。
Step 3 预演(不上传)
python scripts/publish.py publish --version 1.4.0 --dry-run
打印将要上传的文件清单、体积、图标识别结果、被排除的文件及原因,
以及与线上版本的比对结果(versionCheck: OK / SAME / TOO_OLD)。确认无误再真发。
Step 4 发布
python scripts/publish.py publish --version 1.3.0 --changelog "变更说明" \
[--icon icon.png] [--category dev-programming] [--subcategory dev-script]
脚本自动完成:白名单过滤 → 图标两步上传 → 分类 key 校验 → 429 指数退避 → slug 冲突自愈。
成功返回 skillId / versionId / slugUsed / category / subCategories;
失败会打印分类结论 + 下一步动作。
分类建议写进 SKILL.md frontmatter(比分次传参可靠,下次发版自动带上):
category: dev-programming
subCategories: [dev-script, dev-code-gen]
不填分类的话平台会显示「未分类」——注意「选填」不等于可以不管,
市场里未分类的条目曝光会明显吃亏。可选值用 publish.py categories 查。
带图标时务必确认响应里 iconAuditStatus: "pending" —— 若是 null 说明图标没收到
(那通常意味着把图片错当成 multipart part 传了,见上方「图标」注意事项)。
分类则看响应里有没有回显 category 字段。
Step 5 验证发布结果(不用开浏览器)
python scripts/publish.py status # 传目录会自动比对本地/线上版本
python scripts/publish.py status # 只查线上
输出线上版本、下载/安装/收藏数、更新时间,并给出同步状态:
| 同步状态 | 含义 |
|---|---|
✓ 已同步 | 本地版本 == 线上版本,审核已通过 |
↑ 本地更新 | 本地版本更高 —— 还没发,或已提交仍在审核中 |
✗ 版本倒挂 | 本地版本 ≤ 线上版本 —— 发上去会被服务端拒 |
⚠️ search 索引有延迟:刚发布(还在审核)的版本不会立即出现在查询结果里, 可能仍显示上一个线上版本。这是正常的,不是发布失败。
⚠️
status走的是公开搜索接口,看不到未公开条目。要清点「我到底发过什么」 (含审核中、已下架、测试残留),用mine命令 —— 那是另一个接口(/api/v1/dashboard/skills)。
「入库成功」≠「已公开」——两个状态分别怎么查
publish 返回 200 / skillId 只代表版本已入库;能不能被搜到、能下到什么版本,
取决于审核(reviewStatus)。2026-09-29 实测:连发 1.1.1 → 1.1.2 → 1.1.3 三次 CLI
全部返回成功,但公开索引 latestVersion 长时间停在 1.1.1(search、download、
/versions//signature 全指向旧版),一度误判「后两次没发上去」。
权威状态看 mine(/api/v1/dashboard/skills):
{ "version": "1.1.3", "status": "listed", "reviewStatus": "pending" }
status: listed + reviewStatus: pending = 已入库、审核中。此时公开索引滞后属正常,
等审核过即可 —— 不要重发(重发只会撞 409,白折腾)。
不开后台也能自证的两个探针:
| 想知道 | 怎么查 | 判据 |
|---|---|---|
| 版本是否已入库 | 用同版本号重发一次(publish --version ) | 409 VERSION_EXISTS = 已入库;返回 200 = 之前确实没发上 |
| 版本是否已公开 | GET /api/v1/skills/?namespace= 看 latestVersion;或 GET /api/v1/open/skills//versions//signature | signature 200 = 已公开;404 = 未公开 |
latestVersion里带changelog—— 用它反查线上到底是哪一次发布,比只看版本号更直接 (本次正是靠 changelog 认出线上仍是 1.1.1 那次写的文案)。 注意curl查这些公开端点要加--noproxy '*'(本机全局代理会干扰)。
Step 6 清点与清理自己的技能
python scripts/publish.py mine # 列出我名下全部技能(含线上搜索看不到的)
python scripts/publish.py mine --json # 机器可读
python scripts/publish.py rm # 只提示,不执行(安全护栏)
python scripts/publish.py rm --yes # 确认删除:自动「先下架 → 再删除」
mine 与 status 的区别(踩过坑,别搞混):
| 命令 | 数据源 | 看得到什么 |
|---|---|---|
status | 公开搜索 /api/v1/search | 只有已公开条目;未过审/已下架的查不到 |
mine | 我的后台 /api/v1/dashboard/skills | 我发的全部:审核中、已下架、测试残留都在 |
删除是两步(服务端强制):直接 DELETE 会返回 409 只能删除已下架的 Skill,请先下架。
rm 已自动串好 /unlist → DELETE,并对「已下架再删」的重复调用做了容错。
删除不可恢复,所以默认不给 --yes 就只打印风险提示、不执行。
Step 7 ClawHub
clawhub skill publish \
--slug --name "<显示名>" \
--categories "<14 项之一>" --topics "a,b,c" \
--changelog "..."
--source-repo / --source-commit 成对给或都不给,只给一个报 must be provided together。
-
ClawHub CLI 没有
inspect/search(v0.23.3 实测,skill子命令只有publish / verify / tag / rename / merge)。要查「slug 是否被占用 / 线上审核状态」只能用clawhub skill verify;想要竞品下载量数据得回到 SkillHub 侧的publish.py compare。 -
审核期(含刚提交后)
verify返回Skill is hidden by moderation (pending.publication)—— 这是正常状态,不是失败。发布成功的判据是 publish 时那句Update submitted ... pending security scans。 -
⚠️
verify还会返回安全扫描结论——这才是真正会卡住公开的东西(2026-09-29 实测)。 形如{"decision":"fail","reasons":["card.missing","security.status_not_clean"], "security":{"status":"suspicious","confidence":"high","summary":"..."}}:card.missing= 展示卡未生成(审核产物);security.status_not_clean= 扫描未过。suspicious的常见触发:host-policy bypass guidance、high-impact admin elevation、risky credential/config handling、unauthenticated local proxy、local gateway spoofing。 -
⚠️⚠️ summary 只是概述,真实判据在
security.scannerReports..runs[].results[]—— 含ruleId(T01–T0x,扫描器为腾讯 AI-Infra-Guardaig-skill-scan)、精确到文件行号、 一句话原因。只看 summary 会猜错方向:本案 v1.1.1 依 summary 改了措辞就重发, 到 v1.1.2 才发现真实判据是两条代码问题 ——T05 scripts/ccproxy.py:229 Unauthenticated local clients can consume the configured upstream credential与T07 scripts/ccswitch.py:153 Local gateway spoofing can intercept Claude Code traffic。 先挖判据(建议固定用这条,别凭 summary 猜):
clawhub skill verify --version | python -c "
import sys,json
for name,rep in (json.load(sys.stdin)['security'].get('scannerReports') or {}).items():
for run in rep.get('runs',[]):
for r in run.get('results',[]):
print(name, r.get('ruleId'), '|', (r.get('message') or {}).get('text','')[:200])
"
-
改措辞常常不够,要改代码:凡技能涉及「本地起服务 / 监听端口 / 改用户配置」, 扫描器会要求真实防护,必须在实现里做出来、并在 SKILL.md 明写: 入站鉴权(不符返回 401)、对端身份校验(健康检查须校验自身标识)、只绑回环、 配置改动有备份。本案 v1.1.2 补的正是「客户端令牌 +
service=ccproxy校验」; 同时删掉与技能无关的提权/沙箱叙事、把NO_PROXY=*收敛为回环地址列表。 -
区分「措辞问题」与「性质问题」,别无限投入:判据若是「某行代码缺防护」→ 改代码能过; 若是技能功能本身(如「本地网关转发敏感提示与凭证」)→ 加鉴权只降风险等级、 往往仍判 fail。这类就止损:GitHub + SkillHub 两路已能公开分发,ClawHub 不公开 不影响安装或使用(用户 2026-09-29 即选择「接受现状」)。 想真正过 ClawHub 只剩「拆技能」——把触发判定的模块独立成另一个包。
-
verify --version只能验已公开的版本;刚提交的版本返回Version not found(扫描中,正常,不是发布失败)。实测 >5 分钟仍Version not found也正常, 别误判;发布成功的判据始终是 publish 那句Update submitted ... pending security scans。 -
对比实测:SkillHub 侧
mine里新提交的技能会直接显示listed(公开搜索status则可能 因索引延迟查不到),两者不矛盾。
两条容易白费功夫的约束(详见 references/clawhub-catalog.md):
- ClawHub 没有图标能力 —— CLI 全量无
--icon/--logo参数,SKILL.md 里放.png对它无效。别为 ClawHub 折腾图标链路。 - ClawHub 的分类 slug 是另一套(只有 14 个),与 SkillHub 的 13 个一级 key
完全不通用。最容易踩的是
developer-tools❌ → 正确是development。 传错报Unknown skill category slug;超过 3 个报Categories are limited to 3。 - 传了
--categories/--topics就一定发新版本(即使文件没改)——这是给 已发布技能补分类的官方路径,CLI 会自动 bump patch。
Step 8 GitHub
见 references/github-repo.md。本机已有可用凭据,不需要向用户索要 PAT。
版本递增是硬性要求
服务端要求更新时 version 必须严格高于线上版本(相同或更低都会被拒)。
publish 命令会在发布前自动比对并拦下,避免白发一次:
{ "success": false, "blockedBy": "version_check",
"localVersion": "1.2.9", "remoteVersion": "1.3.0",
"error": "版本号 1.2.9 比线上 1.3.0 更低,服务端会拒绝更新",
"fix": "把版本号改成高于 1.3.0 的值(如升到 1.3.1),或加 --force 跳过此检查" }
- 首次发布(线上查不到该 slug)会自动跳过检查。
- 网络异常时降级为提示,不阻断发布。
- 确需绕过:
--force。
竞品对标
python scripts/publish.py compare "<关键词>"
按下载量列出同类技能,用客观数据判断投入方向 —— 比凭感觉判断「我们有什么优势」可靠:
关键词「skill 发布」同类技能(按下载量排序)
版本 下载 安装 技能
1.2.1 998 26 ClawHub Skill 发布避坑指南 @clawhub_tudoubudou
1.0.1 83 0 开源发布(GitHub Skill 发布器) @user_73cb5b59
下载量反映曝光面,安装量反映真实使用。
对新技能的启示(2026-09-29 实测):
compare的返回顺序暴露了平台搜索/推荐的排序偏好 —— 头部清一色是百万级下载的通用技能(编程专家、腾讯文档、Find Skills…), 一个刚发布的垂直小技能几乎不可能靠关键词搜索被刷到。所以「已发布」≠「别人搜得到」。 新技能的可发现性基本只来自两处: ① 描述里的长尾触发词(把用户会说的口语原话写进去,如「claude code 换模型不生效」 「ANTHROPIC_BASE_URL 怎么设」「响应流畸形」); ② 外部引流(分享链接 / 公众号 / GitHub README)。 另外status(公开搜索)有索引延迟:刚发布几分钟内查不到属正常,用mine看真实落库状态。
三平台版本必须一致
发布前对齐六个地方的 slug/name:本地目录名、SKILL.md name、SKILL.md slug、manifest name、
GitHub 仓库名、ClawHub --slug。
SkillHub 已发布的 slug 不可改(更新对话框里只读、无改名入口),所以它以 SkillHub 为准当「锚」, 其余平台向它对齐,不要新建重复 Skill。
资源路由
| 文件 | 什么时候读 |
|---|---|
scripts/preflight.py | Step 1;发布前必跑 |
scripts/publish.py | Step 2-6;日常发布主入口(含 status / compare / mine / rm / categories) |
scripts/waf_bisect.py | 出现 566 / Failed to fetch 时定位根因 |
references/waf-details.md | 需要理解 WAF 命中特征、判据原理与规避写法时 |
references/icon-upload.md | 要传图标/封面,或怀疑图标没生效(iconAuditStatus: null)时 |
references/categories.md | SkillHub 要填/补分类,或后台显示「未分类」时 |
references/clawhub-catalog.md | ClawHub 要填分类/话题,或问 ClawHub 要不要图标时(14 个可用 slug) |
references/path-traps.md | 目录路径没生效、slug 被自动改写,或同名仓库不是扁平技能仓库时 |
references/cli-install.md | 需要安装/修复官方 CLI,或走网页 CDP 兜底路径时 |
references/github-repo.md | 需要建 GitHub 仓库并推送时 |
手头没有现成图标? 用 zero-dep-icon-gen 技能本地生成
(零依赖手写 PNG,不装 Pillow,一条命令出图):
PY="C:/Users/DELL/.workbuddy/binaries/python/versions/3.13.12/python.exe"
$PY ~/.workbuddy/skills/zero-dep-icon-gen/scripts/gen_icons.py \
--spec "my-skill:#4F46E5,#818CF8,browser" -o my-skill/
# 生成 my-skill/my-skill.png,文件名 = slug,find_icon() 会自动兜底找到
可用符号:browser cloud shield folder check download
arrow-up gear search lock text(点阵文字)。--list-symbols 看全量。
打包规范(手工打包时必看)
- 白名单:只收
SKILL.md/manifest.yaml/scripts/*.py。.gitignore/LICENSE/README会被拒。别用 GitHub「Download ZIP」(会带上那几个文件)。实测补充(2026-09-21):
scripts/前缀是放行条件,不限于.py—— 同批上传的scripts/buildkey_cdp.js、scripts/attach_debug.js均被服务端接受 (8 文件全部入库,返回success: true)。也就是说scripts/*.js这类文本文件可以随包发。publish.py的判定是rel in ALLOWED_FILES or rel.startswith(ALLOWED_PREFIXES) or ext in ALLOWED_EXTS, 所以只要放在scripts/、references/、assets/下即可绕过扩展名限制(位图除外)。 2026-09-29 再补:examples/前缀也能过(实测examples/profiles/*.json随包入库, 文件数 4→6、无新增 ERROR)—— 前缀白名单比字面更宽,别急着把示例文件删掉。 另:预检对包内 png 报的 ERROR 属保守判断 ——publish.py会把它排除出包、改走图标单独上传,--dry-run里files不含 png 而icon指向它,属正常,不必为此"修复"。 - 结构:所有文件放进一个与 skill 同名的顶层目录。
- 文件名:
.zip(不带版本号)。≤10MB。 - 图标:走表单单独上传,绝不打进包(zip 内位图会被拒收)。且必须两步走:
先
POST /api/v1/community/skill-icons/upload(multipart 字段名file)拿iconUrl, 再放进payload.iconUrl提交。把图片直接当作cover/iconpart 会被服务端静默忽略 —— 发布仍返回 201,但iconAuditStatus恒为null(pending才是生效)。publish.py --icon xxx.png已封装这条链路,上传失败只告警不阻断发布。 - 打包用 zipfile 手打,键名必须用正斜杠(
os.path.join在 Windows 产生反斜杠会导致KeyError):
import zipfile, os
TOP = ""
with zipfile.ZipFile(out, "w", zipfile.ZIP_DEFLATED) as z:
for rel in ["SKILL.md", "manifest.yaml"] + ["scripts/" + f for f in os.listdir("scripts") if f.endswith(".py")]:
z.write(os.path.join(repo, rel), TOP + "/" + rel)
安全铁律
- 绝不在回复中打印、展示或记录 token(
skh_/gho_/ghp_开头一律脱敏)。 - 发布前必须跑预检、必须获得用户确认。
- 不改动目标 skill 的功能字段,只补平台专用元数据。
- 全程使用绝对路径。
边界与免责
- 预检覆盖已知拒收原因,平台规则随时会变,最终判定以平台审核反馈为准。
- WAF 是累计评分制黑盒,
waf_bisect.py给出的是定位方法而非稳定规则; 命中特征会变化,按「二分定位」的思路排查,别背特征表。 - 预检不是安全审计,不能替代平台安全扫描。
元教训:别信文档,信真实请求
本技能里最贵的两个结论(WAF 566 的真身、图标的两步链路)都不是文档里写的, 而是打真实请求试出来的。踩过的坑值得记住:
- 「接口返回 2xx」不等于「这个字段生效了」。
coverpart 返回 201,但字段被静默忽略。 判断字段是否生效,要看响应体里对应的状态字段(如iconAuditStatus), 而不是看 HTTP 状态码。 - 服务端对不认识的 part 常常静默丢弃,不报错。所以要靠「换个明显非法的值试试」来 反证:如果传一堆垃圾内容它也照收不误,说明它压根没读这个字段。
- 平台只有网页、没有 API 文档时,去前端 bundle 里搜端点名反查真实实现
(见
references/icon-upload.md的「反查方法」),比猜字段名快得多。 - 官方 CLI 没做的功能,不代表平台没有这个 API —— 两边是独立的。
Related skills
Generate and edit Draw.io, Mermaid, and Excalidraw diagrams from natural language using a structured JSON spec.
Join a video meeting as an AI bot with voice, avatar, and screenshare across four operating modes.
Find why your productivity system keeps failing, then apply the smallest fix — capacity math, bottleneck routing, durable local notes.
Fetch raw ad creative, app, ranking, and revenue data from AdMapix as structured JSON.
Write, debug, and tune Playwright specs with locator strategy, trace diagnosis, and CI-aware timeouts.
More from oracis
Browse all skills平台只有网页后台、没有上传 API 时,用本机已装的 Chrome/Edge + CDP 自动化走完上传/发布/填表流程——复用真实登录态、零安装(不下载 500MB Chromium)、能给文件选择框塞文件;并实测富文本编辑器(公众号 / CMS / 邮件模板)里到底哪些 CSS 能活下来,以及在决定是否接入平台自带的「一键排版 / AI 美化」前先抓它输出做结构化 diff。当用户说「只能网页上传」「后台发布」「网页填表自动提交」「发布到技能市场/各平台控制台」「复用已登录的浏览器」「公众号排版样式不生效/保存后样式没了」「一键排版要不要用」「点了按钮没反应/提交没成功也没报错」时使用。
一键安装并实测验证已验证可用的免费 LLM 到 WorkBuddy/Claude Code,无需注册、无需 API Key。当用户说「装免费模型」「加免费模型」「免费 LLM」「免费模型一键装」「验证免费模型可用吗」「免费模型怎么接入」「帮我配几个免费模型」「监控免费模型」「免费模型挂了吗」「kilo 网关」「kilo-auto」「nemotron 免费」「space-bunny」「智谱 glm 免费」「zhipu 免费」「glm-4-flash」「glm-4.7-flash」「glm-z1-flash」「glm-4v-flash」「探测国外免费模型」「国外平台免费 llm」「优先用免费模型」「读图桥接」「vision bridge」「给 glm-4-flash 加读图」「不读图的模型怎么看图」「阶跃星辰」「stepfun」「step 5」「step-5-preview」「限时免费模型」「ccproxy 读图转发」「给 claude code 加读图」时使用。也用于验证已有免费模型配置是否真的可用(tool calling 是否支持、是否限流、是否支持读图),以及定期 watch 监控免费模型是否下线/限流/失去工具调用能力。
在中国大陆网络环境下用 yt-dlp 下载视频(含 Windows GUI 封装)。当用户要下载 YouTube、Bilibili、SoundCloud 等 yt-dlp 支持的站点内容,或遇到「yt-dlp 装不上 / 下载报 502 / Tunnel connection failed / ffmpeg not found / 缺 JS runtime / TLS fingerprint / watch?v=&list= 把整个列表都下了 / Sign in to confirm you're not a bot / The page needs to be reloaded / 下到一半突然下不动 / 下回来的视频糊、有拖影残影 / 下载速度特别慢」等问题时使用。
聚合搜索百度网盘/夸克网盘/阿里云盘等网盘分享链接。当用户想按作者名、课程名、剧名、书名、软件名找网盘下载路径,或提到「网盘搜索」「PanSou」「盘搜」「找到下载链接」「夸克/百度/阿里网盘资源」时使用。包含已验证的 PanSou 协议端点、绕过系统代理的必要写法、以及可直接运行的本地 Web 应用 panradar.py。
在 WorkBuddy(Windows)环境里交付零依赖本地 Web 应用,并绕开官方测试技能完全不覆盖的本机专属坑。当用户要在本机跑起来一个本地 Web 应用 / 单文件工具 / 案例库 / 看板 / 小工具,或要验证刚写完的 HTML/JS/Python 交付物真的能工作时使用。独家覆盖:Bash 缺 coreutils、bash 是 WSL 启动桩、rm 是坏 shim、PowerShell 不回显 stdout、cwd 漂移、预览面板靠 HEAD 探活——这些在干净 Linux 环境里遇不到。
把B站横屏中长视频(读书解读/知识类)自动改造为微信视频号9:16竖屏短视频切片。当用户说"B站视频转视频号""横屏转竖屏切片""读书视频切片""视频号短视频制作""横屏改竖屏"时使用。覆盖下载→转写→选段→横转竖→烧字幕→封面全流程, 含本机环境坑与画质/字幕优化。