pm-claude-skills 29.3.0 → 29.3.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/icon.svg +11 -0
- package/mcp/server.mjs +133 -23
- package/package.json +5 -3
package/icon.svg
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="0 0 256 256" role="img" aria-label="PM Skills">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
|
|
4
|
+
<stop offset="0" stop-color="#e0855f"/>
|
|
5
|
+
<stop offset="1" stop-color="#d9605a"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
</defs>
|
|
8
|
+
<rect width="256" height="256" rx="56" fill="#0d0f14"/>
|
|
9
|
+
<rect x="18" y="18" width="220" height="220" rx="44" fill="url(#g)"/>
|
|
10
|
+
<text x="128" y="170" font-family="-apple-system, Segoe UI, Inter, Roboto, sans-serif" font-size="120" font-weight="800" text-anchor="middle" fill="#1a1207">PM</text>
|
|
11
|
+
</svg>
|
package/mcp/server.mjs
CHANGED
|
@@ -81,46 +81,146 @@ const WORKFLOWS = loadWorkflows();
|
|
|
81
81
|
const wfById = new Map(WORKFLOWS.map((w) => [w.id, w]));
|
|
82
82
|
|
|
83
83
|
// ── Tools ───────────────────────────────────────────────────────────────────
|
|
84
|
+
// Reusable output-schema fragments (so tools declare structured output, not just text).
|
|
85
|
+
const SKILL_ITEM = {
|
|
86
|
+
type: 'object',
|
|
87
|
+
properties: {
|
|
88
|
+
name: { type: 'string', description: 'The skill id (use with get_skill).' },
|
|
89
|
+
title: { type: 'string', description: 'Human-readable title.' },
|
|
90
|
+
tier: { type: 'string', description: 'Maturity tier: production | stable | experimental.' },
|
|
91
|
+
description: { type: 'string', description: 'One-line summary of what the skill does.' },
|
|
92
|
+
},
|
|
93
|
+
required: ['name', 'title', 'description'],
|
|
94
|
+
};
|
|
95
|
+
// All tools are read-only lookups over the bundled library — non-destructive, idempotent, closed-world.
|
|
96
|
+
const READONLY = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
97
|
+
|
|
84
98
|
const TOOLS = [
|
|
85
99
|
{
|
|
86
100
|
name: 'list_skills',
|
|
87
|
-
|
|
101
|
+
title: 'List skills',
|
|
102
|
+
description: 'List available professional skills (name, title, tier, one-line description). Optionally filter by maturity tier.',
|
|
88
103
|
inputSchema: {
|
|
89
104
|
type: 'object',
|
|
90
|
-
|
|
105
|
+
additionalProperties: false,
|
|
106
|
+
properties: { tier: { type: 'string', enum: ['production', 'stable', 'experimental'], description: 'Optional. Only return skills in this maturity tier.' } },
|
|
91
107
|
},
|
|
108
|
+
outputSchema: {
|
|
109
|
+
type: 'object',
|
|
110
|
+
properties: { count: { type: 'integer', description: 'Number of skills returned.' }, skills: { type: 'array', description: 'The matching skills.', items: SKILL_ITEM } },
|
|
111
|
+
required: ['count', 'skills'],
|
|
112
|
+
},
|
|
113
|
+
annotations: { title: 'List skills', ...READONLY },
|
|
92
114
|
},
|
|
93
115
|
{
|
|
94
116
|
name: 'search_skills',
|
|
95
|
-
|
|
117
|
+
title: 'Search skills',
|
|
118
|
+
description: 'Search skills by keyword across name, description, and body. Returns the best-matching skills, ranked.',
|
|
96
119
|
inputSchema: {
|
|
97
120
|
type: 'object',
|
|
98
|
-
|
|
121
|
+
additionalProperties: false,
|
|
122
|
+
properties: {
|
|
123
|
+
query: { type: 'string', description: 'Keywords describing the task, e.g. "prioritise backlog" or "customer churn".' },
|
|
124
|
+
limit: { type: 'integer', minimum: 1, maximum: 50, description: 'Maximum number of results to return (default 10).' },
|
|
125
|
+
},
|
|
99
126
|
required: ['query'],
|
|
100
127
|
},
|
|
128
|
+
outputSchema: {
|
|
129
|
+
type: 'object',
|
|
130
|
+
properties: { query: { type: 'string', description: 'The query that was searched.' }, matches: { type: 'array', description: 'Matching skills, best first.', items: SKILL_ITEM } },
|
|
131
|
+
required: ['query', 'matches'],
|
|
132
|
+
},
|
|
133
|
+
annotations: { title: 'Search skills', ...READONLY },
|
|
101
134
|
},
|
|
102
135
|
{
|
|
103
136
|
name: 'get_skill',
|
|
137
|
+
title: 'Get a skill',
|
|
104
138
|
description: 'Get the full instructions (the SKILL.md body) for one skill by name. Apply these instructions to the user\'s task.',
|
|
105
|
-
inputSchema: {
|
|
139
|
+
inputSchema: {
|
|
140
|
+
type: 'object',
|
|
141
|
+
additionalProperties: false,
|
|
142
|
+
properties: { name: { type: 'string', description: 'The exact skill id, e.g. "rice-prioritisation" (from list_skills / search_skills).' } },
|
|
143
|
+
required: ['name'],
|
|
144
|
+
},
|
|
145
|
+
outputSchema: {
|
|
146
|
+
type: 'object',
|
|
147
|
+
properties: { name: { type: 'string', description: 'The skill id.' }, title: { type: 'string', description: 'Human-readable title.' }, instructions: { type: 'string', description: 'The full SKILL.md body to apply to the task.' } },
|
|
148
|
+
required: ['name', 'instructions'],
|
|
149
|
+
},
|
|
150
|
+
annotations: { title: 'Get a skill', ...READONLY },
|
|
106
151
|
},
|
|
107
152
|
{
|
|
108
153
|
name: 'list_workflows',
|
|
154
|
+
title: 'List workflow recipes',
|
|
109
155
|
description: 'List workflow recipes — named chains that run several skills in sequence, passing each output forward (e.g. ship-a-feature, close-the-quarter). Use when a task spans multiple steps end to end.',
|
|
110
|
-
inputSchema: { type: 'object', properties: {} },
|
|
156
|
+
inputSchema: { type: 'object', additionalProperties: false, properties: {} },
|
|
157
|
+
outputSchema: {
|
|
158
|
+
type: 'object',
|
|
159
|
+
properties: {
|
|
160
|
+
workflows: {
|
|
161
|
+
type: 'array', description: 'Available workflow recipes.',
|
|
162
|
+
items: {
|
|
163
|
+
type: 'object',
|
|
164
|
+
properties: {
|
|
165
|
+
id: { type: 'string', description: 'Recipe id (use with get_workflow).' },
|
|
166
|
+
name: { type: 'string', description: 'Recipe name.' },
|
|
167
|
+
lifecycle: { type: 'string', description: 'The lifecycle stages it spans.' },
|
|
168
|
+
summary: { type: 'string', description: 'What the recipe accomplishes.' },
|
|
169
|
+
skills: { type: 'array', items: { type: 'string' }, description: 'The ordered skill ids in the chain.' },
|
|
170
|
+
},
|
|
171
|
+
required: ['id', 'name', 'skills'],
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
required: ['workflows'],
|
|
176
|
+
},
|
|
177
|
+
annotations: { title: 'List workflow recipes', ...READONLY },
|
|
111
178
|
},
|
|
112
179
|
{
|
|
113
180
|
name: 'get_workflow',
|
|
181
|
+
title: 'Get a workflow recipe',
|
|
114
182
|
description: 'Get one workflow recipe by id: the ordered list of skills to run and what each produces. Run each step in order with get_skill, carrying every output forward as context for the next.',
|
|
115
|
-
inputSchema: {
|
|
183
|
+
inputSchema: {
|
|
184
|
+
type: 'object',
|
|
185
|
+
additionalProperties: false,
|
|
186
|
+
properties: { id: { type: 'string', description: 'The workflow id, e.g. "ship-a-feature" (from list_workflows).' } },
|
|
187
|
+
required: ['id'],
|
|
188
|
+
},
|
|
189
|
+
outputSchema: {
|
|
190
|
+
type: 'object',
|
|
191
|
+
properties: {
|
|
192
|
+
id: { type: 'string', description: 'Recipe id.' },
|
|
193
|
+
name: { type: 'string', description: 'Recipe name.' },
|
|
194
|
+
lifecycle: { type: 'string', description: 'The lifecycle stages it spans.' },
|
|
195
|
+
summary: { type: 'string', description: 'What the recipe accomplishes.' },
|
|
196
|
+
steps: {
|
|
197
|
+
type: 'array', description: 'Ordered steps; run each with get_skill, carrying output forward.',
|
|
198
|
+
items: {
|
|
199
|
+
type: 'object',
|
|
200
|
+
properties: {
|
|
201
|
+
skill: { type: 'string', description: 'The skill id to run at this step.' },
|
|
202
|
+
produces: { type: 'string', description: 'What this step produces.' },
|
|
203
|
+
passes: { type: ['string', 'null'], description: 'What to carry forward to the next step.' },
|
|
204
|
+
},
|
|
205
|
+
required: ['skill'],
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
required: ['id', 'name', 'steps'],
|
|
210
|
+
},
|
|
211
|
+
annotations: { title: 'Get a workflow recipe', ...READONLY },
|
|
116
212
|
},
|
|
117
213
|
];
|
|
118
214
|
|
|
215
|
+
// Each tool returns { text, structured }: human-readable text content (back-compat) plus a
|
|
216
|
+
// structured object matching the tool's outputSchema.
|
|
217
|
+
const skillItem = (s) => ({ name: s.name, title: s.title, tier: s.tier, description: s.description });
|
|
218
|
+
|
|
119
219
|
function runTool(name, args = {}) {
|
|
120
220
|
if (name === 'list_skills') {
|
|
121
221
|
const list = SKILLS.filter((s) => !args.tier || s.tier === args.tier);
|
|
122
|
-
const text = list.map((s) => `- ${s.name} [${s.tier}] — ${s.description}`).join('\n');
|
|
123
|
-
return
|
|
222
|
+
const text = `${list.length} skills:\n` + list.map((s) => `- ${s.name} [${s.tier}] — ${s.description}`).join('\n');
|
|
223
|
+
return { text, structured: { count: list.length, skills: list.map(skillItem) } };
|
|
124
224
|
}
|
|
125
225
|
if (name === 'search_skills') {
|
|
126
226
|
const q = String(args.query || '').toLowerCase().trim();
|
|
@@ -136,27 +236,27 @@ function runTool(name, args = {}) {
|
|
|
136
236
|
}
|
|
137
237
|
return { s, score };
|
|
138
238
|
}).filter((x) => x.score > 0).sort((a, b) => b.score - a.score).slice(0, Math.max(1, Math.min(args.limit || 10, 50)));
|
|
139
|
-
|
|
140
|
-
|
|
239
|
+
const matches = scored.map(({ s }) => skillItem(s));
|
|
240
|
+
const text = matches.length ? matches.map((s) => `- ${s.name} [${s.tier}] — ${s.description}`).join('\n') : `No skills matched "${args.query}".`;
|
|
241
|
+
return { text, structured: { query: String(args.query || ''), matches } };
|
|
141
242
|
}
|
|
142
243
|
if (name === 'get_skill') {
|
|
143
244
|
const s = byName.get(String(args.name || '').trim());
|
|
144
245
|
if (!s) throw new Error(`Unknown skill "${args.name}". Use search_skills or list_skills to find one.`);
|
|
145
|
-
return s.body;
|
|
246
|
+
return { text: s.body, structured: { name: s.name, title: s.title, instructions: s.body } };
|
|
146
247
|
}
|
|
147
248
|
if (name === 'list_workflows') {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
).
|
|
249
|
+
const text = WORKFLOWS.length
|
|
250
|
+
? WORKFLOWS.map((w) => `- ${w.id} (${w.lifecycle}) — ${w.summary}\n chain: ${w.steps.map((s) => s.skill).join(' → ')}`).join('\n')
|
|
251
|
+
: 'No workflow recipes are available in this install.';
|
|
252
|
+
return { text, structured: { workflows: WORKFLOWS.map((w) => ({ id: w.id, name: w.name, lifecycle: w.lifecycle, summary: w.summary, skills: w.steps.map((s) => s.skill) })) } };
|
|
152
253
|
}
|
|
153
254
|
if (name === 'get_workflow') {
|
|
154
255
|
const w = wfById.get(String(args.id || '').trim());
|
|
155
256
|
if (!w) throw new Error(`Unknown workflow "${args.id}". Use list_workflows to see available recipes.`);
|
|
156
|
-
const steps = w.steps.map((s, i) =>
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
return `Workflow: ${w.name} (${w.lifecycle})\n${w.summary}\n\nRun these in order, carrying each output forward as context for the next:\n${steps}`;
|
|
257
|
+
const steps = w.steps.map((s, i) => `${i + 1}. get_skill("${s.skill}") → produces ${s.produces}.${s.passes ? ` Pass forward: ${s.passes}.` : ''}`).join('\n');
|
|
258
|
+
const text = `Workflow: ${w.name} (${w.lifecycle})\n${w.summary}\n\nRun these in order, carrying each output forward as context for the next:\n${steps}`;
|
|
259
|
+
return { text, structured: { id: w.id, name: w.name, lifecycle: w.lifecycle, summary: w.summary, steps: w.steps.map((s) => ({ skill: s.skill, produces: s.produces, passes: s.passes ?? null })) } };
|
|
160
260
|
}
|
|
161
261
|
throw new Error(`Unknown tool: ${name}`);
|
|
162
262
|
}
|
|
@@ -175,7 +275,17 @@ function handle(msg) {
|
|
|
175
275
|
return reply(id, {
|
|
176
276
|
protocolVersion: (params && params.protocolVersion) || '2024-11-05',
|
|
177
277
|
capabilities: { tools: {}, prompts: {}, resources: {} },
|
|
178
|
-
serverInfo: {
|
|
278
|
+
serverInfo: {
|
|
279
|
+
name: SERVER_NAME,
|
|
280
|
+
title: 'PM Skills — Professional Agent Skills',
|
|
281
|
+
version: VERSION,
|
|
282
|
+
websiteUrl: 'https://mohitagw15856.github.io/pm-claude-skills/',
|
|
283
|
+
icons: [{ src: 'https://raw.githubusercontent.com/mohitagw15856/pm-claude-skills/main/icon.svg', mimeType: 'image/svg+xml', sizes: ['any'] }],
|
|
284
|
+
},
|
|
285
|
+
instructions:
|
|
286
|
+
'A library of professional Agent Skills (PRDs, launches, postmortems, compliance, growth, and more) plus multi-skill workflow recipes. ' +
|
|
287
|
+
'To answer a professional task: call search_skills (or list_skills) to find the right skill, then get_skill to fetch its instructions and apply them to the user\'s input. ' +
|
|
288
|
+
'For multi-step work that spans discovery → decision → build → ship, use list_workflows / get_workflow and run the chained skills in order, carrying each output forward.',
|
|
179
289
|
});
|
|
180
290
|
case 'tools/list':
|
|
181
291
|
return reply(id, { tools: TOOLS });
|
|
@@ -211,8 +321,8 @@ function handle(msg) {
|
|
|
211
321
|
case 'tools/call': {
|
|
212
322
|
const toolName = params && params.name;
|
|
213
323
|
try {
|
|
214
|
-
const text = runTool(toolName, (params && params.arguments) || {});
|
|
215
|
-
return reply(id, { content: [{ type: 'text', text }] });
|
|
324
|
+
const { text, structured } = runTool(toolName, (params && params.arguments) || {});
|
|
325
|
+
return reply(id, { content: [{ type: 'text', text }], structuredContent: structured });
|
|
216
326
|
} catch (e) {
|
|
217
327
|
return reply(id, { content: [{ type: 'text', text: `Error: ${e.message}` }], isError: true });
|
|
218
328
|
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pm-claude-skills",
|
|
3
|
-
"version": "29.3.
|
|
3
|
+
"version": "29.3.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"mcpName": "io.github.mohitagw15856/pm-claude-skills",
|
|
6
|
-
"description": "
|
|
6
|
+
"description": "238 professional Agent Skills (SKILL.md) + subagents + slash commands for Claude, ChatGPT, Gemini, Cursor, Codex & Hermes. It's a CLI, not a library: run `npx pm-claude-skills add --agent <tool>` to install into your AI tool — no `npm install` needed. Or try any skill free at https://mohitagw15856.github.io/pm-claude-skills/",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"claude",
|
|
9
9
|
"claude-code",
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
"product-management"
|
|
23
23
|
],
|
|
24
24
|
"license": "MIT",
|
|
25
|
-
"homepage": "https://github.
|
|
25
|
+
"homepage": "https://mohitagw15856.github.io/pm-claude-skills/",
|
|
26
|
+
"icon": "icon.svg",
|
|
26
27
|
"repository": {
|
|
27
28
|
"type": "git",
|
|
28
29
|
"url": "https://github.com/mohitagw15856/pm-claude-skills.git"
|
|
@@ -40,6 +41,7 @@
|
|
|
40
41
|
"pm-claude-skills-mcp": "mcp/server.mjs"
|
|
41
42
|
},
|
|
42
43
|
"files": [
|
|
44
|
+
"icon.svg",
|
|
43
45
|
"bin/",
|
|
44
46
|
"mcp/",
|
|
45
47
|
"skills/",
|