> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qoder.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Skills

本文中的“主会话”指 `query()` 或 `QoderSDKClient` 直接驱动的会话，与通过 `Agent` 工具委派的子 Agent 相对。两类会话的关系见 [子 Agent](/zh/cli/sdk/python/agents)。

`options.skills` 控制主会话的 skill 上下文与 `Skill` 工具调用策略。传字符串列表时，SDK 会同时下发主会话 skill allowlist，并把每一项编译成 `Skill(name)` 后与 `allowed_tools` 合并；传 `"all"` 时允许调用所有已发现 skill，不额外过滤主会话上下文。

<div id="sdk-不加载内置-skills" />

## SDK 不加载内置 skills

SDK 启动 CLI 时**始终**追加 `--disable-builtin-skills`，会话不会拿到 CLI 出厂内置的那批 skill（`simplify`、`debug`、`security-review`、`quest`、`batch`、`agent-creator`、`hook-config`、`mcp-config`、`skill-creator` 等）。`get_server_info()['skills']` 里也不会出现 `source: 'built-in'` 的条目，模型系统提示同样看不到它们。

这是 SDK 的固定行为，没有开关可以打开；如果你想要 CLI 内置 skill 的能力，要么自己在 plugin / 用户目录 / 项目目录里复刻一份 SKILL.md，要么直接复用 CLI 默认场景。

你的会话仍然能用以下来源贡献的 skills：

* **plugin skills**：通过 `options.plugins` 加载，使用插件限定名（`plugin:skill`）。
* **用户 / 项目 skills**：通过 `options.setting_sources` 显式打开 `user` / `project` / `local` 后被发现。
* **Agent 预加载 skills**：在 `options.agents[name].skills` 里声明，只对该子 Agent 生效。

要稳定确认本次会话发现到了哪些 skills，请在运行时读 `client.get_server_info()['skills']`，不要在代码里硬编码集合。

***

<div id="使用-cli-默认策略" />

## 使用 CLI 默认策略

不传 `skills` 时，SDK 不额外注入 `Skill` allowlist，完全交给 CLI 自身策略。由于内置 skill 已经被禁用，没有 `setting_sources` / `plugins` 的会话 `get_server_info()['skills']` 会是空列表。

```python theme={null}
from qoder_agent_sdk import query, QoderAgentOptions

async for msg in query(
    prompt="Analyze the test coverage of this project",
    options=QoderAgentOptions(cwd="/path/to/project"),
):
    print(msg)
```

<div id="启用所有已发现-skills" />

## 启用所有已发现 skills

```python theme={null}
async for msg in query(
    prompt="Use an appropriate skill to perform a code review",
    options=QoderAgentOptions(
        cwd="/path/to/project",
        setting_sources=["project"],
        skills="all",
    ),
):
    print(msg)
```

`skills="all"` 会允许 `Skill` 工具调用所有当前 CLI 发现到的 skill（来源由 `setting_sources` / `plugins` 决定，不再包含内置）。

<div id="只启用指定-skills" />

## 只启用指定 skills

```python theme={null}
async for msg in query(
    prompt="Use the review skill to inspect recent changes",
    options=QoderAgentOptions(
        cwd="/path/to/project",
        setting_sources=["project"],
        skills=["review"],
    ),
):
    print(msg)
```

传字符串列表时，只有列表中匹配的 skill 会出现在主会话模型的 skill 列表中，并可通过 `Skill` 工具调用。列表项支持普通名称和插件限定名；传空列表 `[]` 会让主会话看不到、也无法通过 `Skill` 工具调用任何 skill。

这个列表不会改变 CLI 的发现结果；未列出的 skill 仍可能出现在 [`client.get_server_info()['skills']`](#读取当前会话发现到的-skills) 中。

<div id="启用插件内-skill" />

## 启用插件内 skill

插件内 skill 使用插件限定名 `plugin:skill`。关于 plugin 加载方式见 [Plugins 文档](/zh/cli/sdk/python/plugins)。

```python theme={null}
async for msg in query(
    prompt="Use the echo skill provided by the plugin to handle this input",
    options=QoderAgentOptions(
        plugins=[{"type": "local", "path": "/path/to/sdk-test-plugin"}],
        skills=["sdk-test-plugin:sdk-echo"],
    ),
):
    print(msg)
```

<div id="与显式工具白名单合并" />

## 与显式工具白名单合并

```python theme={null}
async for msg in query(
    prompt="Read the source and use the review skill to produce a list of issues",
    options=QoderAgentOptions(
        cwd="/path/to/project",
        setting_sources=["project"],
        allowed_tools=["FileRead", "Grep"],
        skills=["review"],
    ),
):
    print(msg)
```

上面的配置最终允许 `FileRead`、`Grep` 和 `Skill(review)`。SDK 会合并去重，不会重复写入同名条目。

<div id="隐藏已发现的-skills" />

## 隐藏已发现的 skills

字符串列表形式的 `options.skills` 会过滤主会话模型上下文并限制 `Skill` 工具调用，但不会改变 `client.get_server_info()['skills']` 中的发现结果。想让某个 plugin / 用户 / 项目 skill 连发现清单也不再出现，需要使用 [`settings.skillOverrides`](/zh/cli/sdk/python/references#skilloverrides)。

```python theme={null}
options = QoderAgentOptions(
    plugins=[{"type": "local", "path": "/path/to/sdk-test-plugin"}],
    settings={
        "skillOverrides": {
            "sdk-test-plugin:sdk-echo": "off",
        },
    },
)
```

* `"off"`：完全隐藏，不进 `get_server_info()['skills']`、不进模型系统提示、`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` 可以隐藏主会话的模型上下文，但不会过滤 `get_server_info()['skills']` 发现清单；需要同时从发现清单中隐藏时，使用 `skillOverrides: {name: "off"}`。

***

<div id="读取当前会话发现到的-skills" />

## 读取当前会话发现到的 skills

初始化结果会包含 CLI 在本次会话中发现到的完整 skill 清单，不受字符串列表形式的 `options.skills` 过滤。它适合宿主 UI 展示「已发现的 skills」，不能直接当作主会话当前可调用列表。`query()` 是一次性流，没有便捷查询接口；用 `QoderSDKClient` 才能在握手后读取。

```python theme={null}
from qoder_agent_sdk import QoderAgentOptions, QoderSDKClient

options = QoderAgentOptions(
    cwd="/path/to/project",
    setting_sources=["project"],
    skills="all",
)

async with QoderSDKClient(options) as client:
    info = await client.get_server_info()
    if info:
        for skill in info.get("skills", []):
            print(skill["name"], skill.get("source"))
```

> 字符串列表形式的 `skills` 是主会话上下文与工具可见性控制，不是安全边界。未列出的 skill 不会出现在模型的 skill 列表中，也不能通过 `Skill` 工具调用，但 skill 文件仍在磁盘上，仍可能被普通文件读取工具访问。

***

<div id="自定义-agent-预加载-skills" />

## 自定义 Agent 预加载 Skills

如果你用 `options.agents` 定义自定义子 Agent，可以在 `AgentDefinition` 里声明 `skills`。这样当主会话调用 `Agent` 工具时，子 Agent 会带着指定 skill 运行。

```python theme={null}
from qoder_agent_sdk import AgentDefinition, QoderAgentOptions

options = QoderAgentOptions(
    cwd="/path/to/project",
    allowed_tools=["Agent"],
    agents={
        "sdk-skill-helper": AgentDefinition(
            description="Invoke when the sdk-agent-marker skill is needed.",
            prompt="You are a helper agent that only reads and runs the specified skill.",
            skills=["sdk-agent-marker"],
            maxTurns=2,
        ),
    },
)
```

这类 `skills` 只影响该 Agent 的上下文，不等价于给主会话启用同名 skill —— 主会话 `allowed_tools` 不会被这条改动影响。

***

<div id="options-速查" />

## Options 速查

| 字段                | 类型                                                  | 说明                                                     |
| ----------------- | --------------------------------------------------- | ------------------------------------------------------ |
| `skills`          | `list[str] \| Literal["all"] \| None`               | 列表限制主会话的 skill 上下文与调用；`[]` 禁用全部；`"all"` 启用全部已发现 skills |
| `agents`          | `dict[str, AgentDefinition] \| None`                | 自定义 Agent；`AgentDefinition.skills` 是该 Agent 的独立预加载列表   |
| `allowed_tools`   | `list[str]`                                         | 工具白名单；会与 `skills` 编译出的 `Skill(...)` 条目合并去重             |
| `setting_sources` | `list[Literal["user", "project", "local"]] \| None` | 决定 CLI 是否扫描用户 / 项目目录里的 skills（默认空 = 沙箱）                |
| `plugins`         | `list[PluginSpec] \| None`                          | 加载插件，插件里的 skills 会进入发现集合                               |

`settings`（dict / path / JSON 字符串）有几个 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 版本决定                                                        |

***

<div id="返回值参考" />

## 返回值参考

`client.get_server_info()` 返回的 dict 中包含：

```python theme={null}
{
    "commands": [{"name": str, "description": str, ...}, ...],
    "agents": [{"name": str, "description": str, "model": str | None}, ...],
    "skills": [{"name": str, "description": str | None, "source": str | None}, ...],
    # Also includes models / account / output_style and other fields
}
```

这里只展示 skill 相关字段；完整类型见 [`SDKControlInitializeResponse`](/zh/cli/sdk/python/references#sdkcontrolinitializeresponse)。流式 `SystemMessage(subtype="init").data["skills"]` 是 skill 名称列表，与这里带元数据的发现清单不是同一个结构。

***

<div id="最佳实践" />

## 最佳实践

* **按需启用 `skills`**：`skills="all"` 适合开发和调试；面向最终用户的产品通常应该传明确列表。
* **想要 CLI 内置 skill 的行为，自己复刻**：SDK 不会把 `simplify` / `security-review` 这些塞进会话，需要的话在 plugin 或 `setting_sources` 范围里自己提供 SKILL.md。
* **不要把 `skills` 当沙箱**：安全边界应由 `allowed_tools`、`disallowed_tools`、`can_use_tool`、权限模式和沙箱共同控制。
* **给 UI 用 `get_server_info()['skills']`**：这是 CLI 发现链路的稳定入口，用来展示「已发现的 skill」，不代表主会话当前全部可调用。
* **子 Agent 的 `skills` 单独管理**：它与主会话 `options.skills` 是两套独立的列表，互不覆盖。

***

<div id="当前限制" />

## 当前限制

* `--disable-slash-commands` 是 CLI 一次性禁用所有 slash-command skill 的能力，SDK 当前没有暴露一等 option，不建议依赖 `extra_args` 类非公开路径。
* `settings.skillListingMaxDescChars`、`settings.skillListingBudgetFraction` 是 SDK 已透传的 listing 预算控制字段；当前 qodercli 还没有实现 listing 预算控制，传入不会报错但也不会改变行为。
* Python SDK 暂未提供 `client.supported_skills()` 便捷方法，需要从 `get_server_info()['skills']` 读取（已列入 backlog）。
