npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

skill-tree

v0.2.0

Published

Library for managing agent skill versions and evolution - extract, iterate, and adapt skills from agent trajectories

Downloads

356

Readme

skill-tree

A TypeScript library for managing agent skill versions and evolution. Store, version, serve, sync, and federate reusable skills for AI agents.

Metrics ownership (as of 0.2.0)

skill-tree does not track per-skill usage metrics. The Skill shape no longer carries metrics — historical fields like usageCount, successRate, lastUsed, feedbackScores lived on it but were never updated by any code path in skill-tree, and the snapshots that consumers wrote at publish time drifted from the live data.

Live usage tracking belongs to systems that observe agents running:

  • cognitive-core (playbook.evolution.successCount / failureCount, playbook.confidence) is the canonical home. recordSuccess and recordFailure mutate it on every trajectory.

If you need ranked loadouts driven by live metrics, query that system first, then pass the resulting skill IDs to skill-tree's loadout compile via include: [...]. As of 0.2, include is a presence guarantee — every ID listed is in the result regardless of other filters, in the order specified. Combine with maxSkills: include.length for "exactly these N skills" semantics.

skill-tree's LoadoutCriteria no longer supports minSuccessRate or priorityOrder: 'usage' | 'successRate' | 'recent' — the only recognized priorityOrder value is 'relevance', currently a no-op pending semantic ranking.

See CHANGELOG.md for the full migration guide.

Overview

skill-tree helps you build and maintain a library of reusable skills for AI agents by:

  • Storing skills in a versioned, searchable format (OpenSkills-compatible)
  • Evolving skills through versioning, forking, and merging
  • Serving skills via dynamic loadouts with expand/collapse, profiles, and token budgeting
  • Materializing skills to agent-discoverable paths (.claude/skills/, .agent/skills/) with auto-generated AGENTS.md
  • Syncing skills across agents with git-based multi-agent collaboration
  • Federating skills across repositories for cross-organization sharing

Inspired by research on skill libraries (arXiv:2512.17102), Claudeception, and OpenSkills.

Installation

npm install skill-tree

Quick Start

import { createSkillBank, type Skill } from 'skill-tree';

// Create a skill bank with filesystem storage
const bank = createSkillBank({
  storage: { basePath: './skills' },
});

await bank.initialize();

// Save a skill
await bank.saveSkill({
  id: 'typescript-esm-import-fix',
  name: 'TypeScript ESM Import Fix',
  version: '1.0.0',
  description: 'Fix TypeScript ES module import errors',
  instructions: 'Add .js extension to all relative imports, even for .ts files.\n\nRun `tsc --noEmit` to verify no import errors.',
  author: 'me',
  tags: ['typescript', 'esm'],
  createdAt: new Date(),
  updatedAt: new Date(),
  status: 'active',
} as Skill);

// Search for skills
const skills = await bank.searchSkills('typescript');

// Create a new version
const updated = await bank.createVersion('typescript-esm-import-fix', {
  solution: 'Add .js extension, or use "moduleResolution": "bundler".',
}, { bumpType: 'minor' });

await bank.shutdown();

Core Concepts

Skills

A skill represents a reusable piece of knowledge:

interface Skill {
  id: string;                    // Unique identifier (kebab-case)
  name: string;                  // Human-readable name
  version: string;               // Semantic version
  description: string;           // Short summary for discovery and matching
  instructions: string;          // Free-form markdown body (the SKILL.md content)
  tags: string[];                // Categorization
  status: SkillStatus;           // 'draft' | 'active' | 'deprecated' | 'experimental'
  // ... namespace, taxonomy, lineage, serving metadata
}

Storage

Two backends:

// Filesystem (JSON source of truth + SQLite cache)
const bank = createSkillBank({
  storage: { basePath: './skills' },
});

// Memory (for testing)
const bank = createSkillBank({
  storage: { type: 'memory' },
});

Skills are stored in the OpenSkills format:

skills/
├── my-skill/
│   ├── SKILL.md           # Skill content (YAML + Markdown)
│   └── .skilltree.json    # Metadata and lineage
└── .versions/
    └── my-skill/
        ├── 1.0.0.json     # Version snapshots
        └── 1.1.0.json

Features

Versioning

Semantic versioning with full lineage tracking:

// Create new version
const v2 = await bank.createVersion('my-skill', updates, {
  bumpType: 'minor',
  changelog: 'Added alternative solution',
});

// Get version history
const history = await bank.getVersionHistory('my-skill');

// Rollback to previous version
const restored = await bank.rollbackSkill('my-skill', '1.0.0');

// Compare versions
const diff = await bank.compareVersions('my-skill', '1.0.0', '2.0.0');

// Fork for a specialized use case
const forked = await bank.forkSkill('my-skill', {
  newId: 'my-skill-react',
  newName: 'My Skill (React variant)',
  reason: 'Specialized for React projects',
});

Serving Layer

Dynamic skill loadouts for agent context windows:

const { server } = await bank.createServingLayer({
  maxExpanded: 5,
});

// Orchestrator sets loadout based on task
await server.setLoadoutForTask('Fix authentication bug');

// Or use a built-in profile
await server.setLoadoutFromProfile('debugging');

// Render skills into system prompt
const prompt = server.renderSystemPrompt();

// Agent-side API
const view = server.agentListLoadout();
const skill = server.agentExpandSkill('some-skill-id');
server.agentCollapseSkill('some-skill-id');
await server.agentRequestSkills(['another-skill']);

Multi-Agent Sync

Git-based skill synchronization:

import { createDefaultSyncConfig } from 'skill-tree';

const bank = createSkillBank({
  storage: { basePath: './skills' },
  sync: {
    config: createDefaultSyncConfig({
      repoUrl: '[email protected]:org/skills.git',
      agentId: 'agent-1',
    }),
    pullOnInit: true,
  },
});

await bank.initialize(); // auto-pulls remote changes

// Manual sync
await bank.sync.push();
await bank.sync.pull();
const status = await bank.sync.status();

await bank.shutdown(); // flushes pending sync

Federation

Connect independent skill repositories:

// Add a remote
await bank.federation.addRemote('team', {
  url: '[email protected]:org/team-skills.git',
  access: 'read-write',
});

// Browse remote skills
const remoteSkills = await bank.federation.browse('team');

// Import a skill
const result = await bank.federation.import('team', 'useful-pattern');

// Share a skill
await bank.federation.share('my-skill', 'team');

// Check for upstream updates
const updates = await bank.federation.checkUpstream();

Events

Subscribe to skill bank events:

// Simple synchronous listeners
const unsubscribe = bank.on((event) => {
  switch (event.type) {
    case 'skill:created':
      console.log('New skill:', event.skill.name);
      break;
    case 'skill:updated':
      console.log('Updated:', event.skill.name, 'from', event.previousVersion);
      break;
  }
});

// Advanced: async hooks with priority and filtering
bank.getHookRegistry().register({
  event: 'storage:after-save',
  handler: async (context) => {
    console.log('Skill saved to storage');
  },
  priority: 'normal',
});

Materialization

Make skills discoverable by agents following the Agent Skills standard. Skills stored in .skilltree/ are symlinked to standard discovery paths and AGENTS.md is auto-regenerated on changes.

const bank = createSkillBank({
  storage: { basePath: './my-project' },
  materialization: {
    enabled: true,
    symlinkPaths: ['.claude/skills', '.agent/skills'],
    agentsMdPath: './AGENTS.md',
    agentsMdFormat: 'xml',  // 'xml' | 'markdown' | 'json'
    debounceMs: 500,
  },
});

await bank.initialize();
// Symlinks created, AGENTS.md generated

await bank.saveSkill(mySkill);
// Symlinks updated, AGENTS.md regenerated automatically

This creates:

.claude/skills/
  my-skill -> ../../.skilltree/skills/my-skill  (symlink)
.agent/skills/
  my-skill -> ../../.skilltree/skills/my-skill  (symlink)
AGENTS.md  (auto-generated with <!-- SKILLTREE_START/END --> markers)

Agents activate skills on demand via the CLI:

# Read a skill to stdout (OpenSkills-compatible progressive disclosure)
skill-tree read my-skill

# Read multiple skills
skill-tree read skill-one,skill-two

AGENTS.md Integration

Bidirectional sync between skill bank and AGENTS.md files:

import { createAgentsSync } from 'skill-tree';

const sync = createAgentsSync(bank.getStorage());
const result = await sync.sync('./AGENTS.md', {
  direction: 'bidirectional',
});

Namespace Support

Multi-tier skill trees for team environments:

const bank = createSkillBank({
  storage: { basePath: './skills' },
  namespace: {
    agentId: 'agent-1',
    team: 'frontend',
    defaultScope: 'personal',
    defaultVisibility: 'private',
  },
});

// List skills by scope
const personal = await bank.listSkills({ scope: 'personal', owner: 'agent-1' });
const teamSkills = await bank.listSkills({ scope: 'team', team: 'frontend' });

API Reference

SkillBank

Main orchestrator class, created via createSkillBank(config).

| Method | Description | |--------|-------------| | initialize() | Initialize storage, federation, and sync | | shutdown() | Clean shutdown (flushes sync) | | getSkill(id, version?) | Get skill by ID | | listSkills(filter?) | List skills with optional filter | | searchSkills(query) | Full-text search | | saveSkill(skill) | Save or update a skill | | deleteSkill(id, version?) | Delete a skill | | deprecateSkill(id) | Mark skill as deprecated | | createVersion(id, updates, options?) | Create new version | | forkSkill(id, options) | Fork a skill | | getVersionHistory(id) | Get version history | | getLineage(id) | Get full lineage | | rollbackSkill(id, version) | Rollback to version | | compareVersions(id, vA, vB) | Diff two versions | | on(handler) | Subscribe to events (returns unsubscribe fn) | | off(handler) | Unsubscribe from events | | getStats() | Get skill bank statistics | | exportAll() | Export all skills | | importSkills(skills) | Bulk import skills | | createServingLayer(config?) | Create a SkillGraphServer | | getStorage() | Access underlying storage adapter | | getHookRegistry() | Access hook registry | | sync | SyncManager accessor (throws if not configured) | | federation | FederationManager accessor (requires basePath) |

Versioning Utilities

import {
  parseVersion,
  compareVersions,
  bumpVersion,
  satisfiesRange,
} from 'skill-tree';

bumpVersion('1.2.3', 'minor');  // '1.3.0'
satisfiesRange('1.5.0', '^1.2.0');  // true

Skill Format

Skills use YAML frontmatter + Markdown body (Agent Skills compatible):

---
name: typescript-esm-import-fix
description: |
  Fix TypeScript ES module import errors by adding .js extension
version: 1.0.0
author: extracted
status: active
date: 2024-01-15
tags:
  - typescript
  - esm
  - imports
---

TypeScript with ES modules requires explicit .js extensions in imports.

1. Add `.js` extension to relative imports
2. Even for `.ts` files, use `.js` in the import path

Run `tsc` and verify no module resolution errors.

License

MIT