一句话

给自建 agent 挂自己的方法论技能,正确姿势是 plugins(显式目录) + 环境变量 CLAUDE_CODE_DISABLE_BUNDLED_SKILLS=1。
skills 过滤器不可靠,managedSettings.disableBundledSkills 无效。以下全部实测。

目录结构

my-plugin/
  .claude-plugin/plugin.json     清单:name / version / description / author
  skills/<技能名>/SKILL.md        技能本体,YAML frontmatter + Markdown 正文
  commands/                       可选:自定义斜杠命令
  agents/                         可选:子 agent
  hooks/hooks.json                可选:事件钩子
  .mcp.json                       可选:MCP 配置(可以用 skipMcpDiscovery 忽略)

SKILL.md 文件名必须全大写;技能目录名用 kebab-case;插件名小写短横线。

SKILL.md 格式

---
name: recon
description: 什么时候该用它 —— 这句话是模型唯一常驻能看到的内容,写好
---

正文。只在技能被触发时才读进上下文,可以写长。

引用插件内部路径时用 ${CLAUDE_PLUGIN_ROOT}。

成本:渐进式加载

claude --plugin-dir ./my-plugin plugin details <插件名> 会报预估 token:

Projected token cost
  Always-on:   ~75 tok   added to every session

  component   always-on  on-invoke
  code-audit        ~30       ~660
  recon            < 20       ~380
  report           < 20       ~460
  web-check        < 20       ~530

常驻只有技能名 + 一句描述(合计 ~75 tok),正文按需加载。这就是 skills 相对"把方法论全塞进系统提示词"的全部价值。
注意 --plugin-dir 是顶层参数(claude --plugin-dir <路径> plugin details <名字>),写在 plugin details 后面会报 unknown option。

三个开关的实测结论

做法结果
skills: 'all'❌ 把 Claude Code 自带的 16 个 skill 一起打开(deep-research/dataviz/code-review/claude-api ...)
skills: ['my-plugin:recon']❌ 内置的照样在。显式列表只增不减
skills: []❌ 依然无效,连自己插件的技能都还列着
managedSettings: { disableBundledSkills: true }❌ 实测无效
环境变量 CLAUDE_CODE_DISABLE_BUNDLED_SKILLS=1✅ 有效。16 个 → 只剩自己的

disableBundledSkills 定义在 SDK 的 Settings 接口(settings.json schema)里,不是 Options,文档说它等价于那个环境变量 —— 但只有环境变量这条实际生效。

代码里的做法:配置里仍写 claudeSettings.disableBundledSkills,由拼环境变量的那一层翻译成 env。

关掉前后对比:

关之前: skills = [deep-research, dataviz, update-config, verify, debug, code-review,
                  simplify, batch, fewer-permission-prompts, doctor, loop, claude-api,
                  workflow-authoring, run, run-skill-generator, sec-guard:recon]
关之后: skills = [sec-guard:recon, doctor]

(doctor 是内置斜杠命令,不是 skill,关不掉;slash_commands 里还留着 typable 但模型看不见的那些。)

为什么用 plugins 而不是 settingSources

plugin.path 是显式路径,所以不需要打开 settingSources。
一旦打开 settingSources: ['project'|'user'],宿主机的 CLAUDE.md、settings.json、用户自己的 MCP server 全会渗进来
(见 Claude Agent SDK 配置渗漏与隔离 (Claude Agent SDK Config Bleed and settingSources Isolation))。

skipMcpDiscovery: true 让插件不读自己的 .mcp.json,MCP 连接仍由宿主代码掌握。

技能会不会被触发:不一定

技能是概率性的。列表在上下文里,用不用由模型决定。

同一句"帮我摸一下 10.20.0.1 这台机器":

  • 加了提示词点名之前:2 次里 1 次触发
  • 在系统提示词里加了一张"什么任务加载什么技能"的表之后:连测 3/3 触发

光靠 frontmatter 的 description 不够,系统提示词里点名才稳。

另外:技能是通过 Skill 工具加载的,不是去 Read SKILL.md。检测是否触发要看 tool_use.name === 'Skill',不要找文件读取。

安全提示

官方文档原话:

This is a context filter, not a sandbox: unlisted skills are hidden from the model's listing and rejected by
the Skill tool, but their files remain on disk and are reachable via Read/Bash. Do not store secrets in skill files.

推论:第三方 SKILL.md 是不可信的指令。它不是代码,是注入到模型上下文里的自然语言。
一个来路不明的技能可以在权限范围内指挥模型做过度操作,或试图引导它忽略既有的门禁。

代码层写的门禁绕不过去(见 Agent 权限门禁做在代码层 (Enforcing Permission Gates in Code for LLM Agents)),
但模型行为会被带偏。第三方技能要读一遍再用,别整包拖进来。

相关

出现场景

C:\Users\18086\.workspace\git-workspace\mini-agent,2026-09-11。为网安检查助手挂 recon / web-check / code-audit / report 四个方法论技能时验证。


本文归档于个人知识库 · 领域:CS & AI · 模块:04 Project_CS_AI/AI apps