Skip to main content
Skills are reusable instruction packages — markdown documents that get loaded into the LLM conversation on demand. They provide domain-specific knowledge, workflows, and reference material without executing arbitrary code. Think of them as context-injecting tools: the model calls a skill tool, and the skill’s markdown content is returned as structured output.

Skill File Format

Each skill is a directory containing a SKILL.md file with YAML frontmatter:
my-skill/
  SKILL.md              # Required — skill definition
  references/           # Optional — auxiliary files the model can read
    api.md
  scripts/
    setup.sh
SKILL.md
---
name: my-skill
description: A short description of what this skill does
---

# My Skill

Full markdown content here. This is the prompt that gets injected
into the conversation when the skill is loaded.
Skill names must be lowercase alphanumeric with single hyphens (^[a-z0-9]+(-[a-z0-9]+)*$).

Configuration

Point the agent at one or more directories containing skill folders:
const agent = new Agent({
  name: "dev",
  model: openai("gpt-5.4"),
  tools: { ...fsTools, bash },
  skills: {
    paths: ["./skills", "~/.my-app/skills"],
  },
});
Paths can be absolute, relative (resolved from cwd), or use ~/ for the home directory. When multiple paths contain a skill with the same name, later paths take precedence.

How It Works

When skills is configured, a skill tool is automatically added to the agent’s toolset (similar to how the task tool is auto-generated for subagents). The tool’s description includes an XML listing of all available skills, so the model knows what it can invoke. Skills are discovered lazily on the first run() call and cached for the agent’s lifetime. When the model calls the skill tool:
  1. The skill’s markdown body is returned as structured XML output
  2. Auxiliary files in the skill directory (up to 10) are listed so the model can read them with other tools
  3. The base directory path is included so relative references resolve correctly
Since the skill tool is a regular tool, it emits the standard tool.start and tool.done events. It also goes through the approve callback if one is configured.

Standalone Usage

The discovery and tool creation functions are exported separately for full control:
import { discoverSkills, createSkillTool } from "@openharness/core";

const skills = await discoverSkills({ paths: ["./skills"] });
console.log(skills.map(s => s.name)); // inspect discovered skills

// Create the tool manually and pass it in
const agent = new Agent({
  name: "dev",
  model: openai("gpt-5.4"),
  tools: { ...fsTools, bash, skill: createSkillTool(skills) },
});