SDK Tutorial
Use @skillscraft/core and @skillscraft/spec programmatically in your own tools, CI pipelines, and editors.
1. Install the SDK
The framework ships as two npm packages. Install both for full type safety and runtime functionality.
# Runtime: parser, validator, linter, manifest loader
npm install @skillscraft/core
# Types, JSON schemas, and spec constants
npm install @skillscraft/spec
Both packages are pure ESM and support Node 18+. They have zero runtime dependencies.
@skillscraft/spec ships its own .d.ts files. No separate @types/ package is needed.
2. Parse a SKILL.md
parseSkill() reads a SKILL.md file and returns its YAML frontmatter as a typed object alongside the Markdown body.
import { parseSkill } from "@skillscraft/core";
// Parse from a file path
const parsed = await parseSkill("./my-skill/SKILL.md");
console.log(parsed.frontmatter.name); // "my-skill"
console.log(parsed.frontmatter.description); // "Review PRs for..."
console.log(parsed.body); // Markdown body string
The returned ParsedSkill object contains:
| Property | Type | Description |
|---|---|---|
frontmatter | SkillFrontmatter | Parsed YAML fields: name, description, license, metadata, etc. |
body | string | Everything after the closing --- delimiter. |
raw | string | The original file content, unchanged. |
3. Validate
validateSkill() checks a parsed skill against the Agent Skills specification. It returns a structured result with pass/fail status and any errors.
import { parseSkill, validateSkill } from "@skillscraft/core";
const parsed = await parseSkill("./my-skill/SKILL.md");
const result = validateSkill(parsed);
if (result.valid) {
console.log("Skill passes all spec checks");
} else {
result.errors.forEach(err => {
console.error(`[${err.field}] ${err.message}`);
});
}
Each error in the errors array has:
| Property | Type | Example |
|---|---|---|
field | string | "name", "description" |
message | string | "name exceeds 64 characters" |
severity | "error" | Always "error" for validation. |
4. Lint
lintSkill() goes beyond spec compliance. It checks context budgets, description quality, generic instructions, progressive disclosure, and more.
import { parseSkill, lintSkill } from "@skillscraft/core";
const parsed = await parseSkill("./my-skill/SKILL.md");
const lint = lintSkill(parsed);
lint.diagnostics.forEach(d => {
console.log(`[${d.severity}] ${d.rule}: ${d.message}`);
});
// Example output:
// [warn] context-budget: ~6200 tokens (max 5000). Move content to references/.
// [warn] description-quality: add "Use when..." trigger clause
// [info] gotchas-present: consider adding a "## Gotchas" section
Each diagnostic in the diagnostics array has:
| Property | Type | Description |
|---|---|---|
rule | string | Rule identifier, e.g. "context-budget" |
severity | "error" | "warn" | "info" | Severity level |
message | string | Human-readable explanation |
line | number | undefined | Line number, when applicable |
5. Load a Manifest
loadSkillManifest() reads an entire skill directory and returns the parsed skill plus a list of all bundled files (scripts, references, templates).
import { loadSkillManifest } from "@skillscraft/core";
const manifest = await loadSkillManifest("./my-skill");
console.log(manifest.skill.frontmatter.name); // "my-skill"
console.log(manifest.files);
// [
// "SKILL.md",
// "scripts/setup.sh",
// "references/api-patterns.md",
// "templates/component.tsx"
// ]
The manifest respects .skillignore patterns automatically, excluding files like node_modules/ or .git/ from the file list.
6. Use .skillignore
The .skillignore file uses gitignore syntax to exclude files from the skill manifest. Two functions help you work with it programmatically.
import { loadSkillIgnore, filterFiles } from "@skillscraft/core";
// Load ignore patterns from a skill directory
const patterns = await loadSkillIgnore("./my-skill");
// ["node_modules/", ".git/", "*.log", "dist/"]
// Filter a file list against the patterns
const allFiles = [
"SKILL.md",
"scripts/setup.sh",
"node_modules/foo/index.js",
"debug.log"
];
const included = filterFiles(allFiles, patterns);
// ["SKILL.md", "scripts/setup.sh"]
If no .skillignore file exists, loadSkillIgnore() returns sensible defaults (node_modules/, .git/, .DS_Store).
7. Use Types
Import TypeScript interfaces from @skillscraft/spec for full type safety in your tooling.
import type {
SkillFrontmatter,
ParsedSkill,
ValidationResult,
LintResult,
LintDiagnostic,
SkillManifest
} from "@skillscraft/spec";
// SkillFrontmatter — the YAML header fields
const fm: SkillFrontmatter = {
name: "code-review",
description: "Review PRs. Use when the user submits a pull request.",
license: "MIT",
metadata: { author: "acme-corp", version: "1.0" }
};
// ParsedSkill — output of parseSkill()
const skill: ParsedSkill = {
frontmatter: fm,
body: "# Code Review\n\n## Instructions\n...",
raw: "---\nname: code-review\n---\n# Code Review..."
};
// ValidationResult — output of validateSkill()
const vr: ValidationResult = {
valid: true,
errors: []
};
// LintResult — output of lintSkill()
const lr: LintResult = {
diagnostics: []
};
8. Use Constants
Spec constants are exported so you can reuse them in your own validation logic without hardcoding values.
import { SKILL_NAME_REGEX, SPEC_LIMITS } from "@skillscraft/spec";
// SKILL_NAME_REGEX — validates the `name` field
// Lowercase alphanumeric + hyphens, 2-64 chars, no leading/trailing hyphens
console.log(SKILL_NAME_REGEX.test("code-review")); // true
console.log(SKILL_NAME_REGEX.test("Code Review")); // false
console.log(SKILL_NAME_REGEX.test("-bad-name-")); // false
// SPEC_LIMITS — numeric limits from the spec
console.log(SPEC_LIMITS.nameMaxLength); // 64
console.log(SPEC_LIMITS.descriptionMaxLength); // 1024
console.log(SPEC_LIMITS.bodyMaxTokens); // 5000
console.log(SPEC_LIMITS.bodyMaxLines); // 500
9. Use JSON Schema
A JSON Schema for skill frontmatter is bundled in @skillscraft/spec. Use it with any JSON Schema validator (Ajv, Zod, etc.) for your own tooling.
import Ajv from "ajv";
import skillSchema from "@skillscraft/spec/schemas/skill.schema.json" with { type: "json" };
const ajv = new Ajv();
const validate = ajv.compile(skillSchema);
const frontmatter = {
name: "code-review",
description: "Review PRs. Use when the user submits a PR."
};
if (validate(frontmatter)) {
console.log("Valid frontmatter");
} else {
console.log(validate.errors);
}
The schema file lives at node_modules/@skillscraft/spec/schemas/skill.schema.json and can also be referenced by URL in editor configurations for YAML autocompletion.
10. Build a Custom Validator
Combine parse, validate, and lint into a single pipeline for CI or editor integrations.
import { parseSkill, validateSkill, lintSkill } from "@skillscraft/core";
import type { ValidationResult, LintResult } from "@skillscraft/spec";
interface PipelineResult {
valid: boolean;
validation: ValidationResult;
lint: LintResult;
}
async function checkSkill(path: string): Promise<PipelineResult> {
// 1. Parse
const parsed = await parseSkill(path);
// 2. Validate against spec
const validation = validateSkill(parsed);
// 3. Lint for best practices
const lint = lintSkill(parsed);
// Fail if any validation errors or lint errors (not warnings)
const hasLintErrors = lint.diagnostics.some(d => d.severity === "error");
return {
valid: validation.valid && !hasLintErrors,
validation,
lint
};
}
// Usage in CI
const result = await checkSkill("./my-skill/SKILL.md");
if (!result.valid) {
console.error("Skill check failed:");
result.validation.errors.forEach(e =>
console.error(` [spec] ${e.field}: ${e.message}`)
);
result.lint.diagnostics
.filter(d => d.severity === "error")
.forEach(d =>
console.error(` [lint] ${d.rule}: ${d.message}`)
);
process.exit(1);
}
console.log("All checks passed");
skill validate && skill lint --error-on warn.
11. CLI Usage Recap
The @skillscraft/cli package wraps the SDK into convenient terminal commands. Here are all seven commands.
skill init
Scaffold a new skill from a template.
# Basic skill
skill init my-skill
# With scripts directory
skill init my-skill --template with-scripts
# With references directory
skill init my-skill --template with-references
skill validate
Validate a skill against the Agent Skills specification.
# Validate a specific skill directory
skill validate ./my-skill
# Validate from within the skill directory
cd my-skill && skill validate
skill lint
Lint a skill for best practices.
# Lint with default rules
skill lint ./my-skill
# Auto-fix what can be fixed
skill lint ./my-skill --fix
# Fail on warnings (useful in CI)
skill lint ./my-skill --error-on warn
skill check
Run both validate and lint in one command.
# Full check: validate + lint
skill check ./my-skill
skill manifest
Print the skill manifest (parsed frontmatter + file list).
# JSON output
skill manifest ./my-skill
# Pretty-printed
skill manifest ./my-skill --pretty
skill pack
Bundle a skill directory into a distributable archive.
# Create a .tar.gz archive
skill pack ./my-skill
# Output to a specific path
skill pack ./my-skill -o ./dist/my-skill.tar.gz
skill info
Display summary information about a skill.
# Show skill info
skill info ./my-skill
# Example output:
# name: code-review
# description: Review PRs for security and style issues.
# license: MIT
# files: 4
# body tokens: ~1,200