本文中的"主会话"指
SDK 启动 CLI 时始终追加
不传
传字符串列表时,只有列表中匹配的 skill 会出现在主会话模型的 skill 列表中,并可通过
插件内 skill 使用插件限定名
上面的配置最终允许列出的读取 / 搜索工具和
字符串列表形式的
提供 Skill 选择器的 TypeScript 宿主可以把用户的选择附加到一条流式
初始化结果会包含 CLI 在本次会话中发现到的完整 skill 清单,不受字符串列表形式的
若 TypeScript
如果你用
这类
这里只展示 skill 相关字段;完整类型见 SDK References。Python 中流式
query()(或 Python 的 QoderSDKClient)直接驱动的会话,与通过 Agent 工具委派的子 Agent 相对。两类会话的关系见 子 Agent。
options.skills 控制主会话的 skill 上下文与 Skill 工具调用策略。传字符串列表时,SDK 会同时下发主会话 skill allowlist,并把每一项编译成 Skill(name) 后与工具白名单(allowedTools / allowed_tools)合并;传 'all' 时允许调用所有已发现 skill,不额外过滤主会话上下文。
SDK 不加载内置 skills
SDK 启动 CLI 时始终追加 --disable-builtin-skills,会话不会拿到 CLI 出厂内置的那批 skill(simplify、debug、security-review、quest、batch、agent-creator、hook-config、mcp-config、skill-creator 等)。发现清单(TypeScript 的 initializationResult().skills、Python 的 get_server_info()['skills'])里也不会出现 source: 'built-in' 的条目,模型系统提示同样看不到它们。
这是 SDK 的固定行为,没有开关可以打开;如果你想要 CLI 内置 skill 的能力,要么自己在 plugin / 用户目录 / 项目目录里复刻一份 SKILL.md,要么直接复用 CLI 默认场景。
你的会话仍然能用以下来源贡献的 skills:
- plugin skills:通过
options.plugins加载,使用插件限定名(plugin:skill)。 - 用户 / 项目 skills:通过 setting sources 选项显式打开
user/project/local后被发现。 - Agent 预加载 skills:在
options.agents[name].skills里声明,只对该子 Agent 生效。
使用 CLI 默认策略
不传 skills 时,SDK 不额外注入 Skill allowlist,完全交给 CLI 自身策略。由于内置 skill 已经被禁用,没有 setting sources / plugins 的会话,发现清单会是空列表。
启用所有已发现 skills
skills 取 'all' 会允许 Skill 工具调用所有当前 CLI 发现到的 skill(来源由 setting sources / plugins 决定,不再包含内置)。
只启用指定 skills
Skill 工具调用。列表项支持普通名称和插件限定名;传空列表 [] 会让主会话看不到、也无法通过 Skill 工具调用任何 skill。
这个列表不会改变 CLI 的发现结果;未列出的 skill 仍可能出现在发现清单中。
启用插件内 skill
插件内 skill 使用插件限定名 plugin:skill。关于 plugin 加载方式见 Plugins 文档。
与显式工具白名单合并
Skill(review)。SDK 会合并去重,不会重复写入同名条目。
隐藏已发现的 skills
字符串列表形式的 options.skills 会过滤主会话模型上下文并限制 Skill 工具调用,但不会改变发现清单中的发现结果。想让某个 plugin / 用户 / 项目 skill 连发现清单也不再出现,需要使用 settings.skillOverrides。
'off':完全隐藏,不进发现清单、不进模型系统提示、Skill工具调用也会被拒。- 其它取值:
'on'(默认)、'name-only'(只露名字、不露描述)、'user-invocable-only'(模型看不到,用户仍可通过/name触发)。 - 影响范围:plugin、user、project 等所有 SDK 可见来源都尊重该 override;CLI 内置 skill 已经被
--disable-builtin-skills拦在外面,写不写 override 都不会出现。 - key 命名规则:插件 skill 用插件限定名
plugin:skill;非插件 skill 用裸名。两种形态可以同时写,匹配时先按完整名命中、缺命中则退回裸名。
options.skills可以隐藏主会话的模型上下文,但不会过滤发现清单;需要同时从发现清单中隐藏时,使用skillOverrides: { name: 'off' }。
为单条消息激活用户选择的 Skills
提供 Skill 选择器的 TypeScript 宿主可以把用户的选择附加到一条流式 SDKUserMessage 上。CLI 会在处理该消息前将这些 Skill 作为用户直接意图激活,不需要模型判断并调用 Skill 工具。
TypeScript
selected_skills 仅作用于当前消息,不会改变会话级 options.skills 对模型可见性和 Skill 工具调用的控制。用户直接选择走独立路径,因此被选择的 Skill 不必出现在 options.skills 列表中。每一项包含已发现的 Skill 名称和可选的原始 arguments;多个选择会在所属用户文本之前依次激活。被选择的 Skill 仍必须处于启用状态、允许用户调用,并且支持内联激活;已禁用、找不到、使用 fork context 或属于 workflow 的 Skill 会被拒绝。disable-model-invocation: true 只阻止模型发起的 Skill 工具调用,不会阻止这种用户显式选择。
当宿主 UI 已经解析完 slash command 意图时,设置 client_composed: true。此时,以 / 开头的文本会作为普通输入保留,不会再次被 CLI 解析为命令。如果仍希望 CLI 解析消息文本中的 slash command,不要仅因为消息包含 selected_skills 就设置该字段。
非空的 selected_skills 要求 CLI 声明 selected_skills_v1。连接旧版 CLI 时,SDK 会以 UnsupportedCliCapabilityError 拒绝输入,而不是静默丢弃用户选择。该消息级 API 当前仅由 TypeScript SDK 提供。
读取当前会话发现到的 skills
初始化结果会包含 CLI 在本次会话中发现到的完整 skill 清单,不受字符串列表形式的 options.skills 过滤。它适合宿主 UI 展示「已发现的 skills」,不能直接当作主会话当前可调用列表。Python 中 query() 是一次性流,没有便捷查询接口,用 QoderSDKClient 才能在握手后读取。
字符串列表形式的skills是主会话上下文与工具可见性控制,不是安全边界。未列出的 skill 不会出现在模型的 skill 列表中,也不能通过Skill工具调用,但 skill 文件仍在磁盘上,仍可能被普通文件读取工具访问。
运行中的 Query 刷新 Skills
若 TypeScript Query 运行期间安装、移除或修改了 Skill,可让已连接的 CLI 重扫,而无需重启会话:
skills 是可展示、可由用户调用的完整 Skill 替换快照。应以它整体替换之前渲染的 Skill 列表,而不是合并。响应有意不包含非 Skill 的 plugin command。reloadSkills() 需要 CLI capability reload_skills_v1;不支持的 CLI 会以 UnsupportedCliCapabilityError 拒绝。它只重扫 Skills;如果还需要刷新其他 plugin 资源,应使用 q.reloadPlugins()。
命令目录的范围比 Skills 更广。为了让命令 UI 保持最新,应持续消费 Query;每次收到 system/commands_changed 时整体替换本地命令目录,随后 q.supportedCommands() 会返回同一份最新完整快照。该事件不说明变更来自哪里,因此不能仅凭它判断安装了 Skill。TypeScript SDK 会自动协商此事件;直接集成 JSONL 进程时,初始化请求必须设置 supportsCommandsChanged: true,并在每次模型结果之后继续读取消息。
Python SDK 当前没有等价的运行时刷新 API。初始化后仍可从 get_server_info()['skills'] 读取发现清单。
自定义 Agent 预加载 Skills
如果你用 options.agents 定义自定义子 Agent,可以在 Agent 定义里声明 skills。这样当主会话调用 Agent 工具时,子 Agent 会带着指定 skill 运行。
skills 只影响该 Agent 的上下文,不等价于给主会话启用同名 skill——主会话的工具白名单不会被这条改动影响。
Options 速查
| 字段(TypeScript / Python) | 说明 |
|---|---|
skills / skills | 列表限制主会话的 skill 上下文与调用;[] 禁用全部;'all' 启用全部已发现 skills |
agents / agents | 自定义 Agent;Agent 定义内可声明独立的 skills 预加载列表 |
allowedTools / allowed_tools | 工具白名单;会与 skills 编译出的 Skill(...) 条目合并去重 |
settingSources / setting_sources | 决定 CLI 是否扫描用户 / 项目目录里的 skills(默认空 = 沙箱) |
plugins / plugins | 加载插件,插件里的 skills 会进入发现集合 |
settings 还有几个 skill 相关字段,SDK 都是透传,实际效果取决于 CLI 版本是否实现:
| 字段 | 作用 |
|---|---|
skillOverrides | 按 skill 名设置 'on' | 'name-only' | 'user-invocable-only' | 'off';plugin、user、project 等来源都尊重该 override |
skillListingMaxDescChars | skill listing 里每条描述的字符上限;SDK 原样透传,默认值由 CLI 版本决定 |
skillListingBudgetFraction | 给 skill listing 预留的上下文窗口比例;SDK 原样透传,默认值由 CLI 版本决定 |
返回值参考
SystemMessage(subtype="init").data["skills"] 是 skill 名称列表,与这里带元数据的发现清单不是同一个结构。
最佳实践
- 按需启用
skills:'all'适合开发和调试;面向最终用户的产品通常应该传明确列表。 - 想要 CLI 内置 skill 的行为,自己复刻:SDK 不会把
simplify/security-review这些塞进会话,需要的话在 plugin 或 setting sources 范围里自己提供 SKILL.md。 - 不要把
skills当沙箱:安全边界应由工具白名单 / 黑名单、权限回调、权限模式和沙箱共同控制。 - 为 UI 选择正确的快照:
initializationResult().skills/get_server_info()['skills']是初始发现清单,不代表主会话当前全部可调用。TypeScript 中,运行中的 Skill UI 应以q.reloadSkills().skills替换,命令 UI 则以commands_changed更新。 - 子 Agent 的
skills单独管理:它与主会话options.skills是两套独立的列表,互不覆盖。
当前限制
--disable-slash-commands是 CLI 一次性禁用所有 slash-command skill 的能力,SDK 当前没有暴露一等 option,不建议依赖非公开的透传路径。settings.skillListingMaxDescChars、settings.skillListingBudgetFraction是 SDK 已透传的 listing 预算控制字段;当前 qoderclicn 还没有实现 listing 预算控制,传入不会报错但也不会改变行为。- 运行时刷新 Skill 当前仅支持 TypeScript。Python SDK 没有
client.supported_skills()便捷方法,需要从get_server_info()['skills']读取初始化发现清单。

