Tutorial: Build a Skill End-to-End
Build hello-skill from zero to installed — covering every spec feature and CLI command.
Step 1 — Install the CLI
# Install globally npm install -g @skillscraft/cli # Verify skill --version # 0.9.0
Or use npx: npx @skillscraft/cli validate ...
Step 2 — Scaffold with skill init
# Scaffold a new skill (basic template) skill init hello-skill # Or use a template with scripts skill init hello-skill --template with-scripts
This creates:
hello-skill/
SKILL.md # Frontmatter + body template
With the --template with-scripts flag, it also creates a scripts/ directory with a starter script.
Step 3 — Write the SKILL.md (all frontmatter fields)
Replace the generated SKILL.md with a complete example using every frontmatter field:
# hello-skill/SKILL.md --- name: hello-skill description: > Generate friendly greeting messages in multiple languages. Use when the user asks for a hello message, welcome text, or localized greeting. license: MIT compatibility: Node.js 22+ or any JavaScript runtime metadata: author: your-name version: "1.0" category: utilities tags: greeting localization i18n allowed-tools: Bash Read --- # Hello Skill ## When to use this skill Activate when the user wants to: - Generate a greeting message in a specific language - Create welcome text for an application or document - Translate "hello" into multiple languages ## Instructions 1. Ask the user which language they need (or default to English) 2. Run the greeting script: ``` node scripts/greet.js --lang <language-code> ``` 3. If the language is not supported, check `references/LANGUAGES.md` for the full list and suggest the closest match 4. For custom templates, use the assets in `assets/templates/` ## Output format The script outputs JSON: ```json { "language": "es", "greeting": "Hola, mundo!", "formal": "Buenos dias, estimado usuario." } ``` ## Gotchas - Language codes follow ISO 639-1 (e.g., "en", "es", "ja", "de") - The script defaults to English if an unknown code is passed - Formal greetings are only available for: en, es, fr, de, ja - Keep messages under 200 characters for chat compatibility - See `references/LANGUAGES.md` for the complete supported list
Frontmatter field reference
| Field | Required | Max Length | Used Above |
|---|---|---|---|
name | Yes | 64 chars | hello-skill |
description | Yes | 1024 chars | Multi-line with > (folded scalar) |
license | No | - | MIT |
compatibility | No | 500 chars | Node.js 22+... |
metadata | No | - | author, version, category, tags |
allowed-tools | No | - | Bash Read |
^[a-z0-9]([a-z0-9-]*[a-z0-9])?$. The name must match the directory name.
Step 4 — Add scripts/
Scripts are executable files that agents can run. Create hello-skill/scripts/greet.js:
#!/usr/bin/env node // hello-skill/scripts/greet.js const { parseArgs } = require("node:util"); const GREETINGS = { en: { greeting: "Hello, world!", formal: "Good day, dear user." }, es: { greeting: "Hola, mundo!", formal: "Buenos dias, estimado usuario." }, fr: { greeting: "Bonjour, le monde!", formal: "Bonjour, cher utilisateur." }, de: { greeting: "Hallo, Welt!", formal: "Guten Tag, sehr geehrter Benutzer." }, ja: { greeting: "こんにちは世界!", formal: "こんにちは、ユーザー様。" }, }; const { values } = parseArgs({ options: { lang: { type: "string", default: "en" } }, }); const lang = values.lang; const data = GREETINGS[lang] || GREETINGS.en; console.log(JSON.stringify({ language: lang, greeting: data.greeting, formal: data.formal || null, }, null, 2));
Test it directly:
node hello-skill/scripts/greet.js --lang es
# { "language": "es", "greeting": "Hola, mundo!", "formal": "Buenos dias..." }
Step 5 — Add references/
Reference docs give agents extra context. Create hello-skill/references/LANGUAGES.md:
# hello-skill/references/LANGUAGES.md
# Supported Languages
| Code | Language | Formal Support |
|------|------------|----------------|
| en | English | Yes |
| es | Spanish | Yes |
| fr | French | Yes |
| de | German | Yes |
| ja | Japanese | Yes |
| zh | Chinese | No |
| ko | Korean | No |
| pt | Portuguese | No |
| ar | Arabic | No |
| hi | Hindi | No |
## Adding a new language
1. Add the ISO 639-1 code and greeting to `scripts/greet.js`
2. Update this table
3. Run `skill validate` to verify
Step 6 — Add assets/
Assets hold static files agents can use. Create hello-skill/assets/templates/welcome.txt:
# hello-skill/assets/templates/welcome.txt
Welcome to {{APP_NAME}}!
We are glad to have you here. If you need help,
just ask and our assistant will guide you through.
Best regards,
The {{APP_NAME}} Team
Agents can read this template and substitute {{APP_NAME}} with the project name.
Step 7 — Add tests/
Test scenarios validate the skill works correctly. Create hello-skill/tests/scenarios.json:
// hello-skill/tests/scenarios.json [ { "name": "english-greeting", "input": "Say hello in English", "expectedOutput": "Hello, world!", "tags": ["smoke", "en"] }, { "name": "spanish-greeting", "input": "Greet me in Spanish", "expectedOutput": "Hola, mundo!", "tags": ["smoke", "es"] }, { "name": "unknown-language-fallback", "input": "Say hello in Klingon", "expectedOutput": "Hello, world!", "tags": ["edge-case"] }, { "name": "formal-greeting", "input": "Give me a formal German greeting", "expectedOutput": "Guten Tag, sehr geehrter Benutzer.", "tags": ["formal", "de"] } ]
These follow the TestScenario interface from the extended spec.
Step 8 — Validate with skill validate
Check your skill against the spec:
# Validate the skill
skill validate hello-skill/SKILL.md
Expected output if everything is correct:
✓ Skill "hello-skill" is valid.
Checked:
✓ name is present and within 1-64 characters
✓ name matches regex ^[a-z0-9]([a-z0-9-]*[a-z0-9])?$
✓ name matches directory name
✓ description is present and within 1-1024 characters
✓ compatibility is within 500 characters
✓ frontmatter contains no unknown fields
✓ YAML frontmatter is valid
If there are errors:
✗ Skill has validation errors:
- [error] Name "Hello-Skill" does not match pattern ^[a-z0-9]...
- [error] Description exceeds maximum length of 1024 characters
Fix all errors before proceeding. Use --strict to also fail on warnings.
Step 9 — Lint with skill lint
Check best practices beyond spec compliance:
# Lint for best practices skill lint hello-skill/SKILL.md # With fix suggestions skill lint hello-skill/SKILL.md --fix
Expected output for our skill:
✓ Lint passed — 0 issues found.
Rules checked:
✓ description-quality Description starts with action verb or "Use when"
✓ gotchas-section Body contains a "Gotchas" section
✓ body-length Body is under 500 lines
✓ frontmatter-completeness Has license, compatibility, and metadata
✓ allowed-tools-declared allowed-tools field is present
✓ description-length Description is concise (<200 chars recommended)
✓ name-matches-directory name matches parent directory name
The linter has 7 rules covering description quality, body length, completeness, and naming.
Step 10 — Install with skill install
Install the skill for a specific agent:
# Install for Claude Code skill install hello-skill --target claude # Installed "hello-skill" for claude (project scope) # Source: /path/to/hello-skill # Target: .claude/skills/hello-skill # Install for GitHub Copilot skill install hello-skill --target copilot # Target: .github/skills/hello-skill # Install for OpenAI Codex skill install hello-skill --target codex # Target: .codex/skills/hello-skill # Install generically (works with any agent) skill install hello-skill --target generic # Target: .agents/skills/hello-skill # Install to user scope (global) skill install hello-skill --target claude --scope user # Target: ~/.claude/skills/hello-skill # Force overwrite existing installation skill install hello-skill --target claude --force
Target paths
| Target | Project Scope | User Scope |
|---|---|---|
claude | .claude/skills/<name>/ | ~/.claude/skills/<name>/ |
copilot | .github/skills/<name>/ | Not supported |
codex | .codex/skills/<name>/ | Not supported |
generic | .agents/skills/<name>/ | ~/.agents/skills/<name>/ |
Step 11 — List installed skills
# List all installed skills skill list # Filter by target skill list --target claude # Filter by scope skill list --target generic --scope user
Example output:
claude (project): Path: .claude/skills - hello-skill - Generate friendly greeting messages in multiple languages. generic (project): Path: .agents/skills - hello-skill - Generate friendly greeting messages in multiple languages. 2 skill(s) found.
Step 12 — Publish with skill publish
# Preview what would be published skill publish hello-skill --dry-run # Output: # Validating skill... # ✓ Validation passed # ✓ Lint clean # # Package contents (6 files, 3.2 KB): # SKILL.md (1.1 KB) # scripts/greet.js (0.8 KB) # references/LANGUAGES.md (0.5 KB) # assets/templates/welcome.txt (0.2 KB) # tests/scenarios.json (0.6 KB) # # [dry-run] Would publish skill: hello-skill # Package for real skill publish hello-skill --out-dir ./dist # Then publish to npm: # cd dist/hello-skill && npm publish --access public
Step 13 — Use it programmatically
The framework is also a TypeScript SDK:
// Using @skillscraft/core in your own tooling import { parseSkill, validateSkill, lintSkill } from "@skillscraft/core"; // Parse a SKILL.md file const skill = await parseSkill("hello-skill/SKILL.md"); console.log(skill.frontmatter.name); // "hello-skill" console.log(skill.frontmatter.description); // "Generate friendly..." console.log(skill.frontmatter.license); // "MIT" console.log(skill.frontmatter.metadata); // { author: "your-name", ... } // Validate against the spec const result = validateSkill(skill); console.log(result.valid); // true console.log(result.errors); // [] // Lint for best practices const lint = lintSkill(skill); console.log(lint.passed); // true console.log(lint.diagnostics); // []
// Using @skillscraft/spec for types and constants import type { SkillFrontmatter, ParsedSkill } from "@skillscraft/spec"; import { SKILL_NAME_REGEX, SPEC_LIMITS } from "@skillscraft/spec"; console.log(SPEC_LIMITS.NAME_MAX_LENGTH); // 64 console.log(SPEC_LIMITS.DESCRIPTION_MAX_LENGTH); // 1024 console.log(SKILL_NAME_REGEX.test("hello-skill")); // true console.log(SKILL_NAME_REGEX.test("Hello-Skill")); // false
Final directory structure
hello-skill/ SKILL.md # Required — frontmatter + instructions scripts/ greet.js # Executable script (Node.js) references/ LANGUAGES.md # Reference doc for agents assets/ templates/ welcome.txt # Static template file tests/ scenarios.json # Test scenarios (extended spec)
CLI commands recap
| Command | Purpose |
|---|---|
skill init <name> | Scaffold a new skill |
skill validate <path> | Validate against the spec |
skill lint <path> | Check best practices |
skill install <path> | Install for an agent |
skill list | List installed skills |
skill publish <path> | Package for distribution |