skills — Custom Skill & Macro System

Custom Skill & Macro System

Extensible command system enabling user-defined skills from .claude/skills/ directories, bundled skills like /quick-diff, and MCP skill builders. Skills are prompt-based commands that the model can invoke to extend its capabilities.

20
Files
~4k
Lines of Code
3
Skill Sources
TS
Language

🔵 User Skills 🟢 Bundled Skills 🟡 MCP Integration 🔴 Prompt-Based

💡 What is this?

The skills module is the extensibility backbone of Claude Code. It allows users and the system to register prompt-based commands that the AI model can discover and invoke at runtime, turning the CLI into a fully extensible platform.

🧩 Analogy: Think of it like browser extensions

Just as browser extensions add new capabilities to a browser without modifying its core, skills add new prompt-based commands to Claude Code. User skills are like personal extensions installed from local files, bundled skills are like pre-installed extensions that ship with the browser, and MCP skills are like extensions fetched from a remote marketplace.

Architecture

flowchart LR
  subgraph Sources["Skill Sources"]
    US["User Skills
.claude/skills/"] BS["Bundled Skills
bundledSkills.ts"] MCP["MCP Skills
mcpSkillBuilders.ts"] end subgraph Loader["Skill Loader"] LD["loadSkillsDir.ts"] REG["SkillRegistry"] VAL["Validation & Schema"] end subgraph Runtime["Runtime"] RES["Skill Resolver"] EXE["Skill Executor"] CTX["Prompt Context"] end US --> LD BS --> REG MCP --> REG LD --> REG REG --> RES RES --> EXE EXE --> CTX

Data Flow

flowchart TD
  A["User types /skill-name
or model invokes skill"] --> B["SkillRegistry.lookup()"] B --> C{"Source?"} C -->|User| D["Load from .claude/skills/"] C -->|Bundled| E["Load from bundledSkills map"] C -->|MCP| F["Fetch from MCP server"] D --> G["Parse skill prompt template"] E --> G F --> G G --> H["Inject context variables"] H --> I["Append to conversation
as system prompt"] I --> J["Model executes
skill instructions"]

🚶 Step-by-Step Narrated Walkthrough

Follow a single user skill invocation as it flows through the skills pipeline:

  1. Trigger — User types /my-skill in the REPL or the model decides to invoke a registered skill.
  2. Registry Lookup — SkillRegistry searches all three sources (user, bundled, MCP) for a matching skill name.
  3. Directory Scan — For user skills, loadSkillsDir.ts reads .claude/skills/ and parses the skill definition YAML/markdown.
  4. Validation — The skill schema is validated: required fields (name, prompt), optional fields (description, parameters).
  5. Template Parsing — The skill prompt template is loaded, with placeholder tokens identified for variable injection.
  6. Context Injection — Runtime context (current file, selection, project root) is injected into the prompt template.
  7. Prompt Assembly — The finalized skill prompt is appended to the conversation as a system-level message.
  8. Model Execution — The AI model receives the enriched prompt and executes the skill instructions.
  9. Result Capture — Output from the skill execution is captured and displayed to the user in the REPL.

Key Classes & Functions

NameFileDescription
loadSkillsDirloadSkillsDir.tsScans .claude/skills/ directory tree, parses skill definitions, returns skill objects
bundledSkillsbundledSkills.tsStatic map of built-in skills shipped with Claude Code (e.g., /quick-diff)
mcpSkillBuildersmcpSkillBuilders.tsFactory functions that create skill objects from MCP server capabilities
SkillRegistryregistry.tsCentral registry aggregating all skill sources, provides lookup by name
SkillResolverresolver.tsResolves a skill name to a concrete skill object with loaded prompt template
SkillExecutorexecutor.tsExecutes a resolved skill by injecting context and appending to conversation
parseSkillDefparser.tsParses YAML/markdown skill definition files into structured skill objects
validateSkillSchemaschema.tsValidates skill definitions against the expected schema, returns errors
injectContextcontext.tsReplaces template placeholders with runtime context (file path, selection, etc.)
SkillDefinitiontypes.tsTypeScript interface defining the shape of a skill (name, prompt, params)
listAvailableSkillslist.tsAggregates and returns all available skills from every source for display
getSkillPromptprompt.tsReads and returns the raw prompt template string for a given skill

Configuration

SettingDefaultDescription
skillsDir.claude/skills/Directory to scan for user-defined skill files
enableBundledSkillstrueWhether to load built-in bundled skills
enableMcpSkillstrueWhether to load skills from MCP servers
skillFileExtensions[".md", ".yaml"]File extensions recognized as skill definitions
maxSkillPromptLength8192Maximum character length for a skill prompt template
skillTimeout30000Timeout in ms for MCP skill fetch operations

Directory Map

Source tree for skills
skills/
├── loadSkillsDir.ts           ← Scans user skill directories
├── bundledSkills.ts           ← Built-in skill definitions
├── mcpSkillBuilders.ts        ← MCP skill factory functions
├── registry.ts                ← Central skill registry
├── resolver.ts                ← Resolves skill name → skill object
├── executor.ts                ← Executes skills with context
├── parser.ts                  ← Parses skill definition files
├── schema.ts                  ← Schema validation for skills
├── context.ts                 ← Runtime context injection
├── types.ts                   ← TypeScript type definitions
├── list.ts                    ← Lists all available skills
├── prompt.ts                  ← Reads skill prompt templates
├── index.ts                   ← Public API barrel export
├── __tests__/
│   ├── loadSkillsDir.test.ts  ← Tests for directory scanning
│   ├── registry.test.ts       ← Tests for skill registry
│   ├── parser.test.ts         ← Tests for definition parsing
│   ├── executor.test.ts       ← Tests for skill execution
│   └── schema.test.ts         ← Tests for schema validation
└── fixtures/
    └── sample-skill.md        ← Test fixture skill file

Code Example

import { SkillRegistry } from "./registry";
import { loadSkillsDir } from "./loadSkillsDir";
import { bundledSkills } from "./bundledSkills";
import { mcpSkillBuilders } from "./mcpSkillBuilders";

// Initialize registry with all skill sources
const registry = new SkillRegistry();
registry.registerAll(bundledSkills);
registry.registerAll(await loadSkillsDir(".claude/skills/"));
registry.registerAll(await mcpSkillBuilders.build(mcpServers));

// Resolve and execute a skill
const skill = registry.lookup("quick-diff");
if (skill) {
  const prompt = skill.resolve({ filePath: "src/index.ts" });
  await executor.run(prompt, conversationContext);
}