5.0 KiB
Skills
A skill is a directory of instructions the agent can find, read, and follow:
a SKILL.md (frontmatter + Markdown body) plus whatever bundled files it needs
— scripts, references, templates. Plyngent discovers skills from your own user
directory and from the directories other harnesses install into, so one skill
folder can serve several agents.
Layout
<root>/
pdf-processing/
SKILL.md # required: frontmatter + instructions
scripts/extract.sh # optional bundled files
references/forms.md
SKILL.md:
---
name: pdf-processing
description: Extract text and tables from PDFs; fill forms.
version: 1
allowed-tools: [run_argv, read_file]
---
# PDF processing
Use `scripts/extract.sh <file>` for the text layer, then ...
Roots and discovery
Roots are scanned in priority order; the first skill with a given name wins
and the copies it shadows stay listed (skill_list, /skills) instead of
disappearing:
[skills].paths— explicit roots (highest priority)- our own user directory:
<user config>/skills(plyngent config pathshows the directory that containsplyngent.toml) - other harnesses:
~/.claude/skills, and<workspace>/.claude/skillswheninclude_project_rootsis on (discover = ["plyngent", "claude"]by default)
A root may also be a skill directory (its own SKILL.md), which is handy when
you point paths at a single skill. Missing roots are not an error; /skills
lists the ones with no directory.
[skills]
enabled = true # false = no skill tools
paths = ["~/team-skills"] # explicit roots; `~` expands to your home
discover = ["plyngent", "claude"]
include_project_roots = true
allow_write = false # true = standing grant for skill writes
Frontmatter
The reader covers the YAML subset those files use — top-level key: value
scalars (quoted, plain, true/false, integers), inline [a, b] lists, block
- item lists, and | / > blocks. A plain scalar folds its indented
continuation lines. A nested mapping (say a metadata: block) is skipped rather
than guessed at, and a structurally broken block degrades to "no metadata" with
a note: the skill stays listable instead of vanishing.
| Field | Meaning |
|---|---|
name |
Skill name; must be lowercase letters, digits, and single hyphens (max 64). A name that cannot be used falls back to the directory name, with a note. |
description |
One line shown by skill_list (and /skills for the human). Missing → the first non-heading paragraph of the body. |
version, license, allowed-tools, … |
Kept and shown by skill_list; allowed-tools is recorded, not enforced today. |
What the agent sees
- Notice (a host notice,
agent/notices.py): when skills are enabled and tools are on, the session gets oneskillsnotice describing the tools; it lists nothing, so what exists is asked for and a turn only pays for the skill it actually reads. skill_list— what exists, where it came from, shadowed copies, and the notes from repaired frontmatter.skill_read NAME [file]— theSKILL.mdbody (ranges, line numbers, and a continuation token like any other read) or one bundled file, resolved inside the skill directory only.skill_search PATTERN [skill]— regex over every visible skill; hits come back as<skill>/<file>:<line>: content.
Grants: reading vs writing
- Reading needs no grant. The host registers the roots as read-only roots, so
read_file,regex_files, andlistdirsee skill files too. Writes are denied by the path policy — a skill directory never becomes a write grant. - Writing needs a grant.
skill_create/skill_editask the human for the skill directory:oonce,sfor the rest of the chat, anything else (or a timeout) denies. The prompt is independent of YOLO:--yes//yolonever skips it.[skills].allow_write = trueis the standing grant, and the path denylist ([agent].path_denylist) still wins over everything.
skill_create writes a new SKILL.md (name, description, body) plus any
files you list; skill_edit changes one file by literal replacement
(old_string → new_string, all matches with replace_all), by append, or
by rewriting it. A rewritten SKILL.md is re-parsed, and the reply says so when
the description (or the whole frontmatter) is gone.
Care and safety
- A skill is data, not code: nothing in a skill body bypasses the confirm flow, the path denylist, or the command denylist. Bundled scripts run through the normal process tools, so they still need whatever grant those require.
- Third-party skills (other harnesses' directories, shared repos) are untrusted
input. Read before you follow, keep
pathspointed at directories you trust, and preferallow_write = false+ per-write prompts when a skill comes from outside. - Keep skills small and specific; long bodies are better split into a short
SKILL.mdplus reference files the model reads on demand.