Skills
Skills let an agent load specialized instructions on demand instead of carrying every capability in its system prompt. They follow the agentskills.io convention: each skill is a directory that an agent discovers, reads, and runs only when a task actually calls for it. Skills can also be defined inline in code when a directory on disk isn't a good fit.
AG2 ships three entry points, from highest-level to lowest:
| Entry point | Use it when |
|---|---|
SkillPlugin | Recommended. Injects the catalog into the system prompt and wires the activation tools, so the model knows what's available from the first turn. |
SkillsToolkit | You want the activation tools (plus an explicit list_skills) without prompt injection, or full control over runtimes. |
SkillSearchToolkit | The agent should discover and install new skills from the skills.sh registry at runtime. |
Skill structure#
A skill is a directory with a SKILL.md at its root and, optionally, scripts and resource files:
pdf-processing/
├── SKILL.md # required: YAML frontmatter + instructions
├── scripts/ # optional: runnable .py / .sh files
│ └── extract.py
└── references/ # optional: any bundled resource files
└── form-fields.md
SKILL.md carries YAML frontmatter (name, description, and optionally version, license, compatibility) followed by the instruction body. For the full authoring format, see the agentskills.io documentation.
When surfacing a skill's files, AG2 draws one firm line:
- A script lives under
scripts/and is executed viarun_skill_script. - A resource is any other file (not
SKILL.md, not underscripts/) and is read viaread_skill_resource.
The two are disjoint — a file is one or the other, never both.
Progressive disclosure#
Skills exist to keep context small. The agent only pays the token cost of the detail it actually uses, in three tiers:
| Tier | What's loaded | When |
|---|---|---|
| 1. Catalog | Name + description + location, per skill | At startup (or via list_skills) |
| 2. Instructions | The full SKILL.md body | When the model calls load_skill |
| 3. Resources & scripts | Bundled files and script output | When the instructions reference them (read_skill_resource / run_skill_script) |
An agent with 20 installed skills doesn't load 20 full instruction sets upfront — only the ones a given conversation activates.
SkillPlugin#
SkillPlugin is the recommended way to give an agent local skills. Instead of spending a list_skills tool round-trip, it injects the catalog into the system prompt at startup, so the model can decide which skill is relevant immediately.
By default it scans .agents/skills relative to the current working directory. Pass a path or a LocalRuntime to point elsewhere:
Activation flow#
-
Startup — the plugin discovers every skill and injects an
<available_skills>block into the system prompt. Each entry lists the skill'sname,description, andlocation: -
Load — when a task matches a description, the model calls
load_skill(name). Thenameparameter is constrained to the discovered skills, so the model can't invent one. The tool returns theSKILL.mdbody wrapped in<skill_content>, along with the skill directory and a listing of bundled resources. -
Use resources — the model reads a listed resource with
read_skill_resource(name, resource)or executes a script withrun_skill_script(name, script, args)only when the instructions call for it.
Capability gating#
SkillPlugin only registers the activation tools the installed skills can actually use:
load_skillis always registered (when at least one skill exists).read_skill_resourceis registered only if some skill has resources.run_skill_scriptis registered only if some skill has scripts.
So an agent whose skills are pure instructions never sees a run_skill_script tool it can't use. When no skills are found at all, the plugin contributes nothing — no catalog and no tools.
Tip
SkillPlugin is a snapshot taken at construction time: the catalog, the name constraint, and the gated tools always describe the same set of skills. Rebuild the agent (or the plugin) after installing new skills.
SkillsToolkit#
SkillsToolkit is the lower-level building block behind SkillPlugin. It exposes the same activation tools plus an explicit list_skills tool, but does not inject anything into the prompt — the model discovers skills by calling list_skills itself. Prefer SkillPlugin unless you need that control.
It exposes four tools:
| Tool | Description |
|---|---|
list_skills | Return a catalog of installed skills with name, description, and location |
load_skill | Fetch the full SKILL.md content for a specific skill |
read_skill_resource | Read a bundled resource file from a skill's directory |
run_skill_script | Execute a .py or .sh script from a skill's scripts/ directory |
Every tool is also available as a method, so you can hand-pick a subset:
Runtimes#
A runtime owns where skills live and how their scripts run — it discovers skills, reads their content, and executes their scripts. LocalRuntime is the default: it backs skills with the filesystem and runs scripts in a local subprocess (or a sandbox you supply). Pass one to a toolkit or plugin as a path string or an explicit LocalRuntime:
LocalRuntime takes the install directory plus optional execution and discovery settings. extra_paths adds read-only directories that are scanned for skills but never written to — installed skills always go to the primary dir:
Composing multiple runtimes#
SkillPlugin and SkillsToolkit both accept more than one runtime, so you can serve skills from several locations at once — each with its own configuration. A common pattern is a read-only global library plus a writable project directory:
When the same skill name exists in more than one runtime, the last runtime wins — here the project skill shadows the global one. The rule is applied uniformly: the catalog, the name constraint, load_skill, read_skill_resource, and run_skill_script all resolve to the same winning skill.
Note
Because each runtime can carry its own execution and storage settings (sandbox, timeout, install directory), composition lets global skills run one way and project skills another — something a single runtime can't express.
Code-defined skills#
Not every skill needs to live on disk. A MemorySkill defines a skill inline in code — its instructions, resources, and scripts are Python values rather than files. It's backed by an in-memory runtime (MemoryRuntime) instead of LocalRuntime, but the agent activates it through the same progressive-disclosure flow.
Pass a MemorySkill straight to SkillPlugin (or SkillsToolkit) — it is wrapped in a MemoryRuntime automatically and appears in the catalog alongside any file-based skills.
Resources and scripts as callables#
The @skill.resource and @skill.script decorators register Python callables (sync or async). By default the function name becomes the resource/script name and the docstring becomes its description — pass name= or description= only to override:
- A resource callable runs every time it is read, so it can return live data — current config, a roster, a database lookup — rather than a static file.
- A script callable runs in-process: no subprocess, no
scripts/directory. Its parameter JSON-schema is generated from the signature and disclosed inside the loaded skill content, so the model callsrun_skill_scriptwith named arguments ({"value": 10, "factor": 2}) matching that schema. Arguments are validated and coerced exactly as a regular tool's are.
Both forms support dependency injection — a callable can declare Context, Variable, or Inject parameters and they resolve from the live run context, just like a tool:
Composing with file-based skills#
A MemorySkill composes with paths and runtimes like any other source — declaration order decides precedence, and the last source wins on a name clash:
Grouping is associative: passing loose MemorySkills, wrapping each in its own MemoryRuntime, or grouping several into one MemoryRuntime(...) all behave identically.
Note
MemoryRuntime is read-only — its skills are defined in code, so it cannot be an install target for SkillSearchToolkit.
SkillSearchToolkit#
SkillSearchToolkit extends SkillsToolkit with three tools for discovering and installing skills from the skills.sh registry. It uses the GitHub Tarball API directly — no Node.js required.
It inherits all of SkillsToolkit's tools and adds:
| Tool | Description |
|---|---|
search_skills | Search the skills.sh registry by keyword |
install_skill | Download and install a skill by its registry identifier |
remove_skill | Remove an installed skill by name |
GitHub rate limits#
By default the GitHub API allows 60 unauthenticated requests per hour. Setting a GITHUB_TOKEN environment variable raises this to 5,000 per hour:
You can also pass the token (and other settings) directly via SkillsClientConfig:
Note
SkillSearchToolkit installs into a single runtime. To combine installed skills with skills from other locations, serve them through a SkillPlugin or SkillsToolkit that lists multiple runtimes.