Local Provider
The Local Provider discovers skills from local filesystem directories, searching ~/.claude/skills/ and other agent-specific skill directories for existing SKILL.md files.
createLocalProvider
Create a local filesystem skill provider.
import { createLocalProvider } from 'auto-skill/core/providers';
const provider = createLocalProvider();
Type Signature
function createLocalProvider(skillDirs?: string[]): SkillProvider
Parameters
List of directories containing skills. Defaults to ["~/.claude/skills"].
Returns
A SkillProvider backed by local filesystem.
interface SkillProvider {
name: string; // "Local Skills"
sourceId: string; // "local"
search(query: string, limit?: number): Promise<SkillSearchResult[]>;
getSkillDetails(skillId: string): Promise<SkillSearchResult | null>;
isAvailable(): boolean;
}
Example Usage
Basic Usage (Default Directory)
import { createLocalProvider } from 'auto-skill/core/providers';
const provider = createLocalProvider();
// Search local skills
const results = await provider.search('testing', 5);
console.log(results);
// [
// {
// id: "vitest-setup",
// name: "Vitest Setup",
// description: "Configure Vitest for TypeScript projects",
// source: "local",
// confidence: 0.8,
// tags: ["testing", "vitest"],
// metadata: {
// path: "/Users/name/.claude/skills/vitest-setup/SKILL.md",
// autoGenerated: false
// }
// }
// ]
// Get specific skill
const skill = await provider.getSkillDetails('vitest-setup');
Custom Directories
import { createLocalProvider } from 'auto-skill/core/providers';
import path from 'node:path';
import os from 'node:os';
const provider = createLocalProvider([
path.join(os.homedir(), '.claude', 'skills'),
path.join(os.homedir(), '.cursor', 'skills'),
'/workspace/project-skills',
]);
const results = await provider.search('typescript');
Multi-Agent Support
import { createLocalProvider } from 'auto-skill/core/providers';
import path from 'node:path';
import os from 'node:os';
const homeDir = os.homedir();
const provider = createLocalProvider([
path.join(homeDir, '.claude', 'skills'),
path.join(homeDir, '.cursor', 'skills'),
path.join(homeDir, '.aider', 'skills'),
path.join(homeDir, '.windsurf', 'skills'),
]);
const allSkills = await provider.search('', 100); // Empty query = all skills
console.log(`Found ${allSkills.length} skills across all agents`);
How It Works
Directory Structure
The local provider expects the following structure:
~/.claude/skills/
├── skill-name-1/
│ └── SKILL.md
├── skill-name-2/
│ └── SKILL.md
└── auto/
├── auto-skill-1/
│ └── SKILL.md
└── auto-skill-2/
└── SKILL.md
SKILL.md Parsing
The provider parses YAML frontmatter from SKILL.md files:
---
name: "My Skill"
description: "Does something useful"
tags:
- typescript
- testing
confidence: 0.9
auto-generated: true
---
# Skill Content
...
Search Algorithm
- Iterate directories: Check each configured skill directory
- Find SKILL.md files: Look for subdirectories containing
SKILL.md
- Parse frontmatter: Extract metadata from YAML frontmatter
- Match query: Search name, description, and tags (case-insensitive)
- Return results: Up to
limit matching skills
| Field | Source | Fallback |
|---|
id | frontmatter.name | Directory name |
name | frontmatter.name | Directory name |
description | frontmatter.description | Empty string |
tags | frontmatter.tags (array or comma-separated) | Empty array |
confidence | frontmatter.confidence | 0.8 |
source | Always "local" | - |
metadata.path | Absolute file path | - |
metadata.autoGenerated | frontmatter.auto-generated | false |
Return Values
SkillSearchResult
interface SkillSearchResult {
id: string; // Skill identifier (from frontmatter or dir name)
name: string; // Skill name
description: string; // Skill description
source: string; // Always "local"
confidence: number; // Confidence score (0.0 - 1.0)
author: string; // Always "" for local skills
tags: string[]; // Skill tags
installCount: number; // Always 0 for local skills
sourceUrl: string; // Always "" for local skills
compatibleAgents: string[]; // Always [] for local skills
metadata: {
path: string; // Absolute path to SKILL.md
autoGenerated: boolean; // True if auto-generated
};
}
Empty Results
The provider returns an empty array if:
- No skill directories exist
- Query matches no skills
- All
SKILL.md files fail to parse
const results = await provider.search('nonexistent');
console.log(results); // []
Provider Methods
search(query, limit?)
Search for skills matching a query.
const results = await provider.search('typescript testing', 5);
Parameters:
query (string): Search keywords (matches name, description, tags)
limit (number): Maximum results (default 10)
Returns: Promise<SkillSearchResult[]>
getSkillDetails(skillId)
Get detailed information about a specific skill.
const skill = await provider.getSkillDetails('vitest-setup');
if (skill) {
console.log(`Found: ${skill.name}`);
console.log(`Path: ${skill.metadata.path}`);
}
Parameters:
skillId (string): The skill identifier (matches directory name or frontmatter name)
Returns: Promise<SkillSearchResult | null>
isAvailable()
Check if the provider is available.
const available = provider.isAvailable();
console.log(available); // Always true for local provider
Returns: boolean (always true)
Error Handling
The local provider handles errors gracefully:
- Missing directories: Skipped silently
- Unreadable directories: Skipped silently
- Invalid SKILL.md: Returns
null, continues to next skill
- Missing frontmatter: Returns
null
- Invalid YAML: Returns
null
// These all continue gracefully
await provider.search('query'); // Skips unparseable skills
await provider.getSkillDetails('missing'); // Returns null
- Synchronous file I/O: Uses
fs.readFileSync for simplicity
- No caching: Reads filesystem on every search
- Linear scan: Checks every subdirectory
- Early termination: Stops after
limit results
For large skill directories (100+ skills), consider:
- Using a smaller
limit
- More specific queries
- Organizing skills into subdirectories
Source Code Reference
Implementation: src/core/providers/local-provider.ts:88-170