Skills
Skills are reusable workflow commands packaged as markdown
files. The agent loads a skill on demand via the use_skill tool;
the file's content is returned and the agent follows the
instructions inside. Skills also surface in the client as /command
entries in the slash palette.
Anatomy
my-app/
├── app.yaml
└── skills/
├── commit.md # skill body (markdown)
├── review.md
└── security-audit.md
Declare the skills under dev.skills :
dev:
skills:
- command: /commit
description: "Stage + commit + push the current diff"
path: skills/commit.md
- command: /review
description: "Adversarial code review with focus on security"
path: skills/review.md
- command: /security-audit
description: "Run the standard 6-step security audit"
path: skills/security-audit.md
Skill entry reference
| Field | Type | Required | Description |
|---|---|---|---|
command | string (min 1) | yes | Slash command id (e.g. /commit). |
description | string | no (default "") | One-line description shown in the slash palette and the use_skill catalog. |
path | string (min 1) | yes | Path to the .md file relative to the bundle directory. |
The compiler checks that path: exists (a missing file is a real
compile error - "the command fails the first time it is typed") but
does not read the content into the compiled app: at runtime,
use_skill re-reads the file live from the bundle directory on
every call, not from anything embedded at compile time. In
practice this only matters if the file is deleted or moved after a
successful compile without recompiling - the compile-time check
doesn't protect against that.
A skill referenced only through an agent's capabilities: list
(not through dev.skills) has no compile-time existence check
at all - a typo'd capability name compiles clean and silently loads
nothing at runtime (see below).
How an agent uses a skill
use_skill is one of the
always-available primitives - see
Built-in Tools → use_skill.
When the LLM calls use_skill(command='/commit'), the runtime
looks up the matching skill entry, returns the file content as
the action result, and adds dir (the skill file's own directory,
relative to which any files the skill references should be read or
executed) plus a "Follow these instructions" note.
// LLM call
{"name": "use_skill", "arguments": {"command": "/commit"}}
// Result (returned to the LLM)
{
"success": true,
"data": {
"command": "/commit",
"description": "Stage + commit + push the current diff",
"content": "# Commit workflow\n\n1. Run `git status`...\n",
"dir": "skills",
"note": "Follow these instructions to complete the task. Files they reference are relative to `dir` - read or execute them from there."
}
}
The leading / is optional in the command parameter - the
runtime adds it automatically.
Two complementary surfaces
Don't confuse dev.skills with ui.slash_commands:
| Block | Purpose | Loaded by | Reach |
|---|---|---|---|
dev.skills | Reusable workflow MD files the agent loads via use_skill. | Read live from the bundle on each call. The agent calls use_skill('/cmd'). | Server-side. The agent reads the markdown and follows the steps. |
ui.slash_commands | Pure client-side / palette entries. | the chat client / web client renders the palette; the chosen command's template: becomes the message sent to the agent. | Client-side. The agent never knows the slash palette existed - it just sees a normal user message. |
A typical app declares both: the slash command exposes a typed form
to the user; the resulting message tells the agent to invoke
use_skill with the right command.
Auto-loading per agent
An agent's capabilities: field lists skill names
to auto-load into the agent's system prompt. At the start of
each turn the runtime resolves each name (live from the bundle,
same as use_skill) and appends the content under an
## Available capabilities section. Skills loaded this way don't
need to be invoked explicitly - they're already in the agent's
context.
A capability name resolves in this order: a matching dev.skills[].command
first, then skills/<name>.md, then skills/<name>/SKILL.md - so a
capability can point at a plain skill file even if it has no
dev.skills entry at all (the SKILL.md-in-its-own-folder form is
useful when the skill needs supporting files alongside it - see
dir in the use_skill result above).
agents:
- id: reviewer
role: specialist
capabilities:
- git_review # loads skills/git_review.md into the prompt
- security_audit # loads skills/security_audit.md into the prompt
instructions.file is a separate mechanism for keeping a long
prompt in its own file: the compiler checks the file exists and
merges its content directly into system_prompt at compile time -
content is fixed at compile time, unlike a skill's, which is read
live each time it's used.
agents:
- id: reviewer
role: specialist
specialty: "Adversarial code review"
capabilities: [git_review] # auto-loaded from skills/
instructions:
file: ./instructions/review.md # appended to system_prompt
Skill file format
Skills are plain markdown. The compiler doesn't parse them - it inlines the raw text. Convention:
# /commit - Stage, commit, push
## Goal
Produce a clean conventional-commits message and push to the
current branch.
## Steps
1. Run `git status` to see the working tree.
2. Run `git diff --staged` for any already-staged changes;
`git diff` for unstaged.
3. Group changes by intent. One commit per intent.
4. For each commit:
- Pick a type (feat / fix / refactor / docs / test / chore).
- Stage the relevant files (`git add <paths>`).
- Commit with a clear subject + body explaining the WHY.
5. Push the branch (`git push`).
## Anti-patterns
- DO NOT mix unrelated changes in one commit.
- DO NOT use vague subjects like "WIP" or "fix stuff".
The agent reads this verbatim and follows it. The file is read raw
- there is no template resolution inside it:
{{prompt.X}}or{{include:path}}written inside a skill markdown file is not resolved and reaches the agent literally as that text. (The separate{{skill.X}}macro - using a skill's content to fill in another field - does go through compile-time resolution; that's a different use case from a skill loaded viause_skillorcapabilities:.)
Bundle layout
<bundle>/skills/<name>.md is the convention, not an enforced
rule - path: can point anywhere relative to the bundle root, and
nothing checks the file exists until it's actually loaded (see
above).
For very large apps with many skills, consider grouping them in
sub-folders (skills/git/commit.md, skills/security/audit.md)
and listing each entry's full path.
Compile-time validation
Unknown keys on a skill entry are rejected. What the compiler actually checks:
- Every entry must declare
commandandpath(both non-empty), andcommandmust match the slash-command format. pathmust point to a file that exists in the bundle - a missing file is a compile error.- Duplicate
commandvalues raise an error (skill resolution would be ambiguous at runtime).
What it does not check: a name used only through an agent's
capabilities: list, with no matching dev.skills entry - that
path has no compile-time safety net. Test every capability-loaded
skill with a real turn before shipping - a typo'd capability name
compiles clean and silently loads nothing.
User skills (/use_skill)
Skills on this page are agent-facing: the LLM calls use_skill
and the body comes back as a tool result. The runtime also supports
user-facing skills the end user picks from the composer and
that get injected as a forced role: system directive on the
matching turn. Authored per-user, stored in the daemon database,
gated by a single YAML flag:
dev:
allow_user_skills: true # default false
Full mechanics, CRUD endpoints, the /use_skill <name> <prompt>
parser, the turn-scoped injection slot, and the web composer flow
(including the .md file picker) are documented in:
Reference → Runtime → User Skills & /use_skill
Cross-references
- The
use_skilltool (always-available primitive): Built-in Tools → use_skill dev.skillsfile resolution: Bundle namespaces →{{skill.X}}- The
dev.includefragmentation block (separate from skills): Bundle namespaces →{{include:path}} - Pure client-side slash palette (
ui.slash_commands): Client Manifest - Bundle namespace deep dive (
{{prompt.X}},{{skill.X}},{{include:}}): Bundle namespaces - End-user-authored skills +
/use_skillcommand: Runtime → User Skills