Skills 索引与管理界面
核心原则
索引是结构化事实,不是语义理解。 路径、体积、启用状态这些东西用脚本采集,不用 LLM 逐个读文件。脚本约 2 秒扫完全机 160+ 条,LLM 做同样的事要几分钟且每次结果不同。
LLM 只在两处介入:补分类规则、写一句话摘要。其余交给脚本。
命令
全量扫描,产出三件套:
python scripts/scan_skills.py --workspace "<工作目录>" --emit-html --emit-md
增量扫描,只重扫 SKILL.md 变动过的条目(跳过体积统计这一步)。实测 165 条约从 2.0s 降到 1.4s,文件系统缓存热时可到 0.7s:
python scripts/scan_skills.py --workspace "<工作目录>" --incremental --emit-html --emit-md
在非 skill 目录下运行时,先把 templates/index.html 复制到目标目录再执行,否则脚本找不到模板(脚本会自动识别 skills-index.html 或 index.html)。
覆盖的数据源(WorkBuddy 必须扫四层,只扫一层会漏掉一半)
| 层级 | 路径 | 优先级 |
|---|---|---|
| 项目级 | {workspace}/.workbuddy/skills/ |
0(最高) |
| 用户级 | ~/.workbuddy/skills/ |
1 |
| 插件市场 | ~/.workbuddy/plugins/cache/<market>/<plugin>/<version>/skills/ |
2 |
| 应用内置 | %LOCALAPPDATA%/Programs/WorkBuddy/resources/app.asar.unpacked/resources/plugins/ |
3 |
| 外部 Agent | ~/.claude/skills、~/.codex/skills、~/.agents/skills、~/.trae/skills、~/.openclaw/skills 等 |
4 |
同名 skill 出现在多处时保留优先级最高的,其余记入条目的 shadows 字段。
三个非扫描能拿到的关键数据
~/.workbuddy/.skill-list-cache.json:WorkBuddy 官方 skill 注册表缓存,提供disable(是否禁用)、disableModelInvocation(是否进模型上下文)、canonicalName。这三项扫目录扫不出来,必须读这个文件。- 各 skill 目录下的
_skillhub_meta.json:安装来源、市场版本、installedAt、内容哈希。 ~/.workbuddy/storage/<user>/scoped/<hash>/skills-installed-store.json:应用托管的按 scope 安装快照,改状态时的目标文件。
去重规则(踩过的坑)
- 插件树一个包可含多个 skill:必须遍历版本目录下所有
SKILL.md,不能只取一个。 - 同一 skill 存在多个版本目录:按路径中的版本号取最高,否则重复计数。
- skill 内部资料目录:
references/、examples/、assets/里也常有SKILL.md,不是独立 skill。判定规则是「SKILL.md 的祖先路径中不得出现资料型目录名」。
输出三件套
| 文件 | 读者 | 用途 |
|---|---|---|
skills-index.json |
程序 | 唯一真相来源 |
skills-index.html |
人 | 搜索、筛选、详情抽屉、状态开关 |
SKILLS_INDEX.md |
Agent | 放进上下文用的纯文本索引,路径用 ~/ 简写、全路径只在来源分组区出现一次 |
界面能力
统计条、搜索、层级筛选、状态筛选(已禁用 / 不进上下文 / 多份副本 / 有待办变更)、四种排序、卡片与表格双视图、详情抽屉(含同名副本清单、路径复制、状态开关)。键盘 / 聚焦搜索,Esc 关闭。
状态开关与写入(P2,边界要讲清楚)
界面里的启用/禁用开关只生成待办清单,不直接改系统。点「导出待办」下载 pending-changes.json,再执行:
python scripts/apply_changes.py --list-targets # 看写入目标
python scripts/apply_changes.py --plan pending-changes.json # 预览差异(默认 dry-run)
python scripts/apply_changes.py --plan pending-changes.json --apply --yes
python scripts/apply_changes.py --rollback <备份目录>
为什么默认不直接写:WorkBuddy 没有提供 skill 级开关的官方配置入口。状态落在应用托管的按 scope 缓存里,同一份内容在 8 个 cwd scope 下重复(实测一个 skill 命中 16 条记录),且带 fetchedAt 时间戳,写入后有被应用下次读取覆盖的可能。所以写入器强制走「备份 → 差异预览 → 二次确认 → 原子写入 → 可回滚」,并建议长期开关优先用 WorkBuddy 界面里的入口。
界面上看到的启停状态来自缓存,不代表应用已生效,需重启应用确认。
注意事项
- 索引含本机全路径,不要推到公开仓库,加进
.gitignore。 - 写操作会同时改状态存储与只读缓存(让界面立刻反映),两者都自动备份。
- 分类靠关键词规则,新增 skill 可能落入「未分类」,在
CATEGORY_RULES补词即可。
发布到 SkillHub(skillhub.cn)
CLI 的 frontmatter 解析器只认 key: value 与 key: [a, b] 两种写法,不支持 YAML 块标量(|)与多行嵌套。写 frontmatter 时把 description 压成单行,否则会解析成字面量 |。
必填三项,缺一即被拒绝:
| 字段 | 约束 |
|---|---|
slug |
kebab-case,正则 ^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$,长度 2-128,全网唯一 |
version |
SemVer,形如 1.0.0(v1.0.0 不合法) |
displayName |
非空 |
建议项:summary、description、tags、license、homepage。
发布流程:
# 1. 预检(不发请求)
python <cli>/skills_store_cli.py publish <skill目录> --dry-run
# 2. 登录(Token 从 skillhub.cn/dashboard/keys 创建,需先实名认证)
python <cli>/skills_store_cli.py login --key skh_xxx --host https://api.skillhub.cn
# 3. 发布
python <cli>/skills_store_cli.py publish <skill目录> --changelog "首次发布" --host https://api.skillhub.cn
CLI 本体是纯 Python 标准库脚本,Windows 上直接 python skills_store_cli.py 即可,不必用 WSL。
发布前必须清空 templates/ 里的内联数据。 生成过的 skills-index.html 内联了全部条目与本机绝对路径,直接当模板上传会公开泄露你的用户名、工作区路径与完整技能清单。