# Skill 来源模型 ## 背景 pouch 当前使用 `owned` 表示本仓库 `skills/` 中维护的 Skill,同时还支持 `registry` 外部仓库和用户配置的 custom source。 这些名称混合了不同维度: - `owned` 表示所有权。 - `registry` 表示来源配置存放在哪里。 - `external` 表示内容不在当前仓库。 - `collection` 表示一个来源中包含多个 Skill。 它们不能作为同一层级的互斥类型。例如 custom source 既可能来自外部 Git 仓库, 也可能是 collection;因此 `custom` 与 `external` 并不互斥。 本文建议将用户可见的来源注册方式统一为三类: - `builtin`:随当前 pouch 仓库提供的 Skill。 - `catalog:`:由 pouch 自带目录预先登记的来源。 - `custom:`:用户在本机显式配置的命名来源。 来源注册方式与获取方式、仓库布局相互独立。builtin、catalog 和 custom 中的任意 来源都可以包含一个或多个 Skill;除 builtin 外,catalog 和 custom 都可以使用 Git 仓库或本地目录。 ## 迁移前模型 ```mermaid flowchart TD S[pouch 可发现的 Skills] S --> O["owned
~/.pouch/skills/*"] S --> C["custom source
~/.config/pouch/config.yaml"] S --> R["registry
registry.yaml"] O --> O1["本仓库维护
随 pouch 一起分发"] C --> C1["本地目录
--local PATH"] C --> C2["指定 Git 仓库
repo + skills_path"] R --> R1["外部单 Skill 仓库"] R --> R2["外部 Skill Collection"] R1 --> E["~/.local/share/pouch/externals/"] R2 --> E ``` 迁移前实现中: - `list` 和 `status` 支持 owned、registry 和 custom source。 - `resolve_skill_source` 可以解析三种来源并处理同名歧义。 - `select` 只组装 owned 和 registry 条目,尚未展示 custom source。 - `.pouch.yaml` 默认将未声明来源的 Skill 解释为 `owned`。 - custom source 的 `skills_path` 已经可以包含多个 Skill,本质上也是 collection。 ## 现行模型 ```mermaid flowchart TD A[Skill Provider] A --> B["builtin
仓库内隐式注册"] A --> C["catalog:waza
pouch 预置目录"] A --> D["custom:company
用户本机配置"] B --> B1["skills/ack"] B --> B2["skills/pouch"] B --> B3["skills/builder"] C --> C1["Git 或本地目录"] C1 --> C2["单 Skill"] C1 --> C3["Collection"] C3 --> C4["waza/think"] C3 --> C5["waza/check"] D --> D1["Git 或本地目录"] D1 --> D2["单 Skill"] D1 --> D3["Collection"] D3 --> D4["company/security-review"] D3 --> D5["company/release"] ``` ### 来源注册方式 | 类型 | 含义 | 配置来源 | 用户界面展示 | | --- | --- | --- | --- | | `builtin` | 随当前 pouch 仓库提供 | `skills/` | `builtin` | | `catalog` | pouch 预先登记、所有用户可发现的来源 | `catalog.yaml` | `catalog:` | | `custom` | 用户在本机显式注册的命名来源 | `~/.config/pouch/config.yaml` | `custom:` | `builtin` 比 `owned` 更适合作为用户可见名称,因为它表达 Skill 的分发位置和可用 方式,而不是仓库的所有权关系。 `catalog` 比 `registry` 更准确:当前文件只是 pouch 随仓库维护的预置来源目录, 并不是远程注册中心,也不是一种 Skill 来源协议。 ### 三个正交维度 每个 provider 应由三个维度描述: ```text registration: builtin | catalog | custom transport: bundled | local | git layout: single | collection ``` custom source 示例: ```text registration: custom name: company transport: local | git layout: single | collection ``` catalog entry 示例: ```text registration: catalog name: waza transport: local | git layout: single | collection ``` `external` 只适合描述物理位置,可作为 catalog 和部分 custom provider 的统称, 不应成为与 builtin、custom 并列的持久化类型。 ## `select` 展示 `pouch select` 应同时展示 builtin、catalog 和 custom Skill: ```text [ ] ack builtin [ ] builder builtin [-] company custom source [ ] company/release custom:company [ ] company/security-review custom:company [-] waza catalog source [ ] waza/check catalog:waza [ ] waza/think catalog:waza ``` 建议遵循以下规则: - builtin Skill 直接显示 Skill 名称。 - catalog 和 custom collection 都使用来源名称作为父节点。 - catalog 和 custom Skill 都使用 `/` 作为选择器键。 - 单 Skill 来源可以省略父节点,但仍显示注册方式和来源名称。 - 不同来源安装后名称相同时,继续拒绝同时选择,避免覆盖同一安装路径。 ## 配置表示 新写入的 `.pouch.yaml` 使用以下形式: ```yaml skills: - name: ack source: builtin - name: security-review source: company - name: think source: catalog:waza ``` custom source 在 manifest 中继续保存其逻辑名称,例如 `company`。这样不同机器可以 独立配置仓库地址,而项目只依赖稳定的来源名称。 ## 兼容策略 用户可见术语已经调整,并保留以下读取兼容,避免已有项目立即失效: 1. 对外文档、CLI 输出和 selector 统一使用 `builtin`、`catalog:` 和 `custom:`。 2. 新生成的 `.pouch.yaml` 对内置 Skill 写入 `source: builtin`。 3. 读取旧 manifest 时继续接受 `source: owned`,并在解析时归一化为 `builtin`。 4. CLI 参数在过渡期继续接受 `--source owned`,但帮助和输出只推荐 `builtin`。 5. 读取旧 manifest 中的 `source: registry` 和 `registry: `,归一化为 `catalog:`。 6. 主文件使用 `catalog.yaml`;不存在时兼容读取旧 `registry.yaml`。 7. custom source 的逻辑名称和现有 `config.yaml` 结构保持不变。 8. 将 `builtin`、`catalog` 和兼容别名 `owned`、`registry` 设为 custom source 保留字。 9. `select` 同步接入 custom Skill,并让 custom collection 与 catalog collection 使用相同的父子展示逻辑。 ## 实现范围 当前实现覆盖: - `pouch/skills.py`:来源解析、归一化和 builtin 命名。 - `pouch/project.py`:manifest 默认值、序列化与旧值兼容。 - `pouch/sources.py`:来源保留字。 - `pouch/catalog.py`:catalog 配置、checkout 与 Skill 发现。 - `pouch/cli.py`:`list`、`status`、`add`、`select` 和输出文案。 - `pouch/selector.py`:统一 catalog/custom collection 的父子展示。 - CLI 与来源解析测试。 - 根 README、`pouch/README.md`、`skills/pouch/SKILL.md` 和相关示例。 ## 验证要求 实施完成后至少覆盖: - builtin Skill 可以通过新名称列出、选择、安装和写入 manifest。 - 旧的 `source: owned` manifest 仍可同步。 - custom local source 和 custom Git source 都出现在 selector 中。 - catalog 单 Skill 和 Collection 都保持可选择。 - custom 单 Skill 和 Collection 都保持可选择。 - 多来源同名 Skill 必须显式指定来源。 - 两个选择最终安装为同一个名称时,selector 拒绝冲突。 - `list`、`status`、`select` 对同一来源使用一致术语。 ## 设计前提 迁移前 `registry.yaml` 的真实职责只是维护 pouch 预置的来源目录,而不是提供远程 发布、版本解析或可信签名等注册中心能力,因此现已改为 `catalog.yaml`。如果未来 实现真正的远程 registry,应单独定义其协议和与 catalog 的同步关系,不复用旧名称。