# Skill Publisher

> Publish a completed SKILL.md folder to one or more public marketplaces (ClawHub, Tencent SkillHub, skills.sh, SkillsMP, LobeHub, Agensi, Coze, ClawMart) — validates frontmatter, optionally drafts a bilingual README, strips credential / build / dot-files, tags git, and ships serially. Use when the user names BOTH the action and the destination — e.g. "publish to ClawHub and skills.sh", "把这个 skill 推到腾讯 SkillHub", "ship a new version of my-skill to all 8 marketplaces". Do NOT trigger on bare "发布 skill" or "ship to marketplace" — those alone are too ambiguous for a destructive pipeline. Side effects (see Security & Privacy): local file read/overwrite, optional deletion of credential files (dry-run by default), git tag push, network calls to marketplace APIs, token auth via env vars. Not for: local-only management, drafting an unfinished skill, or single-marketplace docs.

- Skill: `mebusw/skill-publisher` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add mebusw/skill-publisher`
- Raw SKILL.md: https://api.skillmd.com/api/skills/mebusw/skill-publisher/raw
- Safety review: WARNING (external: skill-scanner WARNING, skillspector WARNING)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: mebusw (https://skillmd.com/u/mebusw)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/mebusw/skill-publisher

---


# 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-run` is 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** | The skill prints the exact command, a SHA-pinning note, and asks the user to run it themselves. |
| 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)

```bash
[ ! -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)

```bash
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.

```bash
[ -z "{bilingual}" ] && echo "ℹ️ README.zh-cn.md 跳过（需要 --bilingual 才生成）"
```

### Step 4 — Git tag (no global mutation, push is opt-in)

```bash
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.email` lines 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_dir` if you opt in.**
> The legacy 2.1 SKILL used inline `rm -rf` with 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.

```bash
# 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

```bash
# 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 to `bash` executes 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 to `skillhub login`.

```bash
# 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>`.

```bash
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

```bash
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.

```bash
# 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

```bash
[ -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

```bash
[ -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.

```bash
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_dir` to anywhere it was not asked
> to. The user picks `markets`; the skill does not pick for them.

***

## Known limits

1. SkillHub / Agensi / Coze have human review (5–10 min).
2. LobeHub requires a manual GitHub PR.
3. ClawMart requires manual web publishing.
4. Version must strictly increase; same-version republish is rejected
   unless `--force` is passed.
5. 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.

