Agent Skills
Agent Skills follow the agentskills.io progressive disclosure pattern: metadata in the system prompt (cached), body loaded on demand (uncached).
How It Works
1. discoverSkills() → reads SKILL.md frontmatter → name + description
2. halodem({ skills }) → name + description enters StablePrefix (cached)
3. Agent calls loadSkill("skill-name") at runtime
4. Body loaded from disk → enters MessageLog (uncached, discardable)
5. ContextStrategy can drop skill bodies first when truncatingThis keeps the prefix small (just one line per skill) while giving the agent access to detailed instructions when needed.
Discovering Skills
import { discoverSkills } from "@halo-ai/core";
const skills = await discoverSkills({
directories: [".halo/skills", "~/.halo/skills"],
});Scanning rules:
- Each subdirectory with a
SKILL.mdis a skill nameanddescriptionparsed from YAML frontmatter- First skill with a given name wins (project overrides global)
Writing a Skill
Create skills/my-skill/SKILL.md:
---
name: my-skill
description: Use when the user asks about X or you need to do Y.
---
# My Skill
Detailed instructions, patterns, and examples go here.
This body is loaded when the agent calls `loadSkill("my-skill")`.The description is critical — it's the only thing the agent sees before deciding to load the body. Write it as a trigger condition ("Use when..."), not a summary of the body.
Using Skills with an Agent
const agent = halo.agent({
messages: [{ role: "system", content: "You are a helpful assistant." }],
skills,
tools: { ... },
});
// The system prompt now includes:
// ## Available Skills
// - my-skill: Use when the user asks about X or you need to do Y.The agent can now call loadSkill("my-skill") to load the full body. This tool is auto-registered — you don't need to add it to tools.
Runtime Flow
User: "Help me do X"
→ Agent sees skill description in system prompt
→ Agent calls loadSkill({ name: "my-skill" })
→ Body loaded into MessageLog
→ Agent reads body and follows instructions
→ Body is discardable — dropped first when context gets fullBest Practices
1. Keep descriptions as trigger conditions
# ✅ Good
description: Use when implementing a REST API endpoint with input validation.
# ❌ Bad — summarizes the workflow, agent may skip reading the body
description: REST API with Zod validation — define schema, create handler, add tests.2. Put reusable reference in the body
The body loads into MessageLog, which is limited. Keep it focused. If a skill body is >500 words, consider splitting into multiple skills.
3. Marking skill output as discardable
Skill bodies loaded via loadSkill are automatically marked discardable. When using TruncateStrategy, these are dropped first, before any conversation messages.
4. Project vs global skills
.halo/skills/ ← Project-level, higher priority
~/.halo/skills/ ← User-level, fallbackPlace shared skills (team conventions) in project directories. Place personal skills in user directories.