Helps you write new agent skills that follow the best-practices documented at
https://agentskills.io/skill-creation/ — without you having to re-read those pages
every time. Pairs with skill-creator (which handles eval/iterate/optimize loops
once a draft exists).
When to use this vs skill-creator
| Task | Use |
|---|---|
| "I want to make a new skill for X" | skill-author (scaffold + author) |
| "Scaffold the SKILL.md / a reference / a script" | skill-author |
| "Lint this skill draft" | skill-author |
| "My skill isn't triggering when I want it to" | skill-creator (description optimization) |
| "Run test cases against my skill, benchmark it" | skill-creator (eval loop) |
| "Compare two versions of my skill" | skill-creator (blind comparison) |
If both apply, start here, then hand off to skill-creator once the draft is solid.
Workflow
1. Capture intent (1 minute)
Before scaffolding, get four answers — usually just by asking the user:
- What does it do? (one sentence)
- When should it trigger? (specific user phrases / contexts)
- What does it output? (file, command result, plan, prose)
- Is the output objectively verifiable? (decides whether
skill-creatorevals are worth the effort later)
Write these four down before touching files. They become the seeds for the description, the workflow body, and the future eval set.
2. Scaffold
Use scripts/new-skill.sh to produce the directory layout. The script
auto-detects scope (where to put the skill) and fans out discovery
symlinks for non-universal agents so the skill is loadable immediately.
bash skills/local/skill-author/scripts/new-skill.sh <skill-name>
Three scopes (auto-detected; override with --local / --project / --global):
| Scope | Canonical dir | Symlinks created |
|---|---|---|
| LOCAL (this publishing repo: vendor.yaml / skills/local/ found walking up) | <repo>/skills/local/<name>/ (or skills/vendor/<name>/ with --vendor) |
.agents/skills/<name> + .claude/skills/<name> -> ../../skills/{local,vendor}/<name> |
| PROJECT (inside another git repo) | <repo>/.agents/skills/<name>/ (universal agents — Cursor / Codex / OpenCode / Warp — pick this up directly) |
.claude/skills/<name> -> ../../.agents/skills/<name> (+ any already-present non-universal agent dir at the repo root) |
| GLOBAL (no git repo found) | ~/.agents/skills/<name>/ |
~/.claude/skills/<name> -> ../../.agents/skills/<name> (+ any detected non-universal agent dir under $HOME) |
The template's frontmatter has placeholders that lint will reject — this is on purpose so the agent can't forget to fill them in.
Important: When the user's intent is ambiguous (they're inside a git repo but haven't said whether the skill should live with the project or be available everywhere), ask "system-wide (
--global) or just this project (--project)?" before running the script. The script is non-interactive — once you've picked a scope, files land and symlinks fan out without further prompting.
After running, the script emits a single JSON object on stdout with
{skill, mode, canonical, symlinks[], next_steps[]} so you can chain
follow-up actions deterministically.
3. Author the SKILL.md
Read references/authoring-patterns.md before writing the body. The patterns
that matter most:
- Description must be "pushy" and include concrete trigger contexts. Naive descriptions cause undertriggering — the #1 failure mode of new skills. Keep this within the cross-agent budget: 120-500 chars is the preferred range, 501-900 is valid but context-heavy, 901-1024 is valid but close to hard loader limits, and >1024 is invalid for Codex/Cursor/spec-aligned skills.
- Gotchas section — environment-specific facts that defy reasonable assumptions. The single highest-value section in most skills.
- Output templates — agents pattern-match against concrete structures more reliably than they follow prose descriptions of formats.
- Calibrated specificity — be prescriptive only where the task is fragile; give the agent freedom (and explain why) where multiple approaches are valid.
- Defaults, not menus — pick one tool/approach and mention alternatives as escape hatches.
Keep SKILL.md under 500 lines. If you blow past that, move detail into
references/<topic>.md and tell the agent when to load it ("Read X if Y
happens"), not just that it exists.
4. Design any scripts
Before writing a script, read references/script-design.md. Skills script
design is meaningfully different from "regular" CLI script design because the
caller is an LLM reading your stderr to decide what to do next. The non-obvious
requirements:
- No interactive prompts, ever (agents run in non-interactive shells)
--helpis the primary interface documentation — keep it concise but complete- Errors must say what was expected and what to try, not just what failed
- Structured stdout (JSON/CSV/TSV), prose diagnostics to stderr — separate them
--dry-runfor any destructive operation- Pin versions for
uvx/npx/pipxinvocations
For Python helpers, prefer PEP 723 inline dependencies + uv run over
requirements.txt — the script becomes self-contained and the agent doesn't
have to set up an environment first.
5. Lint
Run the linter before committing or handing off to skill-creator:
bash skills/local/skill-author/scripts/lint-skill.sh skills/local/<skill-name>
It checks three things:
- Frontmatter & length —
nameanddescriptionexist; name is hyphen-case and <=64 chars; description has a "use when" trigger phrase, respects the 1024-char hard limit, and SKILL.md is under 500 lines. - Script hygiene — every
scripts/*.shhas a shebang, is executable, and responds to--help(presence of the flag handler, not necessarily a working script). - Reference reachability — every file in
references/is mentioned at least once fromSKILL.md(no dead reference docs).
Fix every error. Warnings are advisory but usually worth addressing.
6. (Optional) Hand off to skill-creator
Once lint passes and the skill looks right, the next questions are
quantitative: does it trigger reliably? does it produce good output? That's
skill-creator territory. Tell the user: "skill-author got the structure
right. If you want to validate it works on real prompts, the skill-creator
skill runs test cases and benchmarks."
Available scripts
scripts/new-skill.sh <name>— Scaffold the canonical skill dir (SKILL.md, references/, scripts/, assets/) and add discovery symlinks for non-universal agents. Auto-detects scope (LOCAL / PROJECT / GLOBAL); see table in step 2.- Scope flags (mutually exclusive):
--local(force this repo'sskills/local/),--project(force<repo>/.agents/skills/),--global(force~/.agents/skills/). - Other flags:
--vendor(LOCAL only —skills/vendor/<name>/instead ofskills/local/; rare, vendored skills normally come viavendor.yaml);--root DIR(override walk-up);--no-symlinks(skip the fan-out);--dry-run;--force(overwrite existing canonical dir + replace symlinks).
- Scope flags (mutually exclusive):
scripts/lint-skill.sh <skill-dir>— Run frontmatter, script hygiene, and reference reachability checks. Exit non-zero on any error.- Flags:
--strict(treat warnings as errors);--quiet(only print failures).
- Flags:
scripts/lint-frontmatter.sh [PATH...]— YAML-parse the frontmatter of everySKILL.mdunder PATH (default.) with a real parser, and check that the root is a mapping with stringname+description. Catches the breakage classlint-skill.sh's awk extractor cannot see — an unquoteddescription:containing": "makesnpx skills(and Claude Code / Cursor) silently skip the skill.lint-skill.shcalls this for the single-skill case; run it directly to sweep a whole collection.- Flags:
--parser auto|yq|python3|node(node= the jsyamlpackage, exactly whatnpx skillsuses);--quiet.
- Flags:
Bundled assets
Templates that new-skill.sh copies and that you can reference manually:
assets/SKILL.md.template— Frontmatter + workflow skeleton with placeholders.assets/reference.md.template— Reference doc skeleton (TOC + sections).assets/script-bash.template— Bash 3.2 compatible script withset -euo pipefail,--help/--dry-runflag handler, structured-output friendly logging (data → stdout, prose → stderr).assets/script-python.template— Python script with PEP 723 inline-deps block, argparse with help/examples, dry-run support.
Reference files
references/authoring-patterns.md— The agentskills.io "best practices" page condensed: gotchas, templates, validation loops, calibrated specificity, defaults-not-menus, procedures-over-declarations, plan-validate-execute.references/script-design.md— The agentskills.io "using scripts" page condensed: agentic CLI design, structured output, error message style, PEP 723, uvx/npx/pipx version pinning, dry-run patterns.references/this-repo-conventions.md— Conventions specific to this repository: where to put local vs vendor skills, how the 5-level skill search works, AGENTS.md ↔ CLAUDE.md sync, where mirrored scripts live.
Gotchas
- AGENTS.md is a symlink to CLAUDE.md — edit either one; never replace the symlink with a real file.
- Skill discovery is one level deep first, then recursive up to 5 levels.
skills/local/<name>/SKILL.mdworks because of the recursive fallback. Don't nest skills more than 5 deep or they become invisible. bash 3.2compatibility is required for any script that might run on stock macOS. Nomapfile, no${var,,}lowercasing, no[[ -v var ]]. Seereferences/script-design.mdfor the safe subset.descriptionis always-on context and has agent-specific hard limits. Put concrete trigger phrases in frontmatter, but keep local skills in the 120-500 char preferred range when possible. Treat >1024 chars as invalid: Codex and Cursor/spec-aligned validators can skip the skill entirely.- Quote any
descriptioncontaining:,#, or leading punctuation. An unquoted YAML plain scalar cannot contain": "—npx skillsfails with "Nested mappings are not allowed in compact mappings" and drops the skill from the picker without a non-zero exit.#is worse: it parses, but YAML treats the rest as a comment and silently truncates your trigger string. Single quotes need no escaping except'itself. Runscripts/lint-frontmatter.shto catch both; seepitfalls/skill-description-colon-breaks-yaml-frontmatter.mdin this repo. - Don't write a skill that wraps something the agent already does well. If a stock Claude session handles the task in one turn without help, a skill adds context-window cost for no gain. Test the no-skill baseline before investing in authoring.
- Scope auto-detect can surprise you.
new-skill.shwalks up looking for a publishing-repo anchor (vendor.yaml/skills/local//skills/.claude-plugin/) first, then a.git. If you ran it from inside a clone of this repo while meaning to add a skill to your other project, it'll silently land inskills/local/. Pass--projector--globalexplicitly when intent isn't obvious, and prefer asking the user system-wide-vs-project-wide before running. - Discovery symlinks must be
../../-relative, not repo-root-relative — POSIX resolves symlink targets relative to the link's own directory. The script enforces this and verifies each link withtest -e <link>/SKILL.md; if you ever hand-create one, seepitfalls/symlink-target-relative-to-symlink-not-cwd.md.
When the user is updating an existing skill (not creating new)
Same workflow, but skip step 2 (scaffold). Read the existing SKILL.md first,
identify which patterns from references/authoring-patterns.md are missing or
weakly applied, and propose edits one section at a time so the user can sanity
check. After edits, run lint, then offer the skill-creator handoff for
quantitative validation.