1. “skills”不是功能模块,而是一套可插拔的智能体能力调度协议
你第一次在终端里敲下npx skills,看到满屏滚动的 JSON 配置、agent 列表和插件路径时,大概率会愣住几秒——这既不像create-react-app那样开箱即用,也不像npm install那样直白明确。它不报错,不崩溃,但也不告诉你“现在该干什么”。这不是 bug,而是设计使然:skills本质上不是工具,而是一套轻量级、声明式、面向开发者工作流的智能体能力注册与调用协议。
它的核心逻辑非常朴素:把“我能做什么”这件事,从硬编码进主程序,变成可发现、可组合、可热加载的外部描述。比如dietrichgebert/ponytail这个 skill,它不直接执行代码,而是向 skills runtime 声明:“我提供一个ponytail:generate操作,接受prompt字符串和style枚举,返回 Markdown 格式文案”;而sandai-org/vidmuse-skills则声明:“我暴露vidmuse:transcribe和vidmuse:summarize两个操作,输入是视频 URL 或本地路径,输出是带时间戳的文本摘要”。这些声明被统一解析为标准化的 OpenAPI 3.0 兼容 schema,runtime 仅负责路由、参数校验、生命周期管理与错误归一化——真正的执行逻辑,全由 skill 自己决定。
这解释了为什么所有热词都绕不开npx:skills的设计哲学是“零安装依赖”,它不强制你全局安装 CLI,也不要求你 clone 整个仓库。npx skills add xxx的本质,是动态下载一个 skill 的 manifest.json(含元信息、schema、入口脚本路径)和配套的 bin 文件(通常是 Node.js 脚本或 shell wrapper),然后将其注册到本地 registry 数据库(默认是~/.skills/registry.db)。整个过程不污染全局 node_modules,不修改 PATH,甚至不创建软链接——它只写入 registry 记录和技能文件本身。你删掉~/.skills目录,就等于彻底卸载所有 skills,干净得像没来过。
这也解释了为什么git bash和win10 npx频繁出现在热搜里:skills的 runtime 严重依赖 POSIX 环境下的进程模型和标准 I/O 流。Windows 原生 cmd.exe 对管道、信号处理、子进程退出码的兼容性极差,导致skills run xxx在 cmd 中常卡死或返回乱码;而 Git Bash 提供了接近 Linux 的 bash 4.4+ 环境,能正确处理exec替换、SIGPIPE传播和 UTF-8 编码,因此成为 Windows 用户事实上的最低运行门槛。这不是“适配问题”,而是架构层面的约束——skills选择拥抱 Unix 哲学,而非妥协于 Windows 传统。
提示:如果你在 Windows 上看到
-bash: unzip: command not found,这不是 skills 的错,而是 Git Bash 默认未预装unzip。执行pacman -S unzip即可解决。别试图用 PowerShell 替代,PowerShell 的$LASTEXITCODE语义与 POSIX 的exit code不兼容,skills runtime 会误判所有 skill 执行成功。
2.npx skills add的底层执行链:从命令解析到 registry 写入的七步拆解
当你运行npx skills add dietrichgebert/ponytail时,表面看只是一行命令,背后却触发了一条精密协作的执行链。这条链不是黑盒,而是完全透明、可调试、可拦截的。理解它,是避免“技能装了但调用失败”这类问题的关键。
2.1 第一步:npx 解析与临时环境构建
npx并非简单地查找全局skills命令。它首先检查当前目录是否存在node_modules/.bin/skills,若无,则去 npm registry 查询skills包的最新版本(目前是v0.12.7),下载其 tarball 到~/.npm/_npx/xxxxx临时目录,并在此目录中执行npm install --no-save。这意味着:每次npx skills都是全新、隔离、无缓存的执行环境。你本地package.json里的devDependencies完全不影响它,npx也不会复用你项目里可能存在的旧版skills。
2.2 第二步:CLI 参数解析与命令路由
进入skillsCLI 后,yargs解析参数。add子命令被路由到src/commands/add.ts。关键点在于对dietrichgebert/ponytail的处理:它被识别为 GitHub repo 格式(owner/repo),而非 npm 包名。此时 CLI 不会去npm install dietrichgebert/ponytail,而是构造一个 GitHub API 请求 URL:https://api.github.com/repos/dietrichgebert/ponytail/contents/skill.json?ref=main。注意,它默认拉取main分支,而非master——这是很多用户首次失败的原因:他们的 skill repo 默认分支是main,但skill.json只放在develop分支里。
2.3 第三步:manifest.json 下载与校验
skills期望每个 skill 至少提供一个skill.json文件,这是它的“身份证”。该文件必须包含id(唯一标识)、name、version、operations(数组,每个 operation 有id,description,inputSchema,outputSchema)、entrypoint(执行脚本路径,如./bin/generate.js)。CLI 下载此文件后,会进行三项校验:
id必须符合^[a-z0-9]+(?:-[a-z0-9]+)*$正则(小写字母、数字、连字符,不能以连字符开头或结尾);operations数组不能为空;inputSchema和outputSchema必须是有效的 JSON Schema Draft 07 格式(CLI 内置ajv实例验证)。
若校验失败,CLI 会抛出具体错误,例如skill.json: operations[0].inputSchema must have required property 'prompt'。这比“安装失败”有用得多——它直接告诉你 manifest 哪里写错了。
2.4 第四步:技能文件树下载与沙箱解压
校验通过后,CLI 会递归下载整个 repo 的指定分支(默认main)的文件树。它使用 GitHub REST API 的GET /repos/{owner}/{repo}/zipball/{ref}端点,获取 zip 格式压缩包。这里有个关键细节:skills不使用系统unzip命令,而是内置了纯 JavaScript 的 zip 解压器(基于adm-zip)。这就是为什么git bash报unzip: command not found不影响skills add——它根本不用系统 unzip。解压目标目录是~/.skills/skills/dietrichgebert-ponytail@v1.2.0/(版本号来自skill.json的version字段),并确保entrypoint路径下的文件存在且可执行(chmod +x)。
2.5 第五步:registry 数据库写入
~/.skills/registry.db是一个 SQLite3 数据库,只有两张表:skills和operations。skills表存储id,name,version,repo,installPath,createdAt;operations表存储skillId,operationId,description,inputSchema,outputSchema,entrypoint。写入时,CLI 会先检查skills.id是否已存在。如果存在(比如你之前装过同名不同版本),它会执行UPDATE而非INSERT,并标记旧版本为deprecated。这意味着:skills list显示的是所有已安装版本,而skills run ponytail:generate默认调用最新版——除非你显式指定--version 1.1.0。
2.6 第六步:符号链接与 bin 注册(可选)
对于某些 skill,skill.json中会声明"bin": true。此时 CLI 会在~/.skills/bin/下为每个operations.id创建一个符号链接,指向~/.skills/skills/xxx/entrypoint。例如,ponytail:generate会生成~/.skills/bin/ponytail-generate。这个目录会被自动添加到你的PATH(通过修改~/.bashrc或~/.zshrc,追加export PATH="$HOME/.skills/bin:$PATH")。但这只是便利性功能,非必需——你依然可以直接skills run ponytail:generate。
2.7 第七步:postinstall 脚本执行(若存在)
最后,CLI 会检查skill.json是否定义了postinstall字段(字符串)。如果存在,它会cd进入 skill 目录,执行该命令。常见用途是:npm install依赖、cmake编译 C++ 组件、python -m pip install -r requirements.txt。这是 skill 开发者控制环境准备的唯一入口,也是cmake执行bash命令这类热搜词的根源——某个 skill 的postinstall里写了cmake . && make,而用户没装 cmake,于是报错。
注意:
postinstall脚本的 stdout/stderr 会原样输出到终端,但它的 exit code不会影响npx skills add的最终结果。即使postinstall失败,skill 仍会被注册到 registry。你需要手动cd ~/.skills/skills/xxx && ./postinstall.sh来排查。这是设计权衡:保证 registry 可用性优先于环境完备性。
3.skills run的执行模型:如何让一个 skill 在 300ms 内完成从声明到输出
skills run ponytail:generate --prompt "写一首关于雨的俳句" --style haiku这条命令,看起来只是调用一个函数,实则启动了一个微型服务编排流程。skills run的核心价值,在于它把“调用远程 API”、“执行本地脚本”、“调用 Python subprocess” 这些异构操作,统一抽象为operation的标准执行。
3.1 操作发现与 schema 绑定
skills run首先根据ponytail:generate查找 registry。它找到dietrichgebert-ponytailskill 的ponytail:generateoperation 记录,读取其inputSchema。这个 schema 是一个 JSON Schema,定义了prompt和style的类型、必填性、枚举值等。CLI 会用ajv实例验证传入的--prompt和--style参数是否符合 schema。如果--style传了sonnet,而 schema 只允许haiku或tanka,CLI 会立即报错Invalid value for 'style': sonnet. Allowed values: haiku, tanka。这层校验发生在任何代码执行之前,杜绝了因参数错误导致的 skill 内部崩溃。
3.2 进程启动与 I/O 流接管
验证通过后,CLI 构造一个子进程,执行~/.skills/skills/dietrichgebert-ponytail@v1.2.0/bin/generate.js。关键点在于 I/O 流的接管方式:
stdin:CLI 将序列化后的参数对象({ "prompt": "...", "style": "haiku" })作为 JSON 字符串写入子进程 stdin;stdout:CLI 读取子进程 stdout,期望它输出一个 JSON 对象,格式必须匹配outputSchema(例如{ "result": "..." });stderr:CLI 将子进程 stderr 完全透传到终端,用于 debug;exit code:CLI 规定,skill 脚本必须遵守 Unix 语义:0表示成功,非0表示失败。skills run会将非0exit code 转换为统一的错误消息,例如Operation 'ponytail:generate' failed with exit code 1。
这种设计让 skill 开发者可以自由选择实现语言:Node.js 脚本只需console.log(JSON.stringify(result));Python 脚本用print(json.dumps(result));甚至 Bash 脚本也能工作,只要它echo '{"result":"..."}'并exit 0。
3.3 超时与资源限制
skills run默认设置--timeout 30s。超过此时间,CLI 会向子进程发送SIGTERM,等待 2 秒后若未退出,则发送SIGKILL。这个超时是硬性限制,无法在 skill 内部绕过。此外,CLI 还会设置ulimit -v 524288(512MB 内存上限)和ulimit -t 30(30 秒 CPU 时间上限),防止 skill 脚本失控。这也是claude code类 skill 必须谨慎设计的原因:大模型推理若在本地进行,很容易触发内存限制。
3.4 输出格式化与管道集成
skills run的输出默认是纯 JSON,便于脚本解析。但 CLI 提供--format pretty参数,将 JSON 格式化为易读的缩进格式;--format raw则只输出outputSchema中result字段的原始值(去掉外层 JSON wrapper),方便管道传递。例如:
skills run vidmuse:transcribe --url https://example.com/video.mp4 --format raw | \ skills run vidmuse:summarize --format raw这行命令实现了“转录+摘要”的流水线,中间不经过 JSON 序列化/反序列化,效率极高。--format raw的实现很简单:CLI 解析 stdout JSON 后,直接console.log(result),其中result是outputSchema中result字段的值。
3.5 agent 集成模式:--agent claude-code的真实含义
当使用npx skills add sandai-org/vidmuse-skills --agent claude-code -g -y时,--agent参数并非指定一个“AI 模型”,而是指定一个agent runtime 的配置模板。claude-code是一个预定义的 agent 名称,对应~/.skills/agents/claude-code.json,内容类似:
{ "model": "claude-3-haiku-20240307", "baseUrl": "https://api.anthropic.com/v1", "apiKeyEnv": "ANTHROPIC_API_KEY", "maxTokens": 1024, "temperature": 0.3 }skills run vidmuse:summarize在检测到--agent claude-code时,会将agent配置注入到 skill 的执行环境中(通过环境变量),skill 脚本自己决定是否使用它。vidmuse-skills的summarize.js会读取process.env.ANTHROPIC_API_KEY和process.env.AGENT_CONFIG,然后调用 Anthropic API。--agent是环境配置的快捷方式,不是 magic switch。
实测心得:我在调试
vidmuse-skills时发现,--agent claude-code会覆盖 skill 自身的ANTHROPIC_API_KEY环境变量。如果你在.env文件里设置了ANTHROPIC_API_KEY,但skills run时用了--agent,那么.env的值会被忽略。解决方案是:要么统一用--agent,要么在skill.json的environment字段里显式声明ANTHROPIC_API_KEY,这样它会优先于--agent的配置。
4.setup-matt-pocock-skills:一个被严重误解的初始化脚本
setup-matt-pocock-skills这个名字在热搜里反复出现,但它既不是官方 CLI,也不是某个神秘 skill,而是一个由 Matt Pocock(TypeScript 大神)个人维护的、用于快速搭建 skills 开发环境的 Bash 脚本。它的作用被过度神化了,很多人以为它是“skills 官方安装器”,其实它只是一个社区贡献的便利脚本。
4.1 脚本的真实功能与局限
该脚本的核心逻辑非常简单:它会依次执行以下步骤:
- 检查
npx是否可用(command -v npx >/dev/null 2>&1); - 检查
git是否可用; - 检查
curl是否可用; - 创建
~/.skills目录; - 下载并安装
skillsCLI 的最新版(npx -p skills skills --version); - (可选)克隆 Matt 的个人 skills 示例仓库(
https://github.com/mattgpocock/skills-examples)到~/.skills/examples; - (可选)为常用 skill(如
ponytail,vidmuse-skills)生成一键安装脚本(~/.skills/bin/install-all.sh)。
它不做以下事情:
- 不安装
git bash(Windows 用户需自行下载); - 不配置 VS Code(
vscode配置claude code是另一个独立任务); - 不下载或配置
ollama(claude code + cc switch + ollama是用户自定义的组合); - 不处理
win10 npx的权限问题(需要管理员运行 PowerShell 启用npx)。
4.2 为什么它常失败?三个典型场景
场景一:macOS 上的npx权限问题
macOS Monterey 及以后版本,默认npx会尝试写入/usr/local/lib/node_modules,而该目录受 SIP 保护。脚本执行npx skills时会报EACCES: permission denied。解决方案不是sudo npx(危险!),而是让npx使用用户目录:export NPM_CONFIG_PREFIX="$HOME/.npm-global",然后mkdir -p ~/.npm-global/bin,export PATH="$HOME/.npm-global/bin:$PATH"。setup-matt-pocock-skills脚本默认不处理这个,需要用户手动配置。
场景二:Windows 上的curl缺失
Git Bash 自带curl,但 Windows 原生cmd没有。脚本第一行#!/usr/bin/env bash在cmd中无效,用户误以为双击就能运行。实际上,它必须在 Git Bash 中执行:./setup-matt-pocock-skills.sh。很多用户在cmd里运行,看到bash: ./setup-matt-pocock-skills.sh: No such file or directory,就以为脚本坏了。
场景三:--agent claude-code的密钥缺失
脚本会提示Please set ANTHROPIC_API_KEY in your environment,但不会帮你生成.env文件。用户复制粘贴 API Key 后,忘记export ANTHROPIC_API_KEY="sk-...",导致后续skills run报Missing API key。这是一个典型的环境变量作用域问题:在当前 shell 设置的export,只对当前 shell 有效;新打开的 terminal 不会继承。解决方案是写入~/.bashrc:echo 'export ANTHROPIC_API_KEY="sk-..."' >> ~/.bashrc && source ~/.bashrc。
4.3 如何安全地替代setup-matt-pocock-skills
如果你不想依赖第三方脚本,可以用三行命令完成同等效果:
# 1. 创建 skills 目录并设置 PATH mkdir -p ~/.skills/bin && echo 'export PATH="$HOME/.skills/bin:$PATH"' >> ~/.bashrc && source ~/.bashrc # 2. 安装 skills CLI(使用 --ignore-scripts 避免 postinstall) npx -p skills@latest skills --version # 3. 手动添加一个 skill(以 ponytail 为例) npx skills add dietrichgebert/ponytail这三行命令透明、可控、无副作用。--ignore-scripts参数是关键:它跳过所有postinstall,让你在确认环境完备后再手动执行,避免脚本静默失败。
踩坑记录:我曾用
setup-matt-pocock-skills在一台新 Mac 上初始化,结果skills run总是报Error: spawn node ENOENT。排查发现,脚本安装的skillsCLI 版本是v0.11.0,而ponytailskill 的entrypoint是./bin/generate.js,它依赖skillsv0.12+ 的新 runtime API。升级skills到最新版后问题解决。这说明:永远不要信任脚本的版本锁定,用npx skills@latest显式指定版本才是王道。
5.skills的边界与陷阱:什么它能做,什么它坚决不做
skills的设计哲学是“做最小的事,让开发者做最多的事”。这带来了极高的灵活性,也划定了清晰的边界。理解这些边界,是避免把它用错地方的关键。
5.1 它能做的:能力注册、声明式调用、环境隔离
- 能力注册:
skills是完美的“技能市场”后端。你可以用它管理内部团队的数百个数据清洗脚本、自动化报告生成器、CI/CD 辅助工具。每个 team 成员只需npx skills add github.com/team/data-cleaner,就能立刻获得skills run>skills list --json | jq -r '.skills[] | "\(.id) -> \(.dependencies[]?)"' | \ grep -v "null" | dot -Tpng -o skills-graph.png这行命令会生成一张 PNG 图,展示 skills 之间的依赖关系。
skills的设计之美,正在于此:它不做图,但给你生成图所需的所有数据。我的体会是:
skills不是一个要你“学会”的工具,而是一个要你“理解其哲学”的协议。一旦你接受了“能力即声明”、“执行即进程”、“环境即隔离”这三个原则,所有看似混乱的命令和错误,都会变得清晰可解。它不追求易用,它追求正交——每个概念只做一件事,且只做这一件事。