Extend agents with skills changedagent-sdk/skills
Nearest release: v2.1.232, published 7 hours before this site recorded the change. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.
# Agent Skills in the SDK ## Overview ## How Skills Work with the SDK ## Using Skills with the SDK ## Creating Skills ## Tool Restrictions ## Discovering Available Skills ## Testing Skills ## Troubleshooting ### Skills Not Found ### Skill Not Being Used ### Additional Troubleshooting ## Related Documentation ### Skills Guides ### SDK Resources
The whole hunk
329 lines, first recordedThe first capture of this source. The page was already there, and this is what it said.
# Agent Skills in the SDK
> Extend Claude with specialized capabilities using Agent Skills in the Claude Agent SDK
## Overview
Agent Skills extend Claude with specialized capabilities that Claude autonomously invokes when relevant. Skills are packaged as `SKILL.md` files containing instructions, descriptions, and optional supporting resources.
For comprehensive information about Skills, including benefits, architecture, and authoring guidelines, see the [Agent Skills overview](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview).
## How Skills Work with the SDK
When using the Claude Agent SDK, Skills are:
1. **Defined as filesystem artifacts**: you create each Skill as a `SKILL.md` file in its own directory, such as `.claude/skills/<name>/SKILL.md`
2. **Loaded from filesystem**: the SDK loads Skills from the filesystem locations governed by `settingSources` (TypeScript) or `setting_sources` (Python)
3. **Automatically discovered**: once filesystem settings load, the SDK discovers Skill metadata at startup from user and project directories, and loads the full content when Claude invokes the Skill
4. **Model-invoked**: Claude autonomously chooses when to use them based on context
5. **Filtered via the `skills` option**: discovered skills are enabled by default. Pass a list of skill names, `"all"`, or `[]` to control which are available in the session
Unlike subagents (which can be defined programmatically), Skills must be created as filesystem artifacts. The SDK does not provide a programmatic API for registering Skills.
<Note>
Skills are discovered through the filesystem setting sources. With default `query()` options, the SDK loads user and project sources, so skills in `~/.claude/skills/`, `<cwd>/.claude/skills/`, and `.claude/skills/` in any parent directory of `<cwd>` up to the repository root are available. If you set `settingSources` explicitly, include `'user'` or `'project'` to keep skill discovery, or use the [`plugins` option](/docs/en/agent-sdk/plugins) to load skills from a specific path.
</Note>
## Using Skills with the SDK
Set the `skills` option on `query()` to control which Skills are available to the session. When omitted, discovered Skills are enabled and the Skill tool is available, matching CLI behavior. Pass `"all"` to enable every discovered Skill, a list of Skill names to enable only those, or `[]` to disable all. When you set `skills`, the SDK adds the Skill tool to `allowedTools` automatically. If you also pass an explicit `tools` list, include `"Skill"` in that list so Claude can invoke skills.
Once configured, Claude automatically discovers Skills from the filesystem and invokes them when relevant to the user's request.
The following example sets `cwd` to the process's current working directory, so run it from inside a project that has a `.claude/skills/` directory in the current directory or any parent up to the repository root:
<CodeGroup>
```python Python theme={null}
import asyncio
import os
from claude_agent_sdk import query, ClaudeAgentOptions
async def main():
options = ClaudeAgentOptions(
cwd=os.getcwd(), # .claude/skills/ here or in a parent directory
setting_sources=["user", "project"], # Load Skills from filesystem
skills="all", # Enable every discovered Skill
allowed_tools=["Read", "Write", "Bash"],
)
async for message in query(
prompt="Help me process this PDF document", options=options
):
print(message)
asyncio.run(main())
```
```typescript TypeScript theme={null}
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "Help me process this PDF document",
options: {
cwd: process.cwd(), // .claude/skills/ here or in a parent directory
settingSources: ["user", "project"], // Load Skills from filesystem
skills: "all", // Enable every discovered Skill
allowedTools: ["Read", "Write", "Bash"]
}
})) {
console.log(message);
}
```
</CodeGroup>
Near the start of the stream, the SDK yields a system message with subtype `init`. Check its `skills` array to confirm your Skills loaded before Claude starts working. The array lists user-invocable Skills only. A Skill with [`user-invocable: false`](/docs/en/skills#control-who-invokes-a-skill) in its frontmatter loads and remains available to Claude but doesn't appear in the array.
To enable only specific Skills, pass their names. Names match the `name` field in `SKILL.md` or the Skill's directory name. Use `plugin:skill` for plugin-provided Skills.
<Note>
Import statements from the first example are assumed in the following code snippets.
</Note>
<CodeGroup>
```python Python theme={null}
options = ClaudeAgentOptions(skills=["pdf", "docx"])
```
```typescript TypeScript theme={null}
const options = { skills: ["pdf", "docx"] };
```
</CodeGroup>
The list takes exact Skill names only. In the TypeScript SDK, `query()` throws before starting the Claude Code process when a name can't work as an exact Skill name. In the Python SDK, `query()` raises `ValueError` in the same cases, for example:
* An empty name
* A name containing parentheses, commas, or control characters
* A name padded with whitespace
* A wildcard form such as a bare `*` or a `:*` suffix
To enable every discovered Skill, pass `skills: "all"` rather than a wildcard.
The `skills` option is a context filter, not a sandbox. Unlisted Skills are hidden from the model and rejected by the Skill tool, but their files remain on disk and are reachable through Read and Bash.
## Creating Skills
Create each Skill as a directory containing a `SKILL.md` file with YAML frontmatter and Markdown content. The `description` field determines when Claude invokes your Skill.
**Example directory structure**:
```text theme={null}
.claude/skills/processing-pdfs/
└── SKILL.md
```
For complete guidance on creating Skills, including SKILL.md structure, multi-file Skills, and examples, see:
* [Agent Skills in Claude Code](/docs/en/skills): complete guide with examples
* [Agent Skills Best Practices](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices): authoring guidelines and naming conventions
## Tool Restrictions
<Note>
The `allowed-tools` frontmatter field in SKILL.md is only supported when using Claude Code CLI directly. **It does not apply when using Skills through the SDK**.
When using the SDK, control tool access through the main `allowedTools` option in your query configuration.
</Note>
To control tool access for Skills in SDK applications, use `allowedTools` to pre-approve specific tools. Without a `canUseTool` callback, anything not in the list is denied:
<CodeGroup>
```python Python theme={null}
options = ClaudeAgentOptions(
setting_sources=["user", "project"], # Load Skills from filesystem
skills="all",
allowed_tools=["Read", "Grep", "Glob"],
permission_mode="dontAsk", # Deny anything not pre-approved instead of prompting
)
async def main():
async for message in query(prompt="Analyze the codebase structure", options=options):
print(message)
asyncio.run(main())
```
```typescript TypeScript theme={null}
for await (const message of query({
prompt: "Analyze the codebase structure",
options: {
settingSources: ["user", "project"], // Load Skills from filesystem
skills: "all",
allowedTools: ["Read", "Grep", "Glob"],
permissionMode: "dontAsk" // Deny anything not pre-approved instead of prompting
}
})) {
console.log(message);
}
```
</CodeGroup>
## Discovering Available Skills
To see which Skills are available in your SDK application, ask Claude. The example below sets only the `skills` option and omits `settingSources`/`setting_sources`. When you leave `settingSources`/`setting_sources` unset, the SDK still loads Skills from the user and project sources, so the `skills` option set to `"all"` on its own makes them available to list.
<CodeGroup>
```python Python theme={null}
options = ClaudeAgentOptions(skills="all")
async def main():
async for message in query(prompt="What Skills are available?", options=options):
print(message)
asyncio.run(main())
```
```typescript TypeScript theme={null}
for await (const message of query({
prompt: "What Skills are available?",
options: {
skills: "all"
}
})) {
console.log(message);
}
```
</CodeGroup>
Claude will list the available Skills based on your current working directory and installed plugins.
## Testing Skills
Test Skills by asking questions that match their descriptions:
<CodeGroup>
```python Python theme={null}
options = ClaudeAgentOptions(
cwd=os.getcwd(),
setting_sources=["user", "project"], # Load Skills from filesystem
skills="all",
allowed_tools=["Read", "Bash"],
)
async def main():
async for message in query(prompt="Extract text from invoice.pdf", options=options):
print(message)
asyncio.run(main())
```
```typescript TypeScript theme={null}
for await (const message of query({
prompt: "Extract text from invoice.pdf",
options: {
cwd: process.cwd(),
settingSources: ["user", "project"], // Load Skills from filesystem
skills: "all",
allowedTools: ["Read", "Bash"]
}
})) {
console.log(message);
}
```
</CodeGroup>
Claude automatically invokes the relevant Skill if the description matches your request.
## Troubleshooting
### Skills Not Found
**Check settingSources configuration**: Skills are discovered through the `user` and `project` setting sources. If you set `settingSources`/`setting_sources` explicitly and omit those sources, skills are not loaded:
<CodeGroup>
```python Python theme={null}
# Skills not loaded: setting_sources excludes user and project
options = ClaudeAgentOptions(setting_sources=[], skills="all")
# Skills loaded: user and project sources included
options = ClaudeAgentOptions(
setting_sources=["user", "project"],
skills="all",
)
```
```typescript TypeScript theme={null}
// Skills not loaded: settingSources excludes user and project
const optionsWithoutSkills = {
settingSources: [],
skills: "all"
};
// Skills loaded: user and project sources included
const optionsWithSkills = {
settingSources: ["user", "project"],
skills: "all"
};
```
</CodeGroup>
For which skill directories each source loads, see the [filesystem sources table](/docs/en/agent-sdk/claude-code-features#control-filesystem-settings-with-settingsources). For more details on `settingSources`/`setting_sources`, see the [TypeScript SDK reference](/docs/en/agent-sdk/typescript#settingsource) or [Python SDK reference](/docs/en/agent-sdk/python#settingsource).
**Check working directory**: The SDK loads Skills from `.claude/skills/` in the `cwd` option and in every parent directory up to the repository root. Ensure `cwd` points at or below the directory containing `.claude/skills/`, within the same repository:
<CodeGroup>
```python Python theme={null}
# Ensure your cwd points to the directory containing .claude/skills/
options = ClaudeAgentOptions(
cwd="/path/to/project", # .claude/skills/ here or in a parent directory
setting_sources=["user", "project"], # Loads skills from these sources
skills="all",
)
```
```typescript TypeScript theme={null}
// Ensure your cwd points to the directory containing .claude/skills/
const options = {
cwd: "/path/to/project", // .claude/skills/ here or in a parent directory
settingSources: ["user", "project"], // Loads skills from these sources
skills: "all"
};
```
</CodeGroup>
See the "Using Skills with the SDK" section above for the complete pattern.
**Verify filesystem location**:
```bash theme={null}
# Check project Skills
ls .claude/skills/*/SKILL.md
# Check personal Skills
Cut at 300 lines. The page has the rest.
No line in this hunk matches that.