Skip to main content
Version: 2.32-unstable

SkillToolset

Let agents discover and read skills — reusable instruction sets with bundled files — through progressive disclosure.

Mandatory init variablesstore: A SkillStore instance that provides the skills
API referenceSkillToolset
GitHub linkhttps://github.com/deepset-ai/haystack/blob/main/haystack/tools/skills/skill_toolset.py
Package namehaystack-ai

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 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, and PDFs as FileContent. 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 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}")