Skill Publisher — 多市场一键发布 v2.2
Publish a completed skill folder to the public marketplaces you name.
Stop and read "Security & Privacy" below before running. This skill touches local files, git remotes, and external APIs. The defaults are non-destructive (
--dry-runis on for cleanup, no token in plaintext by default), but you must opt in to the rest.
Security & Privacy — what this skill WILL do
Run through this list with the user before the first invocation. Every item below has been the source of a real complaint; the defaults now err on the safe side, but the user must still explicitly request the action.
| # | Side effect | Default | How to opt in / opt out |
|---|---|---|---|
| 1 | Read skill_dir and traverse it |
Always | Cannot disable. |
| 2 | Write / overwrite files in skill_dir (templates, version bumps) |
Off | Pass --write (or any concrete publish flag). |
| 3 | Delete files matching credential / build / dot-file patterns inside skill_dir |
Off — dry-run only | python3 scripts/strip_bundle.py <skill_dir> first, review the list, then re-run without --dry-run. The inline rm -rf paths in the legacy 2.1 SKILL are removed. |
| 4 | Mutate global git config (git config --global user.email/name) |
Removed | No longer happens. If git complains about missing identity, ask the user to set it themselves or pass --git-user-email / --git-user-name for this repo only. |
| 5 | Patch installed CLI files on disk (e.g. sed -i on ~/.npm/.../publish.js) |
Removed | No longer happens. If a CLI bug blocks publish, the skill prints a clear error and asks the user to upgrade the CLI. |
| 6 | Push git tag to origin |
Off | --push-tag or --yes-push. The skill will list the tag it intends to push and stop. |
| 7 | Network call to each marketplace API in the markets list |
Off for any market not listed | Caller passes markets=clawhub,skillsh,skillhub etc. Empty markets = no network calls. |
| 8 | Auth token sent to that marketplace | Token must be in an env var (CLAWHUB_TOKEN, SKILLHUB_TOKEN, etc.) — not a --key flag in shell history |
If only a flag form is available, the skill prints a warning. |
| 9 | **`curl ... | bash` from a remote URL** (SkillHub installer) | Not run automatically |
| 10 | Auto-generate README.zh-cn.md from English content |
Off | --bilingual flag. The default English-only README respects the user's intent. |
| 11 | Report success for marketplaces that only print a manual-instruction URL (LobeHub, ClawMart) | Reports "📋 TODO" not "✅" | The skill distinguishes "actually published" from "instructions printed". |
If the user does not want any of #2–#10, the skill degrades to a read-only validator that prints a checklist and exits.
When to use
| User says | Trigger? |
|---|---|
"publish <slug> to ClawHub and skills.sh" |
✅ |
| "把这个 skill 推到腾讯 SkillHub 和 ClawHub" | ✅ |
"ship a new version of <slug> to all 8 marketplaces" |
✅ |
| "给 skill-publisher 打 v2.2 并发到 ClawHub + skills.sh + SkillHub" | ✅ |
| "发布 skill" (alone, no target) | ❌ — too ambiguous; ask which marketplaces |
| "ship to marketplace" (alone, no target) | ❌ — same |
| "我刚写好一个 skill,帮我看看" | ❌ — that's skill-optimizer, not publish |
| "how do I publish to ClawHub" (asking for docs) | ❌ — read references/clawhub.md instead |
Required user-supplied parameters
| Parameter | Required for | Source | Notes |
|---|---|---|---|
skill_dir |
All | Prompt | Must contain SKILL.md. |
markets |
All | Prompt or flag | Comma-separated. No default — caller must list at least one. |
CLAWHUB_TOKEN |
markets=clawhub |
Env var | Never put on the command line. |
SKILLHUB_TOKEN |
markets=skillhub |
Env var | Never put on the command line. |
GITHUB_TOKEN (optional) |
markets=skillssh,skillsmp,lobehub,agensi |
Env var | Only needed if the repo is private. |
COZE_TOKEN |
markets=coze |
Env var | Never put on the command line. |
AGENSI_KEY |
markets=agensi |
Env var | Never put on the command line. |
--bilingual |
Optional | Flag | Generates README.zh-cn.md from README.md. Off by default. |
--push-tag |
Optional | Flag | Pushes the new git tag to origin. Off by default. |
--confirm-cleanup |
Optional | Flag | Re-runs the cleanup script for real (not dry-run) after the user has reviewed the dry-run output. Off by default. |
--write |
Optional | Flag | Allows Step 3 / Step 5 to write or delete inside skill_dir. Off by default — without this, the skill is read-only. |
--dry-run |
Optional | Flag | Default on. Walks every step, prints what it would do, makes zero side effects. |
Token rule: if the user pastes a token on the command line, the skill will refuse and ask them to set the env var instead. Tokens in shell history leak through screenshots, screen sharing, and process listings.
Execution flow (read top to bottom)
Each step lists its side effects. Steps 1–2 are always read-only. Steps
3–6 require --write and (for destructive parts) --confirm-cleanup or
--push-tag.
Step 1 — Pre-flight (read only)
[ ! -f "{skill_dir}/SKILL.md" ] && { echo "❌ SKILL.md 不存在"; exit 1; }
[ -z "{markets}" ] && { echo "❌ --markets 必填,逗号分隔,例如 clawhub,skillsh"; exit 1; }
for cli in clawhub skillhub; do
which "$cli" >/dev/null 2>&1 || echo "⚠️ $cli 未安装(markets=$cli 时需要)"
done
git --version
Step 2 — SKILL.md frontmatter 校验 (read only)
python3 - <<'PY'
import sys, re, yaml
content = open("{skill_dir}/SKILL.md").read()
m = re.match(r'^---\n(.*?)\n---', content, re.DOTALL)
if not m: sys.exit("❌ frontmatter 缺失")
data = yaml.safe_load(m.group(1))
for k in ("name", "description", "version", "author"):
v = data.get(k)
if v is None: sys.exit(f"❌ {k} 缺失")
print(f"✅ {k}: {v}")
PY
Step 3 — 文档生成 (write, but bilingual is opt-in)
| File | When created | Notes |
|---|---|---|
README.md |
Always (if missing) | English. Refreshes stale version / install command. |
README.zh-cn.md |
Only if --bilingual is set |
Generated from README.md via LLM. Off by default — the user must request it. |
RELEASE_NOTES.md |
Always (if missing) | Generated from CHANGELOG.md or git log. |
Why opt-in for the Chinese README: auto-translating documentation into another language can accidentally leak content the user did not intend to publish, mistranslate legal / compliance language, or create obligations they did not agree to. The default English-only README matches the user's likely intent ("publish my skill") without overreaching.
[ -z "{bilingual}" ] && echo "ℹ️ README.zh-cn.md 跳过(需要 --bilingual 才生成)"
Step 4 — Git tag (no global mutation, push is opt-in)
cd {skill_dir_parent}
# Read existing identity. Do NOT mutate global config.
SKILL_VER=$(grep '^version:' {skill_dir}/SKILL.md | head -1 | cut -d: -f2 | tr -d ' ')
TARGET_TAG="v$SKILL_VER"
CURRENT_TAG=$(git tag --sort=-v:refname | head -1 2>/dev/null || echo "")
if [ "$CURRENT_TAG" = "$TARGET_TAG" ]; then
echo "ℹ️ Tag $TARGET_TAG 已存在"
else
echo "📋 将创建本地 tag: $TARGET_TAG"
git tag -a "$TARGET_TAG" -m "Release $TARGET_TAG"
if [ -n "{push_tag}" ]; then
echo "📋 将推送 tag 到 origin: $TARGET_TAG (--push-tag 已设置)"
git push origin "$TARGET_TAG"
else
echo "ℹ️ tag 未推送。需要推送时重跑并加 --push-tag。"
echo " ⚠️ 推送 tag 可能在 GitHub 触发 CI/CD、Release 流程,"
echo " 并把版本号广播给所有订阅者。请确认后再加 --push-tag。"
fi
fi
Why the old
git config --global user.emaillines are removed: mutating the user's global git identity is an unrelated, persistent change to other repositories. The publisher does not need it. If git complains about missing identity, the skill surfaces that and asks the user to set it once.
Step 5 — Bundle 清理 (DRY-RUN BY DEFAULT, never inline rm -rf)
⚠️ This step WILL delete files inside
skill_dirif you opt in. The legacy 2.1 SKILL used inlinerm -rfwith broad patterns like.env,*.key,*.pem,credentials.*. That is unsafe by default and has been replaced with a reviewable Python script that exits non-zero when it touches credential-looking files.
Use the bundled script — it knows the allowlist, prunes build / dot / cache directories, and reports credentials separately.
# Step 5a — always run dry-run first and show the user
python3 {skill_dir}/../scripts/strip_bundle.py {skill_dir} --dry-run
if [ -n "{confirm_cleanup}" ]; then
# Step 5b — only after the user has reviewed the dry-run list
python3 {skill_dir}/../scripts/strip_bundle.py {skill_dir}
else
echo "ℹ️ 清理未执行(需要 --confirm-cleanup 才真正删除)"
echo " 上面的 [DRY-RUN] 行就是将删除的内容,请人工确认后再加 --confirm-cleanup。"
fi
Exit code 1 from the script means credential-looking files were removed; the skill surfaces this and asks the user to review before continuing.
Step 6 — 串行发布 (per-market, secrets via env)
For each market in --markets, the skill runs the block below. Markets
not listed are skipped entirely — no default-all behavior.
6a. ClawHub
# Note: this skill does NOT patch ~/.npm/.../publish.js with sed anymore.
# If the CLI rejects the publish because of an "acceptLicenseTerms" issue,
# upgrade the CLI: npm i -g clawhub@latest, then re-run.
[ -z "$CLAWHUB_TOKEN" ] && { echo "❌ CLAWHUB_TOKEN 未设置(请用环境变量)"; exit 1; }
CLAWHUB_TOKEN="$CLAWHUB_TOKEN" \
clawhub skill publish {skill_dir} \
--slug {slug} --name "{display_name}" --owner {owner} \
--version {version} \
--changelog "Release v{version}" --tags "latest"
Error handling: 401 → token invalid; 409 → slug taken (suggest suffix);
429 → wait & retry. CLI patches via sed -i on installed files are no
longer in scope.
6b. 腾讯 SkillHub
⚠️ Step 1 (CLI install) is not run automatically. The official installer is
curl -fsSL https://skillhub.cn/install/install.sh | bash. Piping a remote script tobashexecutes whatever the server returns with no integrity check. The skill prints the exact command, the URL, and asks the user to run it themselves. If the user has already installed the CLI, jump toskillhub login.
# Login uses env var, NOT a --key flag in shell history.
[ -z "$SKILLHUB_TOKEN" ] && { echo "❌ SKILLHUB_TOKEN 未设置"; exit 1; }
SKILLHUB_TOKEN="$SKILLHUB_TOKEN" skillhub login
[ ! -f "{skill_dir}/skillhub.yaml" ] && \
skillhub init --name {slug} --category "效率工具" --dir {skill_dir}
cd {skill_dir}
skillhub push --message "Release v{version}"
skillhub publish --version {version} --changelog "Release v{version}"
skillhub search {slug} && echo "✅ SkillHub 完成(审核约 5-10 分钟)"
6c. skills.sh
skills.sh is read-only — it indexes public GitHub repos. There is no
publish API call. The "publish" step is git push of a tag (covered in
Step 4) plus verifying the repo is public. The install command the user
will paste elsewhere is npx skills add https://github.com/<owner>/<slug>.
GH_REPO="{github_repo}"
curl -s "https://api.github.com/repos/$GH_REPO" | python3 -c "
import sys, json
try:
d = json.load(sys.stdin)
print('✅', d['full_name'], '| Stars:', d['stargazers_count'])
except Exception: print('⚠️ Repo 不存在或未公开')
"
echo "📋 skills.sh: 等 GitHub 公开 repo 推送后由 skills.sh 抓取"
echo " 安装命令: npx skills add https://github.com/$GH_REPO"
6d. SkillsMP
echo "📋 SkillsMP: 通过 GitHub repo 聚合,无独立 publish"
echo " 注册独立页面: https://agentskills.io/submit"
echo " 安装: npx skills add https://github.com/{github_repo}"
6e. LobeHub Skills
LobeHub has no automated publish CLI; the user must open a PR or run
lobe-cli skill add themselves. The skill does not print
✅ lobe-cli 添加成功 when only a manual-instruction URL was printed —
that would be a false success.
# Note: previously this block printed "✅ ..." even when it only printed
# a manual-PR link. That misleading output has been removed.
echo "📋 LobeHub: 需要手动完成下列之一"
echo " 1) PR 到 https://github.com/lobehub/lobe-chat#skills"
echo " 2) 或本机运行: npx skills add https://github.com/{github_repo}"
echo " 3) 或本机运行: lobe-cli skill add {github_repo} (需先安装 lobe-cli)"
6f. Agensi
[ -z "$AGENSI_KEY" ] && { echo "❌ AGENSI_KEY 未设置"; exit 1; }
curl -X POST https://api.agensi.ai/v1/skills/publish \
-H "Authorization: Bearer $AGENSI_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "{slug}",
"repo": "{github_repo}",
"version": "{version}",
"description": "...",
"tags": ["productivity"]
}'
echo "📋 Agensi: 已提交,等人工审核"
6g. Coze
[ -z "$COZE_TOKEN" ] && { echo "❌ COZE_TOKEN 未设置"; exit 1; }
curl -X POST "https://api.coze.cn/v1/skills" \
-H "Authorization: Bearer $COZE_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "{slug}",
"description": "...",
"icon_url": "...",
"skill_type": "published"
}'
echo "📋 Coze: 已提交,等人工审核"
6h. ClawMart
ClawMart is a third-party paid marketplace with no CLI. The skill prints instructions and stops — no false success.
echo "📋 ClawMart: 手动发布到 https://clawmart.com/sell"
echo " 参考: https://clawmart.com/publish"
Step 7 — 结果汇总
=========================================
📋 多市场发布结果
✅ = actually published
📋 = manual step required (see above)
{markets, e.g.}
✅ ClawHub clawhub.com/skills/{slug} clawhub install {slug}
✅ 腾讯 SkillHub skillhub.tencent.com/skills skillhub install {slug}
📋 skills.sh agentskill.sh npx skills add <repo> (等 GitHub 抓取)
📋 SkillsMP agentskills.io npx skills add <repo> (聚合)
📋 LobeHub lobehub.com/skills 手动 PR
📋 Agensi agensi.ai 审核中
📋 Coze coze.cn 审核中
📋 ClawMart clawmart.com 手动发布
=========================================
Global flags (summary)
| Flag | Effect | Default |
|---|---|---|
--dry-run |
Read-only walk-through, prints actions | On |
--write |
Allow Step 3/5 to mutate files | Off |
--confirm-cleanup |
Run strip_bundle.py for real after dry-run review |
Off |
--push-tag |
git push origin <tag> after tagging |
Off |
--bilingual |
Generate README.zh-cn.md |
Off |
--markets |
Comma-separated targets | Required — no default |
Privacy & data flow
| Where data goes | What is sent | When |
|---|---|---|
| ClawHub API | skill_dir contents + CLAWHUB_TOKEN |
--markets=clawhub |
| SkillHub API | skill_dir + SKILLHUB_TOKEN |
--markets=skillhub |
| GitHub API | Repo read (stars, existence) | --markets=skillssh,lobehub,skillsmp,agensi |
| Agensi API | Skill metadata + AGENSI_KEY |
--markets=agensi |
| Coze API | Skill metadata + COZE_TOKEN |
--markets=coze |
| skills.sh / SkillsMP / LobeHub / ClawMart | Nothing at runtime — these are GitHub-indexed or manual | Always off |
The skill does not send
skill_dirto anywhere it was not asked to. The user picksmarkets; the skill does not pick for them.
Known limits
- SkillHub / Agensi / Coze have human review (5–10 min).
- LobeHub requires a manual GitHub PR.
- ClawMart requires manual web publishing.
- Version must strictly increase; same-version republish is rejected
unless
--forceis passed. - The cleanup script is conservative — anything it cannot classify as
part of the skill is removed. If a skill genuinely needs a file
outside the standard folders, edit
.clawhubignore(or the script's keep-list) before running.