> ## 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

`options.skills` controls which skills the `Skill` tool can invoke in the current session. The SDK compiles it into the CLI's `Skill` allowlist and merges it with `allowedTools` before passing to qodercli.

<div id="sdk-does-not-load-built-in-skills" />

## SDK Does Not Load Built-in Skills

When the SDK launches the CLI it **always** appends `--disable-builtin-skills`, so the session never sees the CLI's factory built-in skills (`simplify`, `debug`, `security-review`, `quest`, `batch`, `agent-creator`, `hook-config`, `mcp-config`, `skill-creator`, …). No `source: 'built-in'` entries appear in `init.skills`, and the model's system prompt does not see them either.

This is fixed SDK behavior with no opt-in; if you want the capability of a CLI built-in skill, either ship your own copy of the SKILL.md via a plugin / user dir / project dir, or run the CLI directly outside the SDK.

The session can still pick up skills contributed from these sources:

* **plugin skills**: loaded via `options.plugins`, addressed with the plugin-qualified name (`plugin:skill`).
* **user / project skills**: discovered when you opt into `user` / `project` / `local` via `options.settingSources`.
* **agent-preloaded skills**: declared on `options.agents[name].skills`, scoped to that sub-agent only.

To reliably confirm what was discovered in a session, run `query()` once and read `init.skills` — don't hard-code the set.

***

<div id="using-cli-default-policy" />

## Using CLI Default Policy

When `skills` is not passed, the SDK does not inject an additional `Skill` allowlist, leaving everything to the CLI's own policy. Because built-ins are disabled, a session with no `settingSources` / `plugins` will see an empty `init.skills` array.

```typescript theme={null}
import { query } from '@qoder-ai/qoder-agent-sdk';

const q = query({
  prompt: 'Analyze the test coverage of this project',
  options: {
    cwd: '/path/to/project',
  },
});
```

<div id="enabling-all-discovered-skills" />

## Enabling All Discovered Skills

```typescript theme={null}
const q = query({
  prompt: 'Use an appropriate skill to perform a code review',
  options: {
    cwd: '/path/to/project',
    settingSources: ['project'],
    skills: 'all',
  },
});
```

`skills: 'all'` allows the `Skill` tool to invoke every skill the CLI currently discovers (sources are determined by `settingSources` / `plugins`; built-ins are no longer included).

<div id="enabling-only-specific-skills" />

## Enabling Only Specific Skills

```typescript theme={null}
const q = query({
  prompt: 'Use the review skill to inspect recent changes',
  options: {
    cwd: '/path/to/project',
    settingSources: ['project'],
    skills: ['review'],
  },
});
```

<div id="enabling-plugin-skills" />

## Enabling Plugin Skills

Plugin skills use plugin-qualified names. For plugin loading methods, see [Plugins documentation](/en/cli/sdk/plugins).

```typescript theme={null}
const q = query({
  prompt: 'Use the echo skill provided by the plugin to handle this input',
  options: {
    plugins: [{ type: 'local', path: '/path/to/sdk-test-plugin' }],
    skills: ['sdk-test-plugin:sdk-echo'],
  },
});
```

<div id="merging-with-explicit-tool-allowlist" />

## Merging with Explicit Tool Allowlist

```typescript theme={null}
const q = query({
  prompt: 'Read the source and use the review skill to produce a list of issues',
  options: {
    cwd: '/path/to/project',
    settingSources: ['project'],
    allowedTools: ['Read', 'Grep'],
    skills: ['review'],
  },
});
```

The above configuration ultimately allows `Read`, `Grep`, and `Skill(review)`.

<div id="hiding-discovered-skills" />

## Hiding Discovered Skills

`options.skills` controls tool permissions, not discovery filtering. To truly keep a plugin / user / project skill out of `init.skills` and the model's system prompt, use `settings.skillOverrides`.

```typescript theme={null}
const q = query({
  prompt: 'Handle this task',
  options: {
    plugins: [{ type: 'local', path: '/path/to/sdk-test-plugin' }],
    settings: {
      skillOverrides: {
        'sdk-test-plugin:sdk-echo': 'off',
      },
    },
  },
});
```

* `'off'`: Completely hidden — not in `init.skills`, not in model system prompt, `Skill` tool invocations are also rejected.
* Other values: `'on'` (default), `'name-only'` (only shows name, not description), `'user-invocable-only'` (invisible to model, user can still trigger via `/name`).
* Scope of effect: every SDK-visible source (plugin, user, project, …) respects this override; CLI built-ins are already blocked by `--disable-builtin-skills`, so overrides for them have nothing to act on.
* Key naming rules: Plugin skills use the plugin-qualified name `plugin:skill`; non-plugin skills use bare names. Both forms can be written simultaneously; matching is attempted against the fully qualified name first, then falls back to the bare name.

> `options.skills` only controls tool invocation permissions, **it cannot be used to hide skill discovery / context exposure**.

***

<div id="reading-skills-discovered-in-the-current-session" />

## Reading Skills Discovered in the Current Session

The initialization result includes skills discovered by the CLI in this session, which the host UI can use to display "currently available capabilities."

```typescript theme={null}
const q = query({
  prompt: 'Do not execute any task yet',
  options: {
    cwd: '/path/to/project',
    settingSources: ['project'],
    skills: 'all',
  },
});

const init = await q.initializationResult();
console.log(init.skills?.map((skill) => skill.name));
```

> `skills` is context and tool visibility control, not a security boundary. Unlisted skills won't be exposed to the model via the `Skill` tool, but skill files are still on disk and can still be accessed by regular file reading tools.

***

<div id="custom-agent-preloading-skills" />

## Custom Agent Preloading Skills

If you define custom sub-Agents via `options.agents`, you can declare `skills` in the Agent definition. When the main session invokes the `Agent` tool, the sub-Agent will run with the specified skills loaded.

```typescript theme={null}
const q = query({
  prompt: 'Dispatch a helper agent that uses the sdk-agent-marker skill to return the marker',
  options: {
    cwd: '/path/to/project',
    allowedTools: ['Agent'],
    agents: {
      'sdk-skill-helper': {
        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,
      },
    },
  },
});
```

These `skills` only affect that Agent's context and are not equivalent to enabling the same-named skill for the main session.

***

<div id="options-reference" />

## Options Reference

| Field            | Type                                 | Description                                                                                |
| ---------------- | ------------------------------------ | ------------------------------------------------------------------------------------------ |
| `skills`         | `string[] \| 'all'`                  | Controls which skills the main session can invoke via the `Skill` tool                     |
| `agents`         | `Record<string, AgentDefinition>`    | Custom Agents; each Agent can declare an independent `skills` preload list                 |
| `allowedTools`   | `string[]`                           | Tool allowlist; merged with `Skill(...)` entries compiled from `skills` with deduplication |
| `settingSources` | `('user' \| 'project' \| 'local')[]` | Controls whether the CLI scans user / project dirs for skills (default empty = sandboxed)  |
| `plugins`        | `PluginSpec[]`                       | Loads plugins; skills inside contribute to the discovered set                              |

`settings` also has several skill-related fields that the SDK passes through; actual effects depend on whether the CLI version implements them:

| Field                           | Purpose                                                                                                                             |
| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `skillOverrides`                | Set `'on' \| 'name-only' \| 'user-invocable-only' \| 'off'` per skill name; plugin, user, project sources all respect this override |
| `skillListingMaxDescChars`      | Character limit per description in skill listing (SDK default 1536); exceeding it triggers truncation                               |
| `skillListingBudgetFraction`    | Context window fraction reserved for skill listing (SDK default 0.01 = 1%); exceeding it triggers compression                       |
| `strictPluginOnlyCustomization` | Restrict one or more of `skills`, `agents`, `hooks`, `mcp` to only accept contributions from plugin sources                         |

***

<div id="return-value-reference" />

## Return Value Reference

```typescript theme={null}
type SDKControlInitializeResponse = {
  skills?: Array<{ name: string; description?: string; source?: string }>;
  // ...also returns commands / agents / plugins and similar fields
};
```

***

<div id="best-practices" />

## Best Practices

* **Enable `skills` as needed**: `skills: 'all'` is ideal for development and debugging; end-user-facing products should typically pass an explicit list.
* **Want a CLI built-in's behavior? Ship your own copy**: the SDK will not inject `simplify` / `security-review` and the rest. Provide your own SKILL.md via a plugin or a `settingSources`-visible directory.
* **Don't treat `skills` as a sandbox**: Security boundaries should be controlled collectively by `allowedTools`, `disallowedTools`, `canUseTool`, permission mode, and sandboxing.
* **Use `initializationResult().skills` for UI**: This is the stable entry point for the CLI discovery pipeline, used to display "currently available skills."
* **Manage sub-Agent `skills` separately**: They are independent lists from the main session's `options.skills` and do not override each other.
