docs / concepts

核心概念

skillmod 的行为由几条固定规则决定:两个清单文件各司其职,声明与安装按作用域分开,版本只接受不可变形式。这一页把这些规则讲清楚;每条命令的逐字用法在命令参考。

两个文件

SKILL.mod 是人维护、提交进仓库的声明。SKILL.lock 是工具维护的安装记录,确定性生成,禁止手改。每条命令都会读取并校验这两个文件:手改出来的违规清单会被报错,而不是被应用一半。

SKILL.modSKILL.lock
谁维护skillmod
写什么声明:source、可选 version、每个 skill 的 agents安装记录:解析出的 versioncommitdirhash
手改可以,改完提交不行

锁定记录里三个值各自的分工:

  • version:钉住的不可变版本。SKILL.mod 里没写 version 的条目跟随最新的不可变解析结果,由 SKILL.lock 钉住;写了的条目钉在那个 tag 或 commit 上,直到 update 运行。
  • commit:解析出的提交。有它,伪版本在一台从未见过对应 tag 的机器上也能解析。
  • dirhash:锁定的内容摘要。每条锁定记录必须是单个 h1: 开头的 SHA-256 值。
模式版本:两个文件都声明 schemaversion = 1。没有 schemaversion 的旧 SKILL.lock 按版本 1 读取,并在下次 skillmod 写入清单状态时归一化;显式的 0、负数和未知版本会被拒绝。

作用域

skillmod 区分项目与全局两种作用域。默认是项目作用域:清单放在当前目录,skill 装进当前目录的 .agents/skills/--global-g)切到全局作用域:声明放在 ~/.agents/skillmod/global/,装进 ~/.agents/skills/

作用域声明与锁定默认安装目录
项目(默认)当前目录的 SKILL.modSKILL.lock当前目录的 .agents/skills/
全局(--global$SKILLMOD_HOME/global/,默认 ~/.agents/skillmod/global/~/.agents/skills/

skill 装进所选作用域的 .agents/skills/,skillmod 不管理其他目录约定。所有命令都接受 --global-g),普通命令不会合并项目与全局两份清单。

同一个 skill 可以同时声明在两个作用域,此时两者共享同一份磁盘快照:所有作用域共用一个内容存储,项目、全局技能和 CI 运行复用同一批不可变快照,不会重复下载同一个仓库。global/ 目录只放清单,不是第二个快照缓存。

地址形式

仓库地址的形式是:

<repository>[//<subdirectory-or-skill-name>][@<version>]

@<version> 只属于命令行,从不写进 sourcesource 里出现 @version 会被拒绝,版本写在 version 字段。HTTPS 传输是默认,两个文件都只记 host/owner/repo;其他传输因为改变了仓库的获取方式而显式记录。还拼着 https:// 的旧文件可以正常工作,下次 skillmod 写入时改写成短形式。

// 简写

// 后写单段时,skillmod 先试仓库根目录下的精确子目录,再回退到 skills/ 下任意位置的唯一技能名;同名多个时要求写全路径并给出候选。单 skill 仓库不需要 //:省略时,get 会发现根 SKILL.mdskills/ 下的每个 SKILL.md

# 两个来源可能发布同名 skill,用 --alias 安装额外条目
$ skillmod get --alias review-acme github.com/acme/agent-skills//review

两份声明和两份锁定记录都会保留。安装目录等于 name 时,锁定记录省略 dir,只有别名条目才记录它。别名必须是可移植的名字,所有安装目录在 Unicode 规范化和大小写折叠后必须互不相同,同一个项目在 Linux、macOS 和 Windows 上行为一致。用不同别名重新 get 同一来源会保留旧目录,并提示 skillmod prune 可以清掉它。

地址不带凭证:嵌入的用户信息、查询串、片段和控制字符会在地址被使用或持久化之前被拒绝,secret 到不了 SKILL.modSKILL.lock、裸仓库的配置或诊断信息。支持的传输是 httpshttpsshfile,以及 scp 风格的 git@host:pathgit:// 因未认证、未加密被拒绝。SSH 用户名会保留,因为它标识传输方式;密码不会,secret 属于 Git credential helper、SSH agent 或环境变量。

版本

三种不可变形式会被接受,分支名一律拒绝——可变引用无法锁定。

形式示例什么时候用
语义化版本 tagv1.2.0code-review/v1.2.0发布方给发布打 tag
提交 SHA完整 40 字符 SHA需要一个确切修订
伪版本v1.0.96-0.20260624023612-49f948faa925钉住一个提交;仓库有 tag 时 base 取最高 tag,没有 tag 时是纯 v0.0.0

没有 tag 的仓库生成 v0.0.0-<ts>-<hash>;有 base tag 时生成 v<base>-0.<ts>-<hash>。base tag 出现之前写下的锁定记录使用纯 v0.0.0-<ts>-<hash> 形状,继续有效;下一次 update 会把它们迁移到仓库的最新 tag。

安装模式

auto 优先把原生目录符号链接指向共享只读快照,链接不可用时回退逐字节拷贝,包括没有链接权限的 Windows。copy 总是创建独立目录。--install-mode 为单条命令覆盖机器配置。

链接指向机器上所有项目共享的快照,通过链接编辑就是编辑共享内容。要改先脱钩:

$ skillmod sync --relink --install-mode=copy

安装模式、缓存的绝对路径和作用域都被刻意排除在两个文件之外:相同的声明与版本,在任何系统、任何安装模式下都生成相同的清单。

共享存储

只有一个缓存,所有作用域共用 $SKILLMOD_HOME/pkg/mod/,默认 ~/.agents/skillmod/pkg/mod/

~/.agents/skillmod/pkg/mod/
├── github.com/anthropics/skills@v0.0.0-.../ # 可直接浏览的整库快照
└── cache/
├── vcs/ # 裸 Git 仓库,内部按哈希设键
├── download/ # 仓库版本、ref 与解析元数据
└── locks/

快照可读且不可变。HTTPS、默认端口 SSH 和 .git URL 变体共享同一份快照,身份标识不带凭证,URL 里的 token 不可能成为缓存键的一部分。

第一次请求 repo@version 会物化整个仓库快照;之后从同一版本添加另一个 skill,会直接从本地子目录校验并安装,不调用 Git、不碰远程。显式的 @commit 同样复用该提交已有的快照。请求最新版本或运行 skillmod update 保持在线刷新语义。设置 SKILLMOD_HOME 可以搬迁整个存储。

--dry-run 不动清单和安装,但远程来源校验仍可能填充共享缓存。prune 删除过时的安装条目,不删除链接目标或快照;没有自动缓存逐出,手工删除快照之前先确认没有已安装的链接还在用它,也不要用删缓存来移除单个依赖。

分享给 agent

share 把每个 skill 的同名链接放进所选 agent 目录,例如 .claude/skills/<skill>,指向受管的 .agents/skills/<skill>。受管目录是唯一真实副本:改受管 skill 会同时透过每个链接可见,没有需要同步的东西。链接和安装一样使用 auto 回退,不支持符号链接的文件系统收到的是保字节拷贝。

agent 用一个目录段命名,从作用域根下的 .<name>/skills 读取,所以名单是开放的——workbuddyclaude 一样有效。分享记录只写名字,不写目录:存路径在别处无法复现,名字足以重建链接。

# SKILL.mod
[[skill]]
name = "review"
agents = ["claude", "codex"]

sync 在新机器上重建每个条目描述的链接,verify 报告缺失或漂移的链接;本机没有的 agent 目录会被跳过,因为声明表达的是团队意图,不是机器要求。名字用字母、数字、._-;前导点和大小写会被归一化,.Claudeclaude 是同一个目标,不能出现在同一个列表里。不能作为一个可移植目录段的名字会在读取清单时被拒绝。没有 agentsagents 为空的条目,skill 只留在受管目录里。

share --remove --agent <name>-r)是声明的出口:把点名的 agent 从命令指定的 skill 上解绑,并从这些条目的 agent 列表里删掉,放着外来内容的目标不动,链接拆完才保存声明。移除一个 skill 或把它当陈旧条目 prune 掉时,镜像其受管副本的链接一并拆掉,没有了 agent 的条目整个失去该字段。SKILL.lock 也记住创建过的目标:手工删掉一个 agent 名字只是移除分享意图,已有链接留给 removeprune 之后清理。

接下来:每条命令的逐字用法见命令参考;分发、更新、接管存量技能见场景指南