Files
wehub-resource-sync c56bef871b
Sync docs with Docusaurus / sync (push) Waiting to run
Tests / Check if changed (push) Waiting to run
Tests / format (push) Blocked by required conditions
Tests / check-imports (push) Blocked by required conditions
Tests / Unit / macos-latest (push) Blocked by required conditions
Tests / Unit / ubuntu-latest (push) Blocked by required conditions
Tests / Unit / windows-latest (push) Blocked by required conditions
Tests / mypy (push) Blocked by required conditions
Tests / Integration / ubuntu-latest (push) Blocked by required conditions
Tests / Integration / macos-latest (push) Blocked by required conditions
Tests / Integration / windows-latest (push) Blocked by required conditions
Tests / notify-slack-on-failure (push) Blocked by required conditions
Tests / Mark tests as completed (push) Blocked by required conditions
Docker image release / Build base image (push) Waiting to run
CodeQL / Analyze (python) (push) Has been cancelled
Update Platform Components Table / update (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:22:28 +08:00

120 lines
6.1 KiB
Plaintext

---
title: "SkillToolset"
id: skilltoolset
slug: "/skilltoolset"
description: "Let agents discover and read skills — reusable instruction sets with bundled files — through progressive disclosure."
---
# SkillToolset
Let agents discover and read skills — reusable instruction sets with bundled files — through progressive disclosure.
<div className="key-value-table">
| | |
| --- | --- |
| **Mandatory init variables** | `store`: A `SkillStore` instance that provides the skills |
| **API reference** | [SkillToolset](/reference/tools-api#skilltoolset) |
| **GitHub link** | https://github.com/deepset-ai/haystack/blob/main/haystack/tools/skills/skill_toolset.py |
| **Package name** | `haystack-ai` |
</div>
## Overview
A *skill* is a directory (or equivalent storage unit) containing a `SKILL.md` file with YAML frontmatter (`description` is required; `name` is optional and defaults to the directory name) and a markdown body of instructions. Skills may bundle additional files, such as reference docs, examples, or templates.
`SkillToolset` lets an [`Agent`](../pipeline-components/agents-1/agent.mdx) use skills through *progressive disclosure*, similar to how coding assistants like Claude Code expose skills: the model first sees only each skill's name and description, loads the full instructions when a task calls for them, and fetches bundled files only when the instructions reference them. This keeps the context small even with many detailed skills.
The toolset exposes two tools:
- `load_skill`: Returns a skill's full instructions on demand, plus a manifest of its bundled files. The names and descriptions of all discovered skills are baked into this tool's description at warm-up, so the model can see which skills exist without any system prompt injection.
- `read_skill_file`: Reads a file bundled with a skill (with path-traversal protection).
Skills are discovered when the toolset is warmed up — the `Agent` does this automatically before a run. Constructing the toolset does not read any skills.
`SkillToolset` is backed by a `SkillStore`. Use the built-in `FileSystemSkillStore` to load skills from a local directory, or implement the `SkillStore` protocol (`list_skills`, `load_skill`, `read_skill_file`, plus serialization methods) to back the toolset with any storage system — a database, a remote API, and so on.
:::info
The tool names `load_skill` and `read_skill_file` are fixed, so an `Agent` can use at most one `SkillToolset`. It also does not support adding tools or concatenation with other toolsets — to combine it with other tools, pass it to the `Agent` alongside them, for example `tools=[skills_toolset, other_tool]`. To serve skills from multiple sources, back a single toolset with a custom store that merges them.
:::
### Skill format
`FileSystemSkillStore` expects one sub-directory per skill under a root directory:
```
skills/
pdf-forms/
SKILL.md # frontmatter (description required, name optional) + markdown instructions
reference/forms.md # optional bundled file
```
A minimal `SKILL.md` looks like this:
```markdown
---
name: pdf-forms
description: Fill in PDF forms programmatically. Use when the user asks to complete or fill a PDF form.
---
# Filling PDF forms
1. Inspect the form fields first...
2. For the full field reference, read `reference/forms.md`.
```
Only the frontmatter of each `SKILL.md` is read at warm-up to build the catalog; instruction bodies and bundled files are read lazily when the agent calls the corresponding tool.
### Multimodal skill assets
`read_skill_file` returns text files as strings, images as [`ImageContent`](../concepts/data-classes/imagecontent.mdx), and PDFs as [`FileContent`](../concepts/data-classes/filecontent.mdx). Image and file results are passed to the model as content parts of the tool result instead of being converted to a string, so an `Agent` backed by a multimodal chat generator that supports these inputs (for example, `OpenAIResponsesChatGenerator`) can read a skill's visual assets — such as a reference screenshot or a showcase PDF — directly. Binary files that are neither images nor PDFs are rejected with an error.
### Executing bundled scripts
`SkillToolset` only *reads* skills — `load_skill` and `read_skill_file` never execute anything. If your skills bundle executable scripts (for example, a Python helper that the instructions tell the model to run), pass a script-execution tool of your own to the `Agent` alongside the toolset:
```python
agent = Agent(
chat_generator=OpenAIChatGenerator(),
tools=[skills_toolset, run_shell_command_tool], # your own execution tool
)
```
The agent can then read a bundled script with `read_skill_file` and run it through your execution tool. Since such a tool runs model-chosen commands, scope it carefully — restrict what it can execute, sandbox it, or guard it with a [Human in the Loop](../pipeline-components/agents-1/human-in-the-loop.mdx) confirmation strategy.
## Usage
### With an Agent
```python
from haystack.components.agents import Agent
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.dataclasses import ChatMessage
from haystack.skill_stores.file_system import FileSystemSkillStore
from haystack.tools import SkillToolset
store = FileSystemSkillStore("skills/")
skills_toolset = SkillToolset(store)
agent = Agent(chat_generator=OpenAIChatGenerator(), tools=skills_toolset)
# The agent sees the available skills in the `load_skill` tool description,
# loads the matching skill, and follows its instructions.
result = agent.run(messages=[ChatMessage.from_user("Fill in this PDF form for me.")])
print(result["last_message"].text)
```
### Inspecting discovered skills
The `skills` property returns the metadata of all discovered skills as a mapping of skill name to `SkillInfo` (warming up the toolset first if needed):
```python
from haystack.skill_stores.file_system import FileSystemSkillStore
from haystack.tools import SkillToolset
skills_toolset = SkillToolset(FileSystemSkillStore("skills/"))
for name, info in skills_toolset.skills.items():
print(f"{name}: {info.description}")
```