skilldrop-cli 0.8.4 → 0.9.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 +4 -0
- package/agents/README.md +22 -0
- package/bin/skilldrop.js +218 -4
- package/model-routing.json +2 -2
- package/package.json +1 -1
- package/skills/adr-generator/evals/eval_queries.json +34 -0
- package/skills/adr-generator/evals/evals.json +17 -0
- package/skills/api-contract-draft/evals/eval_queries.json +34 -0
- package/skills/api-contract-draft/evals/evals.json +18 -0
- package/skills/architecture-diagrams/evals/eval_queries.json +34 -0
- package/skills/architecture-diagrams/evals/evals.json +16 -0
- package/skills/audience-profile/evals/eval_queries.json +34 -0
- package/skills/audience-profile/evals/evals.json +15 -0
- package/skills/brief-intake/evals/eval_queries.json +34 -0
- package/skills/brief-intake/evals/evals.json +16 -0
- package/skills/council-review/evals/eval_queries.json +38 -0
- package/skills/council-review/evals/evals.json +18 -0
- package/skills/data-contract/evals/eval_queries.json +34 -0
- package/skills/data-contract/evals/evals.json +16 -0
- package/skills/db-schema-design/evals/eval_queries.json +34 -0
- package/skills/db-schema-design/evals/evals.json +16 -0
- package/skills/decision-log/evals/eval_queries.json +34 -0
- package/skills/decision-log/evals/evals.json +17 -0
- package/skills/deck-builder/evals/eval_queries.json +34 -0
- package/skills/deck-builder/evals/evals.json +17 -0
- package/skills/design-doc/evals/eval_queries.json +34 -0
- package/skills/design-doc/evals/evals.json +17 -0
- package/skills/devils-advocate/evals/eval_queries.json +38 -0
- package/skills/devils-advocate/evals/evals.json +19 -0
- package/skills/doc-critique/evals/eval_queries.json +38 -0
- package/skills/doc-critique/evals/evals.json +17 -0
- package/skills/exec-summary/evals/eval_queries.json +34 -0
- package/skills/exec-summary/evals/evals.json +17 -0
- package/skills/figma-diagrams/evals/eval_queries.json +34 -0
- package/skills/figma-diagrams/evals/evals.json +15 -0
- package/skills/incident-comms/evals/eval_queries.json +34 -0
- package/skills/incident-comms/evals/evals.json +16 -0
- package/skills/nfr-spec/evals/eval_queries.json +34 -0
- package/skills/nfr-spec/evals/evals.json +16 -0
- package/skills/observability-plan/evals/eval_queries.json +34 -0
- package/skills/observability-plan/evals/evals.json +16 -0
- package/skills/postmortem-generator/evals/eval_queries.json +34 -0
- package/skills/postmortem-generator/evals/evals.json +17 -0
- package/skills/prd-draft/evals/eval_queries.json +34 -0
- package/skills/prd-draft/evals/evals.json +17 -0
- package/skills/requirements-interview/evals/eval_queries.json +34 -0
- package/skills/requirements-interview/evals/evals.json +16 -0
- package/skills/reverse-architecture/evals/eval_queries.json +34 -0
- package/skills/reverse-architecture/evals/evals.json +16 -0
- package/skills/runbook-generator/evals/eval_queries.json +34 -0
- package/skills/runbook-generator/evals/evals.json +17 -0
- package/skills/slide-outliner/evals/eval_queries.json +34 -0
- package/skills/slide-outliner/evals/evals.json +16 -0
- package/skills/sonar-onboard/evals/eval_queries.json +34 -0
- package/skills/sonar-onboard/evals/evals.json +16 -0
- package/skills/sonar-review/evals/eval_queries.json +34 -0
- package/skills/sonar-review/evals/evals.json +16 -0
- package/skills/threat-model/evals/eval_queries.json +34 -0
- package/skills/threat-model/evals/evals.json +18 -0
package/README.md
CHANGED
|
@@ -14,6 +14,8 @@ npx skilldrop-cli list # sre-oncall, stakehold
|
|
|
14
14
|
|
|
15
15
|
Originally scoped to solution architects, now broadly useful to PMs, founders, consultants, engineering leaders, exec assistants — anyone who turns ideas into stakeholder-ready artifacts.
|
|
16
16
|
|
|
17
|
+
Every skill is a plain `SKILL.md` folder — the [**Agent Skills open standard**](https://agentskills.io) Anthropic ratified — so the same folder runs unchanged in Claude.ai, Claude Code, the Claude Agent SDK, Cursor, Kiro, Codex, Copilot, Antigravity, and anything else that reads the format. Portable by construction: no runtime, no platform, no lock-in.
|
|
18
|
+
|
|
17
19
|
**Why skilldrop over heavier agent platforms:** every skill is a plain folder (`SKILL.md` + `manifest.json` + supporting files) and installs by *copy, never transformation* — what runs in your IDE is byte-identical to what's reviewed in this repo. The flat layout doubles as an open catalog contract: [any repo shaped like this one](#third-party-catalogs--publish-your-own-skills-through-the-same-cli) is installable through the same CLI. Skills are *opinionated* — each ships a quality bar, anti-patterns, and acceptance evals, so the output is an artifact, not a vibe.
|
|
18
20
|
|
|
19
21
|
## How skilldrop works
|
|
@@ -259,8 +261,10 @@ npx skilldrop-cli install --pack sre-oncall --ide kiro # .kiro/skills — Kiro
|
|
|
259
261
|
npx skilldrop-cli install adr-generator --dest .agents/skills # Codex + Copilot CLI (see below)
|
|
260
262
|
npx skilldrop-cli agents # the reviewer subagents
|
|
261
263
|
npx skilldrop-cli install --agent devils-advocate # -> ~/.claude/agents/ (RFC-0012)
|
|
264
|
+
npx skilldrop-cli install --panel review # the whole review fleet: 3 subagents + the pre-merge-review orchestrator (RFC-0020)
|
|
262
265
|
npx skilldrop-cli outdated && npx skilldrop-cli update # skills improve; cp -R never tells you
|
|
263
266
|
npx skilldrop-cli list | skilldrop info <skill> | skilldrop packs | skilldrop uninstall <skill>
|
|
267
|
+
npx skilldrop-cli list --json # machine-readable: list/info/packs/agents/outdated (RFC-0021)
|
|
264
268
|
```
|
|
265
269
|
|
|
266
270
|
`--with-related` also pulls each skill's companions. From a clone (or before the package is published): `node bin/skilldrop.js <same args>`. Scope and design: [RFC-0002](docs/rfcs/0002-skilldrop-cli.md), full command surface in [`docs/designs/skilldrop-cli-design.md`](docs/designs/skilldrop-cli-design.md).
|
package/agents/README.md
CHANGED
|
@@ -26,6 +26,28 @@ npx skilldrop-cli install --agent devils-advocate --ide kiro # .kiro/agents/*.
|
|
|
26
26
|
|
|
27
27
|
They are deliberately **split, not merged.** A single "review my code" agent dilutes all three — bug-hunting, craft, and exploitability pull in different directions. Run them as separate passes; together they are the reviewer panel [`feature-implement-loop`](../skills/feature-implement-loop/SKILL.md) drives after each generation round. `devils-advocate` here is the subagent form of the [`devils-advocate` skill](../skills/devils-advocate/SKILL.md); same persona, packaged for a tool's native agent slot instead of on-demand skill invocation.
|
|
28
28
|
|
|
29
|
+
## Fire them as a panel
|
|
30
|
+
|
|
31
|
+
The three reviewers are meant to run **together** on a change. Install the whole fleet in one command:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx skilldrop-cli install --panel review # 3 subagents + the pre-merge-review orchestrator -> ~/.claude/
|
|
35
|
+
npx skilldrop-cli install --panel review --project # .claude/ (shared with the repo)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The [`pre-merge-review`](../skills/pre-merge-review/SKILL.md) skill is the **portable orchestrator** — it dispatches the three as **parallel subagents** where the tool has a native subagent runner, and sweeps the lenses inline otherwise. The orchestration lives in the *skill* (portable); the reviewers are *native subagents* (per-tool):
|
|
39
|
+
|
|
40
|
+
| Tool | How the panel fires in parallel |
|
|
41
|
+
|---|---|
|
|
42
|
+
| **Claude Code** | Native parallel subagents — `pre-merge-review` fires all three at once. `--panel review` installs both halves. |
|
|
43
|
+
| **Kiro** | Native subagents — `--panel review --ide kiro` installs both halves. |
|
|
44
|
+
| **Codex** | Multi-agent runner — install the agents (`--agent … --ide codex`) + the skill; Codex runs the fleet in parallel (confirm the invocation against your Codex version). |
|
|
45
|
+
| **Antigravity** | Lead → specialist delegation — install the agents (`--agent … --ide antigravity`) + the skill; the lead agent delegates to the three, each in its own context. |
|
|
46
|
+
| **Copilot** | Agents install (`--agent … --ide copilot`); the skill drives them — sequentially unless your Copilot build exposes parallel subagents. |
|
|
47
|
+
| **Cursor** | No agent format — `pre-merge-review` sweeps the three lenses inline (no subagents). |
|
|
48
|
+
|
|
49
|
+
Designing your own fleet? Use [`subagent-design`](../skills/subagent-design/SKILL.md) — the reviewer panel is its "judge panel" topology.
|
|
50
|
+
|
|
29
51
|
## Installing an agent into your tool
|
|
30
52
|
|
|
31
53
|
### Claude Code (native subagents)
|
package/bin/skilldrop.js
CHANGED
|
@@ -20,6 +20,16 @@ const BUNDLED = "bundled";
|
|
|
20
20
|
// Neutral hook vocabulary (RFC-0006). Kept in sync with validate.py's HOOK_EVENTS.
|
|
21
21
|
const HOOK_EVENTS = ["session-start", "pre-commit-review", "on-demand"];
|
|
22
22
|
|
|
23
|
+
// Panels (RFC-0020): a named bundle of reviewer subagents + the orchestrator skill that fires
|
|
24
|
+
// them in parallel. `install --panel <name>` installs the whole fleet in one command.
|
|
25
|
+
const PANELS = {
|
|
26
|
+
review: {
|
|
27
|
+
agents: ["devils-advocate", "security-reviewer", "code-quality"],
|
|
28
|
+
skill: "pre-merge-review",
|
|
29
|
+
blurb: "correctness + security + craft reviewers, fired in parallel by pre-merge-review",
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
23
33
|
const HELP = `skilldrop — portable AI-agent skills for Claude Code, Cursor, Kiro, and more
|
|
24
34
|
|
|
25
35
|
Usage:
|
|
@@ -31,11 +41,16 @@ Usage:
|
|
|
31
41
|
skilldrop install --pack <name> install a whole pack
|
|
32
42
|
skilldrop install --all install every skill in the catalog
|
|
33
43
|
skilldrop install --agent <name...> install reviewer subagents (RFC-0012)
|
|
44
|
+
skilldrop install --panel review install the review panel — the 3 reviewer subagents +
|
|
45
|
+
the pre-merge-review orchestrator that fires them (RFC-0020)
|
|
34
46
|
skilldrop update re-copy installed skills whose version changed
|
|
35
47
|
skilldrop outdated show installed vs current versions, change nothing
|
|
36
48
|
skilldrop uninstall <skill...> remove skills (and wiring files this tool wrote)
|
|
37
49
|
skilldrop uninstall --agent <name...> remove subagents
|
|
38
50
|
skilldrop validate [--from <src>] structural check of a catalog (for catalog authors)
|
|
51
|
+
skilldrop scan [<skill...>] [--from <src>] supply-chain scan — flag network/exec/credential
|
|
52
|
+
patterns in scripts and injection-shaped instructions
|
|
53
|
+
in SKILL.md before you trust a catalog (RFC-0022)
|
|
39
54
|
|
|
40
55
|
Catalogs:
|
|
41
56
|
(default) the catalog bundled with this package
|
|
@@ -60,6 +75,8 @@ Options:
|
|
|
60
75
|
--ide antigravity ~/.gemini/config/agents markdown, subagent: true
|
|
61
76
|
--dest <dir> any directory copied as-is
|
|
62
77
|
Cursor has no agent format — use a custom mode (agents/README.md).
|
|
78
|
+
--json machine-readable output for list | info | packs | agents | outdated —
|
|
79
|
+
one JSON object on stdout, nothing else (for agents, scripts, CI)
|
|
63
80
|
--with-related also install each skill's related companions (one level)
|
|
64
81
|
--with-hooks also wire any hooks a skill declares (RFC-0006) — git pre-commit
|
|
65
82
|
reminders and Claude Code session-start context; degrades where the
|
|
@@ -70,11 +87,16 @@ Options:
|
|
|
70
87
|
function die(msg) { console.error("error: " + msg); process.exit(1); }
|
|
71
88
|
function readJSON(p) { return JSON.parse(fs.readFileSync(p, "utf8")); }
|
|
72
89
|
|
|
90
|
+
/* --json (RFC-0021): the read commands emit one machine-readable object on stdout and nothing
|
|
91
|
+
else, so an agent or script can consume them without scraping aligned columns. Human output is
|
|
92
|
+
unchanged by default — this is additive. Errors still go to stderr and exit non-zero. */
|
|
93
|
+
function emitJSON(obj) { console.log(JSON.stringify(obj, null, 2)); }
|
|
94
|
+
|
|
73
95
|
function parseArgs(argv) {
|
|
74
96
|
const out = { _: [], flags: {} };
|
|
75
97
|
for (let i = 0; i < argv.length; i++) {
|
|
76
98
|
const a = argv[i];
|
|
77
|
-
if (a === "--pack" || a === "--ide" || a === "--dest" || a === "--from") out.flags[a.slice(2)] = argv[++i];
|
|
99
|
+
if (a === "--pack" || a === "--ide" || a === "--dest" || a === "--from" || a === "--panel") out.flags[a.slice(2)] = argv[++i];
|
|
78
100
|
else if (a.startsWith("--")) out.flags[a.slice(2)] = true;
|
|
79
101
|
else out._.push(a);
|
|
80
102
|
}
|
|
@@ -264,6 +286,117 @@ function gate(cat, names) {
|
|
|
264
286
|
if (bad) die(`${bad} skill(s) failed the structural check — nothing was installed`);
|
|
265
287
|
}
|
|
266
288
|
|
|
289
|
+
/* ---------- supply-chain scan (RFC-0022) ----------
|
|
290
|
+
A skill is instruction prose an agent will obey, and its scripts are code that runs on the
|
|
291
|
+
user's machine — so installing a third-party catalog is a supply-chain event. Anthropic's own
|
|
292
|
+
Skills guidance says to audit a skill's files for "unexpected network calls, file access
|
|
293
|
+
patterns, or operations that don't match the Skill's stated purpose"; this automates that first
|
|
294
|
+
pass. It is a HEURISTIC that reports — it never blocks and never replaces reading the skill.
|
|
295
|
+
|
|
296
|
+
Two rule sets, deliberately different:
|
|
297
|
+
- SCRIPT_RULES run over executable files (real code): network, exec, credential, obfuscation.
|
|
298
|
+
- PROSE_RULES run over SKILL.md and only match *instructions to misbehave* — not security
|
|
299
|
+
vocabulary, so a skill that legitimately discusses injection (threat-model) isn't flagged. */
|
|
300
|
+
|
|
301
|
+
const SCRIPT_EXT = new Set([".py", ".js", ".mjs", ".cjs", ".sh", ".bash", ".zsh", ".rb", ".pl", ".ps1"]);
|
|
302
|
+
|
|
303
|
+
const SCRIPT_RULES = [
|
|
304
|
+
{ id: "exec-remote", sev: "🟥", why: "downloads and executes remote content — the classic supply-chain payload",
|
|
305
|
+
re: /(curl|wget)[^\n|]*\|\s*(sudo\s+)?(ba|z|)sh|eval\s*\(\s*(requests|urllib|fetch)|base64\s+(-d|--decode)[^\n|]*\|\s*(ba|z|)sh/i },
|
|
306
|
+
{ id: "shell-exec", sev: "🟧", why: "executes shell commands",
|
|
307
|
+
re: /\b(os\.system|subprocess\.(run|call|Popen|check_output)|child_process|execSync|spawnSync|shell_exec|`[^`\n]*\$\()/ },
|
|
308
|
+
{ id: "network", sev: "🟧", why: "makes outbound network calls",
|
|
309
|
+
re: /\b(requests\.(get|post|put)|urllib\.request|httpx\.|axios\.|node-fetch|\bfetch\s*\(\s*["'`]https?:|curl\s+https?:|wget\s+https?:)/i },
|
|
310
|
+
{ id: "credentials", sev: "🟧", why: "reads credentials or secret material",
|
|
311
|
+
re: /\b(os\.environ|process\.env)\b[^\n]{0,40}(TOKEN|KEY|SECRET|PASSWORD|CREDENTIAL)|~\/\.(aws|ssh|npmrc|netrc)|\.env\b|id_rsa/i },
|
|
312
|
+
{ id: "broad-fs", sev: "🟨", why: "writes outside the skill's own directory",
|
|
313
|
+
re: /\b(shutil\.rmtree|rm\s+-rf\s+[~/]|open\s*\(\s*["'`]\/(etc|usr|bin)|fs\.(unlink|rmSync)\s*\([^)]*\.\.\/)/ },
|
|
314
|
+
];
|
|
315
|
+
|
|
316
|
+
const PROSE_RULES = [
|
|
317
|
+
{ id: "instruction-override", sev: "🟥", why: "tells the agent to ignore its prior instructions",
|
|
318
|
+
re: /ignore\s+(all\s+)?(previous|prior|earlier|above|preceding)\s+(instructions|prompts|rules)/i },
|
|
319
|
+
{ id: "conceal-from-user", sev: "🟥", why: "tells the agent to hide actions from the user",
|
|
320
|
+
re: /(do\s*n[o']?t|never|without)\s+(tell|telling|inform|informing|notify|notifying|mention|mentioning)\s+(the\s+)?(user|human)/i },
|
|
321
|
+
{ id: "memory-overwrite", sev: "🟥", why: "instructs the agent to rewrite its own persistent memory/identity",
|
|
322
|
+
re: /(update|overwrite|append\s+to|modify)\s+your\s+(own\s+)?(SOUL|MEMORY|CLAUDE|AGENTS)\.md/i },
|
|
323
|
+
{ id: "prose-exfil", sev: "🟧", why: "instructs the agent to send data to an external endpoint",
|
|
324
|
+
re: /\b(POST|send|upload|transmit)\b[^\n.]{0,60}\bto\s+https?:\/\//i },
|
|
325
|
+
];
|
|
326
|
+
|
|
327
|
+
function walkFiles(dir, out = []) {
|
|
328
|
+
for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
329
|
+
const p = path.join(dir, e.name);
|
|
330
|
+
if (e.isDirectory()) walkFiles(p, out);
|
|
331
|
+
else out.push(p);
|
|
332
|
+
}
|
|
333
|
+
return out;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/* Scan one skill. Returns [{sev, id, why, file, line, text}] — worst first. */
|
|
337
|
+
function scanSkill(cat, s) {
|
|
338
|
+
const dir = skillDir(cat, s);
|
|
339
|
+
const findings = [];
|
|
340
|
+
if (!dir || !fs.existsSync(dir)) return findings;
|
|
341
|
+
for (const file of walkFiles(dir)) {
|
|
342
|
+
const rel = path.relative(dir, file);
|
|
343
|
+
const ext = path.extname(file).toLowerCase();
|
|
344
|
+
const isScript = SCRIPT_EXT.has(ext);
|
|
345
|
+
const isProse = path.basename(file) === "SKILL.md";
|
|
346
|
+
if (!isScript && !isProse) continue;
|
|
347
|
+
let body = "";
|
|
348
|
+
try { body = fs.readFileSync(file, "utf8"); } catch (e) { continue; }
|
|
349
|
+
const rules = isScript ? SCRIPT_RULES : PROSE_RULES;
|
|
350
|
+
body.split(/\r?\n/).forEach((line, i) => {
|
|
351
|
+
if (line.length > 400) return; // minified/data line — not reviewable prose or code
|
|
352
|
+
for (const r of rules) {
|
|
353
|
+
if (r.re.test(line))
|
|
354
|
+
findings.push({ sev: r.sev, id: r.id, why: r.why, file: rel, line: i + 1, text: line.trim().slice(0, 120) });
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
const order = { "🟥": 0, "🟧": 1, "🟨": 2, "⚪": 3 };
|
|
359
|
+
return findings.sort((a, b) => order[a.sev] - order[b.sev]);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function printScan(cat, names, { compact = false } = {}) {
|
|
363
|
+
let total = 0, worst = null;
|
|
364
|
+
for (const s of names) {
|
|
365
|
+
const f = scanSkill(cat, s);
|
|
366
|
+
if (!f.length) continue;
|
|
367
|
+
total += f.length;
|
|
368
|
+
if (!worst || f[0].sev === "🟥") worst = worst === "🟥" ? worst : f[0].sev;
|
|
369
|
+
console.log(`\n${s}`);
|
|
370
|
+
for (const x of (compact ? f.slice(0, 3) : f))
|
|
371
|
+
console.log(` ${x.sev} ${x.id} — ${x.why}\n ${x.file}:${x.line} ${x.text}`);
|
|
372
|
+
if (compact && f.length > 3) console.log(` … ${f.length - 3} more (skilldrop scan ${s} --from ${cat.source})`);
|
|
373
|
+
}
|
|
374
|
+
return { total, worst };
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function scan(args) {
|
|
378
|
+
const cat = resolveCatalog(args.flags.from);
|
|
379
|
+
const names = args._.length ? args._.slice() : skillsIn(cat);
|
|
380
|
+
for (const s of names) if (!skillExists(cat, s)) die(`unknown skill '${s}' in catalog '${cat.source}'`);
|
|
381
|
+
|
|
382
|
+
if (args.flags.json) {
|
|
383
|
+
const out = names.map((s) => ({ skill: s, findings: scanSkill(cat, s) })).filter((r) => r.findings.length);
|
|
384
|
+
return emitJSON({
|
|
385
|
+
catalog: cat.source, scanned: names.length,
|
|
386
|
+
flagged: out.length, findingCount: out.reduce((n, r) => n + r.findings.length, 0), skills: out,
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
console.log(`Scanning ${names.length} skill(s) in catalog '${cat.source}' for supply-chain patterns…`);
|
|
390
|
+
const { total } = printScan(cat, names);
|
|
391
|
+
if (!total) {
|
|
392
|
+
console.log("\nNo flagged patterns found.");
|
|
393
|
+
} else {
|
|
394
|
+
console.log(`\n${total} flagged pattern(s). These are HEURISTICS, not verdicts — a match can be` +
|
|
395
|
+
` entirely legitimate (a skill that is *about* security, or a script that genuinely needs the network).`);
|
|
396
|
+
console.log("Read the cited lines before installing. Nothing here is executed by skilldrop; installs copy files only.");
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
267
400
|
/* ---------- install targets & ledger ---------- */
|
|
268
401
|
|
|
269
402
|
function target(flags) {
|
|
@@ -567,7 +700,33 @@ function copyOne(cat, s, dest, ide, l, notes) {
|
|
|
567
700
|
return m;
|
|
568
701
|
}
|
|
569
702
|
|
|
703
|
+
/* Install a whole review panel — the reviewer subagents + the orchestrator skill — in one
|
|
704
|
+
command (RFC-0020). Needs a target with BOTH a subagent and a skill format, so it accepts
|
|
705
|
+
the default (Claude Code), --project, --ide kiro, or --dest; other IDEs install the halves
|
|
706
|
+
separately. Delegates to installAgents + install so every existing safety/craft gate applies. */
|
|
707
|
+
function installPanel(args) {
|
|
708
|
+
const name = args.flags.panel;
|
|
709
|
+
const p = PANELS[name];
|
|
710
|
+
if (!p) die(`unknown panel '${name}' — available: ${Object.keys(PANELS).join(", ")}`);
|
|
711
|
+
const ide = args.flags.ide;
|
|
712
|
+
if (ide && ide !== "kiro" && !args.flags.dest)
|
|
713
|
+
die(`--panel installs subagents + the orchestrator skill together, so it needs a target with both formats:\n` +
|
|
714
|
+
` (default | --project) Claude Code, --ide kiro, or --dest <dir>.\n` +
|
|
715
|
+
` For ${ide}: install the agents (skilldrop install --agent ${p.agents.join(" ")} --ide ${ide}) ` +
|
|
716
|
+
`and the skill (skilldrop install ${p.skill} --ide ${ide}) separately.`);
|
|
717
|
+
const flags = Object.assign({}, args.flags);
|
|
718
|
+
delete flags.panel;
|
|
719
|
+
console.log(`Installing the '${name}' panel — ${p.agents.length} reviewer subagents + the ${p.skill} orchestrator skill.\n`);
|
|
720
|
+
installAgents({ _: p.agents.slice(), flags: Object.assign({}, flags, { agent: true }) });
|
|
721
|
+
console.log("");
|
|
722
|
+
install({ _: [p.skill], flags });
|
|
723
|
+
console.log(`\nPanel installed. Fire it with the ${p.skill} skill — e.g. "run a pre-merge review on this change".`);
|
|
724
|
+
console.log(`It dispatches the three subagents in parallel where your tool has native subagents (Claude Code today;`);
|
|
725
|
+
console.log(`Codex / Antigravity multi-agent runners), and sweeps the lenses inline otherwise. Per-tool: agents/README.md.`);
|
|
726
|
+
}
|
|
727
|
+
|
|
570
728
|
function install(args) {
|
|
729
|
+
if (args.flags.panel) return installPanel(args);
|
|
571
730
|
if (args.flags.agent) return installAgents(args);
|
|
572
731
|
const cat = resolveCatalog(args.flags.from);
|
|
573
732
|
let names = expandNames(args, cat);
|
|
@@ -605,8 +764,15 @@ function install(args) {
|
|
|
605
764
|
console.log(`\n${withHooks.join(", ")} declare hooks — re-run with --with-hooks to wire them (git pre-commit reminders / session-start context).`);
|
|
606
765
|
}
|
|
607
766
|
|
|
608
|
-
if (cat.source !== BUNDLED)
|
|
767
|
+
if (cat.source !== BUNDLED) {
|
|
609
768
|
console.log(`\nWARNING: third-party catalog '${cat.source}'. Skills are instructions your AI agent will follow — review each installed SKILL.md under ${dest} before first use. Install copied files only; nothing was executed.`);
|
|
769
|
+
// Supply-chain scan (RFC-0022): surface risky patterns at the moment of trust. Reports only —
|
|
770
|
+
// the files are already copied, and a match is a prompt to read, not a verdict.
|
|
771
|
+
const { total } = printScan(cat, names, { compact: true });
|
|
772
|
+
console.log(total
|
|
773
|
+
? `\n${total} pattern(s) worth reading before you trust these skills. Full detail: skilldrop scan --from ${cat.source}`
|
|
774
|
+
: "\nSupply-chain scan: no flagged patterns.");
|
|
775
|
+
}
|
|
610
776
|
if (ide === "generic")
|
|
611
777
|
console.log("wiring: attach each skill's SKILL.md to your agent (Continue/Cline: @file, Aider: /add, Codex: reference it from AGENTS.md) — see the repo README's per-IDE steps.");
|
|
612
778
|
for (const s of pipDeps)
|
|
@@ -649,8 +815,18 @@ function update(args) {
|
|
|
649
815
|
|
|
650
816
|
function outdated(args) {
|
|
651
817
|
const { dest, rows } = installedRows(args.flags);
|
|
652
|
-
if (!rows.length) return console.log(`nothing installed at ${dest}`);
|
|
653
818
|
const stale = rows.filter((r) => r.current && r.current !== r.installed);
|
|
819
|
+
if (args.flags.json)
|
|
820
|
+
return emitJSON({
|
|
821
|
+
dest,
|
|
822
|
+
count: rows.length,
|
|
823
|
+
outdatedCount: stale.length,
|
|
824
|
+
skills: rows.map((r) => ({
|
|
825
|
+
name: r.s, installed: r.installed, current: r.current,
|
|
826
|
+
source: r.src, outdated: !!(r.current && r.current !== r.installed),
|
|
827
|
+
})),
|
|
828
|
+
});
|
|
829
|
+
if (!rows.length) return console.log(`nothing installed at ${dest}`);
|
|
654
830
|
for (const r of stale) console.log(`${r.s}: installed ${r.installed}, current ${r.current} (${r.src})`);
|
|
655
831
|
console.log(stale.length ? `\n${stale.length} outdated — run: skilldrop update` : "everything up to date.");
|
|
656
832
|
}
|
|
@@ -674,6 +850,15 @@ function uninstall(args) {
|
|
|
674
850
|
function listAgents(args) {
|
|
675
851
|
const cat = resolveCatalog(args.flags.from);
|
|
676
852
|
const names = agentsIn(cat);
|
|
853
|
+
if (args.flags.json)
|
|
854
|
+
return emitJSON({
|
|
855
|
+
catalog: cat.source,
|
|
856
|
+
count: names.length,
|
|
857
|
+
agents: names.map((a) => {
|
|
858
|
+
const m = agentMeta(cat, a);
|
|
859
|
+
return { name: a, description: m.description || null, tools: m.tools || null, model: m.model || null };
|
|
860
|
+
}),
|
|
861
|
+
});
|
|
677
862
|
if (!names.length) return console.log(`catalog '${cat.source}' ships no agents.`);
|
|
678
863
|
const w = Math.max(...names.map((n) => n.length));
|
|
679
864
|
for (const a of names) {
|
|
@@ -741,6 +926,12 @@ function list(args) {
|
|
|
741
926
|
try { const m = manifestOf(cat, s); return [s, m.version || "?", (m.model && m.model.tier) || "?"]; }
|
|
742
927
|
catch (e) { return [s, "?", "?"]; }
|
|
743
928
|
});
|
|
929
|
+
if (args.flags.json)
|
|
930
|
+
return emitJSON({
|
|
931
|
+
catalog: cat.source,
|
|
932
|
+
count: rows.length,
|
|
933
|
+
skills: rows.map(([name, version, tier]) => ({ name, version, tier })),
|
|
934
|
+
});
|
|
744
935
|
const w = Math.max(...rows.map((r) => r[0].length));
|
|
745
936
|
for (const [s, v, t] of rows) console.log(`${s.padEnd(w)} ${v} ${t}`);
|
|
746
937
|
console.log(`\n${rows.length} skills in catalog '${cat.source}'. Details: skilldrop info <skill>`);
|
|
@@ -753,6 +944,21 @@ function info(args) {
|
|
|
753
944
|
const m = manifestOf(cat, s);
|
|
754
945
|
const ps = packsOf(cat) || {};
|
|
755
946
|
const inPacks = Object.entries(ps).filter(([, p]) => p.skills.includes(s)).map(([n]) => n);
|
|
947
|
+
const needsPip = ((m.deps || {}).pip || []).length > 0 || fs.existsSync(path.join(skillDir(cat, s), "requirements.txt"));
|
|
948
|
+
if (args.flags.json)
|
|
949
|
+
return emitJSON({
|
|
950
|
+
catalog: cat.source,
|
|
951
|
+
name: m.name,
|
|
952
|
+
version: m.version || null,
|
|
953
|
+
description: m.description || null,
|
|
954
|
+
tier: (m.model && m.model.tier) || null,
|
|
955
|
+
packs: inPacks,
|
|
956
|
+
related: m.related || [],
|
|
957
|
+
tags: m.tags || [],
|
|
958
|
+
deps: { pip: (m.deps || {}).pip || [], npm: (m.deps || {}).npm || [], requirementsTxt: needsPip },
|
|
959
|
+
env: { required: (m.env || {}).required || [], optional: (m.env || {}).optional || [] },
|
|
960
|
+
hooks: m.hooks || [],
|
|
961
|
+
});
|
|
756
962
|
console.log(`${m.name}@${m.version} (tier: ${(m.model && m.model.tier) || "n/a"})\n\n${m.description}\n`);
|
|
757
963
|
console.log(`catalog: ${cat.source}`);
|
|
758
964
|
console.log(`packs: ${inPacks.join(", ") || "-"}`);
|
|
@@ -765,6 +971,14 @@ function info(args) {
|
|
|
765
971
|
function listPacks(args) {
|
|
766
972
|
const cat = resolveCatalog(args.flags.from);
|
|
767
973
|
const ps = packsOf(cat);
|
|
974
|
+
if (args.flags.json)
|
|
975
|
+
return emitJSON({
|
|
976
|
+
catalog: cat.source,
|
|
977
|
+
count: ps ? Object.keys(ps).length : 0,
|
|
978
|
+
packs: Object.entries(ps || {}).map(([name, p]) => ({
|
|
979
|
+
name, description: p.description || null, skills: p.skills || [],
|
|
980
|
+
})),
|
|
981
|
+
});
|
|
768
982
|
if (!ps) return console.log(`catalog '${cat.source}' defines no packs.`);
|
|
769
983
|
const w = Math.max(...Object.keys(ps).map((n) => n.length));
|
|
770
984
|
for (const [n, p] of Object.entries(ps))
|
|
@@ -792,7 +1006,7 @@ function validateCmd(args) {
|
|
|
792
1006
|
|
|
793
1007
|
const args = parseArgs(process.argv.slice(2));
|
|
794
1008
|
const cmd = args._.shift();
|
|
795
|
-
const commands = { list, info, packs: listPacks, agents: listAgents, install, update, outdated, uninstall, validate: validateCmd };
|
|
1009
|
+
const commands = { list, info, packs: listPacks, agents: listAgents, install, update, outdated, uninstall, validate: validateCmd, scan };
|
|
796
1010
|
if (!cmd || cmd === "help" || args.flags.help) console.log(HELP);
|
|
797
1011
|
else if (commands[cmd]) commands[cmd](args);
|
|
798
1012
|
else die(`unknown command '${cmd}' — run: skilldrop help`);
|
package/model-routing.json
CHANGED
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
"label": "Claude Code (Anthropic)",
|
|
22
22
|
"models": {
|
|
23
23
|
"light": "claude-haiku-4-5-20251001",
|
|
24
|
-
"standard": "claude-sonnet-
|
|
25
|
-
"heavy": "claude-opus-
|
|
24
|
+
"standard": "claude-sonnet-5",
|
|
25
|
+
"heavy": "claude-opus-5"
|
|
26
26
|
},
|
|
27
27
|
"select_via": "`/model <model-id>` in the session, or hand the skill to the model-router agent for automatic dispatch.",
|
|
28
28
|
"automation": ".claude/agents/model-router.md"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skilldrop-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "Portable AI-agent skills for the deliverables knowledge workers ship \u2014 diagrams, ADRs, PRDs, runbooks, decks, reviews \u2014 installable into Claude Code, Cursor, Kiro, and any IDE that takes custom instructions. One command per skill or per role-based pack.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Sanjay Ananthanarayan",
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"query": "Write an ADR for this decision",
|
|
4
|
+
"should_trigger": true
|
|
5
|
+
},
|
|
6
|
+
{
|
|
7
|
+
"query": "Document the 'we decided X because Y' moment as an architecture decision record",
|
|
8
|
+
"should_trigger": true
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"query": "Capture this architectural decision in MADR format",
|
|
12
|
+
"should_trigger": true
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"query": "We picked Postgres over Dynamo — record the decision properly",
|
|
16
|
+
"should_trigger": true
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"query": "Extract the decisions and owners from these meeting notes",
|
|
20
|
+
"should_trigger": false
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"query": "Write a full engineering design doc for this feature",
|
|
24
|
+
"should_trigger": false
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"query": "Critique the ADR I already wrote",
|
|
28
|
+
"should_trigger": false
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"query": "Convene a council to decide which database we should use",
|
|
32
|
+
"should_trigger": false
|
|
33
|
+
}
|
|
34
|
+
]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill_name": "adr-generator",
|
|
3
|
+
"evals": [
|
|
4
|
+
{
|
|
5
|
+
"id": 1,
|
|
6
|
+
"prompt": "Write an ADR: we decided to use Postgres as our primary datastore instead of DynamoDB, because our access patterns are relational and the team already operates Postgres.",
|
|
7
|
+
"assertions": [
|
|
8
|
+
"Status is one of Proposed / Accepted / Deprecated / Superseded by ADR-NNNN, defaulting to Proposed unless the user says it was agreed",
|
|
9
|
+
"Title is a noun phrase naming the decision, not a verb phrase naming the activity",
|
|
10
|
+
"Consequences include real trade-offs and downsides, not only upsides",
|
|
11
|
+
"The alternatives considered each carry a why-not, not just a description",
|
|
12
|
+
"The chosen format is MADR by default; Nygard only when explicitly requested",
|
|
13
|
+
"No invented context — facts not supplied by the user are marked rather than fabricated"
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"query": "Draft the OpenAPI spec for this API",
|
|
4
|
+
"should_trigger": true
|
|
5
|
+
},
|
|
6
|
+
{
|
|
7
|
+
"query": "Write the REST contract for these endpoints",
|
|
8
|
+
"should_trigger": true
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"query": "I need an API contract with a proper error catalog and pagination decided",
|
|
12
|
+
"should_trigger": true
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"query": "Turn this user story into an OpenAPI 3.1 definition",
|
|
16
|
+
"should_trigger": true
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"query": "Define the contract for this Kafka topic our team publishes",
|
|
20
|
+
"should_trigger": false
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"query": "Design the Postgres schema and indexes for this feature",
|
|
24
|
+
"should_trigger": false
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"query": "What latency and availability targets should this service have?",
|
|
28
|
+
"should_trigger": false
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"query": "Review this API implementation for security bugs",
|
|
32
|
+
"should_trigger": false
|
|
33
|
+
}
|
|
34
|
+
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill_name": "api-contract-draft",
|
|
3
|
+
"evals": [
|
|
4
|
+
{
|
|
5
|
+
"id": 1,
|
|
6
|
+
"prompt": "Draft the OpenAPI contract for our orders API — clients need to create an order, fetch one, and list a customer's orders.",
|
|
7
|
+
"assertions": [
|
|
8
|
+
"The emitted YAML is parseable OpenAPI 3.1 and every $ref resolves",
|
|
9
|
+
"Paths are resource-oriented rather than RPC-style verbs in the URL",
|
|
10
|
+
"Every operation enumerates its 4xx set with stable machine-switchable code values — not a bare '400: Bad Request'",
|
|
11
|
+
"Errors follow RFC 9457 problem-details shape",
|
|
12
|
+
"Pagination, idempotency, and versioning are each decided explicitly rather than deferred",
|
|
13
|
+
"Every operation carries at least one example",
|
|
14
|
+
"Each decision in the log has a rationale, and any deviation from the skill's conventions is logged rather than made silently"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"query": "Draw an architecture diagram for this system",
|
|
4
|
+
"should_trigger": true
|
|
5
|
+
},
|
|
6
|
+
{
|
|
7
|
+
"query": "Generate a Mermaid diagram of these services",
|
|
8
|
+
"should_trigger": true
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"query": "Create a C4 container diagram from this description",
|
|
12
|
+
"should_trigger": true
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"query": "Diagram the sequence flow I just described",
|
|
16
|
+
"should_trigger": true
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"query": "Reverse-engineer the architecture from our Terraform and repo",
|
|
20
|
+
"should_trigger": false
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"query": "Read the frames in our Figma file",
|
|
24
|
+
"should_trigger": false
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"query": "Threat model this design",
|
|
28
|
+
"should_trigger": false
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"query": "Write the design doc for this system",
|
|
32
|
+
"should_trigger": false
|
|
33
|
+
}
|
|
34
|
+
]
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill_name": "architecture-diagrams",
|
|
3
|
+
"evals": [
|
|
4
|
+
{
|
|
5
|
+
"id": 1,
|
|
6
|
+
"prompt": "Draw the architecture for a checkout service: an API gateway, an orders service, a payments service calling Stripe, and a Postgres primary with a read replica.",
|
|
7
|
+
"assertions": [
|
|
8
|
+
"The diagram fits on one screen; beyond roughly 15 nodes it is split into separate Context and Container diagrams rather than crammed",
|
|
9
|
+
"Arrows show direction of data flow, not undirected connections",
|
|
10
|
+
"Every arrow crossing a trust boundary is labelled",
|
|
11
|
+
"The diagram is generated from the written description provided — no components are invented beyond it",
|
|
12
|
+
"A named format is produced (Mermaid, PlantUML, or C4) and renders as valid syntax"
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"query": "Who is my audience and what rules should the deck follow?",
|
|
4
|
+
"should_trigger": true
|
|
5
|
+
},
|
|
6
|
+
{
|
|
7
|
+
"query": "What are the structural rules for presenting to a board versus engineers?",
|
|
8
|
+
"should_trigger": true
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"query": "Profile this audience so I know how technical to go",
|
|
12
|
+
"should_trigger": true
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"query": "We have a mixed exec and technical room — how should I pitch it?",
|
|
16
|
+
"should_trigger": true
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"query": "Build the PowerPoint for the board meeting",
|
|
20
|
+
"should_trigger": false
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"query": "Outline the slides for this deck",
|
|
24
|
+
"should_trigger": false
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"query": "Write the one-page executive summary",
|
|
28
|
+
"should_trigger": false
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"query": "Map the customer's journey through our product",
|
|
32
|
+
"should_trigger": false
|
|
33
|
+
}
|
|
34
|
+
]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill_name": "audience-profile",
|
|
3
|
+
"evals": [
|
|
4
|
+
{
|
|
5
|
+
"id": 1,
|
|
6
|
+
"prompt": "We're presenting our platform strategy to a mixed room — the board plus two engineering leads. What audience rules should we design to?",
|
|
7
|
+
"assertions": [
|
|
8
|
+
"Output is concrete and structural (slide count ranges, density, tone, must-have sections, things to avoid) rather than advice like 'keep it short'",
|
|
9
|
+
"A mixed audience resolves to the least-technical archetype, with the more-technical material moved to an appendix",
|
|
10
|
+
"No new archetype is invented for a one-off case — the closest existing one is chosen and the divergence noted",
|
|
11
|
+
"The profile is reusable across deliverables rather than being a deck or summary itself"
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"query": "Turn this Slack thread into a structured brief",
|
|
4
|
+
"should_trigger": true
|
|
5
|
+
},
|
|
6
|
+
{
|
|
7
|
+
"query": "I have a messy transcript — get it into shape for the design-doc skill",
|
|
8
|
+
"should_trigger": true
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"query": "Structure this raw context into a brief before I run the next skill",
|
|
12
|
+
"should_trigger": true
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"query": "Take this half-written Notion page and extract a clean brief",
|
|
16
|
+
"should_trigger": true
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"query": "Extract the decisions, owners, and due dates from this discussion",
|
|
20
|
+
"should_trigger": false
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"query": "Write the ADR itself from this context",
|
|
24
|
+
"should_trigger": false
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"query": "Critique this brief's quality",
|
|
28
|
+
"should_trigger": false
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"query": "Summarize this thread for the executive team",
|
|
32
|
+
"should_trigger": false
|
|
33
|
+
}
|
|
34
|
+
]
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill_name": "brief-intake",
|
|
3
|
+
"evals": [
|
|
4
|
+
{
|
|
5
|
+
"id": 1,
|
|
6
|
+
"prompt": "Here's a messy Slack thread about our caching problem — turn it into a brief I can hand to design-doc.",
|
|
7
|
+
"assertions": [
|
|
8
|
+
"Extracted fields marked [explicit] or [implied] carry a short verbatim snippet from the source so nothing is hallucinated",
|
|
9
|
+
"Relative dates are converted to absolute YYYY-MM-DD, marked implied where computed",
|
|
10
|
+
"Gaps are named as missing rather than filled in with plausible invention",
|
|
11
|
+
"The output names the downstream skill the brief is shaped for",
|
|
12
|
+
"The brief is structured into the fields that downstream skill needs, not a summary"
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|