v0.34.0 a939a2a

skills.md RawHistoryFolder

zut skills

A skill is a reusable instruction set written as a single SKILL.md file with a YAML frontmatter header. Unless a skill disables model invocation, zut discovers it at startup and surfaces it to the model in two ways:

  1. The system prompt gains a short manifest: Available skills: ... - code-review — Run a self-review pass...
  2. A built-in skill tool lets the model load any one skill's full body on demand.

The on-demand-load model keeps token usage cheap: only the manifest goes into every request; the body is fetched as a tool result the one or two turns the model actually needs it.

Anatomy

---
name: code-review
description: Run a thorough self-review pass on a recent change.
allowed-tools: [read, bash]
permissions:
  bash: ["git diff*", "git log*"]
---

# Code review

When asked to review code, ...

Frontmatter fields

field required purpose
name optional skill identifier; defaults to the directory name
description required one-line summary shown in the system prompt
disable-model-invocation optional when true, hide the skill from the model's startup manifest; invoke it explicitly with /skill:<name>
allowed-tools optional list of tool names the skill is meant to use; informational
permissions optional per-tool patterns; informational

allowed-tools and permissions are parsed but not enforced in this version. They appear in the rendered skill body so the model can see them and self-regulate. Future versions may enforce.

The body (everything after the second ---) is plain markdown. There's no template engine; the model sees what you write.

Discovery

zut looks in these directories, in priority order, and registers the first SKILL.md it finds for each unique name:

location scope
./.zut/skills/<name>/SKILL.md project (native)
$ZUT_HOME/skills/<name>/SKILL.md global (native)
./.claude/skills/<name>/SKILL.md project (claude-compat)
~/.claude/skills/<name>/SKILL.md global (claude-compat)
./.agents/skills/<name>/SKILL.md project (agent-compat)
~/.agents/skills/<name>/SKILL.md global (agent-compat)

The compat paths are deliberate: a SKILL.md written for an existing skill ecosystem works in zut unchanged. Drop your existing .claude/skills/ or .agents/skills/ directories into a project and zut will pick them up. User skill roots are scanned recursively, so nested files such as ~/.agents/skills/systems-backend/subskills/golang-patterns/SKILL.md are discovered too. The frontmatter name is the canonical identifier; for nested user skills, the slash-separated directory path relative to the skill root is also accepted by the skill tool and /skill: commands.

Enabled extensions may bundle skills by declaring relative directories in extension.json, for example "skills": ["skills"], with files at skills/<name>/SKILL.md. A declared directory may also contain a single SKILL.md directly; its directory name supplies the fallback skill name and child directories are not scanned. Bundled skills are copied by zut ext install and loaded automatically. User/project skills take precedence over bundled skills; bundled skills take precedence over embedded built-ins. When two extensions provide the same skill name, the first declaration wins. The host rejects manifest paths that escape the extension directory, including symlinked skill files that resolve outside it.

When XDG_STATE_HOME is set on any platform, $ZUT_HOME defaults to $XDG_STATE_HOME/zut. Otherwise it defaults to ~/Library/Application Support/zut/ on macOS, ~/.local/state/zut on Linux, or %LOCALAPPDATA%\zut on Windows.

Inspecting installed skills

In zut, run /skills. A picker lists every discovered skill with its description and source path. Press enter on a row to view the full body inline. Press esc to go back.

Invoking skills

For normal skills, the system prompt tells the model the skill names and short descriptions. When a request matches, the model calls the skill tool to load the full instructions on demand.

To force a specific skill, invoke it as a slash command. Typing /skill: opens a filtered list of discovered user skills. Use the arrow keys to select one, tab to complete its name, or enter to invoke the highlighted skill.

/skill:code-review
/skill:code-review focus on security issues

zut expands the command into a user message containing the complete skill body, its directory for resolving relative references, and any text following the command as the request. This bypasses model-side skill selection.

Set disable-model-invocation: true in a skill's frontmatter when it should only run after explicit user invocation. The skill remains visible in /skills and available through /skill:<name>, but its name and description are omitted from the model's startup context.

Writing good skills

  • Be procedural. Number steps. Tell the model what to do in what order. Skills are habits, not knowledge dumps.
  • Be precise about boundaries. "Stop after step 4" is more effective than "don't go too far".
  • Trim aggressively. A 200-line skill bloats every turn the model uses it. Aim for 20–80 lines.
  • One skill per behaviour. Don't pack three workflows into one SKILL.md; the model picks one path. Two separate skills work better.
  • Lead with the trigger. First paragraph should make it obvious when to use the skill so the model self-selects correctly.

Examples

See examples/skills/ for starter skills:

  • code-review/ — self-review pass on a recent diff
  • test-fix/ — diagnose + minimally fix a failing test

Comparison to other discovery layouts

ecosystem path zut reads it?
(native) .zut/skills/<name>/SKILL.md yes
(claude-style) .claude/skills/<name>/SKILL.md yes
(agent-style) .agents/skills/<name>/SKILL.md yes

Cross-pollination is intentional: pick whichever convention you're already using and zut tags along.

source
1# zut skills
2
3A skill is a reusable instruction set written as a single
4`SKILL.md` file with a YAML frontmatter header. Unless a skill disables
5model invocation, zut discovers it at startup and surfaces it to the model
6in two ways:
7
81. The system prompt gains a short manifest:
9   `Available skills: ... - code-review — Run a self-review pass...`
102. A built-in `skill` tool lets the model load any one skill's full
11   body on demand.
12
13The on-demand-load model keeps token usage cheap: only the manifest
14goes into every request; the body is fetched as a tool result the
15one or two turns the model actually needs it.
16
17## Anatomy
18
19```markdown
20---
21name: code-review
22description: Run a thorough self-review pass on a recent change.
23allowed-tools: [read, bash]
24permissions:
25  bash: ["git diff*", "git log*"]
26---
27
28# Code review
29
30When asked to review code, ...
31```
32
33### Frontmatter fields
34
35| field | required | purpose |
36|---|---|---|
37| `name` | optional | skill identifier; defaults to the directory name |
38| `description` | required | one-line summary shown in the system prompt |
39| `disable-model-invocation` | optional | when `true`, hide the skill from the model's startup manifest; invoke it explicitly with `/skill:<name>` |
40| `allowed-tools` | optional | list of tool names the skill is meant to use; informational |
41| `permissions` | optional | per-tool patterns; informational |
42
43`allowed-tools` and `permissions` are **parsed but not enforced** in
44this version. They appear in the rendered skill body so the model can
45see them and self-regulate. Future versions may enforce.
46
47The body (everything after the second `---`) is plain markdown.
48There's no template engine; the model sees what you write.
49
50## Discovery
51
52zut looks in these directories, in priority order, and registers the
53first `SKILL.md` it finds for each unique name:
54
55| location | scope |
56|---|---|
57| `./.zut/skills/<name>/SKILL.md` | project (native) |
58| `$ZUT_HOME/skills/<name>/SKILL.md` | global (native) |
59| `./.claude/skills/<name>/SKILL.md` | project (claude-compat) |
60| `~/.claude/skills/<name>/SKILL.md` | global (claude-compat) |
61| `./.agents/skills/<name>/SKILL.md` | project (agent-compat) |
62| `~/.agents/skills/<name>/SKILL.md` | global (agent-compat) |
63
64The compat paths are deliberate: a `SKILL.md` written for an existing
65skill ecosystem works in zut unchanged. Drop your existing
66`.claude/skills/` or `.agents/skills/` directories into a project and
67zut will pick them up. User skill roots are scanned recursively, so
68nested files such as `~/.agents/skills/systems-backend/subskills/golang-patterns/SKILL.md`
69are discovered too. The frontmatter `name` is the canonical identifier;
70for nested user skills, the slash-separated directory path relative to the
71skill root is also accepted by the `skill` tool and `/skill:` commands.
72
73Enabled extensions may bundle skills by declaring relative directories in
74`extension.json`, for example `"skills": ["skills"]`, with files at
75`skills/<name>/SKILL.md`. A declared directory may also contain a single
76`SKILL.md` directly; its directory name supplies the fallback skill name and
77child directories are not scanned. Bundled skills are copied by `zut ext
78install` and loaded automatically. User/project skills take precedence over
79bundled skills; bundled skills take precedence over embedded built-ins. When
80two extensions provide the same skill name, the first declaration wins. The
81host rejects manifest paths that escape the extension directory, including
82symlinked skill files that resolve outside it.
83
84When `XDG_STATE_HOME` is set on any platform, `$ZUT_HOME` defaults to
85`$XDG_STATE_HOME/zut`. Otherwise it defaults to `~/Library/Application Support/zut/`
86on macOS, `~/.local/state/zut` on Linux, or `%LOCALAPPDATA%\zut` on Windows.
87
88## Inspecting installed skills
89
90In zut, run `/skills`. A picker lists every discovered skill with its
91description and source path. Press enter on a row to view the full
92body inline. Press esc to go back.
93
94## Invoking skills
95
96For normal skills, the system prompt tells the model the skill names and
97short descriptions. When a request matches, the model calls the `skill` tool
98to load the full instructions on demand.
99
100To force a specific skill, invoke it as a slash command. Typing `/skill:` opens a filtered list of discovered user skills. Use the arrow keys to select one, `tab` to complete its name, or `enter` to invoke the highlighted skill.
101
102```text
103/skill:code-review
104/skill:code-review focus on security issues
105```
106
107zut expands the command into a user message containing the complete skill
108body, its directory for resolving relative references, and any text following
109the command as the request. This bypasses model-side skill selection.
110
111Set `disable-model-invocation: true` in a skill's frontmatter when it should
112only run after explicit user invocation. The skill remains visible in
113`/skills` and available through `/skill:<name>`, but its name and description
114are omitted from the model's startup context.
115
116## Writing good skills
117
118- **Be procedural.** Number steps. Tell the model what to do in what
119  order. Skills are habits, not knowledge dumps.
120- **Be precise about boundaries.** "Stop after step 4" is more
121  effective than "don't go too far".
122- **Trim aggressively.** A 200-line skill bloats every turn the
123  model uses it. Aim for 20–80 lines.
124- **One skill per behaviour.** Don't pack three workflows into one
125  SKILL.md; the model picks one path. Two separate skills work better.
126- **Lead with the trigger.** First paragraph should make it
127  obvious *when* to use the skill so the model self-selects correctly.
128
129## Examples
130
131See `examples/skills/` for starter skills:
132
133- `code-review/` — self-review pass on a recent diff
134- `test-fix/` — diagnose + minimally fix a failing test
135
136## Comparison to other discovery layouts
137
138| ecosystem | path | zut reads it? |
139|---|---|---|
140| (native) | `.zut/skills/<name>/SKILL.md` | yes |
141| (claude-style) | `.claude/skills/<name>/SKILL.md` | yes |
142| (agent-style) | `.agents/skills/<name>/SKILL.md` | yes |
143
144Cross-pollination is intentional: pick whichever convention you're
145already using and zut tags along.

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 476

↑↓ moveenter openesc close