@jaypie/tildeskill
Prerequisites: npm install @jaypie/tildeskill
Status: Experimental - APIs may change
Overview
Section titled “Overview”@jaypie/tildeskill provides a storage abstraction for skill/vocabulary documents with markdown frontmatter support. It’s used internally by @jaypie/mcp for serving skill documentation to AI assistants.
Installation
Section titled “Installation”npm install @jaypie/tildeskillQuick Reference
Section titled “Quick Reference”Core Exports
Section titled “Core Exports”| Export | Purpose |
|---|---|
createSkillService |
Fabric service factory for skill lookup |
createLayeredStore |
Compose multiple stores with namespace prefixes |
createMarkdownStore |
File-based store (reads .md files) |
createMemoryStore |
In-memory store (for testing) |
expandIncludes |
Expand included skills into content |
isValidAlias |
Check if alias is valid |
validateAlias |
Validate and normalize alias (throws on invalid) |
normalizeAlias |
Normalize alias to lowercase |
| Type | Description |
|---|---|
SkillRecord |
Skill document with alias, content, description, includes, name, nicknames, related, tags |
SkillStore |
Store interface with find, get, getByNickname, list, put, search methods |
ListFilter |
Filter options for list (namespace, tag) |
LayeredStoreLayer |
Layer definition with namespace and store |
LayeredStoreOptions |
Options for createLayeredStore |
Store Factories
Section titled “Store Factories”Markdown Store
Section titled “Markdown Store”Reads skill documents from a directory of markdown files:
import { createMarkdownStore } from "@jaypie/tildeskill";
const store = createMarkdownStore({ path: "./skills" });
// Get a specific skillconst skill = await store.get("aws");if (skill) { console.log(skill.alias); // "aws" console.log(skill.description); // From frontmatter console.log(skill.content); // Markdown body console.log(skill.related); // ["errors", "lambda"]}
// List all skillsconst skills = await store.list();skills.forEach(s => console.log(`${s.alias}: ${s.description}`));Memory Store
Section titled “Memory Store”In-memory store for testing:
import { createMemoryStore } from "@jaypie/tildeskill";
const store = createMemoryStore([ { alias: "test", content: "# Test\n\nContent", description: "Test skill" }, { alias: "another", content: "# Another", related: ["test"] },]);
// Supports all store operationsconst skill = await store.get("test");await store.put({ alias: "new", content: "# New Skill" });Include Expansion
Section titled “Include Expansion”Compose skills by including other skills’ content:
import { expandIncludes, createMemoryStore } from "@jaypie/tildeskill";
const store = createMemoryStore([ { alias: "base", content: "Base content" }, { alias: "main", content: "Main content", includes: ["base"] },]);
const record = await store.get("main");const expanded = await expandIncludes(store, record);// expanded = "Base content\n\nMain content"Features:
- Recursively expands nested includes
- Prevents circular references
- Skips missing includes silently
Filtering and Search
Section titled “Filtering and Search”// Filter by namespace prefixconst kitSkills = await store.list({ namespace: "kit:" });
// Filter by tagconst cloudSkills = await store.list({ tag: "cloud" });
// Combined filtersconst kitCloudSkills = await store.list({ namespace: "kit:", tag: "cloud" });
// Search across alias, name, description, content, and tagsconst results = await store.search("lambda");
// Lookup by nickname (alternate alias)const skill = await store.getByNickname("amazon");Skill File Format
Section titled “Skill File Format”Skill files use YAML frontmatter followed by markdown content:
---description: Brief description shown in skill listingsincludes: base-skill, common-utilsname: Display Titlenicknames: alt-name, another-aliasrelated: alias1, alias2, alias3tags: category1, category2---
# Skill Title
Markdown content with documentation, code examples, etc.Frontmatter Fields
Section titled “Frontmatter Fields”| Field | Type | Description |
|---|---|---|
description |
string |
Brief description for listings |
includes |
string |
Comma-separated list of skills to auto-expand |
name |
string |
Display title for the skill |
nicknames |
string |
Comma-separated alternate lookup keys |
related |
string |
Comma-separated list of related skill aliases |
tags |
string |
Comma-separated categorization tags |
All frontmatter fields accept either comma-separated strings or YAML arrays.
Validation Utilities
Section titled “Validation Utilities”isValidAlias
Section titled “isValidAlias”Check if an alias is valid without throwing:
import { isValidAlias } from "@jaypie/tildeskill";
isValidAlias("my-skill"); // trueisValidAlias("my_skill"); // trueisValidAlias("skill123"); // trueisValidAlias("../../etc"); // false (path traversal)isValidAlias(""); // false (empty)isValidAlias("a".repeat(100)); // false (too long)validateAlias
Section titled “validateAlias”Validate and normalize, throwing BadRequestError on invalid input:
import { validateAlias } from "@jaypie/tildeskill";
validateAlias("Valid"); // returns "valid" (normalized)validateAlias("MY-SKILL"); // returns "my-skill"validateAlias("../bad"); // throws BadRequestErrornormalizeAlias
Section titled “normalizeAlias”Normalize alias to lowercase (does not validate):
import { normalizeAlias } from "@jaypie/tildeskill";
normalizeAlias("MY-Skill"); // "my-skill"normalizeAlias("Test_123"); // "test_123"Testing
Section titled “Testing”With @jaypie/testkit
Section titled “With @jaypie/testkit”import { afterEach, beforeEach, describe, expect, it } from "vitest";import { mockTildeskill, restoreTildeskill } from "@jaypie/testkit";
describe("MyComponent", () => { beforeEach(() => { mockTildeskill(); });
afterEach(() => { restoreTildeskill(); });
it("works with mocked store", async () => { // Your tests here });});Direct Memory Store
Section titled “Direct Memory Store”import { createMemoryStore } from "@jaypie/tildeskill";
const testStore = createMemoryStore([ { alias: "test", content: "# Test", description: "Test skill" },]);
// Inject into your component/serviceconst service = createService({ store: testStore });Error Handling
Section titled “Error Handling”import { validateAlias } from "@jaypie/tildeskill";import { BadRequestError } from "@jaypie/errors";
try { validateAlias("../malicious");} catch (error) { if (error instanceof BadRequestError) { console.log("Invalid alias:", error.message); }}Skill Service Factory
Section titled “Skill Service Factory”createSkillService wraps a SkillStore as a fabricService, compatible with MCP servers and Llm.operate toolkits:
import { createSkillService, createMarkdownStore } from "@jaypie/tildeskill";
const store = createMarkdownStore({ path: "./skills" });const skillService = createSkillService(store);
// Get skill content (with automatic expandIncludes)const content = await skillService({ alias: "aws" });
// List all skillsconst index = await skillService({ alias: "index" });// or: await skillService()
// Use with fabricTool for Llm.operateimport { fabricTool } from "@jaypie/fabric/llm";const { tool } = fabricTool({ service: skillService });Layered Stores
Section titled “Layered Stores”Compose multiple stores with namespace prefixes. Earlier layers win for single-result lookups:
import { createLayeredStore, createMarkdownStore } from "@jaypie/tildeskill";
const layered = createLayeredStore({ layers: [ { namespace: "local", store: createMarkdownStore({ path: "./my-skills" }) }, { namespace: "jaypie", store: createMarkdownStore({ path: "./jaypie-skills" }) }, ],});
await layered.get("aws"); // first layer wins → { alias: "local:aws", ... }await layered.get("jaypie:aws"); // targets specific layerawait layered.find("skills"); // per-layer plural/singular fallbackawait layered.list(); // all layers, prefixed aliasesRelated
Section titled “Related”- @jaypie/mcp - MCP server using tildeskill
- @jaypie/fabric - Service patterns
- @jaypie/testkit - Testing utilities