Contents6 sections
A skill explains how to work; a tool executes an action
The research-brief agent already has search and read tools plus RAG sources. New tasks also need stable methods: how to verify versions, prefer official sources, or check whether an English translation omitted a section.
Task ──▶ Skill: steps, decision rules, required resources
│
├──▶ Tool: execute search, read, or write
├──▶ RAG: retrieve task evidence
└──▶ Script: run deterministic validationA skill is a reusable package of procedural knowledge. It may reference tools and sources, but it does not replace tool permissions or automatically become long-term memory.
Contents of a skill directory
skills/research-brief/
├── SKILL.md
├── references/
│ ├── source-policy.md
│ └── citation-rules.md
├── scripts/
│ └── validate_claims.py
└── assets/
└── brief-template.mdSKILL.md states trigger conditions, workflow, inputs and outputs, allowed tools, required references, and acceptance. References contain longer rules, scripts perform deterministic actions, and assets store reusable templates.
Load SKILL.md progressively
At startup, load only name, description, and location. After a task matches, read the complete SKILL.md. Load a reference or script instruction only when SKILL.md explicitly names it.
---
name: research-brief
description: Create a cited technical brief from approved sources.
---
1. Validate the topic and audience.
2. Search approved sources before drafting.
3. Preserve source IDs for every claim.
4. Run `scripts/validate_claims.py` before requesting save approval.This approach avoids placing every skill body in the system prompt. The agent receives only the procedure and resources required for the current task.
Build a skill catalog
from dataclasses import dataclass
from pathlib import Path
@dataclass(frozen=True)
class SkillMeta:
name: str
description: str
path: Path
version: str
class SkillCatalog:
def __init__(self, skills: list[SkillMeta]) -> None:
self._skills = {skill.name: skill for skill in skills}
def list_descriptions(self) -> list[dict]:
return [
{"name": skill.name, "description": skill.description}
for skill in self._skills.values()
]
def load(self, name: str) -> str:
skill = self._skills.get(name)
if skill is None:
raise KeyError("skill_not_found")
return (skill.path / "SKILL.md").read_text(encoding="utf-8")The catalog reads skills only from an allowed root supplied by deployment configuration. The model cannot name an arbitrary directory.
Select and execute a skill
A simple implementation routes in code: a research_brief task loads the matching skill. As the catalog grows, the model can select from descriptions, while the application still checks the allowed set.
Classify task ─▶ Select skill name ─▶ Allowlist check ─▶ Load SKILL.md
│
▼
Run steps and tools
│
▼
Run acceptance scriptThe trace records skill name, version, references actually read, and scripts executed. A result can then be reproduced from the method used at the time, not only the model version.
Test skill boundaries
- Trigger conditions have positive and negative cases so one skill does not load for every task.
- Every file referenced by SKILL.md exists and remains inside the skill root.
- Required tools appear in the current task allowlist.
- Scripts run independently in a no-model environment.
- A skill upgrade reruns the original task set to confirm that changed steps do not lower quality.
Chapter 9 combines state, approval, and security into one complete boundary. A skill may tell the agent when to request saving, while the runtime and tool layer enforce pause, authorization, and directory limits.
REFERENCES
References
Series
AI AGENT Beginner's Guide