Skip to content

Skills

Instruction packages the model loads on demand, per the Agent Skills spec.

A skill is a directory with a SKILL.md file, per the Agent Skills standard. The system prompt lists only the name and description of each skill. The model loads the full instructions when it needs them.

Skill layout#

Text
my-skill/
  SKILL.md       # Required: frontmatter + instructions
  scripts/       # Optional: executable code
  references/    # Optional: documentation
  assets/        # Optional: templates, data
markdown
---
name: my-skill
description: When to activate this skill.
allowed-tools: Bash Read Write
metadata:
  zidane.model: claude-opus-4-7
  zidane.thinking: low
  zidane.paths: "src/**/*.ts,test/**/*.ts"
---

Full instructions the agent receives on activation.

Top-level model, thinking and paths are deprecated. They still load: the parser moves them to metadata["zidane.*"] and adds a diagnostic.

allowed-tools takes three shapes, all normalized to string[]:

YAML
allowed-tools: Read Bash(git:*)        # spec-canonical, whitespace-separated
allowed-tools: [Read, Bash(git:*)]     # YAML flow list
allowed-tools:                          # YAML block list
  - Read
  - Bash(git:*)

Shell interpolation#

!`cmd` in the instructions runs cmd on each activation and inlines its output, for example !`git branch --show-current`. These commands bypass the allowed-tools gate, and skills can come from third parties. skills.allowShellInterpolation: false turns interpolation off (default true). skills.approveShellInterpolation is a callback that approves or refuses each command.

Loading and discovery#

zidane scans these folders in order. On a name clash the first wins, so project skills beat user skills.

OrderFolderScope
1<root>/.agents/skillsProject, any agent
2<root>/.zidane/skillsProject, zidane only
3~/.agents/skillsYou, any agent
4~/.zidane/skillsYou, zidane only
5.claude/skills, .codex/skills, .pi/skills in the project, then ~/.claude/skills, ~/.codex/skills, ~/.pi/agent/skillsApps only, with the setting Import configurations from other agents on
6.ruler/skills in the project, then your global Ruler folderApps only, with the setting Support Ruler configuration (.ruler) on (default)

<root> is the working directory in the library. The apps use the git root above the folder of the session, or the folder itself outside git. So a session in repo/packages/foo finds repo/.zidane/skills. User skills stay in ~/.zidane/skills on Linux too (files).

TypeScript
import { basic, createAgent, defineSkill } from 'zidane'

createAgent({
  ...basic,
  provider,
  skills: {
    scan: ['./custom-skills'],
    write: [defineSkill({ name: 'review', description: 'Code review.', instructions: '...' })],
    exclude: ['deprecated-skill'],
    enabled: ['review', 'deploy'],
  },
})
OptionDefaultEffect
enabledtruefalse or [] turns skills off. A string[] is an allow-list.
scanExtra directories
writeSkills written to disk at start, then loaded
catalogPre-resolved skills. They win name clashes.
excludeNames to drop
skipDefaultPathsfalseSkip the default scan paths
tooltrueAdd the skills tools
maxActiveunlimitedActive skills per run
scriptTimeoutMs60000skills_run_script timeout
trustProjectSkillstruefalse skips project skills, for untrusted repos

Activation#

Once the catalog has a skill, the agent gets three tools:

ToolDoes
skills_usemode: 'activate' (default) returns the body in a <skill_content> block. mode: 'deactivate' (a zidane addition to the spec) releases the skill and its allowed-tools limit.
skills_readReads a file from an active skill's references/ or assets/
skills_run_scriptRuns a script from scripts/, returns { exitCode, stdout, stderr }
TypeScript
await agent.activateSkill('pdf-processing')   // fires skills:activate, via: 'explicit'
agent.activeSkills                            // readonly ActiveSkill[]
await agent.deactivateSkill('pdf-processing') // fires skills:deactivate, reason: 'explicit'

activateSkill resolves the catalog on its first call, so it works before run(). To resolve early, call await agent.warmup() or set eager: true. activateSkill throws for an unknown name, when skills are off, and when maxActive is reached. Skill hooks are on hooks.

In the apps, /<skill-name> activates that skill for the next message. It wins over a Markdown command of the same name. Settings › Skills has an on/off switch per skill. Both apps install, edit and delete skills there.

Enforcement and resume#

When an active skill declares allowed-tools, a tool:gate handler blocks calls outside the union of the lists of the active skills. The three skills tools stay allowed. A blocked call throws AgentToolNotAllowedError. Its message tells the model to call skills_use({ mode: 'deactivate', name }).

On resume, zidane rebuilds the active set from the skills_use calls in the history. The last mode wins per skill. Resumed activations fire with via: 'resume'. skills:deactivate does not fire during the rebuild.

agent.activateSkill(name) writes no history, so the skill ends with the run. A host that needs it across runs (for example a TUI slash command) must activate it again before each run().

Add skills from a repository#

The Skills step of the setup wizard and Settings › Skills list the skills of a source before you install them. Settings shows a compact version, with the recommended sources as small chips. Type a source, or open a recommended one. Each skill shows its name, its description and its folder. Pick skills from one source or from several, then install them.

A source can be any of these:

  • owner/repo, or a GitHub link such as https://github.com/cursor/plugins/tree/HEAD/pstack/skills
  • owner/repo/path/to/folder, the form of the skills CLI
  • a skills.sh link, or a pasted npx skills add … command
  • an npm package

A pack is a repository with no skills of its own whose README links skills in other repositories, such as antfu/skills-pack. Its list holds each linked skill, and each one installs from its own repository.

zidane reads the file list and the head of each SKILL.md through GitHub. With a GitHub token (GH_TOKEN, GITHUB_TOKEN or your gh login), GitHub allows 5,000 calls an hour instead of 60. When GitHub refuses, zidane downloads the source and lists it from its files. zidane keeps each listing for ten minutes. Nothing in a source runs, because a skill is text.

SourceRepositorySkills for
Matt Pocockmattpocock/skillsEngineering habits for real projects: test-driven development, code review, research and planning.
Anthony Fu's packantfu/skills-packA hand-picked pack of skills from several authors, in one list.
Anthony Fuantfu/skillsConventions for Vue, Nuxt, Vite, Vitest, UnoCSS and pnpm projects.
Cursor pstackcursor/plugins/pstack/skillsPrinciples and workflows from the pstack plugin: design, verification and clear writing.
Anthropicanthropics/skillsThe official examples: documents, spreadsheets, design, the Claude API and MCP servers.

From code#

browseSkillSource lists a source. Each skill carries the spec that installs it, and groupSkillPicks turns picks into one install per source.

TypeScript
import { groupSkillPicks, skillPickOf } from 'zidane/chat/pure'
import { browseSkillSource, installSkillFromSpec } from 'zidane/skills'

const listing = await browseSkillSource('mattpocock/skills')
const picks = listing.skills.filter(skill => ['tdd', 'research'].includes(skill.name)).map(skill => skillPickOf(skill, listing))
for (const group of groupSkillPicks(picks))
  await installSkillFromSpec({ source: group.source, skills: group.rels, scope: 'user' })

Install skills#

installSkillFromSpec takes the same sources as the extensions installer: GitHub owner/repo[#ref][:subdir], a GitHub URL, an npm package, or a skills.sh/<owner>/<repo>[/<skill>] URL.

TypeScript
import { installSkillFromSpec } from 'zidane'

await installSkillFromSpec({ source: 'vercel-labs/agent-skills', skill: 'react-best-practices', scope: 'user' })
await installSkillFromSpec({ source: 'https://skills.sh/anthropics/skills/frontend-design', scope: 'project' })

skills: [...] installs a picked subset of a source, by name or folder. The apps send this option. Skills install to ~/.zidane/skills/<name> (user) or <gitRoot>/.zidane/skills/<name> (project). If the call names one skill and the skills CLI from skills.sh is on PATH, that CLI runs the install and writes to .agents/skills/. preferSkillsCli: false turns this off.

Validation parses SKILL.md and does not run code. The parser is lenient. Skills with minor deviations load, with warnings in SkillConfig.diagnostics. The authoring helpers defineSkill and writeSkillToDisk follow the spec strictly.

Reference#