Skip to content

skill.yaml reference

The skill.yaml manifest is validated against a strict schema. Unknown keys are rejected (with did-you-mean suggestions, so typos surface immediately), name and at least one step are required, and step ids and output names must be unique. Keys are snake_caseon_error, tool_mode, goto_step.

This page documents every field. For the YAML that goes at the top of a step’s prompt file, see Step-file frontmatter. For the {{ ... }} syntax used in values, see Templating with Liquid.

KeyTypeRequiredNotes
namestringyesHuman-readable name
stepslistyesAt least one step; see Steps
descriptionstringnoDefault ""
versionstringnoSemver (x.y.z), default 1.0.0
idstringnoDefaults to the folder name
authorstringno
inputslistnoSee Inputs
modelsmapnodefault + aliases; see Models
toolsmapnoaliases; see Tools
on_errorenumnoabort (default) or continue
outputmapnosummary, and an optional to output sink

The greeter example skill uses most of them:

.skiller/skills/greeter/skill.yaml
id: greeter
name: Greeter
description: A simple greeting workflow demonstrating multi-step skills with confirmation
version: "1.1.0"
inputs:
- name: name
type: string
description: Your name
required: true
prompt: "What is your name?"
models:
default: gpt-4o
steps:
- id: greet
type: llm
file: steps/01-greet.md
output: greeting
- id: confirm
type: confirmation
message: |
{{ outputs.greeting }}
Would you like me to also generate a fun fact?
options:
- { label: "Yes, give me a fun fact", action: continue }
- { label: "No thanks, just the greeting", action: abort }
output: user_choice
- id: fact
type: llm
file: steps/02-fact.md
model: gpt-4.1 # per-step model override
output: fun_fact
on_error: abort
output:
summary: "{{ outputs.fun_fact }}"

inputs[] declares the values collected from the user before the skill runs. Each input is read in templates as {{ inputs.<name> }}.

FieldTypeNotes
namestringRequired. Unique within the skill
typeenumstring (default), number, boolean, array
descriptionstringDefault ""
requiredbooleanDefault true
defaultanyUsed when the value is not provided
promptstringShown when the value is collected interactively
enumlist of stringsRestrict to these values (≥1 entry)
patternstringRegex the value must match (string inputs)
fromstringFill this input from editor context at launch instead of prompting; see Binding inputs to editor context
inputs:
- name: category
type: string
required: false
default: "anything"
prompt: "What kind of thing is it?"
enum: # offer a fixed set of choices
- "anything"
- "an animal"
- "a place"
- name: ticket
type: string
required: true
prompt: "Ticket key?"
pattern: "^[A-Z]+-[0-9]+$" # e.g. PROJ-123

Pass inputs when launching: @skiller /skill <id> ticket=PROJ-12 "positional value" — named values match by name; positional values fill the remaining inputs in declaration order.

from fills an input from the editor at launch instead of prompting — so a skill launched from the editor (a code action, the context menu, the Command Palette) picks up the selection, file, diff, or diagnostics it needs without asking. An explicit launch argument or a default always wins; the context only fills an input that would otherwise be empty.

from valueResolves to
selectionThe selected text in the active editor
activeFileThe active file’s full text (alias for activeFile.content)
activeFile.contentThe active file’s full text
activeFile.pathThe active file’s path
activeFile.languageThe active file’s language id (e.g. typescript)
git.stagedgit diff --staged for the workspace
git.workinggit diff (unstaged working-tree changes)
diagnosticsThe active file’s problems, one ‹line›: ‹message› per line
inputs:
- name: code
type: string
from: selection # filled from the highlighted code; prompts if nothing is selected
- name: language
type: string
from: activeFile.language

from is validated against the list above, so a typo is caught when the skill is parsed rather than silently resolving to nothing. For the full launch-and-deliver model see Editor-native skills.

models is optional. Omit it to use the model selected in the chat picker.

FieldTypeNotes
defaultstringModel used by steps that don’t set their own model
aliasesmapFriendly name → model ID, usable as a step’s model
models:
default: gpt-4o
aliases:
fast: gpt-4o-mini
smart: gpt-4o

A step then refers to an alias or a direct ID via its model field (see llm steps). A model picked in the chat model dropdown overrides all of this and shows a banner — see Use & override models.

tools.aliases maps a friendly name to an underlying tool name — a built-in tool or a configured MCP tool. Steps usually reference the alias (a tool step also accepts a raw tool name, but aliasing is recommended). Append ? to mark a tool optional: if it isn’t available at run time, steps that use it are skipped instead of failing.

tools:
aliases:
create_file: skiller_createFile # alias -> built-in LM tool
search: my_mcp_searchTool # alias -> a configured MCP tool
notify: my_mcp_notify? # optional: skipped if unavailable

steps[] is the ordered list of work. Every step shares a set of common fields; each type then adds its own.

Common fields (all step types):

FieldRequiredNotes
idyesUnique. Starts with a letter; letters, numbers, _, -
typeyesllm, confirmation, or tool — no default
descriptionnoShown in the live execution graph
outputnoUnique name; stores the step result as outputs.<name>
whennoLiquid condition; the step is skipped when it evaluates falsy
requiresnoList of step ids that must run before this one

when is evaluated permissively — an undefined variable is treated as falsy rather than throwing, so it is safe to guard a step against state that may not exist yet:

- id: summarize
type: llm
file: steps/summarize.md
when: "outputs.findings" # bare expression — runs only once findings exist
requires: [research] # research must run first
output: summary

Write when as a bare Liquid expression (e.g. outputs.findings, inputs.count > 0) — Skiller evaluates its truthiness for you. Don’t wrap it in {% if %} or {{ }}; a wrapped value never evaluates correctly and the step is always skipped.

Send a prompt to the model. Provide the prompt with exactly one of file or message.

FieldNotes
filePath to a Markdown prompt file, relative to the skill folder
messageInline prompt (alternative to file)
modelAlias or direct model ID; overrides models.default for this step
toolsList of tool aliases the model may call (agentic use)
tool_modeauto (model decides) or required (must call a tool; needs non-empty tools)
tools:
aliases:
search: my_mcp_searchTool # a real MCP tool you configured in VS Code
steps:
- id: research
type: llm
file: steps/01-research.md
tools: [search]
tool_mode: auto # "auto" (model decides) | "required" (must call a tool; needs non-empty tools)
output: findings

When an llm reply is valid JSON it is auto-parsed, so you can read fields with {{ outputs.findings.title }}. Otherwise the reply is stored as a raw string.

Pause and show the user a choice. Provide the message with message or file.

FieldNotes
messageInline prompt text (Liquid-interpolated)
filePath to a Markdown message file (alternative to message)
optionsList of choices; defaults to Continue / Cancel if omitted

Each entry in options:

FieldRequiredNotes
labelyesButton text
actionyescontinue, abort, or goto
goto_stepwhen action: gotoTarget step id to jump to

A goto can point backward (loop) or forward (branch):

- id: answer
type: confirmation
message: "{{ outputs.turn.question }}"
options:
- { label: "Yes", action: goto, goto_step: ask } # loop back
- { label: "No", action: goto, goto_step: ask }
- { label: "I'm ready — guess now!", action: goto, goto_step: guess } # branch forward
output: reply

The step’s output is an object:

FieldTypeNotes
selectedOptionstringThe chosen option’s label
selectedIndexnumber1-based index as shown to the user
actionstringcontinue, abort, or goto
timestampnumberWhen the user confirmed

Read it as {{ outputs.reply.selectedOption }}. See Branch & loop with confirmations for the full pattern.

Invoke a single tool. Takes a tool (an alias from tools.aliases, or a raw tool name) and optional params. A tool step must not carry tools or tool_mode — those apply only to llm steps.

FieldRequiredNotes
toolyesA tool alias from tools.aliases, or a raw tool name
paramsnoMap passed to the tool; values are recursively Liquid-interpolated
tools:
aliases:
create_file: skiller_createFile # alias -> built-in LM tool
steps:
- id: save
type: tool
tool: create_file
params:
filePath: "notes.md"
content: "{{ outputs.draft.text }}"
output: saved

Top-level. Controls what happens when a step fails.

ValueBehavior
abortStop the skill on the first error (default)
continueSkip the failed step and keep going

Top-level, optional. Two keys:

KeyTypeNotes
summarystringLiquid template rendered after the skill finishes — the closing message
tostringOptional output sink: where summary is delivered. Omit for chat only

output.summary is rendered and shown to the user when the skill completes:

output:
summary: "✅ Saved to {{ outputs.saved.filePath }}."

When to is set, the rendered summary is delivered to that destination instead of (just) being shown in chat. The destination is captured at launch, so an editor sink writes back where the skill was started even after chat takes focus.

to valueDelivers to
newDocumentA new untitled document
file:‹path›A workspace file at ‹path› (created/overwritten; workspace-confined like the file tools)
editor.replaceSelectionReplaces the launch selection (inserts at the caret if there was none)
editor.insertInserts at the launch caret
diffOpens a reviewable diff against the launch document — you Apply it
terminalTypes the text into the terminal without running it — you review and press Enter
terminal.runTypes the text into the terminal and runs it — pair with a confirmation step, since it executes on delivery
output:
summary: "{{ outputs.command }}"
to: terminal.run # the shell-it skill: drafts a command, then runs it after you confirm

to may be templated (file:notes/{{ inputs.name }}.md). The write-back sinks (editor.replaceSelection, editor.insert, diff) never clobber: if the launch document changed since the skill started, the result opens in a new tab instead. For the full model and safety behaviour see Editor-native skills.