skill-tree 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +230 -158
  2. package/dist/chunk-3SRB47JW.mjs +8344 -0
  3. package/dist/chunk-43YOKLZP.mjs +6081 -0
  4. package/dist/chunk-4AGZU52D.mjs +7918 -0
  5. package/dist/chunk-4OC5QFIF.mjs +11267 -0
  6. package/dist/chunk-55SMGVTP.mjs +7126 -0
  7. package/dist/chunk-6FX4IK4Z.mjs +5368 -0
  8. package/dist/chunk-7EGDKOHV.mjs +9439 -0
  9. package/dist/chunk-7LMOQW5H.mjs +4893 -0
  10. package/dist/chunk-7QIQJVNP.mjs +14206 -0
  11. package/dist/chunk-7VB4ZRZO.mjs +7127 -0
  12. package/dist/chunk-BPVRW25O.mjs +6089 -0
  13. package/dist/chunk-CI4476KM.mjs +6607 -0
  14. package/dist/chunk-DDXYQ74I.mjs +13969 -0
  15. package/dist/chunk-DQOFJXBX.mjs +6595 -0
  16. package/dist/chunk-E2CVK23F.mjs +8751 -0
  17. package/dist/chunk-F3YEUQAP.mjs +654 -0
  18. package/dist/chunk-FKJJ4RJG.mjs +13874 -0
  19. package/dist/chunk-II7DECZQ.mjs +9111 -0
  20. package/dist/chunk-INKVOZXK.mjs +15898 -0
  21. package/dist/chunk-K6NRCSAZ.mjs +4355 -0
  22. package/dist/chunk-OYHYXKXO.mjs +7297 -0
  23. package/dist/chunk-PDPN7FW7.mjs +1045 -0
  24. package/dist/chunk-TEUB6DZR.mjs +6453 -0
  25. package/dist/chunk-TWPEHDW4.mjs +1067 -0
  26. package/dist/chunk-Y54UK2J3.mjs +13071 -0
  27. package/dist/chunk-ZQVS7MQK.mjs +6081 -0
  28. package/dist/cli/index.js +7140 -10072
  29. package/dist/cli/index.mjs +3023 -13417
  30. package/dist/index.d.mts +1830 -4319
  31. package/dist/index.d.ts +1830 -4319
  32. package/dist/index.js +7107 -13152
  33. package/dist/index.mjs +78 -14158
  34. package/dist/sqlite-OLU72GHB.mjs +6 -0
  35. package/dist/sqlite-XJRPMNAJ.mjs +6 -0
  36. package/dist/sync-BSWMMDA6.mjs +14 -0
  37. package/package.json +1 -1
  38. package/dist/cli/index.js.map +0 -1
  39. package/dist/cli/index.mjs.map +0 -1
  40. package/dist/index.js.map +0 -1
  41. package/dist/index.mjs.map +0 -1
package/README.md CHANGED
@@ -1,15 +1,17 @@
1
1
  # skill-tree
2
2
 
3
- A TypeScript library for managing agent skill versions and evolution. Extract, iterate, and adapt skills from agent trajectories.
3
+ A TypeScript library for managing agent skill versions and evolution. Store, version, serve, sync, and federate reusable skills for AI agents.
4
4
 
5
5
  ## Overview
6
6
 
7
7
  skill-tree helps you build and maintain a library of reusable skills for AI agents by:
8
8
 
9
- - **Extracting skills** from agent sessions/trajectories (manual or automatic)
10
9
  - **Storing skills** in a versioned, searchable format (OpenSkills-compatible)
11
10
  - **Evolving skills** through versioning, forking, and merging
12
- - **Quality gates** to ensure extracted skills are reusable and non-trivial
11
+ - **Serving skills** via dynamic loadouts with expand/collapse, profiles, and token budgeting
12
+ - **Materializing skills** to agent-discoverable paths (`.claude/skills/`, `.agent/skills/`) with auto-generated AGENTS.md
13
+ - **Syncing skills** across agents with git-based multi-agent collaboration
14
+ - **Federating skills** across repositories for cross-organization sharing
13
15
 
14
16
  Inspired by research on skill libraries ([arXiv:2512.17102](https://arxiv.org/abs/2512.17102)), [Claudeception](https://github.com/blader/Claudeception), and [OpenSkills](https://github.com/numman-ali/openskills).
15
17
 
@@ -22,139 +24,73 @@ npm install skill-tree
22
24
  ## Quick Start
23
25
 
24
26
  ```typescript
25
- import { createSkillBank } from 'skill-tree';
27
+ import { createSkillBank, type Skill } from 'skill-tree';
26
28
 
27
29
  // Create a skill bank with filesystem storage
28
- const skillBank = createSkillBank({
29
- storage: {
30
- type: 'filesystem',
31
- basePath: './skills',
32
- openSkillsCompatible: true,
33
- },
30
+ const bank = createSkillBank({
31
+ storage: { basePath: './skills' },
34
32
  });
35
33
 
36
- await skillBank.initialize();
37
-
38
- // Parse a Claude Code session
39
- const trajectory = await skillBank.parseSession(sessionContent);
34
+ await bank.initialize();
40
35
 
41
- // Extract a skill manually
42
- const result = await skillBank.extractManual(trajectory, {
43
- suggestedName: 'typescript-import-fix',
36
+ // Save a skill
37
+ await bank.saveSkill({
38
+ id: 'typescript-esm-import-fix',
39
+ name: 'TypeScript ESM Import Fix',
40
+ version: '1.0.0',
44
41
  description: 'Fix TypeScript ES module import errors',
45
- tags: ['typescript', 'imports'],
46
- });
47
-
48
- if (result.success) {
49
- console.log('Extracted skill:', result.skill.name);
50
- }
42
+ instructions: 'Add .js extension to all relative imports, even for .ts files.\n\nRun `tsc --noEmit` to verify no import errors.',
43
+ author: 'me',
44
+ tags: ['typescript', 'esm'],
45
+ createdAt: new Date(),
46
+ updatedAt: new Date(),
47
+ status: 'active',
48
+ metrics: { usageCount: 0, successRate: 0, feedbackScores: [] },
49
+ } as Skill);
51
50
 
52
51
  // Search for skills
53
- const skills = await skillBank.searchSkills('typescript error');
52
+ const skills = await bank.searchSkills('typescript');
54
53
 
55
54
  // Create a new version
56
- const updated = await skillBank.createVersion('typescript-import-fix', {
57
- solution: 'Updated solution...',
55
+ const updated = await bank.createVersion('typescript-esm-import-fix', {
56
+ solution: 'Add .js extension, or use "moduleResolution": "bundler".',
58
57
  }, { bumpType: 'minor' });
58
+
59
+ await bank.shutdown();
59
60
  ```
60
61
 
61
62
  ## Core Concepts
62
63
 
63
64
  ### Skills
64
65
 
65
- A skill represents a reusable piece of knowledge extracted from agent interactions:
66
+ A skill represents a reusable piece of knowledge:
66
67
 
67
68
  ```typescript
68
69
  interface Skill {
69
- id: string; // Unique identifier
70
+ id: string; // Unique identifier (kebab-case)
70
71
  name: string; // Human-readable name
71
72
  version: string; // Semantic version
72
- description: string; // For semantic matching
73
- problem: string; // What problem this solves
74
- triggerConditions: TriggerCondition[]; // When to apply
75
- solution: string; // Step-by-step solution
76
- verification: string; // How to verify it worked
77
- examples: SkillExample[]; // Usage examples
78
- // ... metadata, metrics, lineage
79
- }
80
- ```
81
-
82
- ### Trajectories
83
-
84
- Agent sessions are parsed into trajectories:
85
-
86
- ```typescript
87
- interface Trajectory {
88
- sessionId: string;
89
- turns: Turn[]; // User/assistant/tool interactions
90
- metadata: TrajectoryMetadata;
91
- outcome?: TrajectoryOutcome;
73
+ description: string; // Short summary for discovery and matching
74
+ instructions: string; // Free-form markdown body (the SKILL.md content)
75
+ tags: string[]; // Categorization
76
+ status: SkillStatus; // 'draft' | 'active' | 'deprecated' | 'experimental'
77
+ metrics: SkillMetrics; // Usage tracking
78
+ // ... namespace, taxonomy, lineage, serving metadata
92
79
  }
93
80
  ```
94
81
 
95
- ### Quality Gates
96
-
97
- Extraction includes quality gates (inspired by Claudeception) to ensure skills are:
98
-
99
- - **Reusable**: Applicable across multiple future tasks
100
- - **Non-trivial**: Involves discovery beyond documentation lookup
101
- - **Specific**: Has clear trigger conditions
102
- - **Verified**: Solution demonstrably works
103
-
104
- ## Features
105
-
106
- ### Session Adapters
107
-
108
- Parse different agent session formats:
109
-
110
- ```typescript
111
- // Built-in: Claude Code JSONL
112
- const trajectory = await skillBank.parseSession(jsonlContent);
113
-
114
- // Register custom adapters
115
- skillBank.registerAdapter(myCustomAdapter);
116
- ```
117
-
118
- ### Extraction Modes
119
-
120
- **Manual extraction** with user guidance:
121
-
122
- ```typescript
123
- const result = await skillBank.extractManual(trajectory, {
124
- turnRange: [5, 15], // Extract specific turns
125
- suggestedName: 'my-skill',
126
- tags: ['debugging'],
127
- });
128
- ```
129
-
130
- **Automatic extraction** using LLM:
131
-
132
- ```typescript
133
- skillBank.setLLMProvider(myLLMProvider);
134
-
135
- const results = await skillBank.extractAutomatic(trajectory, {
136
- minConfidence: 0.7,
137
- });
138
- ```
139
-
140
82
  ### Storage
141
83
 
142
- **Filesystem storage** (OpenSkills-compatible):
84
+ Two backends:
143
85
 
144
86
  ```typescript
145
- const skillBank = createSkillBank({
146
- storage: {
147
- type: 'filesystem',
148
- basePath: '~/.skills',
149
- openSkillsCompatible: true, // YAML frontmatter + Markdown
150
- },
87
+ // Filesystem (JSON source of truth + SQLite cache)
88
+ const bank = createSkillBank({
89
+ storage: { basePath: './skills' },
151
90
  });
152
- ```
153
91
 
154
- **Memory storage** (for testing):
155
-
156
- ```typescript
157
- const skillBank = createSkillBank({
92
+ // Memory (for testing)
93
+ const bank = createSkillBank({
158
94
  storage: { type: 'memory' },
159
95
  });
160
96
  ```
@@ -172,45 +108,111 @@ skills/
172
108
  └── 1.1.0.json
173
109
  ```
174
110
 
111
+ ## Features
112
+
175
113
  ### Versioning
176
114
 
177
115
  Semantic versioning with full lineage tracking:
178
116
 
179
117
  ```typescript
180
118
  // Create new version
181
- const v2 = await skillBank.createVersion('my-skill', updates, {
119
+ const v2 = await bank.createVersion('my-skill', updates, {
182
120
  bumpType: 'minor',
183
121
  changelog: 'Added alternative solution',
184
122
  });
185
123
 
186
124
  // Get version history
187
- const history = await skillBank.getVersionHistory('my-skill');
125
+ const history = await bank.getVersionHistory('my-skill');
188
126
 
189
127
  // Rollback to previous version
190
- const restored = await skillBank.rollbackSkill('my-skill', '1.0.0');
128
+ const restored = await bank.rollbackSkill('my-skill', '1.0.0');
191
129
 
192
130
  // Compare versions
193
- const diff = await skillBank.compareVersions('my-skill', '1.0.0', '2.0.0');
194
- ```
195
-
196
- ### Skill Evolution
131
+ const diff = await bank.compareVersions('my-skill', '1.0.0', '2.0.0');
197
132
 
198
- Fork and merge skills:
199
-
200
- ```typescript
201
133
  // Fork for a specialized use case
202
- const forked = await skillBank.forkSkill('my-skill', {
134
+ const forked = await bank.forkSkill('my-skill', {
203
135
  newId: 'my-skill-react',
204
136
  newName: 'My Skill (React variant)',
205
137
  reason: 'Specialized for React projects',
206
138
  });
139
+ ```
140
+
141
+ ### Serving Layer
142
+
143
+ Dynamic skill loadouts for agent context windows:
144
+
145
+ ```typescript
146
+ const { server } = await bank.createServingLayer({
147
+ maxExpanded: 5,
148
+ });
149
+
150
+ // Orchestrator sets loadout based on task
151
+ await server.setLoadoutForTask('Fix authentication bug');
152
+
153
+ // Or use a built-in profile
154
+ await server.setLoadoutFromProfile('debugging');
155
+
156
+ // Render skills into system prompt
157
+ const prompt = server.renderSystemPrompt();
158
+
159
+ // Agent-side API
160
+ const view = server.agentListLoadout();
161
+ const skill = server.agentExpandSkill('some-skill-id');
162
+ server.agentCollapseSkill('some-skill-id');
163
+ await server.agentRequestSkills(['another-skill']);
164
+ ```
165
+
166
+ ### Multi-Agent Sync
167
+
168
+ Git-based skill synchronization:
169
+
170
+ ```typescript
171
+ import { createDefaultSyncConfig } from 'skill-tree';
172
+
173
+ const bank = createSkillBank({
174
+ storage: { basePath: './skills' },
175
+ sync: {
176
+ config: createDefaultSyncConfig({
177
+ repoUrl: 'git@github.com:org/skills.git',
178
+ agentId: 'agent-1',
179
+ }),
180
+ pullOnInit: true,
181
+ },
182
+ });
183
+
184
+ await bank.initialize(); // auto-pulls remote changes
185
+
186
+ // Manual sync
187
+ await bank.sync.push();
188
+ await bank.sync.pull();
189
+ const status = await bank.sync.status();
190
+
191
+ await bank.shutdown(); // flushes pending sync
192
+ ```
193
+
194
+ ### Federation
195
+
196
+ Connect independent skill repositories:
197
+
198
+ ```typescript
199
+ // Add a remote
200
+ await bank.federation.addRemote('team', {
201
+ url: 'git@github.com:org/team-skills.git',
202
+ access: 'read-write',
203
+ });
204
+
205
+ // Browse remote skills
206
+ const remoteSkills = await bank.federation.browse('team');
207
+
208
+ // Import a skill
209
+ const result = await bank.federation.import('team', 'useful-pattern');
207
210
 
208
- // Merge improvements back
209
- const merged = await skillBank.lineageTracker.mergeSkill(
210
- 'my-skill',
211
- 'my-skill-react',
212
- { fields: ['solution', 'examples'] }
213
- );
211
+ // Share a skill
212
+ await bank.federation.share('my-skill', 'team');
213
+
214
+ // Check for upstream updates
215
+ const updates = await bank.federation.checkUpstream();
214
216
  ```
215
217
 
216
218
  ### Events
@@ -218,40 +220,135 @@ const merged = await skillBank.lineageTracker.mergeSkill(
218
220
  Subscribe to skill bank events:
219
221
 
220
222
  ```typescript
221
- const unsubscribe = skillBank.on((event) => {
223
+ // Simple synchronous listeners
224
+ const unsubscribe = bank.on((event) => {
222
225
  switch (event.type) {
223
226
  case 'skill:created':
224
227
  console.log('New skill:', event.skill.name);
225
228
  break;
226
- case 'extraction:completed':
227
- console.log('Extraction confidence:', event.result.confidence);
229
+ case 'skill:updated':
230
+ console.log('Updated:', event.skill.name, 'from', event.previousVersion);
228
231
  break;
229
232
  }
230
233
  });
234
+
235
+ // Advanced: async hooks with priority and filtering
236
+ bank.getHookRegistry().register({
237
+ event: 'storage:after-save',
238
+ handler: async (context) => {
239
+ console.log('Skill saved to storage');
240
+ },
241
+ priority: 'normal',
242
+ });
243
+ ```
244
+
245
+ ### Materialization
246
+
247
+ Make skills discoverable by agents following the [Agent Skills standard](https://agentskills.io). Skills stored in `.skilltree/` are symlinked to standard discovery paths and AGENTS.md is auto-regenerated on changes.
248
+
249
+ ```typescript
250
+ const bank = createSkillBank({
251
+ storage: { basePath: './my-project' },
252
+ materialization: {
253
+ enabled: true,
254
+ symlinkPaths: ['.claude/skills', '.agent/skills'],
255
+ agentsMdPath: './AGENTS.md',
256
+ agentsMdFormat: 'xml', // 'xml' | 'markdown' | 'json'
257
+ debounceMs: 500,
258
+ },
259
+ });
260
+
261
+ await bank.initialize();
262
+ // Symlinks created, AGENTS.md generated
263
+
264
+ await bank.saveSkill(mySkill);
265
+ // Symlinks updated, AGENTS.md regenerated automatically
266
+ ```
267
+
268
+ This creates:
269
+ ```
270
+ .claude/skills/
271
+ my-skill -> ../../.skilltree/skills/my-skill (symlink)
272
+ .agent/skills/
273
+ my-skill -> ../../.skilltree/skills/my-skill (symlink)
274
+ AGENTS.md (auto-generated with <!-- SKILLTREE_START/END --> markers)
275
+ ```
276
+
277
+ Agents activate skills on demand via the CLI:
278
+
279
+ ```bash
280
+ # Read a skill to stdout (OpenSkills-compatible progressive disclosure)
281
+ skill-tree read my-skill
282
+
283
+ # Read multiple skills
284
+ skill-tree read skill-one,skill-two
285
+ ```
286
+
287
+ ### AGENTS.md Integration
288
+
289
+ Bidirectional sync between skill bank and AGENTS.md files:
290
+
291
+ ```typescript
292
+ import { createAgentsSync } from 'skill-tree';
293
+
294
+ const sync = createAgentsSync(bank.getStorage());
295
+ const result = await sync.sync('./AGENTS.md', {
296
+ direction: 'bidirectional',
297
+ });
298
+ ```
299
+
300
+ ### Namespace Support
301
+
302
+ Multi-tier skill trees for team environments:
303
+
304
+ ```typescript
305
+ const bank = createSkillBank({
306
+ storage: { basePath: './skills' },
307
+ namespace: {
308
+ agentId: 'agent-1',
309
+ team: 'frontend',
310
+ defaultScope: 'personal',
311
+ defaultVisibility: 'private',
312
+ },
313
+ });
314
+
315
+ // List skills by scope
316
+ const personal = await bank.listSkills({ scope: 'personal', owner: 'agent-1' });
317
+ const teamSkills = await bank.listSkills({ scope: 'team', team: 'frontend' });
231
318
  ```
232
319
 
233
320
  ## API Reference
234
321
 
235
322
  ### SkillBank
236
323
 
237
- Main orchestrator class.
324
+ Main orchestrator class, created via `createSkillBank(config)`.
238
325
 
239
326
  | Method | Description |
240
327
  |--------|-------------|
241
- | `initialize()` | Initialize storage (required before use) |
242
- | `parseSession(content, adapter?)` | Parse session into trajectory |
243
- | `extractManual(trajectory, options?)` | Extract skill with guidance |
244
- | `extractAutomatic(trajectory, options?)` | Extract skills using LLM |
328
+ | `initialize()` | Initialize storage, federation, and sync |
329
+ | `shutdown()` | Clean shutdown (flushes sync) |
245
330
  | `getSkill(id, version?)` | Get skill by ID |
246
331
  | `listSkills(filter?)` | List skills with optional filter |
247
- | `searchSkills(query)` | Search skills by text |
332
+ | `searchSkills(query)` | Full-text search |
248
333
  | `saveSkill(skill)` | Save or update a skill |
249
334
  | `deleteSkill(id, version?)` | Delete a skill |
335
+ | `deprecateSkill(id)` | Mark skill as deprecated |
250
336
  | `createVersion(id, updates, options?)` | Create new version |
251
337
  | `forkSkill(id, options)` | Fork a skill |
252
338
  | `getVersionHistory(id)` | Get version history |
339
+ | `getLineage(id)` | Get full lineage |
253
340
  | `rollbackSkill(id, version)` | Rollback to version |
254
- | `on(handler)` | Subscribe to events |
341
+ | `compareVersions(id, vA, vB)` | Diff two versions |
342
+ | `on(handler)` | Subscribe to events (returns unsubscribe fn) |
343
+ | `off(handler)` | Unsubscribe from events |
344
+ | `getStats()` | Get skill bank statistics |
345
+ | `exportAll()` | Export all skills |
346
+ | `importSkills(skills)` | Bulk import skills |
347
+ | `createServingLayer(config?)` | Create a SkillGraphServer |
348
+ | `getStorage()` | Access underlying storage adapter |
349
+ | `getHookRegistry()` | Access hook registry |
350
+ | `sync` | SyncManager accessor (throws if not configured) |
351
+ | `federation` | FederationManager accessor (requires basePath) |
255
352
 
256
353
  ### Versioning Utilities
257
354
 
@@ -269,7 +366,7 @@ satisfiesRange('1.5.0', '^1.2.0'); // true
269
366
 
270
367
  ## Skill Format
271
368
 
272
- Skills use YAML frontmatter + Markdown (OpenSkills-compatible):
369
+ Skills use YAML frontmatter + Markdown body ([Agent Skills](https://agentskills.io) compatible):
273
370
 
274
371
  ```markdown
275
372
  ---
@@ -286,37 +383,12 @@ tags:
286
383
  - imports
287
384
  ---
288
385
 
289
- ## Problem
290
-
291
386
  TypeScript with ES modules requires explicit .js extensions in imports.
292
387
 
293
- ## Trigger Conditions
294
-
295
- - **error**: `Cannot find module './utils'`
296
- - **pattern**: `import .* from '\./[^']+(?<!\.js)'`
297
-
298
- ## Solution
299
-
300
388
  1. Add `.js` extension to relative imports
301
389
  2. Even for `.ts` files, use `.js` in the import path
302
390
 
303
- ## Verification
304
-
305
391
  Run `tsc` and verify no module resolution errors.
306
-
307
- ## Examples
308
-
309
- ### Basic import fix
310
-
311
- **Before:**
312
- ```typescript
313
- import { helper } from './utils'
314
- ```
315
-
316
- **After:**
317
- ```typescript
318
- import { helper } from './utils.js'
319
- ```
320
392
  ```
321
393
 
322
394
  ## License