skill-gen 0.0.1

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.
package/README.md ADDED
@@ -0,0 +1,90 @@
1
+ # skillify
2
+
3
+ Generate SKILL.md files for npm packages following [Anthropic's Agent Skills specification](https://agentskills.io/specification).
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install -g skillify
9
+ ```
10
+
11
+ Or use directly:
12
+
13
+ ```bash
14
+ npx skill-gen .
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ```bash
20
+ # Current directory
21
+ npx skill-gen .
22
+
23
+ # Specific path
24
+ npx skill-gen ~/projects/my-package
25
+
26
+ # Print to stdout
27
+ npx skill-gen . --stdout
28
+
29
+ # Dry run (preview only)
30
+ npx skill-gen . --dry-run
31
+
32
+ # Custom output path
33
+ npx skill-gen . -o ./docs/SKILL.md
34
+ ```
35
+
36
+ ## What it Does
37
+
38
+ 1. Reads `package.json` for name, description, keywords, bin, exports
39
+ 2. Analyzes CLI entry point for flags/commands
40
+ 3. Extracts exported functions from main module
41
+ 4. Generates SKILL.md with:
42
+ - Proper YAML frontmatter (name, description)
43
+ - "When to Use" triggers
44
+ - Quick Start examples
45
+ - CLI Reference (if applicable)
46
+ - API Reference (if applicable)
47
+
48
+ ## Output Format
49
+
50
+ ```yaml
51
+ ---
52
+ name: my-package
53
+ description: Does X and Y. Use when working with Z.
54
+ ---
55
+
56
+ # my-package
57
+
58
+ ## When to Use
59
+ ...
60
+
61
+ ## Quick Start
62
+ ...
63
+ ```
64
+
65
+ ## Why SKILL.md?
66
+
67
+ SKILL.md is the [Agent Skills](https://agentskills.io) standard for AI agent documentation:
68
+
69
+ - **Discoverable**: Agents find skills by name + description
70
+ - **Progressive disclosure**: Metadata loads first, details on-demand
71
+ - **Portable**: Works with Claude Code, Cursor, Copilot, Codex
72
+
73
+ ## Best Practices Applied
74
+
75
+ Based on [Anthropic's guidelines](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices):
76
+
77
+ - Third person descriptions ("Builds X" not "I build X")
78
+ - Includes "when to use" triggers
79
+ - Concrete examples over abstract descriptions
80
+ - Under 500 lines for optimal performance
81
+
82
+ ## Related
83
+
84
+ - [Agent Skills Specification](https://agentskills.io/specification)
85
+ - [Anthropic Skills Repository](https://github.com/anthropics/skills)
86
+ - [fund-agent](https://npmjs.com/package/fund-agent)
87
+
88
+ ## License
89
+
90
+ MIT
package/SKILL.md ADDED
@@ -0,0 +1,229 @@
1
+ ---
2
+ name: skillify
3
+ description: Generates SKILL.md files for npm packages following Anthropic's Agent Skills specification. Use when adding agent documentation to an npm package, making a package AI-agent friendly, or creating skills from existing code.
4
+ ---
5
+
6
+ # Skillify
7
+
8
+ Generate a SKILL.md file for an npm package, making it discoverable and usable by AI agents.
9
+
10
+ ## When to Use
11
+
12
+ - Adding agent documentation to an npm package
13
+ - Making a library AI-agent friendly
14
+ - Creating a skill from existing CLI tool
15
+ - Preparing a package for the Agent Skills ecosystem
16
+
17
+ ## Quick Start
18
+
19
+ ```bash
20
+ /skillify . # Current directory
21
+ /skillify ~/path/to/package # Local package
22
+ /skillify btctx # npm package name
23
+ ```
24
+
25
+ ## Process
26
+
27
+ ### Step 1: Gather Package Information
28
+
29
+ Read these files (in order of importance):
30
+
31
+ 1. **package.json** (required)
32
+ - `name` → skill name (kebab-case)
33
+ - `description` → base for skill description
34
+ - `bin` → CLI commands available
35
+ - `main`/`exports` → API entry points
36
+ - `keywords` → trigger words
37
+
38
+ 2. **README.md** (if exists)
39
+ - Usage examples
40
+ - API documentation
41
+ - Installation instructions
42
+
43
+ 3. **CLI entry point** (if `bin` exists)
44
+ - Parse for `--help` output
45
+ - Extract flags and commands
46
+
47
+ 4. **Main module** (if `main`/`exports` exists)
48
+ - Exported functions
49
+ - JSDoc comments
50
+ - Type definitions
51
+
52
+ ### Step 2: Analyze for Agent Usage
53
+
54
+ Determine:
55
+ - **What it does** - core functionality in one sentence
56
+ - **When to use** - specific triggers/contexts
57
+ - **How to use** - primary usage pattern (CLI or API)
58
+ - **Examples** - concrete input/output pairs
59
+
60
+ ### Step 3: Generate SKILL.md
61
+
62
+ Follow this template:
63
+
64
+ ```yaml
65
+ ---
66
+ name: <package-name-kebab-case>
67
+ description: <What it does>. <When to use - specific triggers>.
68
+ ---
69
+ ```
70
+
71
+ **Description rules:**
72
+ - Third person only ("Builds X" not "I build X")
73
+ - Under 1024 characters
74
+ - Include both WHAT and WHEN
75
+ - Use specific keywords for discovery
76
+
77
+ **Body structure:**
78
+
79
+ ```markdown
80
+ # <Package Name>
81
+
82
+ ## When to Use
83
+
84
+ Invoke when you need to:
85
+ - <specific trigger 1>
86
+ - <specific trigger 2>
87
+ - <specific trigger 3>
88
+
89
+ ## Quick Start
90
+
91
+ <primary usage pattern - CLI or code>
92
+
93
+ ## Examples
94
+
95
+ **Example 1: <use case>**
96
+
97
+ Input:
98
+ <concrete input>
99
+
100
+ Output:
101
+ <concrete output>
102
+
103
+ ## CLI Reference (if applicable)
104
+
105
+ <flags and commands>
106
+
107
+ ## API Reference (if applicable)
108
+
109
+ <key exported functions>
110
+ ```
111
+
112
+ ### Step 4: Write the File
113
+
114
+ Save to: `<package-root>/SKILL.md`
115
+
116
+ ## Quality Checklist
117
+
118
+ Before finalizing, verify:
119
+
120
+ - [ ] Description is third person
121
+ - [ ] Description includes WHAT and WHEN
122
+ - [ ] Description under 1024 characters
123
+ - [ ] Name is kebab-case, lowercase
124
+ - [ ] Examples are concrete (not abstract)
125
+ - [ ] Body under 500 lines
126
+ - [ ] No time-sensitive information
127
+ - [ ] Consistent terminology
128
+
129
+ ## Description Formula
130
+
131
+ ```
132
+ <Verb>s <object> [details]. Use when <trigger1>, <trigger2>, or <trigger3>.
133
+ ```
134
+
135
+ **Good examples:**
136
+ ```yaml
137
+ description: Builds Bitcoin Taproot transactions from inputs and outputs. Use when creating P2TR transactions, spending UTXOs, or working with Taproot addresses.
138
+ ```
139
+
140
+ ```yaml
141
+ description: Broadcasts signed Bitcoin transactions to the network. Use when sending transactions to mempool, publishing to testnet4, or checking broadcast status.
142
+ ```
143
+
144
+ **Bad examples:**
145
+ ```yaml
146
+ description: Helps with Bitcoin stuff. # Too vague
147
+ description: I can build transactions. # Wrong POV
148
+ description: A library for transactions. # No "when to use"
149
+ ```
150
+
151
+ ## Naming Convention
152
+
153
+ Convert package name to kebab-case:
154
+
155
+ | package.json name | SKILL.md name |
156
+ |-------------------|---------------|
157
+ | `btctx` | `btctx` |
158
+ | `sendTx` | `send-tx` |
159
+ | `BitcoinBuilder` | `bitcoin-builder` |
160
+ | `@scope/pkg` | `pkg` (drop scope) |
161
+
162
+ ## Example Output
163
+
164
+ For a package like `btctx`:
165
+
166
+ ```yaml
167
+ ---
168
+ name: btctx
169
+ description: Builds Bitcoin Taproot (P2TR) transactions from UTXOs. Use when creating Bitcoin transactions, spending Taproot outputs, or building raw transaction hex.
170
+ ---
171
+
172
+ # btctx
173
+
174
+ ## When to Use
175
+
176
+ Invoke when you need to:
177
+ - Build a Bitcoin transaction from UTXOs
178
+ - Create Taproot (P2TR) outputs
179
+ - Generate signed transaction hex for broadcasting
180
+
181
+ ## Quick Start
182
+
183
+ ```javascript
184
+ import { buildTx } from 'btctx';
185
+
186
+ const { hex, txid } = await buildTx({
187
+ privateKey: '...',
188
+ publicKey: '...',
189
+ txid: '<input-txid>',
190
+ vout: 0,
191
+ inputAmount: 100000,
192
+ outputs: [{ pubkey: '<recipient>', amount: 99000 }]
193
+ });
194
+ ```
195
+
196
+ ## Examples
197
+
198
+ **Example: Simple transfer**
199
+
200
+ Input:
201
+ - 100,000 sats from UTXO
202
+ - Send to one recipient
203
+
204
+ Output:
205
+ - Signed transaction hex
206
+ - Transaction ID (txid)
207
+
208
+ ## API Reference
209
+
210
+ ### `buildTx(options)`
211
+
212
+ Builds and signs a Taproot transaction.
213
+
214
+ Options:
215
+ - `privateKey` - 64-char hex signing key
216
+ - `publicKey` - 64-char hex x-only pubkey
217
+ - `txid` - Input transaction ID
218
+ - `vout` - Output index to spend
219
+ - `inputAmount` - Satoshis in input
220
+ - `outputs` - Array of `{ pubkey, amount }`
221
+
222
+ Returns: `{ hex, txid }`
223
+ ```
224
+
225
+ ## References
226
+
227
+ - [Agent Skills Specification](https://agentskills.io/specification)
228
+ - [Anthropic Best Practices](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices)
229
+ - [GitHub: anthropics/skills](https://github.com/anthropics/skills)
@@ -0,0 +1,325 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * skillify - Generate SKILL.md for npm packages
5
+ *
6
+ * Usage:
7
+ * npx skill-gen . # Current directory
8
+ * npx skill-gen ~/path/to/pkg # Local package
9
+ * npx skill-gen btctx # npm package (fetches info)
10
+ */
11
+
12
+ import fs from 'fs';
13
+ import path from 'path';
14
+ import { fileURLToPath } from 'url';
15
+
16
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
17
+
18
+ // CLI args
19
+ const args = process.argv.slice(2);
20
+
21
+ if (args.includes('--help') || args.includes('-h') || args.length === 0) {
22
+ console.log(`
23
+ skillify v0.0.1 - Generate SKILL.md for npm packages
24
+
25
+ Usage:
26
+ npx skill-gen <path> Generate SKILL.md for local package
27
+ npx skill-gen . Current directory
28
+
29
+ Options:
30
+ -h, --help Show this help
31
+ -v, --version Show version
32
+ -o, --output Output path (default: ./SKILL.md)
33
+ --stdout Print to stdout instead of file
34
+ --dry-run Show what would be generated
35
+
36
+ Examples:
37
+ npx skill-gen .
38
+ npx skill-gen ~/projects/my-package
39
+ npx skill-gen . --stdout
40
+ `);
41
+ process.exit(0);
42
+ }
43
+
44
+ if (args.includes('--version') || args.includes('-v')) {
45
+ console.log('0.0.1');
46
+ process.exit(0);
47
+ }
48
+
49
+ // Parse flags
50
+ const stdout = args.includes('--stdout');
51
+ const dryRun = args.includes('--dry-run');
52
+ const outputIdx = args.indexOf('-o') !== -1 ? args.indexOf('-o') : args.indexOf('--output');
53
+ const outputPath = outputIdx !== -1 ? args[outputIdx + 1] : null;
54
+
55
+ // Get target path
56
+ const targetArg = args.find(a => !a.startsWith('-') && a !== outputPath);
57
+ const targetPath = path.resolve(targetArg || '.');
58
+
59
+ /**
60
+ * Convert string to kebab-case
61
+ */
62
+ function toKebabCase(str) {
63
+ return str
64
+ .replace(/^@[^/]+\//, '') // Remove scope
65
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
66
+ .replace(/[_\s]+/g, '-')
67
+ .toLowerCase();
68
+ }
69
+
70
+ /**
71
+ * Extract CLI info from a file
72
+ */
73
+ function extractCliInfo(filePath) {
74
+ try {
75
+ const content = fs.readFileSync(filePath, 'utf8');
76
+ const flags = [];
77
+
78
+ // Look for common flag patterns
79
+ const flagPatterns = [
80
+ /--(\w[-\w]*)/g,
81
+ /-([a-zA-Z]),\s*--(\w[-\w]*)/g,
82
+ ];
83
+
84
+ for (const pattern of flagPatterns) {
85
+ let match;
86
+ while ((match = pattern.exec(content)) !== null) {
87
+ flags.push(match[1] || match[2]);
88
+ }
89
+ }
90
+
91
+ return [...new Set(flags)].filter(f => !['help', 'version'].includes(f));
92
+ } catch {
93
+ return [];
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Extract exports from main module
99
+ */
100
+ function extractExports(filePath) {
101
+ try {
102
+ const content = fs.readFileSync(filePath, 'utf8');
103
+ const exports = [];
104
+
105
+ // Named exports
106
+ const namedExports = content.matchAll(/export\s+(?:async\s+)?(?:function|const|let|var|class)\s+(\w+)/g);
107
+ for (const match of namedExports) {
108
+ exports.push(match[1]);
109
+ }
110
+
111
+ // Export { ... }
112
+ const bracketExports = content.matchAll(/export\s*\{([^}]+)\}/g);
113
+ for (const match of bracketExports) {
114
+ const names = match[1].split(',').map(s => s.trim().split(/\s+as\s+/)[0].trim());
115
+ exports.push(...names);
116
+ }
117
+
118
+ return [...new Set(exports)];
119
+ } catch {
120
+ return [];
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Generate description from package info
126
+ */
127
+ function generateDescription(pkg, hasCliCommands, exportedFunctions) {
128
+ let desc = pkg.description || `Provides ${pkg.name} functionality`;
129
+
130
+ // Ensure it ends with a period
131
+ if (!desc.endsWith('.')) desc += '.';
132
+
133
+ // Add "Use when" triggers based on keywords
134
+ const triggers = [];
135
+
136
+ if (pkg.keywords?.length) {
137
+ const keywordTriggers = pkg.keywords.slice(0, 3).map(k => `working with ${k}`);
138
+ triggers.push(...keywordTriggers);
139
+ }
140
+
141
+ if (hasCliCommands) {
142
+ triggers.push(`using the ${pkg.name} CLI`);
143
+ }
144
+
145
+ if (triggers.length) {
146
+ desc += ` Use when ${triggers.slice(0, 2).join(' or ')}.`;
147
+ }
148
+
149
+ // Truncate to 1024 chars
150
+ if (desc.length > 1024) {
151
+ desc = desc.slice(0, 1020) + '...';
152
+ }
153
+
154
+ return desc;
155
+ }
156
+
157
+ /**
158
+ * Generate SKILL.md content
159
+ */
160
+ function generateSkillMd(pkg, options = {}) {
161
+ const { cliFlags = [], exports = [], readme = '' } = options;
162
+
163
+ const name = toKebabCase(pkg.name);
164
+ const description = generateDescription(pkg, cliFlags.length > 0, exports);
165
+
166
+ let content = `---
167
+ name: ${name}
168
+ description: ${description}
169
+ ---
170
+
171
+ # ${pkg.name}
172
+
173
+ `;
174
+
175
+ // When to Use
176
+ content += `## When to Use
177
+
178
+ Invoke when you need to:
179
+ `;
180
+
181
+ if (pkg.keywords?.length) {
182
+ pkg.keywords.slice(0, 4).forEach(kw => {
183
+ content += `- Work with ${kw}\n`;
184
+ });
185
+ } else {
186
+ content += `- Use ${pkg.name} functionality\n`;
187
+ }
188
+
189
+ content += '\n';
190
+
191
+ // Quick Start
192
+ content += `## Quick Start
193
+
194
+ `;
195
+
196
+ if (pkg.bin) {
197
+ const binName = typeof pkg.bin === 'string' ? pkg.name : Object.keys(pkg.bin)[0];
198
+ content += `\`\`\`bash
199
+ npx ${binName} --help
200
+ \`\`\`
201
+
202
+ `;
203
+ }
204
+
205
+ if (exports.length) {
206
+ content += `\`\`\`javascript
207
+ import { ${exports.slice(0, 3).join(', ')} } from '${pkg.name}';
208
+ \`\`\`
209
+
210
+ `;
211
+ }
212
+
213
+ // CLI Reference
214
+ if (pkg.bin && cliFlags.length) {
215
+ content += `## CLI Reference
216
+
217
+ \`\`\`
218
+ npx ${Object.keys(pkg.bin)[0]} [options]
219
+ \`\`\`
220
+
221
+ **Options:**
222
+ `;
223
+ cliFlags.slice(0, 10).forEach(flag => {
224
+ content += `- \`--${flag}\`\n`;
225
+ });
226
+ content += '\n';
227
+ }
228
+
229
+ // API Reference
230
+ if (exports.length) {
231
+ content += `## API Reference
232
+
233
+ **Exported functions:**
234
+ `;
235
+ exports.slice(0, 10).forEach(exp => {
236
+ content += `- \`${exp}\`\n`;
237
+ });
238
+ content += '\n';
239
+ }
240
+
241
+ // References
242
+ content += `## References
243
+
244
+ `;
245
+ if (pkg.homepage) {
246
+ content += `- [Documentation](${pkg.homepage})\n`;
247
+ }
248
+ if (pkg.repository?.url) {
249
+ const repoUrl = pkg.repository.url.replace(/^git\+/, '').replace(/\.git$/, '');
250
+ content += `- [GitHub](${repoUrl})\n`;
251
+ }
252
+ content += `- [npm](https://www.npmjs.com/package/${pkg.name})\n`;
253
+
254
+ return content;
255
+ }
256
+
257
+ // Main
258
+ async function main() {
259
+ console.log('skillify v0.0.1\n');
260
+
261
+ // Check if path exists
262
+ if (!fs.existsSync(targetPath)) {
263
+ console.error(`Error: Path not found: ${targetPath}`);
264
+ process.exit(1);
265
+ }
266
+
267
+ // Read package.json
268
+ const pkgPath = path.join(targetPath, 'package.json');
269
+ if (!fs.existsSync(pkgPath)) {
270
+ console.error(`Error: No package.json found at ${targetPath}`);
271
+ process.exit(1);
272
+ }
273
+
274
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
275
+ console.log(`Package: ${pkg.name}@${pkg.version}`);
276
+
277
+ // Extract CLI info
278
+ let cliFlags = [];
279
+ if (pkg.bin) {
280
+ const binPath = typeof pkg.bin === 'string'
281
+ ? path.join(targetPath, pkg.bin)
282
+ : path.join(targetPath, Object.values(pkg.bin)[0]);
283
+
284
+ if (fs.existsSync(binPath)) {
285
+ cliFlags = extractCliInfo(binPath);
286
+ console.log(`CLI flags found: ${cliFlags.length}`);
287
+ }
288
+ }
289
+
290
+ // Extract exports
291
+ let exports = [];
292
+ const mainPath = path.join(targetPath, pkg.main || 'index.js');
293
+ if (fs.existsSync(mainPath)) {
294
+ exports = extractExports(mainPath);
295
+ console.log(`Exports found: ${exports.length}`);
296
+ }
297
+
298
+ // Read README
299
+ let readme = '';
300
+ const readmePath = path.join(targetPath, 'README.md');
301
+ if (fs.existsSync(readmePath)) {
302
+ readme = fs.readFileSync(readmePath, 'utf8');
303
+ console.log(`README.md: ${readme.length} chars`);
304
+ }
305
+
306
+ // Generate SKILL.md
307
+ const skillMd = generateSkillMd(pkg, { cliFlags, exports, readme });
308
+
309
+ if (dryRun || stdout) {
310
+ console.log('\n--- Generated SKILL.md ---\n');
311
+ console.log(skillMd);
312
+ if (dryRun) {
313
+ console.log('--- dry-run: not written ---');
314
+ }
315
+ } else {
316
+ const outPath = outputPath || path.join(targetPath, 'SKILL.md');
317
+ fs.writeFileSync(outPath, skillMd);
318
+ console.log(`\nWritten: ${outPath}`);
319
+ }
320
+ }
321
+
322
+ main().catch(err => {
323
+ console.error(`Error: ${err.message}`);
324
+ process.exit(1);
325
+ });
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "skill-gen",
3
+ "version": "0.0.1",
4
+ "description": "Generate SKILL.md files for npm packages following Anthropic's Agent Skills specification",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "bin": {
8
+ "skill-gen": "./bin/skillify.js"
9
+ },
10
+ "keywords": [
11
+ "agent",
12
+ "skills",
13
+ "anthropic",
14
+ "claude",
15
+ "ai",
16
+ "documentation",
17
+ "npm"
18
+ ],
19
+ "author": "Melvin Carvalho",
20
+ "license": "MIT",
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "https://github.com/melvincarvalho/skillify"
24
+ },
25
+ "engines": {
26
+ "node": ">=18.0.0"
27
+ }
28
+ }