# EONYX skills: how Agent Skills and SKILL.md work


A **skill** is a folder with a `SKILL.md` file: an instruction the agent loads when a task matches it. Skills let you package repetitive procedures — a code review, a deploy checklist, the rules for formatting a report — so that they don't take up context until they're needed.

<!--more-->

## How a skill works

A skill is a folder with an instruction; let's look at how the model loads it, what `SKILL.md` consists of, and what finished skills look like.

### Progressive disclosure

The key idea: only the **name and description** of each skill make it into the system prompt — a short catalog under the `## Available Skills` heading. The model receives the full text of a skill only when it calls the `load_skill` tool itself:

```text
## Available Skills
- **review**: Check the diff for bugs and style before committing
- **deploy**: Production rollout checklist

→ the model decides the task is about a review
→ calls load_skill {"name": "review"}
→ receives the full text of SKILL.md
```

That way a dozen skills cost a couple hundred tokens of context instead of tens of thousands. The model makes the "when to load" decision — which is why the quality of the `description` field decides everything.

### The structure of a skill

A skill is a subdirectory with a `SKILL.md` file:

```text
skills/
└── review/
    └── SKILL.md
```

`SKILL.md` starts with frontmatter between `---`, followed by the body of the skill:

```markdown
---
name: review
description: Check the diff for bugs, style, and tests before committing. Use it for phrases like "review", "check my changes", "before I commit".
tags: [git, quality]
---

# Reviewing changes

1. Look at the diff: `git_diff`, with staged=true if needed.
2. Go through every changed file: logic, mistakes, stray edits.
3. Verify that the tests were run: `go test ./...`.
4. Structure the answer like this: critical → nice to have → nitpicks.
```

Frontmatter fields:

| Field         | Required   | Purpose                                                 |
| ------------- | ---------- | ------------------------------------------------------- |
| `name`        | no         | the skill name; defaults to the directory name          |
| `description` | desirable  | the model uses it to decide whether to load the skill   |
| `tags`        | no         | a list of labels, shown in the catalog                  |

Frontmatter is written in YAML (`key: value`); a JSON object is accepted as well. If `description` is not set, the catalog gets a `No description provided` placeholder — the model is unlikely to figure out that it should load such a skill.

{{< admonition type="tip" title="How to write a description" >}}
The description is a trigger. Write both **what the skill does** and **when to apply it**, including the words you yourself use to phrase the task: "use it when asked to prepare a release, roll out, deploy". A vague "useful deployment tips" won't work.
{{< /admonition >}}

### Skill examples

{{< tabs defaultTab="0" >}}
{{< tab title="Deploy checklist" markdown="true" >}}

```markdown
---
name: deploy
description: Production rollout checklist. Use it when asked to deploy, roll out, or prepare a release.
tags: [ops]
---

# Deploy

1. `git_status` — the working tree is clean, the branch is main.
2. `go test ./...` and `go vet ./...` — green.
3. Build the tag: the version from `git describe --tags` + an increment.
4. NEVER push a tag without confirmation from the user.
```

{{< /tab >}}
{{< tab title="Commit style" markdown="true" >}}

```markdown
---
name: commits
description: The rules for writing commit messages in this project. Use it before any git_commit.
tags: [git]
---

# Commits

- Subject: imperative mood, English, up to 60 characters.
- No mentions of tools or bots.
- A body only if the "why" isn't obvious from the subject.
```

{{< /tab >}}
{{< /tabs >}}

{{< admonition type="note" title="Skills are data, not code" >}}
`SKILL.md` is just text that the model receives. It is not executed. If a skill requires commands, the model runs them through the regular tools, with all the permission gates in place.
{{< /admonition >}}

## Discovery and management

What's left is understanding where EONYX takes skills from and how to turn them on right inside a session.

### Search directories

Directories are scanned in priority order — **on a name collision the first one found wins**:

| Priority | Directory                       | What it is                     |
| -------- | ------------------------------- | ------------------------------ |
| 1        | `<project>/.eonyx/skills`       | project skills                 |
| 2        | `~/.config/eonyx/skills`        | personal skills                |
| 3        | `~/.config/agents/skills`       | the shared agent skills folder |

So a project-level `review` overrides your global `review`. In addition:

- The `EONYX_SKILLS_DIR` variable (a list of paths separated by the OS separator) **replaces** the entire list of directories.
- The `skills` array in `eonyx.json` **appends** directories after the standard ones:

```json
"skills": ["/opt/team-skills", "../shared-skills"]
```

What was found is visible in `eonyx config` (the Skills section) and in the TUI header: the `# skills` segment lists the active skills.

### Managing skills in a session

**Ctrl+K** opens the capabilities dialog, the **Skills** tab: any skill can be turned off or on on the fly (`✓`/`✗`). Toggling immediately rebuilds the catalog in the system prompt and rebinds `load_skill` to the active set — the model no longer sees a disabled skill and cannot load it.

`load_skill` is a read-only tool by its nature, but formally it isn't in the always-allowed list; in the TUI its call goes through the regular permission dialog, or you can add it to `allowed_tools`.

## Summary

{{< admonition type="abstract" title="Cheat sheet" >}}
- **A skill**
  - a directory with a `SKILL.md`: frontmatter `name`/`description`/`tags` + the instruction body
  - `SKILL.md` is not executed — it's data for the model
- **Progressive disclosure**
  - the prompt holds only the catalog of names and descriptions
  - the model gets the full text through `load_skill`
- **Discovery**
  - the project's `.eonyx/skills` → `~/.config/eonyx/skills` → `~/.config/agents/skills`; the first match by name wins
  - `EONYX_SKILLS_DIR` replaces the list, the `skills` config key extends it
- **Management**
  - `Ctrl+K` → the Skills tab: on/off on the fly
  - active skills are visible in the header
- **The key field**
  - `description`: what the skill does and when to apply it, in the user's own words
{{< /admonition >}}

