
Company News
Socket Named Top Sales Organization by RepVue
Socket won two 2026 Reppy Awards from RepVue, ranking in the top 5% of all sales orgs. AE Alexandra Lister shares what it's like to grow a sales career here.
@vibe-agent-toolkit/agent-skills
Advanced tools
Build, validate, and package agent skills in the Agent Skills format
Build, validate, and import Agent Skills for Claude Desktop, Claude Code, and VAT agents.
This package provides runtime support for Agent Skills including:
npm install @vibe-agent-toolkit/agent-skills
import { validateSkill } from '@vibe-agent-toolkit/agent-skills';
const result = await validateSkill({
skillPath: './my-skill/SKILL.md',
});
if (result.status === 'error') {
console.error('Validation failed:');
for (const issue of result.issues) {
console.error(` [${issue.code}] ${issue.message}`);
}
}
import { importSkillToAgent } from '@vibe-agent-toolkit/agent-skills';
const result = await importSkillToAgent({
skillPath: './my-skill/SKILL.md',
outputPath: './my-agent/agent.yaml', // Optional
force: false, // Optional
});
if (result.success) {
console.log(`Imported to: ${result.agentPath}`);
} else {
console.error(`Import failed: ${result.error}`);
}
import { buildAgentSkill } from '@vibe-agent-toolkit/agent-skills';
await buildAgentSkill({
agentPath: './my-agent',
outputPath: './dist/skills/my-agent',
});
Validate an Agent Skill (SKILL.md) for quality and compatibility.
Options:
interface ValidateOptions {
skillPath: string; // Path to SKILL.md
rootDir?: string; // Root directory for resolving links
isVATGenerated?: boolean; // Treat as VAT-generated (stricter validation)
}
Returns:
interface ValidationResult {
path: string; // Path to skill file
type: 'agent-skill' | 'vat-agent'; // Detected type
status: 'success' | 'warning' | 'error';
summary: string; // Human-readable summary
issues: ValidationIssue[]; // All validation issues
metadata?: { // Extracted metadata
name?: string;
description?: string;
lineCount?: number;
};
}
interface ValidationIssue {
severity: 'error' | 'warning' | 'info';
code: IssueCode; // Machine-readable code
message: string; // Human-readable message
location?: string; // File:line location
fix?: string; // Suggested fix
}
Example:
const result = await validateSkill({
skillPath: './my-skill/SKILL.md',
rootDir: './my-skill',
});
console.log(`Status: ${result.status}`);
console.log(`Summary: ${result.summary}`);
// Check for specific error types
const nameErrors = result.issues.filter(
i => i.code === 'SKILL_NAME_INVALID'
);
if (nameErrors.length > 0) {
console.error('Name validation failed');
}
The validator checks for:
Frontmatter Errors:
SKILL_MISSING_FRONTMATTER - No YAML frontmatter foundSKILL_MISSING_NAME - Required "name" field missingSKILL_MISSING_DESCRIPTION - Required "description" field missingSKILL_NAME_INVALID - Name doesn't match pattern: ^[a-z0-9]+(-[a-z0-9]+)*$SKILL_NAME_RESERVED_WORD - Name contains "claude" or "anthropic"SKILL_NAME_XML_TAGS - Name contains < or > charactersSKILL_DESCRIPTION_TOO_LONG - Description exceeds 1024 charactersSKILL_DESCRIPTION_EMPTY - Description is empty or whitespace-onlySKILL_DESCRIPTION_XML_TAGS - Description contains < or > charactersLink Errors:
LINK_INTEGRITY_BROKEN - Link points to non-existent filePATH_STYLE_WINDOWS - Link uses Windows backslashes ()SKILL_TOO_LONG - Skill exceeds 5000 linesCOMPAT_REQUIRES_LOCAL_SHELL - References Write, Edit, Bash, or NotebookEdit tools (see validation-codes.md)COMPAT_REQUIRES_BROWSER_AUTH - Requires a browser login flow (MSAL, cloud SSO, OAuth redirect) (see validation-codes.md)COMPAT_REQUIRES_EXTERNAL_CLI - Invokes an unbundled external CLI (az, aws, gcloud, kubectl, docker, terraform, gh, op) (see validation-codes.md)See Best Practices Guide for detailed guidance.
Convert an Agent Skill (SKILL.md) to VAT agent format (agent.yaml).
Options:
interface ImportOptions {
skillPath: string; // Path to SKILL.md
outputPath?: string; // Custom output path (default: same dir as SKILL.md)
force?: boolean; // Overwrite existing agent.yaml (default: false)
}
Returns:
type ImportResult =
| { success: true; agentPath: string }
| { success: false; error: string };
Example:
// Basic import
const result = await importSkillToAgent({
skillPath: './my-skill/SKILL.md',
});
// Custom output path
const result = await importSkillToAgent({
skillPath: './my-skill/SKILL.md',
outputPath: './agents/my-agent/agent.yaml',
});
// Force overwrite
const result = await importSkillToAgent({
skillPath: './my-skill/SKILL.md',
force: true,
});
if (!result.success) {
console.error(`Import failed: ${result.error}`);
process.exit(1);
}
What Gets Converted:
| SKILL.md Field | agent.yaml Field | Notes |
|---|---|---|
name | metadata.name | Required |
description | metadata.description | Required |
metadata.version | metadata.version | Defaults to "0.1.0" |
metadata.tags | metadata.tags | Optional |
license | metadata.license | Optional |
compatibility | spec.compatibility | Optional |
The generated agent.yaml will have:
metadata:
name: skill-name
description: Skill description
version: 1.0.0
spec:
runtime: agent-skills
Build an Agent Skill from a VAT agent manifest.
Options:
interface BuildOptions {
agentPath: string; // Path to agent directory or manifest
outputPath: string; // Where to write skill bundle
}
Returns:
interface BuildResult {
outputPath: string; // Path to generated SKILL.md
metadata: {
name: string;
description: string;
version: string;
};
}
Example:
const result = await buildAgentSkill({
agentPath: './my-agent',
outputPath: './dist/skills/my-agent',
});
console.log(`Built skill: ${result.outputPath}`);
console.log(`Version: ${result.metadata.version}`);
Strict schema for console-compatible Agent Skills:
import { AgentSkillFrontmatterSchema } from '@vibe-agent-toolkit/agent-skills';
import { z } from 'zod';
const frontmatter = {
name: 'my-skill',
description: 'Does something useful',
compatibility: 'Requires Node.js 18+',
};
const result = AgentSkillFrontmatterSchema.safeParse(frontmatter);
if (result.success) {
// TypeScript type: AgentSkillFrontmatter
const validated = result.data;
}
Required Fields:
name - Skill identifier (lowercase, hyphens, max 64 chars)description - What skill does (max 1024 chars)Optional Fields:
license - License identifiercompatibility - Environment requirements (max 500 chars)metadata - Additional properties (Record<string, string>)allowed-tools - Pre-approved tools (experimental)Extended schema for VAT-generated skills:
import { VATAgentSkillFrontmatterSchema } from '@vibe-agent-toolkit/agent-skills';
const frontmatter = {
name: 'my-skill',
description: 'Does something useful',
metadata: {
version: '1.0.0', // Required for VAT skills
tags: ['utility', 'data'],
},
};
const result = VATAgentSkillFrontmatterSchema.safeParse(frontmatter);
Additional Requirements:
metadata.version - Semantic version (required for VAT)Parse YAML frontmatter from SKILL.md content.
Example:
import { parseFrontmatter } from '@vibe-agent-toolkit/agent-skills';
import * as fs from 'node:fs';
const content = fs.readFileSync('./SKILL.md', 'utf-8');
const result = parseFrontmatter(content);
if (result.success) {
console.log('Frontmatter:', result.frontmatter);
console.log('Body:', result.body);
} else {
console.error('Parse error:', result.error);
}
import {
validateSkill,
importSkillToAgent
} from '@vibe-agent-toolkit/agent-skills';
// Validate first
const validation = await validateSkill({
skillPath: './my-skill/SKILL.md',
});
if (validation.status === 'error') {
console.error('Validation failed, cannot import');
process.exit(1);
}
// Import if validation passes
const importResult = await importSkillToAgent({
skillPath: './my-skill/SKILL.md',
});
if (importResult.success) {
console.log(`Imported to: ${importResult.agentPath}`);
}
import { validateSkill } from '@vibe-agent-toolkit/agent-skills';
import * as fs from 'node:fs/promises';
import * as path from 'node:path';
async function validateAllSkills(dir: string) {
const entries = await fs.readdir(dir, { withFileTypes: true });
const results = [];
for (const entry of entries) {
if (entry.isDirectory()) {
const skillPath = path.join(dir, entry.name, 'SKILL.md');
try {
const result = await validateSkill({ skillPath });
results.push({ skill: entry.name, result });
} catch (error) {
console.error(`Error validating ${entry.name}:`, error);
}
}
}
return results;
}
const results = await validateAllSkills('./skills');
const failed = results.filter(r => r.result.status === 'error');
console.log(`Validated ${results.length} skills`);
console.log(`Failed: ${failed.length}`);
import { validateSkill } from '@vibe-agent-toolkit/agent-skills';
const result = await validateSkill({
skillPath: './my-skill/SKILL.md',
});
// Filter by severity
const errors = result.issues.filter(i => i.severity === 'error');
const warnings = result.issues.filter(i => i.severity === 'warning');
// Group by error code
const byCode = result.issues.reduce((acc, issue) => {
if (!acc[issue.code]) acc[issue.code] = [];
acc[issue.code].push(issue);
return acc;
}, {} as Record<string, typeof result.issues>);
// Check for specific issues
const hasLinkErrors = result.issues.some(
i => i.code === 'LINK_INTEGRITY_BROKEN'
);
if (hasLinkErrors) {
console.error('Fix broken links before proceeding');
}
This package powers these CLI commands:
vat agent audit - Validates skills using validateSkill()vat agent import - Imports skills using importSkillToAgent()See CLI Documentation for command usage.
// ci-validate.ts
import { validateSkill } from '@vibe-agent-toolkit/agent-skills';
import * as fs from 'node:fs/promises';
async function validateInCI() {
const files = await fs.readdir('./skills', { recursive: true });
const skills = files.filter(f => f.endsWith('SKILL.md'));
let hasErrors = false;
for (const skill of skills) {
const result = await validateSkill({
skillPath: `./skills/${skill}`,
});
if (result.status === 'error') {
console.error(`❌ ${skill}:`);
for (const issue of result.issues) {
if (issue.severity === 'error') {
console.error(` ${issue.message}`);
}
}
hasErrors = true;
}
}
if (hasErrors) {
process.exit(1);
}
console.log('✅ All skills validated successfully');
}
validateInCI();
The package exports all types for TypeScript users:
import type {
ValidateOptions,
ValidationResult,
ValidationIssue,
IssueCode,
IssueSeverity,
AgentSkillFrontmatter,
VATAgentSkillFrontmatter,
ImportOptions,
ImportResult,
BuildOptions,
BuildResult,
} from '@vibe-agent-toolkit/agent-skills';
All async functions use standard Promise rejection for errors:
try {
const result = await validateSkill({
skillPath: './invalid-path/SKILL.md',
});
} catch (error) {
if (error instanceof Error) {
console.error(`Validation error: ${error.message}`);
}
}
Validation errors are returned in the ValidationResult object, not thrown:
const result = await validateSkill({ skillPath: './skill/SKILL.md' });
// result.status will be 'error', not thrown
if (result.status === 'error') {
// Handle validation failures
}
Validation is optimized for:
Typical performance:
Memory usage is proportional to skill size:
For large-scale validation, validate in batches to control memory.
The package is fully cross-platform:
node:path for Windows/Unix compatibilityTested on:
@vibe-agent-toolkit/discovery - File discovery for skills@vibe-agent-toolkit/cli - CLI commands using this package@vibe-agent-toolkit/utils - Shared utilitiesThe package includes comprehensive tests:
# Unit tests
bun run test:unit
# Integration tests
bun run test:integration
# Watch mode
bun run test:watch
MIT
FAQs
Build, validate, and package agent skills in the Agent Skills format
We found that @vibe-agent-toolkit/agent-skills demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Company News
Socket won two 2026 Reppy Awards from RepVue, ranking in the top 5% of all sales orgs. AE Alexandra Lister shares what it's like to grow a sales career here.

Security News
NIST will stop enriching most CVEs under a new risk-based model, narrowing the NVD's scope as vulnerability submissions continue to surge.

Company News
/Security News
Socket is an initial recipient of OpenAI's Cybersecurity Grant Program, which commits $10M in API credits to defenders securing open source software.