<!-- Last verified: 2026-04-05 by Claude Code -->
# Skills

Skills extend an agent with domain expertise using the [AgentSkills](https://agentskills.io) open standard. A skill is a directory containing a `SKILL.md` file with instructions the agent can load on demand.

## How it works

Skills use **progressive disclosure** to manage context efficiently:

1. **Metadata** (~100 tokens/skill) — name + description, always in the system prompt
2. **Instructions** (<5k tokens) — SKILL.md body, loaded when the agent decides the skill is relevant
3. **Resources** (unlimited) — scripts, references, assets — loaded only when needed

The agent decides when to activate a skill based on the description alone. No trigger engine needed.

## Skill format

```
my-skill/
├── SKILL.md          # Required: YAML frontmatter + instructions
├── scripts/          # Optional: executable code
├── references/       # Optional: documentation loaded on demand
└── assets/           # Optional: templates, static resources
```

SKILL.md uses YAML frontmatter:

```markdown
---
name: git
description: Git operations — commit, branch, merge, rebase. Use when the user mentions version control.
---

# Git Skill

## Workflow
1. Run `git status` first
2. Stage changes, write conventional commit messages
3. For merges, check for conflicts first

## Scripts
For complex diffs: `bash {baseDir}/scripts/diff_summary.sh`
```

## Loading skills

```rust
use phi_core::SkillSet;
use std::path::PathBuf;

// Load from multiple directories (later dirs override earlier on name conflict)
let skills = SkillSet::load(&[PathBuf::from("./skills"), PathBuf::from("~/.phi-core/skills")]);

// Or load from a single directory with a label
let workspace_skills = SkillSet::load_dir("./skills", "workspace");
```

## Using with Agent

```rust
use phi_core::{BasicAgent, SkillSet};
use phi_core::provider::ModelConfig;
use std::path::PathBuf;

let api_key = std::env::var("ANTHROPIC_API_KEY").unwrap();
let skills = SkillSet::load(&[PathBuf::from("./skills")]);

let agent = BasicAgent::new(ModelConfig::anthropic(
    "claude-sonnet-4-20250514",
    "Claude Sonnet 4",
    &api_key,
))
.with_system_prompt("You are a coding assistant.")
.with_skills(skills)  // Appends skill index to system prompt
.with_tools(tools);
```

The agent's system prompt will include:

```xml
<available_skills>
  <skill>
    <name>git</name>
    <description>Git operations — commit, branch, merge, rebase.</description>
    <location>/path/to/skills/git/SKILL.md</location>
  </skill>
</available_skills>
```

When the agent encounters a task matching a skill, it reads the SKILL.md using the `read_file` tool and follows the instructions. No special infrastructure needed.

## Precedence

When loading from multiple directories, later directories take precedence. A skill in `./skills/` overrides the same-named skill in `~/.phi-core/skills/`.

You can also merge skill sets explicitly:

```rust
let mut base = SkillSet::load_dir("/usr/share/phi-core/skills", "bundled")?;
let user = SkillSet::load_dir("~/.phi-core/skills", "user")?;
let workspace = SkillSet::load_dir("./skills", "workspace")?;

base.merge(user);
base.merge(workspace); // workspace wins on conflict
```

## Compatibility

By following the AgentSkills standard, skills written for phi-core work with Claude Code, Codex CLI, Gemini CLI, Cursor, OpenCode, Goose, and any other compatible agent. Write once, use everywhere.

## Design philosophy

Skills are deliberately simple:

- **No trigger engine** — the LLM decides from descriptions
- **No compile-time registration** — skills use existing tools (read_file, bash)
- **No plugin API** — skills are just files
- **No runtime loading** — loaded at startup, that's it

If a skill needs a custom tool, it can provide an [MCP](./mcp.md) server.
