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.
🔵 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:
- Trigger — User types
/my-skillin the REPL or the model decides to invoke a registered skill. - Registry Lookup —
SkillRegistrysearches all three sources (user, bundled, MCP) for a matching skill name. - Directory Scan — For user skills,
loadSkillsDir.tsreads.claude/skills/and parses the skill definition YAML/markdown. - Validation — The skill schema is validated: required fields (name, prompt), optional fields (description, parameters).
- Template Parsing — The skill prompt template is loaded, with placeholder tokens identified for variable injection.
- Context Injection — Runtime context (current file, selection, project root) is injected into the prompt template.
- Prompt Assembly — The finalized skill prompt is appended to the conversation as a system-level message.
- Model Execution — The AI model receives the enriched prompt and executes the skill instructions.
- Result Capture — Output from the skill execution is captured and displayed to the user in the REPL.
Key Classes & Functions
| Name | File | Description |
|---|---|---|
loadSkillsDir | loadSkillsDir.ts | Scans .claude/skills/ directory tree, parses skill definitions, returns skill objects |
bundledSkills | bundledSkills.ts | Static map of built-in skills shipped with Claude Code (e.g., /quick-diff) |
mcpSkillBuilders | mcpSkillBuilders.ts | Factory functions that create skill objects from MCP server capabilities |
SkillRegistry | registry.ts | Central registry aggregating all skill sources, provides lookup by name |
SkillResolver | resolver.ts | Resolves a skill name to a concrete skill object with loaded prompt template |
SkillExecutor | executor.ts | Executes a resolved skill by injecting context and appending to conversation |
parseSkillDef | parser.ts | Parses YAML/markdown skill definition files into structured skill objects |
validateSkillSchema | schema.ts | Validates skill definitions against the expected schema, returns errors |
injectContext | context.ts | Replaces template placeholders with runtime context (file path, selection, etc.) |
SkillDefinition | types.ts | TypeScript interface defining the shape of a skill (name, prompt, params) |
listAvailableSkills | list.ts | Aggregates and returns all available skills from every source for display |
getSkillPrompt | prompt.ts | Reads and returns the raw prompt template string for a given skill |
Configuration
| Setting | Default | Description |
|---|---|---|
skillsDir | .claude/skills/ | Directory to scan for user-defined skill files |
enableBundledSkills | true | Whether to load built-in bundled skills |
enableMcpSkills | true | Whether to load skills from MCP servers |
skillFileExtensions | [".md", ".yaml"] | File extensions recognized as skill definitions |
maxSkillPromptLength | 8192 | Maximum character length for a skill prompt template |
skillTimeout | 30000 | Timeout 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);
}