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.1.4

Published

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

Readme

skill-tree

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

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
  • 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',
  problem: 'TypeScript with ES modules requires explicit .js extensions',
  triggerConditions: [{ type: 'error', value: "Cannot find module './utils'" }],
  solution: 'Add .js extension to all relative imports.',
  verification: 'Run tsc --noEmit to verify no import errors',
  examples: [],
  author: 'me',
  tags: ['typescript', 'esm'],
  createdAt: new Date(),
  updatedAt: new Date(),
  status: 'active',
  metrics: { usageCount: 0, successRate: 0, feedbackScores: [] },
} 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
  name: string;                  // Human-readable name
  version: string;               // Semantic version
  description: string;           // For search and matching
  problem: string;               // What problem this solves
  triggerConditions: TriggerCondition[];  // When to apply
  solution: string;              // Step-by-step solution
  verification: string;          // How to verify it worked
  examples: SkillExample[];      // Usage examples
  tags: string[];                // Categorization
  status: SkillStatus;           // 'draft' | 'active' | 'deprecated' | 'experimental'
  metrics: SkillMetrics;         // Usage tracking
  // ... namespace, taxonomy, lineage
}

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',
});

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 (OpenSkills-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
---

## Problem

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

## Trigger Conditions

- **error**: `Cannot find module './utils'`
- **pattern**: `import .* from '\./[^']+(?<!\.js)'`

## Solution

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

## Verification

Run `tsc` and verify no module resolution errors.

License

MIT