---
name: publish-skill
description: 通过 SSH 将本地 Codex Skill 或项目级 skills/index.json 同步到一个或多个 Skills Hub，并保持 index.json 的 directory、files 与服务器目录一致。用户要求部署、上传、同步、发布或贡献本地 Skill 时使用。
---

# 发布 Skill

## 硬性规则：远程写入必须人工确认

只要操作会通过 SSH、`publish` 或 `sync` 向目标服务器写入、覆盖或删除任何文件，必须严格执行以下顺序：

1. 先使用 `--dry-run` 或等价的只读方式生成待执行计划；不得在预览前建立远程写入会话。
2. 向用户展示本次实际要推送的每一个文件：本地路径、目标服务器路径、文件大小，以及文本文件的完整内容。二进制文件不能直接可读展示时，必须展示其来源文件内容、归档内文件清单、大小和 SHA-256。
3. 明确列出新增、覆盖、删除和远程目录变更，并等待用户在当前对话中明确确认。确认必须发生在展示之后；“帮我发布”“继续”“使用 `--yes`”等先前指令不能替代这次确认。
4. 只有在用户确认本次列出的完整计划后，才能执行实际的 `publish`、`sync` 或 SSH 写入命令。执行时可以把 CLI 的 `--yes` 作为已获得人工确认后的技术参数，但不得用它跳过展示或确认。
5. 用户拒绝、确认内容与计划不一致、计划发生任何变化，或无法展示完整内容时，立即停止，不得写入远程服务器。

这是不可选的安全门槛，不能因批量发布、自动化、脚本调用、非交互终端、重试或“用户之前已经确认过”而跳过。每次远程写入都必须重新预览并确认。

## SSH 权限边界

`ssh` 工具仅允许向所选目标配置的 `remoteDir` 下上传文件或目录。不得使用绝对越界路径、`..` 路径、其他目录或其他主机；不得删除、重命名、移动、修改权限或执行远程 Shell。任何服务器脚本都必须由用户在服务器上手动执行。

`rm -rf`、递归删除、`find -delete`、磁盘/文件系统操作、服务/电源操作、下载后管道执行 Shell、`chmod`、`chown` 及同类危险命令均列入黑名单。即使命令看起来无害，Agent 也不得执行远程 Shell；需要服务器脚本时必须停止并要求人工处理。

本 Skill 是面向 Agent 的发布编排层，必须调用 `swing-cli skill-hub` 完成校验、SSH 传输和注册表更新。项目级 `skills/` 目录必须使用 `skill-hub sync`，它会以根部 `index.json` 的 `directory` 和 `files` 为唯一路径来源；不要在本 Skill 中自行实现 SSH、文件复制或 `index.json` 修改。

## 工作流程

1. 确认发布对象：单个 Skill 目录必须包含 `SKILL.md`；项目级归档目录必须包含根部 `index.json`，且每个条目的 `directory` 指向真实 Skill 目录。frontmatter 中的 `name` 必须是小写字母、数字和连字符组成的名称，`description` 不能为空。
2. 先预览清单和目标，不连接服务器、不写入远端：

   ```powershell
   swing-cli skill-hub validate "$env:USERPROFILE/.agents/skills/my-skill"
   swing-cli skill-hub publish "$env:USERPROFILE/.agents/skills/my-skill" --dry-run
   swing-cli skill-hub sync "<project>/skills" --dry-run
   ```

3. 如果目标尚未配置，先使用 Skill Hub 的配置入口补齐服务器 IP/主机名、端口、用户名、密码或私钥路径，以及 Hub 远端目录：

   ```powershell
   swing-cli skill-hub config set tw-site
   swing-cli skill-hub config list
   ```

   密码只能在隐藏输入中输入或从本地 `.env` 读取，禁止作为命令行参数传递。当前服务器的默认目录是 `/opt/tw-site-app/tw-site/public/.well-known/skills`，只有操作者确认后才能采用。
4. 在实际发布前展示 Skill 名称、文件清单、所有目标、远端目录、公开 URL（如果配置）和覆盖影响，取得明确确认。若线上注册表或 Skill 目录存在同名 Skill，发布器会逐目标询问是否覆盖；用户拒绝时跳过该目标，不修改线上文件。
5. 发布到一个或多个已配置目标：

   ```powershell
   swing-cli skill-hub publish "$env:USERPROFILE/.agents/skills/my-skill" --target tw-site --yes
   swing-cli skill-hub publish "$env:USERPROFILE/.agents/skills/my-skill" --target tw-site --target staging --yes
   swing-cli skill-hub publish "$env:USERPROFILE/.agents/skills/my-skill" --all --yes
   # 仅在用户明确要求自动覆盖同名 Skill 时使用
   swing-cli skill-hub publish "$env:USERPROFILE/.agents/skills/my-skill" --all --yes --overwrite
   ```

   项目级 `skills/` 归档必须使用以下命令；它会整体替换远端 Hub 根目录，保持本地索引和目录结构一致：

   ```powershell
   swing-cli skill-hub sync "<project>/skills" --target tw-site --yes
   swing-cli skill-hub sync "<project>/skills" --all --yes
   ```

6. 按目标报告结果。一个目标失败时不要静默重试；保留其他目标的成功结果，并单独检查失败目标。

## 配置规则

连接配置只保存到已加入 `.gitignore` 的本地 `.env`。多目标命名规则参见仓库中的 `.env.example` 和 `docs/skill-hub-design.md`：

```dotenv
SWING_SSH_TARGETS=tw-site
SWING_SSH_TW_SITE_HOST=203.0.113.10
SWING_SSH_TW_SITE_PORT=22
SWING_SSH_TW_SITE_USERNAME=deploy
SWING_SSH_TW_SITE_PASSWORD=local-only
SWING_SKILL_HUB_TW_SITE_REMOTE_DIR=/opt/tw-site-app/tw-site/public/.well-known/skills
SWING_SKILL_HUB_TW_SITE_PUBLIC_URL=https://www.example.com
```

密码只能通过隐藏会话输入或本地 `.env` 提供，绝不能放入命令参数、聊天内容、日志或 Skills Hub。`swing-cli ssh targets` 和 `swing-cli skill-hub targets` 不会打印凭据。

## Hub 目录契约

每个目标必须使用与本地 `skills/index.json` 一致的目录结构：

```text
<remote-dir>/
  index.json
  swing-cli/
    SKILL.md
  action-gen/
    SKILL.md
  swing-wechat-workflow/
    SKILL.md
```

根部索引中的 `directory` 是远端 Skill 目录的相对路径，`files` 是相对于该目录的文件路径：

```json
{
  "skills": [
    {
      "name": "action-gen",
      "directory": "action-gen",
      "description": "...",
      "files": ["SKILL.md"]
    }
  ]
}
```

发布器必须将文件上传到 `<remote-dir>/<name>/<file>`；`directory` 必须等于 `name`。这是 `npx skills` v1 固定请求 `/.well-known/skills/<name>/SKILL.md` 的要求。分类目录不能作为可安装 Skill 的父目录。单 Skill `publish` 也使用同样的独立目录布局：

```text
<remote-dir>/
  index.json
  my-skill/
    SKILL.md
    agents/openai.yaml
    scripts/...
```

归档同步会以本地 `index.json` 为整体内容上传，并镜像替换远端 Hub 根目录；旧的分类目录、`skills-artifacts` 和索引外文件都会被清理。`.env`、`.env.*`、版本控制目录、缓存目录和软链接都会被排除。

发布后的公开布局兼容以下安装流程：

```bash
npx skills add <public-url> --skill <name>
```

客户端先读取 `/.well-known/skills/index.json`，再按照注册表中的 `name` 和 `files` 从 `/.well-known/skills/<name>/` 下载文件。

## 安全边界

- 任何远端写入都必须在预览后使用 `--yes` 明确确认。
- 不得擅自使用 `--overwrite`；同名覆盖必须有用户明确授权。
- 未确认目标目录、覆盖范围或凭据来源时，不执行发布。
- 不把密码、私钥内容或 Token 写入 Skill、`index.json`、日志或回复。
- 多目标发布按目标独立执行，必须报告每个目标的成功或失败状态。
