# `Planck.Agent.Skill`
[🔗](https://github.com/alexdesousa/planck/blob/v0.1.0/lib/planck/agent/skill.ex#L1)

Filesystem-based agent skills.

A skill is a subdirectory under a skills directory (e.g. `.planck/skills/`)
containing a `SKILL.md` file. The file has YAML frontmatter with `name` and
`description`, followed by usage instructions, resource references, and any
other context the agent needs.

## Directory layout

    .planck/skills/
    └── n8n-expert/
        ├── SKILL.md            ← required
        ├── docs/
        │   └── node-types.md   ← lazily loaded by the agent via `read`
        └── scripts/
            └── validate.sh     ← runnable via `bash`

## SKILL.md format

    ---
    name: n8n-expert
    description: Expert at building n8n workflows and automation.
    ---

    # N8N Expert

    You are an expert at n8n...

    ## Resources

    - `docs/node-types.md` — reference for all n8n node types
    - `scripts/validate.sh` — validates a workflow JSON file

Only `name` and `description` are parsed from the frontmatter. The rest of
the file is plain Markdown consumed by the agent when it loads the skill.

## Usage

    skills = Planck.Agent.Skill.load_all(["~/.planck/skills"])

    # Skills are typically threaded through AgentSpec.to_start_opts/2 via
    # skill_pool:, which resolves spec.skills names and appends the skill
    # section to system_prompt for the relevant agent.
    start_opts = Planck.Agent.AgentSpec.to_start_opts(spec, skill_pool: skills)

The agent discovers skills from the system prompt index and loads `SKILL.md`
via the `read` tool when a skill is relevant. Scripts are run via `bash`.
No special runtime support is required — skills are just files.

# `t`

```elixir
@type t() :: %Planck.Agent.Skill{
  description: String.t(),
  name: String.t(),
  path: Path.t(),
  skill_file: Path.t()
}
```

A loaded skill.

- `:name` — identifier used in the system prompt index
- `:description` — one-line summary shown to the agent
- `:path` — absolute path to the skill directory
- `:skill_file` — absolute path to `SKILL.md`

# `from_file`

```elixir
@spec from_file(Path.t()) :: {:ok, t()} | {:error, String.t()}
```

Load a single skill from a `SKILL.md` file path.

Returns `{:ok, skill}` or `{:error, reason}`.

# `list_skills_tool`

```elixir
@spec list_skills_tool([t()]) :: Planck.Agent.Tool.t()
```

Build a `list_skills` tool that returns all available skill names and descriptions.

This is an opt-in discovery tool. Add `"list_skills"` to an agent's TEAM.json
`"tools"` array when that agent needs to autonomously discover what skills exist.
Workers that receive skill names from the orchestrator do not need this tool.

# `load_all`

```elixir
@spec load_all([Path.t()]) :: [t()]
```

Load all skills from a list of directories.

Each directory is scanned for subdirectories containing a `SKILL.md` file.
Directories that do not exist are silently skipped. Invalid `SKILL.md` files
are skipped with a warning.

Paths are expanded via `Path.expand/1` so `~` and relative paths resolve
correctly.

# `load_skill_tool`

```elixir
@spec load_skill_tool([t()]) :: Planck.Agent.Tool.t()
```

Build a `load_skill` tool that loads a skill's `SKILL.md` by name.

The tool is a closure over the given skill pool. It is automatically added to
every agent when skills are available — agents do not need to declare it in
their TEAM.json `"tools"` array.

# `system_prompt_section`

```elixir
@spec system_prompt_section([t()]) :: String.t() | nil
```

Generate a skills section for injection into an agent's system prompt.

Produces a compact index of skill names and descriptions, followed by an
instruction to load skills via the `load_skill` tool. Returns `nil` when
the list is empty.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
