skilldrop-cli 0.4.1 → 0.6.0

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 CHANGED
@@ -3,7 +3,9 @@
3
3
  [![npm](https://img.shields.io/npm/v/skilldrop-cli)](https://www.npmjs.com/package/skilldrop-cli)
4
4
  [![license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
5
5
 
6
- **48 portable AI-agent skills for the deliverables knowledge workers actually ship** — diagrams, design docs, ADRs, PRDs, runbooks, decks, decision logs, threat models, adversarial reviews — installable into **Claude Code**, **Cursor**, **Kiro**, and any AI tool that accepts custom instructions, one skill or one role-based pack at a time:
6
+ **[Browse the catalogue →](https://sananthanarayan.github.io/skilldrop/)** — all 49 skills, filterable by pack, tag, and model tier.
7
+
8
+ **49 portable AI-agent skills for the deliverables knowledge workers actually ship** — diagrams, design docs, ADRs, PRDs, runbooks, decks, decision logs, threat models, adversarial reviews — installable into **Claude Code**, **Cursor**, **Kiro**, **Codex**, **GitHub Copilot**, and any AI tool that accepts custom instructions, one skill or one role-based pack at a time:
7
9
 
8
10
  ```bash
9
11
  npx skilldrop-cli install --pack product-manager # or: solution-architect, dev-team,
@@ -252,6 +254,8 @@ npx skilldrop-cli install --pack dev-team --project # .claude/skills — als
252
254
  npx skilldrop-cli install prfaq --ide cursor # + writes .cursor/rules/prfaq.mdc
253
255
  npx skilldrop-cli install --pack sre-oncall --ide kiro # .kiro/skills — Kiro IDE + Kiro CLI, discovered natively
254
256
  npx skilldrop-cli install adr-generator --dest .agents/skills # Codex + Copilot CLI (see below)
257
+ npx skilldrop-cli agents # the reviewer subagents
258
+ npx skilldrop-cli install --agent devils-advocate # -> ~/.claude/agents/ (RFC-0012)
255
259
  npx skilldrop-cli outdated && npx skilldrop-cli update # skills improve; cp -R never tells you
256
260
  npx skilldrop-cli list | skilldrop info <skill> | skilldrop packs | skilldrop uninstall <skill>
257
261
  ```
@@ -269,6 +273,31 @@ npx skilldrop-cli install devils-advocate --with-hooks --project
269
273
 
270
274
  The CLI emits per target and **degrades gracefully** — a `pre-commit-review` hook becomes an IDE-agnostic git hook (needs a git repo); a `session-start` hook becomes a Claude Code `settings.json` entry, and is cleanly skipped where the target has no equivalent (Cursor, Kiro, plain `--dest`), printing what it did and where. Kiro, Codex, and Copilot all have native hook mechanisms the CLI does not emit into yet — see [`docs/designs/ide-primitive-coverage.md`](docs/designs/ide-primitive-coverage.md) for the per-tool survey. Hooks are reminders/context, not autonomous execution — skilldrop skills are agent instructions, so the hook prompts *you* to run the review, it doesn't silently run an AI pass. `skilldrop uninstall` removes any hook artifacts it wrote. Vocabulary and the per-target mapping are in the RFC.
271
275
 
276
+ ### Reviewer subagents
277
+
278
+ Two personas you delegate review to, rather than invoke as a skill: [`devils-advocate`](agents/devils-advocate.md) ("will this break?") and [`code-quality`](agents/code-quality.md) ("will the next engineer hate this?"). A subagent runs in its own context with its own tool allowlist — a contract a skill can't express — which is why they live in [`agents/`](agents/) instead of `skills/`.
279
+
280
+ ```bash
281
+ npx skilldrop-cli agents # list them
282
+ npx skilldrop-cli install --agent devils-advocate # ~/.claude/agents/
283
+ npx skilldrop-cli install --agent code-quality --project # .claude/agents/, shared with the repo
284
+ ```
285
+
286
+ Then delegate by name: *"use the devils-advocate agent on this diff."*
287
+
288
+ Four targets, each projecting only as much as the tool's format demands:
289
+
290
+ | Target | Writes | Projection |
291
+ |---|---|---|
292
+ | *(default)* | `~/.claude/agents/<name>.md` | none — the file already is Claude Code's format |
293
+ | `--ide copilot` | `.github/agents/<name>.agent.md` | a rename |
294
+ | `--ide kiro` | `.kiro/agents/<name>.json` | generated JSON; tool names mapped to Kiro's built-ins |
295
+ | `--dest <dir>` | `<dir>/<name>.md` | none |
296
+
297
+ The Kiro emitter maps `Read`/`Grep`/`Glob`/`Bash` to `read`/`grep`/`glob`/`shell` against [Kiro's built-in tool reference](https://kiro.dev/docs/cli/reference/built-in-tools/), and **names any tool it can't map instead of dropping it silently** — a mistranslated permission is worse than a missing one. It omits `allowedTools` so you're prompted per tool call.
298
+
299
+ Codex and Antigravity still refuse, printing why: Codex's `.toml` agent schema was never confirmed, and emitting a guess is the one thing worse than not shipping the target. [`agents/README.md`](agents/README.md) has the manual route.
300
+
272
301
  ### Third-party catalogs — publish your own skills through the same CLI
273
302
 
274
303
  Any git repo or directory shaped like this one is a **catalog**: `skills/<name>/` folders each holding `SKILL.md` + `manifest.json`, optionally a root `packs.json`. That's the whole contract ([RFC-0003](docs/rfcs/0003-third-party-catalogs.md)):
@@ -0,0 +1,84 @@
1
+ # agents
2
+
3
+ Portable **reviewer agents** — opinionated personas you delegate code and test review to. Each is a single markdown file: Claude Code subagent frontmatter (`name`, `description`, `tools`, `model`) on top, a self-contained system prompt below.
4
+
5
+ The frontmatter makes the file a drop-in **Claude Code subagent**. The body is plain enough to paste into any other tool's agent / mode / system-prompt slot.
6
+
7
+ Nothing auto-discovers *this* folder at the repo root, so it is the **canonical source of truth** and the table below says where to copy each file. That framing used to be simpler: as of the [July 2026 survey](../docs/designs/ide-primitive-coverage.md), **five tools have a native subagent format** — Claude Code, Kiro, Codex, Copilot, and Antigravity, which registers subagents from a directory literally named `agents/` inside a plugin bundle. The CLI does not install agents into any of them yet ([RFC-0010](../docs/rfcs/0010-install-target-table.md) has to settle the projection model first), so copying by hand remains the route.
8
+
9
+ ## The agents
10
+
11
+ | Agent | Reviews for | Question it answers |
12
+ |---|---|---|
13
+ | [`devils-advocate`](devils-advocate.md) | Correctness — edge cases, broken assumptions, staff-engineer pushback, test-coverage gaps | "Will this break?" |
14
+ | [`code-quality`](code-quality.md) | Craft — naming, structure, duplication, needless complexity, readability | "Will the next engineer hate this?" |
15
+
16
+ They are deliberately **split, not merged.** A single "review my code" agent dilutes both jobs — bug-hunting and craft pull in different directions. Run them as two passes. `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.
17
+
18
+ ## Installing an agent into your tool
19
+
20
+ ### Claude Code (native subagents)
21
+
22
+ Claude Code reads subagents from `.claude/agents/`. Copy the file in as-is — the frontmatter is already correct:
23
+
24
+ ```bash
25
+ # project-scope (shared with the team via the repo)
26
+ mkdir -p .claude/agents && cp agents/devils-advocate.md .claude/agents/
27
+
28
+ # user-scope (every project on your machine)
29
+ mkdir -p ~/.claude/agents && cp agents/code-quality.md ~/.claude/agents/
30
+ ```
31
+
32
+ Then delegate by name — "use the devils-advocate agent on this diff" — or let Claude Code auto-route based on the `description`. Each subagent runs in its own context window.
33
+
34
+ ### Cursor (custom modes / rules)
35
+
36
+ Cursor has no subagent file format. Two options:
37
+
38
+ - **Custom mode** (cleanest): Settings → Chat → Custom Modes → New. Paste the agent's **body** (everything below the frontmatter) as the mode's instructions; use the `description` as the mode name.
39
+ - **Project rule**: create `.cursor/rules/<agent>.mdc`, paste the body under a frontmatter block (`description:` from the agent file, `alwaysApply: false`). Invoke by attaching it with `@` or describing the review task.
40
+
41
+ ### Codex (native subagents)
42
+
43
+ Codex shipped subagents with GPT-5.5 in April 2026 — `.toml` agent definitions under `.codex/`. That superseded the old advice here, which was to paste the body into a section of `AGENTS.md` because Codex "has no subagent concept."
44
+
45
+ The exact filename and schema were **not confirmed** in the survey, so check Codex's own docs rather than trusting a shape written here. The fallback still works: keep the file at `agents/<name>.md` and open the review turn with "Follow the instructions in `agents/<name>.md` for the diff below."
46
+
47
+ ### Kiro (native custom agents)
48
+
49
+ Kiro reads JSON agent definitions from `.kiro/agents/` (local) or `~/.kiro/agents/` (global). The filename minus `.json` becomes the agent's name.
50
+
51
+ Its `prompt` field accepts a **`file://` URI**, so the definition can point at the markdown instead of duplicating it — the cleanest projection of any tool surveyed:
52
+
53
+ ```json
54
+ {
55
+ "name": "devils-advocate",
56
+ "description": "<paste the description from the agent's frontmatter>",
57
+ "prompt": "file://./agents/devils-advocate.md",
58
+ "tools": ["read", "grep", "execute"]
59
+ }
60
+ ```
61
+
62
+ **Don't use a steering file for this.** Earlier advice here said to drop the agent at `.kiro/steering/<agent>.md`; a steering file with no inclusion mode is loaded into *every* session, which is a permanent context cost for a persona you want on demand. Same reason the CLI stopped writing steering shims for skills.
63
+
64
+ ### GitHub Copilot (native custom agents)
65
+
66
+ Copilot reads `.github/agents/<name>.agent.md` (repo) or `~/.copilot/agents/` (personal). The filename minus `.agent.md` is the invocation name — `copilot --agent devils-advocate`. Copy the file in and rename it; the frontmatter needs `name` and `description`, and takes an optional `tools` list.
67
+
68
+ ### Antigravity CLI (plugin subagents)
69
+
70
+ Antigravity registers subagent templates from an `agents/` directory **inside a plugin bundle** at `~/.gemini/antigravity-cli/plugins/<plugin>/agents/`. There is no project-root `agents/` convention, so this is a copy into a bundle you own, not a drop-in.
71
+
72
+ ### Continue, Cline, Aider, and other tools
73
+
74
+ No standard agent directory. Two patterns work everywhere:
75
+
76
+ - **Context attachment** — keep the file in the repo and attach it to the review turn (Continue/Cline `@file`, Aider `/add agents/<agent>.md`), then tell the tool to follow it.
77
+ - **Custom prompt** — paste the agent body into the tool's custom-prompt / system-prompt config. The `description` field is a good seed for the agent's name.
78
+
79
+ ## Adding a new agent
80
+
81
+ 1. Create `agents/<name>.md` with the frontmatter shape above (`name` = filename, use-case-first `description` ending in trigger phrases, read-only `tools` for a reviewer).
82
+ 2. Write the body as a self-contained system prompt: who the agent is, what it reviews, how it reports (severity tags + `file:line` + concrete fix), and what it explicitly does *not* do.
83
+ 3. Match the repo voice — opinionated, concrete, `✅`/`❌` and `🟥`/`🟧`/`🟨`/`⚪` used semantically (see [AGENTS.md](../AGENTS.md)).
84
+ 4. Add a row to **The agents** table above.
@@ -0,0 +1,40 @@
1
+ ---
2
+ name: code-quality
3
+ description: Craft-and-maintainability reviewer of just-written code. Finds what the next engineer will hate — bad names, tangled structure, duplication, needless complexity, leaky abstractions, dead code, and unreadable control flow. Does NOT hunt for bugs (that's the devils-advocate agent). Delegate to it when code works but you want it to read well before it ships.
4
+ tools: Read, Grep, Glob, Bash
5
+ model: inherit
6
+ ---
7
+
8
+ You are a senior engineer reviewing for craft, not correctness. The code under review works — you assume the tests pass and the logic is sound. Your job is the question the author can't ask about their own code: **will the engineer who touches this in six months understand it fast, or curse the author?**
9
+
10
+ You review **the change, not the repo.** Scope is the just-written diff or the files the user points at. Never restyle the whole codebase.
11
+
12
+ ## What you review
13
+
14
+ Run the change through five lenses. Skip lenses that don't apply.
15
+
16
+ 1. **Naming.** Names that lie, abbreviate without need, or carry no information (`data`, `tmp`, `handle`, `doStuff`). A good name makes a comment unnecessary. Propose the better name.
17
+ 2. **Structure & cohesion.** Functions doing five things, classes with split responsibility, modules importing across boundaries they shouldn't, logic that belongs one layer up or down. Point at the seam where it should split.
18
+ 3. **Duplication.** Copy-pasted blocks, parallel structures that drift, the third occurrence of a pattern that wants extracting. Name all copies by `file:line`.
19
+ 4. **Needless complexity.** Cleverness over clarity, premature abstraction, deep nesting that a guard clause flattens, a config flag nobody uses, a layer that only forwards. Simpler is the goal — show the simpler form.
20
+ 5. **Readability & dead weight.** Control flow you have to trace twice, comments that restate the code instead of explaining why, commented-out code, unreachable branches, unused params/imports/exports.
21
+
22
+ ## How you report
23
+
24
+ - Lead with a one-line read: is this clean, acceptable, or in need of work before it ships?
25
+ - Then findings, each tagged by severity:
26
+ - 🟧 **major** — actively misleading or will compound into a maintenance problem (a lying name, a god function, the same logic in three places).
27
+ - 🟨 **minor** — friction the next reader pays for (awkward structure, a comment that should be a name, avoidable nesting).
28
+ - ⚪ **nit** — polish. Optional, batch these.
29
+ - Every finding has: `file:line`, what's wrong in one sentence, and the concrete improvement — show the better name, the extracted function signature, or the flattened control flow. Don't just say "this is complex."
30
+ - End with **"what reads well"** — the parts that are clean, so the author keeps them.
31
+
32
+ ## Rules
33
+
34
+ - ✅ Show, don't lecture. ❌ "This function is too long" → ✅ "`syncOrders()` at sync.go:88 does fetch + transform + persist + notify. Split `notify` out — it's the only part with external side effects and it makes the rest unit-testable."
35
+ - ✅ Respect the surrounding style. Match the file's existing idiom, naming convention, and comment density — don't impose your taste over a consistent house style.
36
+ - ❌ Don't flag correctness, security, or test gaps — that's the **devils-advocate** agent's job. If you spot a real bug while reviewing, note it in one line and hand it off; don't review it here.
37
+ - ❌ Don't propose a rewrite when a rename or an extracted function fixes it. The smallest change that removes the friction wins.
38
+ - ❌ Don't invent findings to hit a count. "This reads well, no major findings" is a valid and useful result.
39
+
40
+ This is the craft reviewer. For "will it break?" — bugs, edge cases, broken assumptions, missing tests — delegate to the **devils-advocate** agent instead.
@@ -0,0 +1,40 @@
1
+ ---
2
+ name: devils-advocate
3
+ description: Adversarial reviewer of just-written code and tests. Hunts for what will break — edge cases the first pass missed, assumptions that won't survive future requirements, what a staff engineer would push back on in review, and test-coverage gaps. Delegate to it right after a feature is declared "done", before opening a PR or merging.
4
+ tools: Read, Grep, Glob, Bash
5
+ model: inherit
6
+ ---
7
+
8
+ You are a senior engineer in code review whose only job is to find what the implementation missed. Code that "works on the happy path" is the default state of just-written code — your job is to break that assumption.
9
+
10
+ You review **the change, not the repo.** Scope is the just-written diff, the files the user points at, or `git diff` of the working tree. Never sweep the whole codebase.
11
+
12
+ ## What you challenge
13
+
14
+ Run the change through four lenses. Skip lenses that don't apply; don't pad.
15
+
16
+ 1. **Edge cases the first pass missed.** Empty input, nulls, zero, negative, max-size, Unicode, concurrent callers, partial failure, retries, timeouts. For each: state the input, the current behavior, and what it should do.
17
+ 2. **Assumptions that won't survive 6 months.** Hard-coded limits, single-region/single-tenant baked in, ordering assumed, "this list is always small", schema that can't evolve. Name the assumption and the future requirement that breaks it.
18
+ 3. **What a staff engineer pushes back on.** Concurrency and race conditions, error handling and error mapping, security (authz, injection, secrets, SSRF), observability (can you debug this at 3am?), blast radius, idempotency, resource leaks.
19
+ 4. **Test-coverage gaps.** Which new code paths have no test? Which tests assert the happy path only? Which tests would still pass if the code were subtly wrong (assertion theater)? Name the missing test case concretely.
20
+
21
+ ## How you report
22
+
23
+ - Lead with a one-line verdict: is this safe to merge or not?
24
+ - Then findings, each tagged by severity:
25
+ - 🟥 **blocker** — will cause incorrect behavior, data loss, or a security hole. Do not merge.
26
+ - 🟧 **major** — real bug or gap under realistic conditions. Fix before merge.
27
+ - 🟨 **minor** — works but fragile or surprising. Fix soon.
28
+ - ⚪ **nit** — style/polish. Optional.
29
+ - Every finding has: `file:line` evidence, a one-sentence reproducible scenario, and a concrete fix or the exact missing test case.
30
+ - End with a short **"what's solid"** section — what the implementation got right, so the author knows what not to touch.
31
+
32
+ ## Rules
33
+
34
+ - ✅ Be concrete. ❌ "Consider adding more validation" → ✅ "`parseDate()` at handler.go:42 throws on empty string; the API contract allows an empty `since` param. Add a guard returning the default window."
35
+ - ✅ Default to suspicion. If you can't tell whether a path is handled, say so and tell the author what to check.
36
+ - ❌ Don't invent findings to hit a count. Zero blockers is a valid result — say so.
37
+ - ❌ Don't rewrite the whole thing. You point; the author fixes.
38
+ - ❌ Not a substitute for human review — this is a pre-pass that catches the obvious-in-hindsight before a human spends their attention.
39
+
40
+ This is the bug-and-gap reviewer. For craft and maintainability (naming, structure, duplication, readability) delegate to the **code-quality** agent instead — keep the two reviews separate so neither dilutes the other.
package/bin/skilldrop.js CHANGED
@@ -24,12 +24,15 @@ Usage:
24
24
  skilldrop list [--from <src>] all skills in a catalog (name, version, tier)
25
25
  skilldrop info <skill> [--from <src>] description, related, packs, deps
26
26
  skilldrop packs [--from <src>] role-based packs
27
+ skilldrop agents [--from <src>] reviewer subagents in a catalog
27
28
  skilldrop install <skill...> install skills (default: Claude Code, user scope)
28
29
  skilldrop install --pack <name> install a whole pack
29
30
  skilldrop install --all install every skill in the catalog
31
+ skilldrop install --agent <name...> install reviewer subagents (RFC-0012)
30
32
  skilldrop update re-copy installed skills whose version changed
31
33
  skilldrop outdated show installed vs current versions, change nothing
32
34
  skilldrop uninstall <skill...> remove skills (and wiring files this tool wrote)
35
+ skilldrop uninstall --agent <name...> remove subagents
33
36
  skilldrop validate [--from <src>] structural check of a catalog (for catalog authors)
34
37
 
35
38
  Catalogs:
@@ -46,6 +49,12 @@ Install/update/uninstall targets (pick one):
46
49
  .github/skills (Copilot), Continue / Cline / Aider
47
50
 
48
51
  Options:
52
+ --agent operate on subagents instead of skills. Targets:
53
+ (default) ~/.claude/agents Claude Code (--project for repo scope)
54
+ --ide kiro ./.kiro/agents generated JSON, tools mapped
55
+ --ide copilot ./.github/agents <name>.agent.md
56
+ --dest <dir> any directory copied as-is
57
+ Codex and Antigravity still refuse with the reason — see agents/README.md.
49
58
  --with-related also install each skill's related companions (one level)
50
59
  --with-hooks also wire any hooks a skill declares (RFC-0006) — git pre-commit
51
60
  reminders and Claude Code session-start context; degrades where the
@@ -93,6 +102,30 @@ function skillsIn(cat) {
93
102
  return fs.readdirSync(cat.skillsDir).filter((d) => fs.statSync(path.join(cat.skillsDir, d)).isDirectory()).sort();
94
103
  }
95
104
  function manifestOf(cat, s) { return readJSON(path.join(cat.skillsDir, s, "manifest.json")); }
105
+
106
+ /* Agents (RFC-0012): single markdown files, frontmatter is already Claude Code's format.
107
+ Optional in a catalog — a third-party catalog with no agents/ is still valid. */
108
+ function agentsIn(cat) {
109
+ const d = path.join(cat.dir, "agents");
110
+ if (!fs.existsSync(d)) return [];
111
+ return fs.readdirSync(d).filter((f) => f.endsWith(".md") && f !== "README.md").map((f) => f.slice(0, -3)).sort();
112
+ }
113
+ function agentPath(cat, a) { return path.join(cat.dir, "agents", `${a}.md`); }
114
+ function agentMeta(cat, a) {
115
+ const fm = (fs.readFileSync(agentPath(cat, a), "utf8").split("---")[1] || "");
116
+ const get = (k) => { const m = fm.match(new RegExp("^" + k + ":\\s*(.+)$", "m")); return m ? m[1].trim() : ""; };
117
+ return { name: get("name"), description: get("description"), tools: get("tools"), model: get("model") };
118
+ }
119
+
120
+ /* Same gate the skills get, applied to agents before anything is copied. */
121
+ function checkAgent(cat, a) {
122
+ const problems = [];
123
+ if (!fs.existsSync(agentPath(cat, a))) return [`agents/${a}.md missing`];
124
+ const m = agentMeta(cat, a);
125
+ if (m.name !== a) problems.push(`frontmatter name '${m.name}' != filename '${a}'`);
126
+ if (!m.description) problems.push("frontmatter missing description");
127
+ return problems;
128
+ }
96
129
  function packsOf(cat) {
97
130
  const p = path.join(cat.dir, "packs.json");
98
131
  return fs.existsSync(p) ? readJSON(p).packs : null;
@@ -145,6 +178,71 @@ function target(flags) {
145
178
  die(`unknown --ide '${ide}' (claude | cursor | kiro; use --dest for anything else)`);
146
179
  }
147
180
 
181
+ /* Claude Code tool name -> Kiro built-in tool name. Confirmed against
182
+ kiro.dev/docs/cli/reference/built-in-tools/ — not inferred. Agent configs use these
183
+ simplified names; Kiro's *hook* matchers use internal names (fs_read, execute_bash)
184
+ instead, and mixing the two silently grants nothing. */
185
+ const KIRO_TOOLS = {
186
+ Read: "read", Grep: "grep", Glob: "glob", Bash: "shell",
187
+ Write: "write", Edit: "write", WebSearch: "web_search", WebFetch: "web_fetch",
188
+ };
189
+
190
+ function kiroAgentJSON(meta, body) {
191
+ const declared = meta.tools ? meta.tools.split(",").map((s) => s.trim()).filter(Boolean) : [];
192
+ const tools = [], unmapped = [];
193
+ for (const d of declared) (KIRO_TOOLS[d] ? tools : unmapped).push(KIRO_TOOLS[d] || d);
194
+ // The prompt is inlined rather than a file:// reference: the docs' example is
195
+ // relative, but whether it resolves against the workspace root or the JSON file is
196
+ // not stated, and a wrong path fails silently. One self-contained file cannot.
197
+ const agent = { name: meta.name, description: meta.description, prompt: body, tools };
198
+ // allowedTools is deliberately omitted — it is auto-approval, so leaving it out means
199
+ // the user is prompted per tool call. Also sidesteps kirodotdev/Kiro#6714, where
200
+ // allowedTools does not load as configured.
201
+ return { json: JSON.stringify(agent, null, 2) + "\n", unmapped: [...new Set(unmapped)] };
202
+ }
203
+
204
+ /* Only plain-copy targets ship in RFC-0012. Everything else needs a projection the
205
+ install-target model (RFC-0010) has not settled — so say so instead of guessing a path. */
206
+ const AGENT_MANUAL = {
207
+ codex: ".codex/*.toml — the schema was never confirmed, so emitting one would be a guess",
208
+ antigravity: "an agents/ directory inside a plugin bundle you own",
209
+ cursor: "a custom mode — Cursor has no agent file format",
210
+ };
211
+ function agentTarget(flags) {
212
+ if (flags.dest) return { dest: path.resolve(flags.dest), ide: "generic" };
213
+ const ide = flags.ide || "claude";
214
+ if (ide === "claude")
215
+ return flags.project
216
+ ? { dest: path.resolve(".claude", "agents"), ide }
217
+ : { dest: path.join(os.homedir(), ".claude", "agents"), ide };
218
+ if (ide === "kiro")
219
+ return flags.project === false
220
+ ? { dest: path.join(os.homedir(), ".kiro", "agents"), ide }
221
+ : { dest: path.resolve(".kiro", "agents"), ide };
222
+ if (ide === "copilot") return { dest: path.resolve(".github", "agents"), ide };
223
+ const hint = AGENT_MANUAL[ide];
224
+ die(`--agent has no target for '${ide}'${hint ? ` — it needs ${hint}` : ""}.\n` +
225
+ ` Copy it by hand (see agents/README.md), or use --dest <dir>. Tracked in RFC-0012.`);
226
+ }
227
+
228
+ /* Write one agent into a target, projecting only where the target's format demands it.
229
+ Returns the filename written plus any warning worth printing. */
230
+ function writeAgent(cat, a, dest, ide) {
231
+ const src = agentPath(cat, a);
232
+ if (ide === "kiro") {
233
+ const raw = fs.readFileSync(src, "utf8");
234
+ const body = raw.split("---").slice(2).join("---").trim();
235
+ const { json, unmapped } = kiroAgentJSON(agentMeta(cat, a), body);
236
+ fs.writeFileSync(path.join(dest, `${a}.json`), json);
237
+ return { file: `${a}.json`, warn: unmapped.length
238
+ ? ` ${a}: no Kiro equivalent for ${unmapped.join(", ")} — dropped from tools, add by hand if needed`
239
+ : null };
240
+ }
241
+ const name = ide === "copilot" ? `${a}.agent.md` : `${a}.md`;
242
+ fs.copyFileSync(src, path.join(dest, name));
243
+ return { file: name, warn: null };
244
+ }
245
+
148
246
  function ledger(dest) {
149
247
  const p = path.join(dest, LEDGER);
150
248
  return { path: p, data: fs.existsSync(p) ? readJSON(p) : {} };
@@ -317,6 +415,7 @@ function copyOne(cat, s, dest, ide, l, notes) {
317
415
  }
318
416
 
319
417
  function install(args) {
418
+ if (args.flags.agent) return installAgents(args);
320
419
  const cat = resolveCatalog(args.flags.from);
321
420
  let names = expandNames(args, cat);
322
421
  if (args.flags["with-related"]) {
@@ -404,6 +503,7 @@ function outdated(args) {
404
503
  }
405
504
 
406
505
  function uninstall(args) {
506
+ if (args.flags.agent) return uninstallAgents(args);
407
507
  if (!args._.length) die("pass skill names to uninstall");
408
508
  const { dest, ide } = target(args.flags);
409
509
  const l = ledger(dest);
@@ -418,6 +518,68 @@ function uninstall(args) {
418
518
  saveLedger(l);
419
519
  }
420
520
 
521
+ function listAgents(args) {
522
+ const cat = resolveCatalog(args.flags.from);
523
+ const names = agentsIn(cat);
524
+ if (!names.length) return console.log(`catalog '${cat.source}' ships no agents.`);
525
+ const w = Math.max(...names.map((n) => n.length));
526
+ for (const a of names) {
527
+ const m = agentMeta(cat, a);
528
+ console.log(`${a.padEnd(w)} ${m.description}`);
529
+ }
530
+ console.log(`\n${names.length} agent(s). Install one: skilldrop install --agent <name>`);
531
+ }
532
+
533
+ function installAgents(args) {
534
+ const cat = resolveCatalog(args.flags.from);
535
+ const available = agentsIn(cat);
536
+ if (!available.length) die(`catalog '${cat.source}' ships no agents`);
537
+ const names = args._.length ? args._.slice() : (args.flags.all ? available : []);
538
+ if (!names.length) die("nothing to install — pass agent names, or --all");
539
+ for (const a of names) if (!available.includes(a)) die(`unknown agent '${a}' in catalog '${cat.source}'`);
540
+
541
+ let bad = 0;
542
+ for (const a of names) {
543
+ const problems = checkAgent(cat, a);
544
+ for (const pr of problems) console.error(`refused ${a}: ${pr}`);
545
+ if (problems.length) bad++;
546
+ }
547
+ if (bad) die(`${bad} agent(s) failed the structural check — nothing was installed`);
548
+
549
+ const { dest, ide } = agentTarget(args.flags);
550
+ fs.mkdirSync(dest, { recursive: true });
551
+ const l = ledger(dest);
552
+ const warns = [];
553
+ for (const a of names) {
554
+ const { file, warn } = writeAgent(cat, a, dest, ide);
555
+ if (warn) warns.push(warn);
556
+ l.data[a] = { version: null, source: cat.source, file }; // agents carry no version yet (RFC-0012)
557
+ console.log(`installed ${a} -> ${path.join(dest, file)}`);
558
+ }
559
+ saveLedger(l);
560
+ console.log(`\n${names.length} agent(s) installed (${ide}).`);
561
+ if (warns.length) console.log(`\nTool mapping:\n${warns.join("\n")}`);
562
+ if (ide === "claude") console.log("Delegate by name, e.g. \"use the devils-advocate agent on this diff\".");
563
+ if (ide === "kiro") console.log("Kiro grants `tools` but not auto-approval — you are prompted per call by design.");
564
+ if (ide === "copilot") console.log("Invoke with: copilot --agent <name>");
565
+ if (cat.source !== BUNDLED)
566
+ console.log(`\nWARNING: third-party catalog '${cat.source}'. An agent is a system prompt your tool will adopt — read it before first use. Install copied files only; nothing was executed.`);
567
+ }
568
+
569
+ function uninstallAgents(args) {
570
+ if (!args._.length) die("pass agent names to uninstall");
571
+ const { dest } = agentTarget(args.flags);
572
+ const l = ledger(dest);
573
+ for (const a of args._) {
574
+ const rec = l.data[a];
575
+ for (const f of new Set([rec && rec.file, `${a}.md`, `${a}.json`, `${a}.agent.md`].filter(Boolean)))
576
+ fs.rmSync(path.join(dest, f), { force: true });
577
+ delete l.data[a];
578
+ console.log(`removed ${a} from ${dest}`);
579
+ }
580
+ saveLedger(l);
581
+ }
582
+
421
583
  function list(args) {
422
584
  const cat = resolveCatalog(args.flags.from);
423
585
  const rows = skillsIn(cat).map((s) => {
@@ -475,7 +637,7 @@ function validateCmd(args) {
475
637
 
476
638
  const args = parseArgs(process.argv.slice(2));
477
639
  const cmd = args._.shift();
478
- const commands = { list, info, packs: listPacks, install, update, outdated, uninstall, validate: validateCmd };
640
+ const commands = { list, info, packs: listPacks, agents: listAgents, install, update, outdated, uninstall, validate: validateCmd };
479
641
  if (!cmd || cmd === "help" || args.flags.help) console.log(HELP);
480
642
  else if (commands[cmd]) commands[cmd](args);
481
643
  else die(`unknown command '${cmd}' — run: skilldrop help`);
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "skilldrop-cli",
3
- "version": "0.4.1",
4
- "description": "Portable AI-agent skills for the deliverables knowledge workers ship — diagrams, ADRs, PRDs, runbooks, decks, reviews — installable into Claude Code, Cursor, Kiro, and any IDE that takes custom instructions. One command per skill or per role-based pack.",
3
+ "version": "0.6.0",
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
  "bin": {
6
6
  "skilldrop": "bin/skilldrop.js"
7
7
  },
8
8
  "files": [
9
9
  "bin/",
10
10
  "skills/",
11
+ "agents/",
11
12
  "packs.json",
12
13
  "model-routing.json"
13
14
  ],
@@ -5,7 +5,7 @@
5
5
  "entrypoint": "SKILL.md",
6
6
  "deps": {
7
7
  "npm": [],
8
- "pip": ["python-pptx>=0.6.21"]
8
+ "pip": ["python-pptx==1.0.2"]
9
9
  },
10
10
  "env": { "required": [], "optional": [] },
11
11
  "related": ["audience-profile", "slide-outliner"],
@@ -1 +1,3 @@
1
- python-pptx>=0.6.21
1
+ # Pinned, not ranged: an open range lets a future release install itself unreviewed.
2
+ # python-pptx 1.0.2 requires Python >= 3.8.
3
+ python-pptx==1.0.2
@@ -55,7 +55,8 @@ If `FIGMA_TOKEN` is not set, tell the user how to set it before running the scri
55
55
  cd path/to/figma-diagrams && python3 scripts/inspect_file.py <FILE_KEY>
56
56
  ```
57
57
 
58
- Dependencies (just `requests`) are declared in `manifest.json` and `requirements.txt`. Install once with:
58
+ Dependencies (just `requests`, pinned) are declared in `manifest.json` and `requirements.txt`.
59
+ **Requires Python 3.10+** — the pinned `requests` drops older interpreters. Install once with:
59
60
 
60
61
  ```bash
61
62
  python3 -m pip install -r requirements.txt
@@ -6,7 +6,7 @@
6
6
  "deps": {
7
7
  "npm": [],
8
8
  "pip": [
9
- "requests>=2.28"
9
+ "requests==2.34.2"
10
10
  ]
11
11
  },
12
12
  "env": {
@@ -1 +1,3 @@
1
- requests>=2.28
1
+ # Pinned, not ranged: an open range lets a future release install itself unreviewed.
2
+ # requests 2.34.2 requires Python >= 3.10.
3
+ requests==2.34.2