Skip to content
@jaypie/tildeskill logo

@jaypie/tildeskill

**Prerequisites:** `npm install @jaypie/tildeskill`

finlaysonstudio/jaypie0installs1stars

SKILL.md

Full skill instructions

@jaypie/​tildeskill

Prerequisites: npm install @jaypie/​tildeskill

Status: Experimental - APIs may change

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

npm install @jaypie/​tildeskill

Quick Reference

Core Exports

ExportPurpose
createSkillServiceFabric service factory for skill lookup
createLayeredStoreCompose multiple stores with namespace prefixes
createMarkdownStoreFile-based store (reads .md files)
createMemoryStoreIn-memory store (for testing)
expandIncludesExpand included skills into content
isValidAliasCheck if alias is valid
validateAliasValidate and normalize alias (throws on invalid)
normalizeAliasNormalize alias to lowercase

Types

TypeDescription
SkillRecordSkill document with alias, content, description, includes, name, nicknames, related, tags
SkillStoreStore interface with find, get, getByNickname, list, put, search methods
ListFilterFilter options for list (namespace, tag)
LayeredStoreLayerLayer definition with namespace and store
LayeredStoreOptionsOptions for createLayeredStore

Store Factories

Markdown Store

Reads skill documents from a directory of markdown files:

import { createMarkdownStore } from "@jaypie/​tildeskill";

const store = createMarkdownStore({ path: "./​skills" });

// Get a specific skill
const 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 skills
const skills = await store.list();
skills.forEach(s => console.log(`${s.alias}: ${s.description}`));

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 operations
const skill = await store.get("test");
await store.put({ alias: "new", content: "# New Skill" });

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

// Filter by namespace prefix
const kitSkills = await store.list({ namespace: "kit:" });

// Filter by tag
const cloudSkills = await store.list({ tag: "cloud" });

// Combined filters
const kitCloudSkills = await store.list({ namespace: "kit:", tag: "cloud" });

// Search across alias, name, description, content, and tags
const results = await store.search("lambda");

// Lookup by nickname (alternate alias)
const skill = await store.getByNickname("amazon");

Skill File Format

Skill files use YAML frontmatter followed by markdown content:

---
description: Brief description shown in skill listings
includes: base-skill, common-utils
name: Display Title
nicknames: alt-name, another-alias
related: alias1, alias2, alias3
tags: category1, category2
---

# Skill Title

Markdown content with documentation, code examples, etc.

Frontmatter Fields

FieldTypeDescription
descriptionstringBrief description for listings
includesstringComma-separated list of skills to auto-expand
namestringDisplay title for the skill
nicknamesstringComma-separated alternate lookup keys
relatedstringComma-separated list of related skill aliases
tagsstringComma-separated categorization tags

All frontmatter fields accept either comma-separated strings or YAML arrays.

Validation Utilities

isValidAlias

Check if an alias is valid without throwing:

import { isValidAlias } from "@jaypie/​tildeskill";

isValidAlias("my-skill");     // true
isValidAlias("my_skill");     // true
isValidAlias("skill123");     // true
isValidAlias("../​../​etc");    // false (path traversal)
isValidAlias("");             // false (empty)
isValidAlias("a".repeat(100)); // false (too long)

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 BadRequestError

normalizeAlias

Normalize alias to lowercase (does not validate):

import { normalizeAlias } from "@jaypie/​tildeskill";

normalizeAlias("MY-Skill");   // "my-skill"
normalizeAlias("Test_123");   // "test_123"

Testing

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

import { createMemoryStore } from "@jaypie/​tildeskill";

const testStore = createMemoryStore([
  { alias: "test", content: "# Test", description: "Test skill" },
]);

// Inject into your component/​service
const service = createService({ store: testStore });

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

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 skills
const index = await skillService({ alias: "index" });
// or: await skillService()

// Use with fabricTool for Llm.operate
import { fabricTool } from "@jaypie/​fabric/​llm";
const { tool } = fabricTool({ service: skillService });

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 layer
await layered.find("skills");      // per-layer plural/​singular fallback
await layered.list();              // all layers, prefixed aliases

Related