# seek PRD v2：Skill 生命周期管理子系统

> 目标版本：seek v0.3.x
> 依赖基础：v0（Skill 加载机制、工具系统、permission policy）
> 前置阅读：[PRD v0](v0.md) §4.6（Skill）、§4.8（Tool）
> 状态：🚀 已交付（v0.3.x，含 v2 扩展）

---

## 1. 动机

v0 把 Skill 当作「一个 Markdown 文件丢进目录就生效」的极简模型——这在自举阶段是对的：零安装、零状态、跟 Claude Code 生态零摩擦。但随着 skill 数量增长和外部贡献到来，三个问题浮出水面：

- **没有「安装」**——用户从 GitHub 复制粘贴一段 markdown，存到哪个目录、文件名叫什么、是否会被 loader 看到，全靠经验。要换电脑、要给同事推荐时，没有可复制的命令。
- **没有「被调用过」的痕迹**——`/skills` 只显示"哪些被加载了"，回答不了"哪些真的被模型用过"、"上次什么时候用过"、"哪个最常用"。这让作者无法知道自己写的 skill 是否在帮人；让用户无法知道哪个 skill 是死代码。
- **没有「生效保障」**——用户把 skill 装在错误的目录、frontmatter 写错、name 冲突被覆盖，目前只有启动横幅一行汇总，事后无法回溯。`/skills` 不告诉你 `foo` 是从哪个文件加载的、是否被同名 skill 遮蔽。

v0 的设计原则不变（详见 [v0.md §4.6](v0.md)）——skill 是注入到模型上下文的 Markdown，不是远程能力；本 PRD 只补齐**生命周期管理**和**可观测性**两块。

## 2. 三个变化（核心设计）

```
┌──────────────────────────────────────────────────────────────────┐
│  1. Skill 升级为目录包（兼容 Anthropic Agent Skills 形态）         │
│     foo.md  →  foo/SKILL.md（frontmatter 内联元数据）              │
│                + 可选 references/ examples/ scripts/ ...          │
│     单文件 .md 永远兼容；只是没有 version/license 等扩展字段       │
└──────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────┐
│  2. seek skill 子命令族                                           │
│     install / list / status / uninstall / update / stats          │
│     CLI 和 TUI slash 命令（/skill install ...）镜像同一份能力     │
└──────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────┐
│  3. 调用统计（轻量、本地、append-only）                            │
│     ~/.seek/skills/.stats.jsonl                                   │
│     每次 Skill(name=...) 调用写一行：{ts, name, session, model}   │
└──────────────────────────────────────────────────────────────────┘
```

这三件事彼此独立可上线，但合在一起完成「装—用—看—卸」闭环。验证（"skill 真的有效吗？"）和跨模型评测（"哪个模型用得最好？"）**v2 不做**——留给 v3 的 eval harness。

## 3. 设计目标与不做什么

### 目标

1. **目录包是新能力，单文件 .md 永远兼容**——目录里同时存在 `foo.md` 和 `bar/SKILL.md` 都正常加载，互不干扰
2. **零格式发明**——目录包格式直接对齐 Anthropic Agent Skills 规范（`<dir>/SKILL.md` + frontmatter），不发明 seek 私有 schema
3. **三种安装来源开箱即用**：本地路径、Git URL、HTTPS 压缩包（无中心化注册表，避免生态包袱）
4. **统计纯本地、零远端**——`~/.seek/skills/.stats.jsonl` 一个 append-only 文件，可 `cat | jq`
5. **`seek skill status <name>` 是核心断言工具**——一条命令告诉你：来源、是否被遮蔽、frontmatter 是否合法、最近一次调用、累计次数
6. **`internal/skill` API 向下兼容**——`Set`/`Skill`/`Load()` 签名不变；新字段加在 `Skill` 结构体尾部，零调用方修改即可加载目录包
7. **安装是显式的，不写隐藏目录**——本地路径安装走 `cp -r` 到 `~/.seek/skills/<name>/`，所有副作用可见

### 不做什么（v2 明确延后）

- ❌ 中心化注册表 / `seek skill search`（v3：先看生态需要再设计）
- ❌ 自动测试 / eval（v3 eval harness——v2 用户用人眼判断）
- ❌ 跨模型评测（v3）
- ❌ Skill 间依赖管理 / lockfile（v3，等真出现依赖再说）
- ❌ Skill 沙箱——`scripts/` 里的脚本通过模型调 `bash` 工具执行，沿用 v0 的 permission policy（`ModeAsk` inline 审批）兜底，**不为 skill 引入额外的工具白名单机制**
- ❌ 强制 `allowed-tools`——frontmatter 的 `allowed-tools` 字段在 v2 仅作为 `Skill.AllowedTools` 记录、显示在 `status` 里，**不收紧模型实际能调用的工具集**（这是一个独立的工具裁剪机制，留给 v3 设计）
- ❌ 在线热更新——`update` 是手动命令，不自动拉
- ❌ 单文件 .md 的弃用计划——永远共存

## 4. 数据模型

### 4.1 Skill 包目录布局（对齐 Anthropic Agent Skills）

**核心原则**：v2 不发明格式——直接采用 Anthropic Agent Skills 已有的目录约定（`<dir>/SKILL.md` + frontmatter 内联元数据 + 任意子目录）。这意味着 GitHub 上任何符合 Claude Code skill 规范的仓库都可被 seek 零转换安装。

```
my-skill/
├── SKILL.md            # 必需。入口文件，frontmatter 含元数据，body 是 markdown 主体
├── references/         # 可选约定。供 SKILL.md 用 [link](references/foo.md) 引用
├── examples/           # 可选约定。代码片段、示例数据
├── scripts/            # 可选约定。SKILL.md body 引用的辅助脚本；执行路径是「模型读到 SKILL.md 里的 `Run scripts/foo.sh` 指令 → 调 bash 工具运行」，跟 Claude Code 一样；seek 不为 scripts/ 提供任何特殊执行管线
├── assets/             # 可选约定。图片等
└── README.md           # 可选。给人看（loader 不读取）
```

**子目录是 skill 作者的自由**——seek 不强制 `references/` 必须叫这个名字，也不为它增加任何特殊语义。loader 只看 `SKILL.md`；其他文件由 body 里的 markdown 链接决定。

**`SKILL.md` frontmatter 字段**（v2 识别的字段集合）：

```markdown
---
name: my-skill                    # 必需。kebab-case，建议与目录名一致
description: |                    # 必需。单行或多行，多行时整体作为 manifest 描述
  When the user asks how to do X with library Y, follow these steps.
version: 1.2.0                   # 可选。semver；用于 update 比较和 status 显示
license: MIT                     # 可选。仅记录，不做合规校验
author: foo@example.com          # 可选
allowed-tools:                   # 可选。Anthropic 规范字段。v2 仅记录，不做权限约束（留给 v3）
  - Read
  - Grep
keywords: [go, testing]          # 可选。v2 不用，留给 v3 搜索
---

# Skill body 从这里开始

...markdown 正文...
```

字段语义沿用 v0 §4.6.1——`name` 和 `description` 的解析、校验、注入 manifest 的逻辑零变更。新增字段全部**可选**，未识别字段写入 `Skill.Extra map[string]string`（v0 `parseFrontmatter` 本来就保留未知字段，只是没暴露）。

**关于大小写**：`SKILL.md` 是 Anthropic 规范的标准写法。loader 同时容忍小写 `skill.md` 作为 fallback，因为：(a) 现有 seek 单文件 .md 是小写，作者改成目录包时可能不会重命名；(b) 跨平台文件系统大小写敏感性不一致。优先级：`SKILL.md` > `skill.md`。同时存在时取 `SKILL.md` 并在 `LoadStats.Errors` 报 warning。

**与现有单文件 .md 的关系**：单文件 `foo.md`（顶层带 frontmatter 的 markdown）等价于一个「只有 SKILL.md、没有任何子目录」的简化包。loader 内部走同一条解析路径，对外暴露的 `Skill.Type` 区分 `package` / `single-file` / `builtin` 仅用于 `status` 显示。

### 4.2 安装记录（install sidecar）

`seek skill install <source>` 在目标目录写一个隐藏 sidecar：

`<skill-dir>/.install.json`（**用户级 skill 才会写入；项目级 install 不写**，见下面）：
```json
{
  "schema_version": 1,
  "installed_at": "2026-05-22T13:15:00Z",
  "type": "git",                          // "local" | "git" | "https"
  "url": "https://github.com/foo/bar",
  "ref": "v1.2.0",                        // 仅 git
  "subpath": "skills/my-skill",           // 仅 git，包在仓库内的子目录
  "checksum_sha256": "a3b9f1...",         // 仅 https tarball
  "resolved_commit": "9f8a1c..."          // 仅 git，install 时记录的 commit
}
```

JSON 故意是**扁平**结构——这是 seek 私有的本地状态，没有需要嵌套 `source` 对象的理由。

**为什么 sidecar 而不是写进 `SKILL.md` frontmatter**：`SKILL.md` 是作者编辑的、有可能从上游 git 仓库同步回来；安装记录是 seek 写的、本地特有。混在一起会让作者每次更新都要避开 install 字段，反过来 seek 也得保留作者改的部分，复杂度不值。手动 `cp -r` 装来的 skill 没有 `.install.json`，loader 把它当 "manual" 来源——除了 `update` 不能用之外其他都正常。

**项目级 install 不写 `.install.json`**——`seek skill install --project ./foo` 把 skill 拷到 `<project>/.seek/skills/foo/` 时**只写 skill 内容**，不留 install sidecar。项目级 skill 概念上是「进 git 共享」的，安装记录是本机状态、不该污染 git。代价：项目级 skill 不能被 `seek skill update` 跟踪——要换版本就重装（与"团队共享、版本控制走 git"的语义一致）。`.gitignore` 模板因此**不需要**——根本没有要忽略的文件。

### 4.3 调用统计

文件：`~/.seek/skills/.stats.jsonl`（append-only，每行一条）

```json
{"ts":"2026-05-22T13:15:00Z","name":"go-test-runner","session_id":"20260522-131459-a3b9","project_id":"a3b9f1c2e8d4a7b6","model":"deepseek-chat","provider":"deepseek"}
```

**字段**（schema_version 隐含在文件路径里，未来 break schema 时改文件名为 `.stats.v2.jsonl`）：

| 字段 | 类型 | 说明 |
|---|---|---|
| `ts` | RFC3339 | skill 被调用的时刻（写入 stats 的时刻，不是 session 开始的时刻） |
| `name` | string | 被调用的 skill name |
| `session_id` | string | 触发本次调用的 session id |
| `project_id` | string | 项目 id——复用 v1 memory 的 `sha256(abs-project-path)[:16]`；空字符串表示非项目 session（罕见） |
| `model` | string | 当时使用的模型（如 `deepseek-reasoner`） |
| `provider` | string | provider（`deepseek` / `anthropic` / `openai` / `gemini`） |

**只记这六个字段**——足以回答："哪些 skill 被用过、各被用了多少次、用在哪些 session/项目、各 provider 的使用分布"。`project_id` 复用 v1 memory 系统已经在算的哈希，启动时已经有值，写入零额外成本。**不记调用上下文、不记调用结果**——这些属于 v3 eval。

**写入时机**：`skilltool.Tool.Execute` 在成功返回 body 之前同步 append 一行。失败（skill 未找到等）不写——只统计实际拿到 body 的调用。

**轮转**：v2 不轮转，文件 append 增长。10K 次调用 ≈ 1.5MB，按经验值用户几年都用不到这个量。v3 再加轮转策略。

### 4.4 单文件 .md skill：什么变了，什么没变

| 维度 | 单 .md | 目录包 |
|---|---|---|
| 加载 | ✅（v0 路径不变） | ✅（v2 新增） |
| `Skill` 工具调用 | ✅ | ✅ |
| 出现在 `/skills` 列表 | ✅ | ✅ |
| 出现在 `.stats.jsonl` | ✅（用 `name` 作为 key） | ✅ |
| 扩展元数据（version / license / allowed-tools） | ❌（frontmatter 仅 name/description） | ✅（SKILL.md frontmatter 内联） |
| 可被 `seek skill update` | ❌（无安装记录） | ✅（如果是 install 装的） |
| 可被 `seek skill uninstall` | ✅（删文件） | ✅（删目录） |
| 在 `seek skill status` 里显示 source 类型 | "frontmatter only" | "package" |

「单 .md 永远兼容」的具体含义：**v2 不引入任何让旧 .md 失效的检查**。`.claude/skills/` 兼容路径也包括目录包——`~/.claude/skills/foo/SKILL.md` 是 Anthropic 生态的标准形态，loader 用同一份解析逻辑读它，**零适配**。

## 5. CLI 与 TUI 命令

### 5.1 CLI 子命令

所有命令幂等，失败时 exit code ≠ 0 并打印一行可解析错误。

```
seek skill install <source> [--name <override>] [--force]
    本地路径：       seek skill install ./my-skill
                    seek skill install /abs/path/my-skill
    Git URL：       seek skill install https://github.com/foo/bar
                    seek skill install https://github.com/foo/bar#v1.2.0
                    seek skill install https://github.com/foo/bar#main --subpath skills/foo
    HTTPS tarball： seek skill install https://example.com/foo-1.0.0.tar.gz
                    seek skill install https://example.com/foo.zip --sha256 a3b9...

    目标目录：~/.seek/skills/<name>/
    冲突处理：同名已存在 → 报错并提示 --force；--force 时先删旧目录再装
    name 解析：优先 --name；其次 SKILL.md frontmatter 的 name；其次目录名

seek skill list [--source <which>]
    列出已加载 skills，列：name、source（project .seek / user / builtin / .claude 兼容路径）、
    type（package / single-file / builtin）、调用次数（来自 stats）、最近调用时间
    --source 过滤（user / project / builtin）

seek skill status <name>
    单个 skill 的详细诊断：
      - 来源文件路径
      - 是否被同名 skill 遮蔽，如有列出被遮蔽的路径
      - SKILL.md frontmatter 解析状态（OK or 报错，列出未识别字段）
      - 安装来源（如有 .install.json）
      - 调用次数 + 最近 5 次调用时间 + 各 model/provider 分布
      - body 字符数 / 估计 token 数（给上下文预算参考）

seek skill uninstall <name> [--keep-stats]
    删 ~/.seek/skills/<name>/（目录包）或 ~/.seek/skills/<name>.md（单文件）。
    项目级 skill 不能用这个命令卸（rm 由用户自己做，因为进 git）。
    --keep-stats：保留 .stats.jsonl 里的历史记录（默认保留，--purge 才会删）

seek skill update <name>
seek skill update --all
    只对有 .install.json 的 skill 生效。
    git 源：fetch + 重置到 install 时记录的 ref（如果 ref 是 branch，拉最新；如果是 tag/commit，no-op 提示）
    https 源：重新下载 + 校验 sha256
    本地源：从原始路径重新 cp（如果原始路径仍存在）

seek skill stats [--top N] [--since <duration>]
    调用排行榜：默认 --top 10 --since 30d
    输出：name | count | last_used | top_model | top_provider

seek skill create <name> [--description "..."] [--project] [--into <dir>]
    脚手架一个新 skill 包，给作者起手用。生成（与 Anthropic Agent Skills 形态一致）：
      <target>/<name>/
      ├── SKILL.md        # 入口文件。frontmatter 预填 name、description（来自 --description）、
      │                   # version: 0.1.0；body 含 when-to-use / 步骤 / references 三段 TODO 占位
      ├── references/     # 空目录 + .gitkeep，提示作者把长文档拆到这里
      └── README.md       # 给人看的简介模板

    target 决定：
      --into <dir>      显式指定父目录（优先级最高）
      --project         否则有此 flag 时用 <cwd>/.seek/skills/
      （都没有）         默认 ~/.seek/skills/

    冲突：目标已存在直接报错，**不接 --force**——创建命令理应是新建，覆盖已有内容用 install --force。
    name 校验：与 install / loader 用同一份 kebab-case 正则；非法字符立即拒绝。
    交互模式：未传 --description 时进入一次 readline 提示，避免作者忘了写
    （`description` 没填 skill 加载会报错——前置兜底胜过事后纠错）。
```

### 5.2 TUI slash 命令镜像

TUI 内（`/skill ...`）镜像同一份能力，参数和输出格式一致——纯调用 `pkg/skillmgr` 同一个入口。这样脚本党用 CLI、交互党用 TUI，零代码重复。

### 5.3 输出格式

所有 `list` / `status` / `stats` 默认输出人类可读表格；加 `--json` 输出 JSON——后者给脚本和未来的 RPC（v0 §M7 的 `--rpc` 模式可以 expose）。

## 6. 与现有系统的集成

| 子系统 | 集成点 | 改动量 |
|---|---|---|
| `internal/skill` | 加目录包解析路径（`<dir>/SKILL.md`）；`Skill` 结构体新增 `Type`（package/single-file/builtin）、`Version`、`License`、`AllowedTools`、`Extra map[string]string`、`InstallSource` 字段；`parseFrontmatter` 扩展为支持简单列表（`allowed-tools:`） | 中（解析 + Load 分支） |
| `internal/tools/skilltool` | `Execute` 成功返回前同步 append `.stats.jsonl` | 小（注入 `stats.Writer`） |
| `internal/paths` | 新增 `UserSkillStats() string`（默认 `~/.seek/skills/.stats.jsonl`） | 极小 |
| `cmd/seek` | 加 `skill` 子命令族；现有启动逻辑零变更 | 中（新增 subcommand 入口 ~300 行） |
| TUI | `/skill install ...` 等 slash 命令；`/skills` 显示统计列 | 中（slash 命令解析 + 表格渲染） |
| Permission Policy（install/update 侧） | `seek skill install` / `update` 走 CLI 不走 agent 循环——**不需要** permission 集成；`update` 后 skill body 变化要重新加载，loader 不允许 session 中途换 body（prefix-cache 约束）——命令提示用户重启 seek 才生效 | 小（提示文案） |
| Permission Policy（scripts 执行侧） | skill 包内 `scripts/` 的执行**完全沿用** v0 `bash` 工具的 permission gate：模型按 `SKILL.md` 指令调 `bash` 执行 `python scripts/foo.py` 等，每次都走 `ModeAsk` inline 审批（`--yolo` 全放，`ModeDeny` 全拒）。seek 不在工具层做命令白名单（如「允许 python 禁 curl」），不预检 python/node 运行时是否存在；运行失败时模型从 stderr 自行决策（如建议用户安装）。**v2 不引入任何新的权限机制** | 0（零代码改动；仅 PRD 文档显式声明这条契约） |
| Prefix cache | skill manifest 是注入 system prompt 的——`update` / `install` 后 manifest 变了，下一次会话 prefix-cache miss 一次，这是预期的成本 | 文档说明 |
| Session | 无变更——stats 写入用 session_id 但不反向依赖 | 0 |

**`internal/skillmgr` 新包**：CLI 子命令和 TUI slash 命令共用的业务逻辑（install / uninstall / update / stats 查询）。`internal/skill` 仍只负责加载和 manifest 渲染——管理动作单独成包，避免 loader 包变重。

### 6.1 AI 侧安装（v2 扩展）

v2 之后新增了**模型可调用的 skill 安装工具**，让 AI 代理（而非仅用户）驱动 skill 安装流程：

- **`skill_fetch(source, name?, subpath?, sha256?)`** — 从本地路径 / Git URL / HTTPS tarball 获取 skill 包，校验目录结构，暂存到 `/tmp/seek-skill-staging-*`。模型可以 `read` 暂存区内的 `SKILL.md` 和任意文件供用户审阅。
- **`skill_commit(staging, name, source, scope)`** — 将暂存的 skill 安装到最终位置。**必须**在安装前由用户选择 scope（`user` 或 `project`，参见下方），且用户需通过交互式 y/N 确认才能落盘。安装后提示用户 `/new` 重启会话以使新 skill 可见（manifest 在启动时固定）。

**Scope 机制**（v2 中 `seek skill install --project` 的 AI 侧映射）：

| Scope | 目标路径 | 特点 |
|---|---|---|
| `user` | `~/.seek/skills/<name>/` | 本机全部 session 可见，不进入 git |
| `project` | `<cwd>/.seek/skills/<name>/` | 进入 git，团队可见，无 `.install.json` sidecar |

AI 侧工具与 CLI 共享 `internal/skillmgr` 业务逻辑，但走不同的入口：CLI 直接调用 golang API，AI 工具通过 `internal/tools/skillfetch` / `internal/tools/skillcommit` 的 `Execute` 方法路由到 skillmgr。两条路径的同一条验证链（frontmatter 校验、冲突检测）由 skillmgr 统一维护。

## 7. 验收标准

| # | 标准 | 验证方式 |
|---|---|---|
| 1 | `seek skill install ./testdata/foo-pkg` 把目录拷到 `~/.seek/skills/foo/`，下次启动 `foo` 出现在 `/skills` 列表 | 集成测试 |
| 2 | `seek skill install https://github.com/...#v1.0.0` 克隆 + checkout 到指定 ref，写 `.install.json` | 集成测试（用 file:// 协议或测试 git server） |
| 3 | `seek skill install https://.../foo.tar.gz --sha256 ...` 校验 sha256 不匹配时 abort 且不留落盘文件 | 单元测试 |
| 4 | 单文件 `~/.seek/skills/foo.md` 和目录包 `~/.seek/skills/bar/` 共存时都被加载 | 单元测试 |
| 5 | 同名 skill 冲突时（project .seek > user > builtin），低优先级的被遮蔽——`status <name>` 列出所有被遮蔽路径 | 单元测试 |
| 6 | `seek skill uninstall foo` 删目录但默认保留 `.stats.jsonl` 历史；`--purge` 才删 stats | 单元测试 |
| 7 | `Skill(name=foo)` 工具调用成功后 `.stats.jsonl` 多一行；失败（name 不存在）不写 | 单元测试 |
| 8 | `.stats.jsonl` append 是 fsync-safe，并发多 session 调用不撕裂行（用文件锁或 `O_APPEND` 写小于 PIPE_BUF 的整行） | 单元测试 + `-race` |
| 9 | `seek skill stats --top 5 --since 7d` 正确过滤时间窗 + 排序 | 单元测试 |
| 10 | `update` 后下一次会话 system-prompt skill manifest 反映了新内容（旧 session 不影响） | 集成测试 |
| 11 | `SKILL.md` frontmatter 缺失 `name` 或非法字符 → install 拒绝，目录不落盘 | 单元测试 |
| 11b | 从公开的 Anthropic 风格 skill 仓库（含 `SKILL.md` + `references/` + `examples/`）`seek skill install <git>` 零修改可加载 | 集成测试（fixture 用 `zero-skills` 包结构） |
| 12 | 现有 `.claude/skills/foo.md` 测试集（v0 兼容性测试）全部仍绿 | 现有测试套件 |
| 13 | `seek skill create foo --description "x"` 生成的目录立即可被 loader 加载（`/skills` 看到 foo）；不传 `--description` 且非交互终端时退出码 ≠ 0 不落盘 | 集成测试 |
| 14 | `seek skill create foo` 目标已存在时报错且不修改已有目录任何文件 | 单元测试 |

## 8. 实现计划

接续 v0 的 M0–M7 主线，编号 M8.x：

| 子 ms | 内容 | 估时 |
|---|---|---|
| **M8.0** | 目录包加载路径（`<dir>/SKILL.md` + 小写 fallback）；`Skill` 结构体扩字段（`Type`、`Version`、`AllowedTools`、`Extra`）；loader 区分 package / single-file | ~2 天 |
| **M8.1** | `pkg/skillmgr` install/uninstall 核心：本地路径 + git + https tarball 三种源 | ~3 天 |
| **M8.2** | `.install.json` sidecar + `seek skill update` 命令 | ~1.5 天 |
| **M8.3** | `.stats.jsonl` 写入路径 + 并发安全；`skilltool` 集成 | ~1.5 天 |
| **M8.4** | `seek skill list / status / stats` 三个查询命令 + `--json` 输出 | ~1.5 天 |
| **M8.5** | TUI `/skill` slash 命令镜像 + `/skills` 表格扩列 | ~1 天 |
| **M8.6** | 集成测试 + pitfall 记录 + 文档（README + AGENTS.md 一行说明） | ~1 天 |
| **M8.7** | `seek skill create` 脚手架命令 + 内置模板 + TUI `/skill create` 镜像 | ~1 天 |
| **合计** | | **~12.5 天** |

M8.7 放最后是有意的：先把「装别人写的 skill」整条链跑通，作者侧的脚手架是锦上添花。如果时间紧，M8.0–M8.6 单独发 v0.3.0；create 作为 v0.3.1 的招牌功能。

每个子里程碑独立可发布（v0.3.0 / v0.3.1 / ...），用户可以只装 M8.0+M8.3 享受目录包 + 统计，不强求一次性切换。

## 9. 风险

| 风险 | 缓解 |
|---|---|
| `seek skill install <git>` 调用系统 git——网络/认证失败模式繁多 | 优先 `os/exec git clone --depth=1`；失败时报清晰错误；文档建议预先 `ssh-add` |
| HTTPS tarball 没 sha256 时不能保证完整性 | `--sha256` 不是必需但**强烈推荐**；缺时给 warning 不阻断（用户拉自己的 release 时常没 hash） |
| `seek skill install <git>` 实质是把任意远端代码（`scripts/` 内可执行文件）落到本机，等模型按 SKILL.md 指令调 `bash` 跑 | 不引入新机制——沿用 v0 permission policy：`bash` 工具默认 `ModeAsk`，每次执行前用户 inline 确认。用户在心智上应把「装 skill」等同于「装 npm/brew 包」，PRD §3「不做什么」已显式声明 v2 不做 skill 沙箱。文档建议默认只装可信作者的 skill。|
| 并发 session 同时 append `.stats.jsonl` 撕裂 | 单行 < PIPE_BUF（4KB on Linux/macOS）→ POSIX 保证 `O_APPEND` 原子；记得每行先序列化成单个 `[]byte` 再一次 write |
| `update` 时 skill body 变化但当前 session 已注入旧 manifest → 模型行为不一致 | `update` 命令打印 "重启 seek 后生效"；loader 不允许 session 中途换 manifest（prefix-cache 死线） |
| 目录包变大（assets/ 进图片）→ `seek skill install` 慢 | v2 不限制；v3 加体积告警（>10MB 提示） |
| Anthropic Agent Skills 规范未来扩展新 frontmatter 字段（如 `entrypoint` 之类） | 未知字段全部进 `Skill.Extra`，loader 不报错只在 `status` 显示 unknown 字段名；下一个 seek 版本可选择性识别 |
| Anthropic 改变 `SKILL.md` 命名约定（理论可能） | loader 容忍 `SKILL.md`/`skill.md` 两种大小写；规范真变了再加一层 alias |
| `.install.json` 被用户手动改坏 → update 失败 | parse 失败时降级为「无安装记录」，update 提示用户重装 |

## 10. 后续版本

- **v3**：Skill eval harness（v2 用户呼声决定优先级）——每个 skill 可选 `tests/` 目录，跑跨 provider/model 的回归 + 选型评分
- **v3**：注册表 / `seek skill search`——可能形态是 `awesome-seek-skills` GitHub repo + 简单 JSON index，不做中心化服务
- **v3**：跨模型评测报告——基于 v2 的 `.stats.jsonl` + v3 eval 结果生成可分享的 markdown 报告
- **v3**：lockfile 与 skill 间依赖（如果生态真出现 skill 互相 import 的需要）
- **v4**：项目级 `seek skill install` 写到 `<project>/.seek/skills/`（进 git），团队成员 `seek skill sync` 一键拉齐
