Skip to main content

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

skillDirs
string[]
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

  1. Iterate directories: Check each configured skill directory
  2. Find SKILL.md files: Look for subdirectories containing SKILL.md
  3. Parse frontmatter: Extract metadata from YAML frontmatter
  4. Match query: Search name, description, and tags (case-insensitive)
  5. Return results: Up to limit matching skills

Field Extraction

FieldSourceFallback
idfrontmatter.nameDirectory name
namefrontmatter.nameDirectory name
descriptionfrontmatter.descriptionEmpty string
tagsfrontmatter.tags (array or comma-separated)Empty array
confidencefrontmatter.confidence0.8
sourceAlways "local"-
metadata.pathAbsolute file path-
metadata.autoGeneratedfrontmatter.auto-generatedfalse

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

Performance Considerations

  • 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:
  1. Using a smaller limit
  2. More specific queries
  3. Organizing skills into subdirectories

Source Code Reference

Implementation: src/core/providers/local-provider.ts:88-170

Build docs developers (and LLMs) love