skilldrop-cli 0.8.0 → 0.8.2

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,9 +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
- **[Browse the catalogue →](https://sananthanarayan.github.io/skilldrop/)** — all 49 skills, filterable by pack, tag, and model tier.
6
+ **[Browse the catalogue →](https://sananthanarayan.github.io/skilldrop/)** — all 50 skills, filterable by pack, tag, and model tier.
7
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:
8
+ **50 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:
9
9
 
10
10
  ```bash
11
11
  npx skilldrop-cli install --pack product-manager # or: solution-architect, dev-team,
@@ -151,6 +151,8 @@ Designing the agentic systems themselves — the loops, orchestrations, and budg
151
151
  | [`agent-budget`](skills/agent-budget/SKILL.md) | The spend spec for an agentic workflow: cheapest-adequate **tier per stage** (light/standard/heavy — heavy verification is never downgraded to save money), three numbers per stage (expected, hard cap, on-cap action — "warn and continue" banned), a run-level cap *below* the sum of stage caps, a **degradation ladder where verification is last and never cut**, and **cost-per-outcome** as the governing metric with a comparison line against the manual alternative — so "$900/week" becomes answerable. Estimates tagged `[assumption]` until calibrated on real runs. |
152
152
  | [`agent-threat-model`](skills/agent-threat-model/SKILL.md) | Security review of an agent's **capability surface** against the lethal trifecta — private data, untrusted content, an exfiltration vector. Inventories data reach *transitively* (the filesystem tool reaches every secret in `.env`), applies a writer-authorization test that classifies almost every content source untrusted, and sweeps egress past the obvious network tool (rendered markdown images, CI logs, error text, DNS). Scores **paths, not tools** — `fetch` is fine alone and lethal beside a secrets file — then names the architectural fix that breaks a leg, with a verification step. Structurally refuses the two answers teams reach for first: a system prompt telling the model to ignore injected instructions is not a control, and an injection classifier is defense in depth, never a broken leg. |
153
153
 
154
+ | [`agents-md-generator`](skills/agents-md-generator/SKILL.md) | Generate or audit the `AGENTS.md` that Claude Code, Codex, Cursor, Copilot, Kiro and Antigravity all read before your prompt. Built around one rule: **every command traces to evidence in the repo** — a CI step, a Makefile target, a `package.json` script — or it appears as `[missing: no test command in CI or manifests]` rather than a guess, because an invented command is a fault the agent will trust over the filesystem. Convention lines must pass a **counterfactual test** (without this line, would a competent agent do the wrong thing?); virtue instructions — "clean", "best practice", "thorough" — are *stripped, not softened*, since they spend context and change no behaviour. Names forbidden actions explicitly, the section most files omit. Hard ~150-line cap when generating, a warning when auditing, because an existing file may be long for good reason. Audit mode emits a diff, never a silent rewrite. Satellites (`CLAUDE.md`, `.github/copilot-instructions.md`) are opt-in and **delta-only** — a satellite that repeats `AGENTS.md` is guaranteed drift. |
155
+
154
156
  ### AI adoption & observability
155
157
 
156
158
  | Skill | What it does |
@@ -262,6 +264,17 @@ npx skilldrop-cli list | skilldrop info <skill> | skilldrop packs | skilldrop un
262
264
 
263
265
  `--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).
264
266
 
267
+ ### Or: the Claude Code plugin marketplace
268
+
269
+ skilldrop is also a **Claude Code plugin marketplace** — install the whole catalogue as one plugin, no npm step:
270
+
271
+ ```text
272
+ /plugin marketplace add sananthanarayan/skilldrop
273
+ /plugin install skilldrop@skilldrop
274
+ ```
275
+
276
+ Every skill then invokes as `/skilldrop:<name>` (e.g. `/skilldrop:prfaq`), and the reviewer subagents come with it. The marketplace ships the flat `skills/` and `agents/` trees at the repo root unchanged — same copy-install premise, expressed in Claude's own plugin format. `.claude-plugin/{marketplace,plugin}.json` are generated from `package.json` by [`build_marketplace.py`](build_marketplace.py) (`--check` guards drift in CI). Use the CLI above when you want per-pack or per-skill granularity, another IDE, or hooks; use the marketplace when you're in Claude Code and want everything in two lines. Rationale and the deferred per-pack-plugin step: [RFC-0014](docs/rfcs/0014-agentbundle-interop.md).
277
+
265
278
  ### Hooks (opt-in) — wire a skill to an event
266
279
 
267
280
  Some loop-shaped skills declare **hooks** — event-triggered nudges the CLI wires into your environment when you pass `--with-hooks` ([RFC-0006](docs/rfcs/0006-per-ide-hooks.md)). It's off by default, so a plain install never touches your git repo or editor settings.
@@ -313,6 +326,13 @@ npx skilldrop-cli install --pack starter --from ../local-catalog
313
326
  npx skilldrop-cli update # updates bundled and third-party skills side by side — the ledger remembers each skill's source
314
327
  ```
315
328
 
329
+ The CLI also reads **agentbundle-shaped catalogs** ([agent-ready-repo](https://github.com/eugenelim/agent-ready-repo)) — `packs/<pack>/.apm/skills/<name>/SKILL.md` with a `pack.toml` per pack — so you can install *its* packs through the same command ([RFC-0014](docs/rfcs/0014-agentbundle-interop.md)). Both shapes share the agentskills.io `SKILL.md`, so the reader just maps his packs onto the accessors above:
330
+
331
+ ```bash
332
+ npx skilldrop-cli packs --from https://github.com/eugenelim/agent-ready-repo
333
+ npx skilldrop-cli install --pack contracts --from https://github.com/eugenelim/agent-ready-repo --dest .agents/skills
334
+ ```
335
+
316
336
  Safety model: installs **copy files only — nothing from a catalog is ever executed**; every skill passes a structural check before copying (broken folders are refused with reasons); and third-party installs print a review-before-use warning, because skills are instructions your AI agent will follow — read a stranger's `SKILL.md` before letting your agent obey it.
317
337
 
318
338
  **Authoring a catalog:** mirror the layout above, then check it with `npx skilldrop-cli validate --from <your-repo-or-path>` before publishing. `related`, `packs.json`, and `requirements.txt` all work in third-party catalogs exactly as they do here.
package/bin/skilldrop.js CHANGED
@@ -3,8 +3,10 @@
3
3
  * or any directory, from the bundled catalog or any third-party catalog
4
4
  * (--from <path | git-url[#ref]>). Zero dependencies; copy-only, never executes
5
5
  * catalog content at install time.
6
+ * Reads two catalog shapes: skilldrop (flat skills/) and agentbundle (packs/<p>/.apm/skills).
6
7
  * Design: skilldrop-cli-design/skilldrop-cli-design.md
7
- * Scope: docs/rfcs/0002-skilldrop-cli.md, docs/rfcs/0003-third-party-catalogs.md
8
+ * Scope: docs/rfcs/0002-skilldrop-cli.md, docs/rfcs/0003-third-party-catalogs.md,
9
+ * docs/rfcs/0014-agentbundle-interop.md (the agentbundle reader)
8
10
  */
9
11
  "use strict";
10
12
  const fs = require("fs");
@@ -37,8 +39,9 @@ Usage:
37
39
 
38
40
  Catalogs:
39
41
  (default) the catalog bundled with this package
40
- --from <dir> any local directory shaped like skills/<name>/{SKILL.md,manifest.json}
41
- --from <git-url> any git repo with that shape; append #<branch-or-tag> to pin
42
+ --from <dir|url> a skilldrop catalog (skills/<name>/{SKILL.md,manifest.json}) OR an
43
+ agentbundle one (packs/<pack>/.apm/skills/<name>/SKILL.md); a git URL
44
+ works for either — append #<branch-or-tag> to pin
42
45
 
43
46
  Install/update/uninstall targets (pick one):
44
47
  (default) ~/.claude/skills Claude Code, user scope
@@ -78,7 +81,16 @@ function parseArgs(argv) {
78
81
  return out;
79
82
  }
80
83
 
81
- /* ---------- catalogs ---------- */
84
+ /* ---------- catalogs ----------
85
+ Two on-disk shapes are read (RFC-0003, RFC-0014):
86
+ "skilldrop" — flat skills/<name>/{SKILL.md,manifest.json} + optional packs.json
87
+ "apm" — agentbundle (agent-ready-repo): packs/<pack>/{pack.toml,
88
+ .apm/skills/<name>/SKILL.md, .apm/agents/<name>.md}
89
+ The apm reader normalizes into the same accessors the native path uses — skills keyed by
90
+ folder name, a per-skill manifest synthesized from the SKILL.md frontmatter + the pack.toml
91
+ version, each pack.toml's [pack] table a virtual pack — so `--from git+https://…/agent-ready-repo`
92
+ installs his packs through this same CLI. Skill accessors: skillsIn / skillDir / skillExists /
93
+ manifestOf; never touch cat.skillsDir directly (it exists only on the skilldrop shape). */
82
94
 
83
95
  const catalogCache = {};
84
96
  function resolveCatalog(source) {
@@ -96,23 +108,101 @@ function resolveCatalog(source) {
96
108
  die(`could not fetch catalog '${source}' — not a local path, and git clone failed`);
97
109
  }
98
110
  }
99
- const skillsDir = path.join(dir, "skills");
100
- if (!fs.existsSync(skillsDir)) die(`'${source || dir}' is not a skilldrop catalog — no skills/ directory`);
101
- return (catalogCache[key] = { dir, skillsDir, source: source || BUNDLED });
111
+ const src = source || BUNDLED;
112
+ if (fs.existsSync(path.join(dir, "skills")))
113
+ return (catalogCache[key] = { dir, source: src, shape: "skilldrop", skillsDir: path.join(dir, "skills") });
114
+ if (fs.existsSync(path.join(dir, "packs")))
115
+ return (catalogCache[key] = readApmCatalog(dir, src));
116
+ die(`'${src}' is not a catalog — expected a skills/ (skilldrop) or packs/ (agentbundle) directory`);
117
+ }
118
+
119
+ /* Minimal TOML read — the [pack] table's basic-string scalars (name, version, description).
120
+ pack.toml is small and regular; a full TOML parser would be dead weight in a zero-dep CLI. */
121
+ function packMeta(tomlText) {
122
+ const out = {};
123
+ let inPack = false;
124
+ for (const raw of tomlText.split(/\r?\n/)) {
125
+ const t = raw.trim();
126
+ if (t.startsWith("[")) { inPack = t === "[pack]"; continue; }
127
+ if (!inPack || !t || t.startsWith("#")) continue;
128
+ const m = t.match(/^([A-Za-z0-9_.-]+)\s*=\s*"((?:[^"\\]|\\.)*)"/);
129
+ if (m) out[m[1]] = m[2].replace(/\\"/g, '"').replace(/\\\\/g, "\\");
130
+ }
131
+ return out;
132
+ }
133
+
134
+ /* SKILL.md frontmatter (agentskills.io: name optional, description carries the trigger). */
135
+ function frontmatter(mdPath) {
136
+ let fm = "";
137
+ try { fm = fs.readFileSync(mdPath, "utf8").split("---")[1] || ""; } catch (e) { return {}; }
138
+ const get = (k) => { const m = fm.match(new RegExp("^" + k + ":\\s*(.+)$", "m")); return m ? m[1].trim() : ""; };
139
+ return { name: get("name"), description: get("description") };
140
+ }
141
+
142
+ /* Read an agentbundle catalog into the native accessor shape. First-wins on a skill name
143
+ (skilldrop's own generated catalogue duplicates a multi-pack skill into each pack — the
144
+ flat skill list dedups, while packsData still lists it under every pack it belongs to). */
145
+ function readApmCatalog(dir, source) {
146
+ const packsDir = path.join(dir, "packs");
147
+ const skillIndex = {}, agentIndex = {}, packsData = {};
148
+ for (const pack of fs.readdirSync(packsDir)) {
149
+ const pdir = path.join(packsDir, pack);
150
+ if (!fs.statSync(pdir).isDirectory()) continue;
151
+ const ptoml = path.join(pdir, "pack.toml");
152
+ const pm = fs.existsSync(ptoml) ? packMeta(fs.readFileSync(ptoml, "utf8")) : {};
153
+ const version = pm.version || "0.0.0";
154
+ const skills = [];
155
+ const skillsRoot = path.join(pdir, ".apm", "skills");
156
+ if (fs.existsSync(skillsRoot))
157
+ for (const s of fs.readdirSync(skillsRoot)) {
158
+ const sdir = path.join(skillsRoot, s);
159
+ if (!fs.statSync(sdir).isDirectory()) continue;
160
+ skills.push(s);
161
+ if (!skillIndex[s])
162
+ skillIndex[s] = { dir: sdir, manifest: {
163
+ name: s, description: frontmatter(path.join(sdir, "SKILL.md")).description || "",
164
+ version, related: [], tags: [],
165
+ deps: { pip: [], npm: [] }, env: { required: [], optional: [] },
166
+ } };
167
+ }
168
+ const agentsRoot = path.join(pdir, ".apm", "agents");
169
+ if (fs.existsSync(agentsRoot))
170
+ for (const f of fs.readdirSync(agentsRoot))
171
+ if (f.endsWith(".md") && f !== "README.md") agentIndex[f.slice(0, -3)] = path.join(agentsRoot, f);
172
+ packsData[pack] = { description: pm.description || "", skills };
173
+ }
174
+ return { dir, source, shape: "apm", skillIndex, agentIndex, packsData };
102
175
  }
176
+
103
177
  function skillsIn(cat) {
178
+ if (cat.shape === "apm") return Object.keys(cat.skillIndex).sort();
104
179
  return fs.readdirSync(cat.skillsDir).filter((d) => fs.statSync(path.join(cat.skillsDir, d)).isDirectory()).sort();
105
180
  }
106
- function manifestOf(cat, s) { return readJSON(path.join(cat.skillsDir, s, "manifest.json")); }
181
+ function skillDir(cat, s) {
182
+ if (cat.shape === "apm") return cat.skillIndex[s] && cat.skillIndex[s].dir;
183
+ return path.join(cat.skillsDir, s);
184
+ }
185
+ function skillExists(cat, s) { const d = skillDir(cat, s); return !!d && fs.existsSync(d); }
186
+ function manifestOf(cat, s) {
187
+ if (cat.shape === "apm") {
188
+ if (!cat.skillIndex[s]) throw new Error(`no such skill '${s}'`);
189
+ return cat.skillIndex[s].manifest;
190
+ }
191
+ return readJSON(path.join(cat.skillsDir, s, "manifest.json"));
192
+ }
107
193
 
108
194
  /* Agents (RFC-0012): single markdown files, frontmatter is already Claude Code's format.
109
- Optional in a catalog — a third-party catalog with no agents/ is still valid. */
195
+ Optional in a catalog — a third-party catalog with no agents is still valid. */
110
196
  function agentsIn(cat) {
197
+ if (cat.shape === "apm") return Object.keys(cat.agentIndex).sort();
111
198
  const d = path.join(cat.dir, "agents");
112
199
  if (!fs.existsSync(d)) return [];
113
200
  return fs.readdirSync(d).filter((f) => f.endsWith(".md") && f !== "README.md").map((f) => f.slice(0, -3)).sort();
114
201
  }
115
- function agentPath(cat, a) { return path.join(cat.dir, "agents", `${a}.md`); }
202
+ function agentPath(cat, a) {
203
+ if (cat.shape === "apm") return cat.agentIndex[a];
204
+ return path.join(cat.dir, "agents", `${a}.md`);
205
+ }
116
206
  function agentMeta(cat, a) {
117
207
  const fm = (fs.readFileSync(agentPath(cat, a), "utf8").split("---")[1] || "");
118
208
  const get = (k) => { const m = fm.match(new RegExp("^" + k + ":\\s*(.+)$", "m")); return m ? m[1].trim() : ""; };
@@ -122,13 +212,15 @@ function agentMeta(cat, a) {
122
212
  /* Same gate the skills get, applied to agents before anything is copied. */
123
213
  function checkAgent(cat, a) {
124
214
  const problems = [];
125
- if (!fs.existsSync(agentPath(cat, a))) return [`agents/${a}.md missing`];
215
+ const p = agentPath(cat, a);
216
+ if (!p || !fs.existsSync(p)) return [`agent '${a}' missing`];
126
217
  const m = agentMeta(cat, a);
127
218
  if (m.name !== a) problems.push(`frontmatter name '${m.name}' != filename '${a}'`);
128
219
  if (!m.description) problems.push("frontmatter missing description");
129
220
  return problems;
130
221
  }
131
222
  function packsOf(cat) {
223
+ if (cat.shape === "apm") return Object.keys(cat.packsData).length ? cat.packsData : null;
132
224
  const p = path.join(cat.dir, "packs.json");
133
225
  return fs.existsSync(p) ? readJSON(p).packs : null;
134
226
  }
@@ -136,8 +228,14 @@ function packsOf(cat) {
136
228
  /* Structural gate (RFC-0003): a skill must pass before it is copied anywhere. */
137
229
  function checkSkill(cat, s) {
138
230
  const problems = [];
139
- const dir = path.join(cat.skillsDir, s);
140
- if (!fs.existsSync(path.join(dir, "SKILL.md"))) problems.push("SKILL.md missing");
231
+ const dir = skillDir(cat, s);
232
+ if (!dir || !fs.existsSync(path.join(dir, "SKILL.md"))) problems.push("SKILL.md missing");
233
+ if (cat.shape === "apm") {
234
+ // agentbundle skills carry name/description in SKILL.md frontmatter (agentskills.io);
235
+ // version lives in pack.toml and there is no model tier — gate only the portable fields.
236
+ if (!problems.length && !manifestOf(cat, s).description) problems.push("SKILL.md frontmatter missing description");
237
+ return problems;
238
+ }
141
239
  let m = null;
142
240
  try { m = manifestOf(cat, s); } catch (e) { problems.push("manifest.json missing or invalid JSON"); }
143
241
  if (m) {
@@ -456,13 +554,13 @@ function expandNames(args, cat) {
456
554
  return p.skills.slice();
457
555
  }
458
556
  if (!args._.length) die("nothing to install — pass skill names, --pack <name>, or --all");
459
- for (const s of args._) if (!fs.existsSync(path.join(cat.skillsDir, s))) die(`unknown skill '${s}' in catalog '${cat.source}'`);
557
+ for (const s of args._) if (!skillExists(cat, s)) die(`unknown skill '${s}' in catalog '${cat.source}'`);
460
558
  return args._.slice();
461
559
  }
462
560
 
463
561
  function copyOne(cat, s, dest, ide, l, notes) {
464
562
  const m = manifestOf(cat, s);
465
- fs.cpSync(path.join(cat.skillsDir, s), path.join(dest, s), { recursive: true });
563
+ fs.cpSync(skillDir(cat, s), path.join(dest, s), { recursive: true });
466
564
  const note = writeWiring(ide, dest, s, m.description);
467
565
  if (note && notes) notes.push(note);
468
566
  l.data[s] = { version: m.version, source: cat.source };
@@ -478,7 +576,7 @@ function install(args) {
478
576
  for (const s of names.slice()) {
479
577
  let related = [];
480
578
  try { related = manifestOf(cat, s).related || []; } catch (e) { /* gated below */ }
481
- for (const r of related) if (!seen.has(r) && fs.existsSync(path.join(cat.skillsDir, r))) { seen.add(r); names.push(r); }
579
+ for (const r of related) if (!seen.has(r) && skillExists(cat, r)) { seen.add(r); names.push(r); }
482
580
  }
483
581
  }
484
582
  gate(cat, names);
@@ -488,7 +586,7 @@ function install(args) {
488
586
  const pipDeps = [], suggestions = new Set(), notes = [];
489
587
  for (const s of names) {
490
588
  const m = copyOne(cat, s, dest, ide, l, notes);
491
- if (fs.existsSync(path.join(cat.skillsDir, s, "requirements.txt"))) pipDeps.push(s);
589
+ if (fs.existsSync(path.join(skillDir(cat, s), "requirements.txt"))) pipDeps.push(s);
492
590
  for (const r of m.related || []) if (!names.includes(r) && !l.data[r]) suggestions.add(r);
493
591
  console.log(`installed ${s}@${m.version} -> ${dest}`);
494
592
  }
@@ -525,7 +623,7 @@ function installedRows(flags) {
525
623
  let current = null, cat = null;
526
624
  try {
527
625
  cat = resolveCatalog(src === BUNDLED ? undefined : src);
528
- if (fs.existsSync(path.join(cat.skillsDir, s))) current = manifestOf(cat, s).version;
626
+ if (skillExists(cat, s)) current = manifestOf(cat, s).version;
529
627
  } catch (e) { /* unreachable source: current stays null */ }
530
628
  return { s, src, cat, installed: lver(l.data[s]), current };
531
629
  });
@@ -651,15 +749,15 @@ function list(args) {
651
749
  function info(args) {
652
750
  const cat = resolveCatalog(args.flags.from);
653
751
  const s = args._[0] || die("pass a skill name");
654
- if (!fs.existsSync(path.join(cat.skillsDir, s))) die(`unknown skill '${s}' in catalog '${cat.source}'`);
752
+ if (!skillExists(cat, s)) die(`unknown skill '${s}' in catalog '${cat.source}'`);
655
753
  const m = manifestOf(cat, s);
656
754
  const ps = packsOf(cat) || {};
657
755
  const inPacks = Object.entries(ps).filter(([, p]) => p.skills.includes(s)).map(([n]) => n);
658
- console.log(`${m.name}@${m.version} (tier: ${m.model && m.model.tier})\n\n${m.description}\n`);
756
+ console.log(`${m.name}@${m.version} (tier: ${(m.model && m.model.tier) || "n/a"})\n\n${m.description}\n`);
659
757
  console.log(`catalog: ${cat.source}`);
660
758
  console.log(`packs: ${inPacks.join(", ") || "-"}`);
661
759
  console.log(`related: ${(m.related || []).join(", ") || "-"}`);
662
- if (((m.deps || {}).pip || []).length || fs.existsSync(path.join(cat.skillsDir, s, "requirements.txt")))
760
+ if (((m.deps || {}).pip || []).length || fs.existsSync(path.join(skillDir(cat, s), "requirements.txt")))
663
761
  console.log("deps: python (requirements.txt)");
664
762
  if (((m.env || {}).required || []).length) console.log(`env: ${m.env.required.join(", ")} (required)`);
665
763
  }
@@ -146,6 +146,7 @@
146
146
  "agent-loop-design": { "tier": "standard", "rationale": "Design synthesis against a fixed state-machine pattern and exit-criteria catalog. The gate-placement judgment is bounded by the blast-radius rule; escalate via ambiguous-input when the task itself is contested." },
147
147
  "subagent-design": { "tier": "standard", "rationale": "Design synthesis against a fixed topology catalog and role-card template. The fan-out-or-refuse judgment is bounded by the three-reasons rule; escalate via ambiguous-input on genuinely novel workflow shapes." },
148
148
  "agent-budget": { "tier": "standard", "rationale": "Quantitative spec synthesis against a fixed tier vocabulary and degradation ladder. Cap-setting judgment is bounded by the 3-5x rule; escalate via ambiguous-input when the workflow itself is undefined." },
149
+ "agents-md-generator": { "tier": "standard", "rationale": "Repo inspection plus synthesis against a fixed section order and line budget — the same shape as reverse-architecture. The judgment is the counterfactual test on each convention line, which is bounded; escalate via large-input on monorepos." },
149
150
  "agent-threat-model": { "tier": "heavy", "rationale": "Adversarial reasoning over a capability graph — the judgment is which mitigations are architectural versus theatrical, and that call is exactly where a weaker model produces a confident wrong answer. Never downgraded." }
150
151
  }
151
152
  }
package/package.json CHANGED
@@ -1,7 +1,11 @@
1
1
  {
2
2
  "name": "skilldrop-cli",
3
- "version": "0.8.0",
3
+ "version": "0.8.2",
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
+ "author": {
6
+ "name": "Sanjay Ananthanarayan",
7
+ "url": "https://github.com/sananthanarayan"
8
+ },
5
9
  "bin": {
6
10
  "skilldrop": "bin/skilldrop.js"
7
11
  },
package/packs.json CHANGED
@@ -14,6 +14,7 @@
14
14
  "tech-comparison-matrix",
15
15
  "threat-model",
16
16
  "agent-threat-model",
17
+ "agents-md-generator",
17
18
  "api-contract-draft",
18
19
  "data-contract",
19
20
  "db-schema-design",
@@ -41,8 +42,9 @@
41
42
  ]
42
43
  },
43
44
  "dev-team": {
44
- "description": "Build-and-ship loop: story implementation with adversarial review, test plans, triage, migrations, release notes, and code-quality gates.",
45
+ "description": "Build-and-ship loop: story implementation with adversarial review, test plans, triage, migrations, release notes, agent-policy files, and code-quality gates.",
45
46
  "skills": [
47
+ "agents-md-generator",
46
48
  "user-story-splitter",
47
49
  "feature-implement-loop",
48
50
  "devils-advocate",
@@ -0,0 +1,80 @@
1
+ ---
2
+ name: agents-md-generator
3
+ description: Generate or audit a repository's AGENTS.md — the agent-policy file Claude Code, Codex, Cursor, Copilot, Kiro and Antigravity read — with every command traced to real evidence in the repo, generic virtue instructions stripped, and forbidden actions named. Use when a repo has no AGENTS.md, when an existing one is stale or ignored, when onboarding a codebase to agentic coding, or when an agent keeps running commands that don't exist.
4
+ ---
5
+
6
+ # agents-md-generator
7
+
8
+ Produces the file agents read *before* the user's prompt. An `AGENTS.md` is not documentation — it is the context an agent spends on every turn, so a line that changes no decision is a line stolen from the task.
9
+
10
+ The failure that makes these files worse than useless is an **invented command**. `npm test` in a repo with no test script sends every agent down a path that fails, and the agent trusts the file over the filesystem. So the rule this skill is built around: **every command traces to evidence in the repo, or it does not appear.**
11
+
12
+ Two modes, chosen by what's already there:
13
+ - **Generate** — no `AGENTS.md` exists. Produce one under the line cap.
14
+ - **Audit** — one exists. Score it, name what can't be verified, emit a diff. Never silently rewrite a hand-tuned file.
15
+
16
+ ## How to respond
17
+
18
+ 1. **Inventory the real command surface before writing anything.** Read, in this order: `package.json` (`scripts`), `Makefile`, `pyproject.toml` / `setup.cfg`, `Cargo.toml`, `go.mod`, `composer.json`, `.github/workflows/*.yml`, `justfile`, `Taskfile.yml`, and any `CONTRIBUTING.md`. CI workflows are the highest-value source: they contain the commands that actually have to pass.
19
+
20
+ For each command record its **provenance** — the file and key it came from. Provenance is what makes audit mode possible later.
21
+
22
+ 2. **Apply the evidence rule without exception.** A command appears only if it traces to a file in the repo. Never infer from ecosystem convention: a Python repo does not necessarily run `pytest`, and a repo with `jest` in `devDependencies` may still have no test script.
23
+
24
+ When a section needs a command that doesn't exist, write the marker, not a guess: ✅ *"Test: `[missing: no test script in package.json or CI]`"* — ❌ *"Test: `npm test`"*. The marker is useful; the guess is a trap.
25
+
26
+ 3. **Derive file placement from the actual tree**, not from what the framework usually does. Name the directories that exist and what belongs in each. Two or three rows beat a full tree dump.
27
+
28
+ 4. **Extract only conventions an agent would otherwise get wrong.** The test is counterfactual: *would a competent agent, without this line, do the wrong thing?* Naming rules that are enforced somewhere, invariants that look arbitrary but aren't, a generated file that must never be hand-edited. If the answer is no, cut the line.
29
+
30
+ Generic virtue instructions — "write clean code", "be thorough", "follow best practices", "use good naming" — are **stripped, not softened.** They consume context and change no behaviour.
31
+
32
+ 5. **Name forbidden actions explicitly.** This is the section most files omit and the one that prevents the most damage: paths that must not be touched, commands that must never run unattended, files that are generated, secrets that must never be committed. Concrete and few.
33
+
34
+ 6. **Assemble under ~150 lines.** In generate mode this is a **hard cap** — go over and cut, lowest value first (background prose, then examples, then convention lines that failed the counterfactual test). In audit mode it is a **warning**: report the overage and name the sections you would cut, because an existing file may be long for good reason.
35
+
36
+ 7. **Satellites only on request, and only as a delta.** If asked to wire a specific tool, emit a satellite (`CLAUDE.md`, `.github/copilot-instructions.md`, `GEMINI.md`) that contains **only what is specific to that tool**, plus one line pointing at `AGENTS.md` for everything shared. **Refuse to copy shared content into a satellite** — four copies of a command list is four chances to be wrong, and the drift is invisible. See [`reference.md`](reference.md) for the per-tool shapes.
37
+
38
+ 8. **Emit.** Generate mode: the file, plus a provenance table showing where each command came from and what was marked `[missing]`. Audit mode: verdict, the unverifiable lines quoted, the virtue instructions to cut, the line-count position, and a concrete diff.
39
+
40
+ **Non-interactive runs:** unstated conventions are simply omitted — an `AGENTS.md` is allowed to be short. If the repo cannot be read at all, emit `BLOCKED: need repo access — every command must trace to a file`. Never produce an `AGENTS.md` from a description of a repo; the whole artifact is a claim about what is in the tree.
41
+
42
+ ## Useful references in this skill
43
+
44
+ - [`reference.md`](reference.md) — where each tool looks, the evidence-source table, the satellite shapes, and the strip-list of virtue phrasings
45
+ - [`templates/agents-md.md`](templates/agents-md.md) — the output skeleton with the section order and the line budget per section
46
+
47
+ ## Quality bar
48
+
49
+ - **Zero unverified commands.** Every one traces to a file and key, or carries a `[missing: …]` marker. This is the bar; a file that fails it is worse than no file.
50
+ - **A newcomer agent could build and test from this file alone** — or can see plainly that the repo has no such command.
51
+ - **Forbidden actions are named**, not implied.
52
+ - **Every convention line passes the counterfactual test.** If an agent would do the right thing without it, it is padding.
53
+ - **≤150 lines generated.** Over the cap means something was kept that should have been cut.
54
+ - **No virtue instructions survive.** Search the output for "clean", "best practice", "thorough", "appropriate", "as needed" — each hit is a line that changes nothing.
55
+ - **It does not restate the README.** Different reader, different job: the README sells and explains, `AGENTS.md` constrains.
56
+
57
+ ## When to use this skill
58
+
59
+ - ✅ A repo is adopting agentic coding and has no `AGENTS.md`
60
+ - ✅ An existing `AGENTS.md` is stale, ignored, or full of advice rather than facts
61
+ - ✅ Agents keep running commands that don't exist in the repo
62
+ - ✅ Onboarding a legacy codebase where the real commands live only in CI
63
+ - ✅ After `reverse-architecture` — its extraction is good input for the conventions section
64
+
65
+ ## When NOT to use this skill
66
+
67
+ - ❌ Writing human contributor docs — that's `CONTRIBUTING.md`, a different reader
68
+ - ❌ Explaining what the project *is* — that's the README
69
+ - ❌ Operating a running service — that's `runbook-generator`
70
+ - ❌ Reviewing an existing document's prose quality — that's `doc-critique`, which takes documents; this one takes a repository
71
+
72
+ ## Anti-patterns to avoid
73
+
74
+ - ❌ **Inventing a command that "should" exist.** The single most damaging thing this artifact can do. A `[missing]` marker is a finding; a guess is a fault the agent will trust.
75
+ - ❌ **Virtue instructions.** "Write clean, maintainable code" is context spent on nothing. Agents already try.
76
+ - ❌ **Dumping the file tree.** Placement rules earn their space; a directory listing does not — the agent can run `ls`.
77
+ - ❌ **Restating the README.** If it's already there, link it.
78
+ - ❌ **A satellite that duplicates `AGENTS.md`.** Guaranteed drift, invisible until an agent acts on the stale copy.
79
+ - ❌ **Silently rewriting a hand-tuned file.** Audit mode emits a diff and lets a human choose; the file may encode decisions the repo can't show you.
80
+ - ❌ **Writing to the cap.** 150 lines is a ceiling, not a target. Most repos need far less.
@@ -0,0 +1,15 @@
1
+ [
2
+ { "query": "Write an AGENTS.md for this repo", "should_trigger": true },
3
+ { "query": "Our AGENTS.md is stale — review it", "should_trigger": true },
4
+ { "query": "The agent keeps running commands that don't exist in our project", "should_trigger": true },
5
+ { "query": "Set this codebase up for agentic coding", "should_trigger": true },
6
+ { "query": "Create a CLAUDE.md for this project", "should_trigger": true },
7
+ { "query": "What should go in an agent instructions file?", "should_trigger": true },
8
+
9
+ { "query": "Write a CONTRIBUTING.md for this repo", "should_trigger": false },
10
+ { "query": "Document what this service does for new hires", "should_trigger": false },
11
+ { "query": "Reverse-engineer the architecture of this codebase", "should_trigger": false },
12
+ { "query": "Write a runbook for this service", "should_trigger": false },
13
+ { "query": "Review this design doc for gaps", "should_trigger": false },
14
+ { "query": "Design a supervised agent loop", "should_trigger": false }
15
+ ]
@@ -0,0 +1,50 @@
1
+ {
2
+ "skill_name": "agents-md-generator",
3
+ "evals": [
4
+ {
5
+ "id": 1,
6
+ "prompt": "Write an AGENTS.md for this repo. It's a Python service: pyproject.toml declares pytest and ruff in dev dependencies, there's a Makefile with `run` and `migrate` targets, and .github/workflows/ci.yml runs `ruff check .` then `pytest -q`. No test script anywhere else. Migrations are in alembic/versions/.",
7
+ "assertions": [
8
+ "Commands are traced to their source — CI for ruff/pytest, Makefile for run/migrate — not inferred from the dependency list",
9
+ "The test command is `pytest -q` as CI runs it, not a guessed `pytest` or `make test` that does not exist",
10
+ "No command appears that cannot be traced to pyproject.toml, the Makefile, or the workflow",
11
+ "Alembic migrations produce a convention or forbidden-action line (append-only / never edit a committed migration)",
12
+ "A `Do not` section exists with concrete entries, not implied caution",
13
+ "Output is at or under ~150 lines",
14
+ "No virtue instructions appear — no 'clean', 'best practice', 'thorough', 'maintainable'",
15
+ "Conventions included would each change agent behaviour if removed"
16
+ ]
17
+ },
18
+ {
19
+ "id": 2,
20
+ "prompt": "Here's our AGENTS.md — audit it. It says: 'Run `npm test` to test. Write clean, maintainable code and follow best practices. Be thorough in reviews.' Our package.json has scripts for build and lint only, no test.",
21
+ "assertions": [
22
+ "Audit mode is used — a verdict and diff, not a silent rewrite",
23
+ "`npm test` is flagged as unverifiable: package.json has no test script",
24
+ "The three virtue instructions are named for removal, with the reason that they change no behaviour",
25
+ "What the file is missing is stated — real commands (build, lint), file placement, forbidden actions",
26
+ "The line-count position is reported rather than the file being failed for length",
27
+ "A concrete replacement or diff is offered, not just criticism"
28
+ ]
29
+ },
30
+ {
31
+ "id": 3,
32
+ "prompt": "Also wire it up for Claude Code and Copilot.",
33
+ "assertions": [
34
+ "Satellites are emitted as deltas only — each points at AGENTS.md for shared content",
35
+ "No satellite repeats the command table, file placement, or conventions",
36
+ "CLAUDE.md carries only Claude-Code-specific content; .github/copilot-instructions.md only Copilot-specific content",
37
+ "If there is no genuinely tool-specific content, that is said rather than a file padded to justify itself"
38
+ ]
39
+ },
40
+ {
41
+ "id": 4,
42
+ "prompt": "[Non-interactive run — no repo access] Generate an AGENTS.md for a typical Node microservice.",
43
+ "assertions": [
44
+ "No AGENTS.md is produced — the output is BLOCKED: need repo access",
45
+ "No commands are invented from ecosystem convention",
46
+ "The reason given is that every command must trace to a file in the tree"
47
+ ]
48
+ }
49
+ ]
50
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "agents-md-generator",
3
+ "version": "0.1.0",
4
+ "description": "Generate or audit a repository's AGENTS.md — the agent-policy file Claude Code, Codex, Cursor, Copilot, Kiro and Antigravity read — with every command traced to real evidence in the repo, generic virtue instructions stripped, and forbidden actions named. Use when a repo has no AGENTS.md, when an existing one is stale or ignored, when onboarding a codebase to agentic coding, or when an agent keeps running commands that don't exist.",
5
+ "entrypoint": "SKILL.md",
6
+ "deps": { "npm": [], "pip": [] },
7
+ "env": { "required": [], "optional": [] },
8
+ "related": ["doc-critique", "reverse-architecture", "runbook-generator"],
9
+ "tags": ["agents-md", "agent-policy", "repo-onboarding", "context-engineering", "agentic", "conventions"],
10
+ "model": { "tier": "standard", "rationale": "Repo inspection plus synthesis against a fixed section order and line budget — the same shape as reverse-architecture. The judgment is the counterfactual test on each convention line, which is bounded; escalate via large-input on monorepos." }
11
+ }
@@ -0,0 +1,89 @@
1
+ # agents-md-generator — reference
2
+
3
+ ## Who reads what
4
+
5
+ Confirmed in the July 2026 survey ([`docs/designs/ide-primitive-coverage.md`](../../docs/designs/ide-primitive-coverage.md)). A root `AGENTS.md` is the broadest single file; satellites are a reach fix for specific tools, not the norm.
6
+
7
+ | Tool | Reads |
8
+ |---|---|
9
+ | Codex | root `AGENTS.md` |
10
+ | GitHub Copilot | root `AGENTS.md`, `.github/copilot-instructions.md`, `.github/instructions/*.instructions.md`, and also root `CLAUDE.md` / `GEMINI.md` |
11
+ | Claude Code | `CLAUDE.md` (auto-loaded) |
12
+ | Cursor | root `AGENTS.md`, plus `.cursor/rules/*.mdc` for rules |
13
+ | Kiro | root `AGENTS.md`, plus `.kiro/steering/` for always-on context |
14
+ | Antigravity | root `AGENTS.md` |
15
+
16
+ **Precedence matters more than reach.** Several of these load on every turn regardless of relevance. A file that is always in context should carry only what earns its place there — the same reason an always-included steering file is a poor home for a persona.
17
+
18
+ ## Evidence sources, in priority order
19
+
20
+ Every command must trace to one of these. Record the file and key as provenance.
21
+
22
+ | Source | What it proves |
23
+ |---|---|
24
+ | `.github/workflows/*.yml` (and other CI) | **Strongest.** These commands must pass or the build fails |
25
+ | `Makefile` / `justfile` / `Taskfile.yml` | Named entry points the team actually uses |
26
+ | `package.json` `scripts` | Node entry points; check the script body, not just the key |
27
+ | `pyproject.toml` / `setup.cfg` / `tox.ini` | Python entry points and runners |
28
+ | `Cargo.toml`, `go.mod`, `composer.json`, `Gemfile` | Ecosystem defaults *only if* the file confirms them |
29
+ | `CONTRIBUTING.md`, `README.md` | Human-facing; **verify against the above before trusting** — docs go stale faster than CI |
30
+ | Dev container / Dockerfile | Setup steps and version pins |
31
+
32
+ **A dependency is not a command.** `jest` in `devDependencies` does not mean `npm test` exists. Check for the script.
33
+
34
+ ## What earns a line — the counterfactual test
35
+
36
+ Ask: *without this line, would a competent agent do the wrong thing?*
37
+
38
+ | ✅ Earns its place | ❌ Cut |
39
+ |---|---|
40
+ | "Generated — never hand-edit `src/api/types.ts`; run `make codegen`" | "Keep the codebase clean and well organised" |
41
+ | "Migrations are append-only; never edit a committed migration" | "Follow database best practices" |
42
+ | "Tests live beside the source as `*_test.go`, not in `tests/`" | "Write comprehensive tests" |
43
+ | "`main` is protected; open a PR" | "Follow good git hygiene" |
44
+ | "Do not run `terraform apply` — plan only, a human applies" | "Be careful with infrastructure" |
45
+
46
+ ## Strip list
47
+
48
+ Search generated output for these; each hit is a line that changes no behaviour:
49
+
50
+ `clean` · `best practice` · `thorough` · `appropriate` · `as needed` · `where possible` · `make sure to` · `try to` · `robust` · `maintainable` · `readable` · `well-structured` · `properly` · `high-quality` · `idiomatic` (unless a specific idiom is named)
51
+
52
+ ## Satellite shapes — delta only
53
+
54
+ A satellite carries what is specific to its tool **and nothing else**. Every shared fact stays in `AGENTS.md` and is pointed at.
55
+
56
+ **`CLAUDE.md`** — Claude Code auto-loads it:
57
+
58
+ ```markdown
59
+ # CLAUDE.md
60
+
61
+ The substantive guidance lives in [AGENTS.md](AGENTS.md). Read it first.
62
+
63
+ This file exists because Claude Code auto-loads `CLAUDE.md`. Everything below is
64
+ Claude-Code-specific and does not belong in the cross-IDE file.
65
+
66
+ ## <tool-specific section>
67
+ …e.g. `${CLAUDE_SKILL_DIR}` semantics, `.claude/settings.json`, subagent delegation…
68
+ ```
69
+
70
+ **`.github/copilot-instructions.md`** — same shape, Copilot-specific content only (custom agents in `.github/agents/`, `.github/hooks/*.json`).
71
+
72
+ **`GEMINI.md`** — same shape, for Gemini/Antigravity specifics.
73
+
74
+ **Refuse** to emit a satellite containing the command table, file placement, or conventions that already live in `AGENTS.md`. If a tool needs those, it reads `AGENTS.md` — and if it genuinely cannot, say so plainly rather than duplicating.
75
+
76
+ ## Line budget
77
+
78
+ 150 lines total. A workable split:
79
+
80
+ | Section | Lines |
81
+ |---|---|
82
+ | Repo in one paragraph | 3–5 |
83
+ | Commands (with provenance verified) | 15–30 |
84
+ | File placement | 10–20 |
85
+ | Conventions that pass the counterfactual test | 20–40 |
86
+ | Forbidden actions | 5–15 |
87
+ | Pointers to deeper docs | 3–5 |
88
+
89
+ Over budget: cut background prose first, then examples, then convention lines that only *probably* pass the test.
@@ -0,0 +1,48 @@
1
+ # AGENTS.md — {project name}
2
+
3
+ > {One line: what an agent needs to know it is working on.}
4
+
5
+ ## Repo in one paragraph
6
+
7
+ {What this is, what it produces, and the one structural fact an agent must hold. 3–5 lines.}
8
+
9
+ ## Commands
10
+
11
+ <!-- Every row traces to a file. No row may be inferred from ecosystem convention. -->
12
+
13
+ | Task | Command | Source |
14
+ |---|---|---|
15
+ | Install | `{cmd}` | `{file}` → `{key}` |
16
+ | Build | `{cmd}` | `{file}` → `{key}` |
17
+ | Test | `{cmd}` *or* `[missing: no test command in CI or manifests]` | `{file}` → `{key}` |
18
+ | Lint | `{cmd}` | `{file}` → `{key}` |
19
+ | Run locally | `{cmd}` | `{file}` → `{key}` |
20
+
21
+ {Drop the Source column from the final file if it crowds the budget — but only after every row has been verified with it present.}
22
+
23
+ ## File placement
24
+
25
+ | Kind | Where |
26
+ |---|---|
27
+ | {thing} | `{path}` |
28
+
29
+ ## Conventions
30
+
31
+ <!-- Each line must pass: without it, would a competent agent do the wrong thing? -->
32
+
33
+ - **{Rule stated as a rule.}** {One clause of why, only if the why changes how it is applied.}
34
+
35
+ ## Do not
36
+
37
+ - {Path, command, or action that must never happen unattended — concrete.}
38
+ - {Generated artifacts that must not be hand-edited, and the command that regenerates them.}
39
+
40
+ ## Pointers
41
+
42
+ - {Deeper doc}: `{path}`
43
+ - {Architecture / design}: `{path}`
44
+
45
+ <!--
46
+ Line budget: 150. Provenance for every command was verified at generation time.
47
+ Commands marked [missing] are findings, not omissions — the repo has no such command.
48
+ -->
@@ -0,0 +1,42 @@
1
+ # Worked example — build vs. buy a feature-flag system
2
+
3
+ Input → output oracle for `business-case`. Shows the ask first (< 40 words), Option 0
4
+ costed, benefits as re-runnable calculations with confidence tags, all three cost
5
+ layers, ranges, the flip-assumption, and a singular recommendation that states the
6
+ runner-up's best argument fairly.
7
+
8
+ ## Input
9
+
10
+ > "Should [Acme] build an in-house feature-flag system or buy a SaaS one? ~30
11
+ > engineers, currently gating releases with config files and redeploys."
12
+
13
+ ## Output
14
+
15
+ ### The ask
16
+ **Buy the SaaS feature-flag service (~$18–30k/yr).** It pays back in < 3 months against ~$140k of first-year build cost and recurring toil, and frees roadmap capacity now. Decision needed before next quarter's release-velocity commitments.
17
+
18
+ ### Options (Option 0 is costed)
19
+
20
+ | Option | Build (one-time) | Run (yr 1) | Opportunity cost |
21
+ |---|--:|--:|--:|
22
+ | **0 — Status quo** (config + redeploy) | $0 | ~$60–90k/yr toil | Slow releases → est. 1–2 delayed launches/yr |
23
+ | **1 — Build in-house** | ~$110–160k | ~$25–40k/yr (on-call, maint.) | 2 eng × 3–4 mo off roadmap |
24
+ | **2 — Buy SaaS** | ~$5k (integrate) | ~$18–30k/yr license | ~1 eng-week integration |
25
+
26
+ ### Benefits (re-runnable calculations, sourced, confidence-tagged)
27
+
28
+ - **Toil removed vs. Option 0:** each gated release currently costs ~1 eng-hr of redeploy coordination × ~15 releases/mo × $120 loaded/hr = **~$22k/yr** recovered. *(confidence: medium — release count from deploy logs; hourly is loaded-cost estimate.)*
29
+ - **Incident reduction:** flag-based instant rollback vs. redeploy shortens mean remediation from ~40 min to ~5 min; at ~6 rollback-worthy incidents/yr that's ~3.5 hrs × team = **~$8–15k/yr** avoided. *(confidence: low — incident count is small-sample; range reflects it.)*
30
+ - **Release velocity:** decoupling deploy from release plausibly removes 1–2 launch slips/yr; value is real but **not costed here** (depends on launch revenue) — flagged for the decision owner.
31
+
32
+ Totals are ranges; the **lower end is likelier** for the hard-dollar items (toil is the solid number; incident/velocity are directional).
33
+
34
+ ### The flip-assumption
35
+ The case flips to **Build** only if **flag evaluation must run in a data plane the SaaS can't reach** (e.g. strict data-residency or sub-ms in-process evaluation at scale). Confidence that this *doesn't* apply is medium. **De-risking step before committing to Buy:** a 1-week spike confirming the SaaS SDK meets latency + residency requirements — cheap insurance against the one assumption that would reverse the decision.
36
+
37
+ ### Recommendation
38
+ **Buy (Option 2).** Lowest first-year cost, fastest payback, and it returns ~2 engineers to the roadmap that Build would consume. **The runner-up's best argument, stated fairly:** Build is genuinely better *if* flag evaluation becomes a core differentiator or a hard data-residency constraint emerges — in that world the SaaS boundary bites and owning the system is worth the cost. The spike above is what tells us which world we're in.
39
+
40
+ ## Why this passes the quality bar
41
+
42
+ The ask leads in under 40 words; Option 0 is present and costed; every benefit is a calculation with sourced inputs and a confidence tag; outputs are ranges naming the likelier end; all three cost layers appear per option; the flip-assumption is identified with a de-risking step; and the recommendation is singular while stating the runner-up's strongest case honestly.
@@ -33,7 +33,7 @@ Five **standing seats** — each a distinct mandate with a lane it stays in. Rea
33
33
  | ⚖️ **Pragmatist** | Is this the simplest thing that works? Over-engineered? Do we even need it? | [`seats/pragmatist.md`](seats/pragmatist.md) |
34
34
  | 👤 **User-Advocate** | Is it correct for the people who use it? Edge cases, errors, contracts, compat? | [`seats/user-advocate.md`](seats/user-advocate.md) |
35
35
 
36
- Plus a **bench** of optional seats (Performance, Cost/FinOps, Data & Migration, Accessibility, Compliance) — seat them only when the change warrants. See [`seats/bench.md`](seats/bench.md).
36
+ Plus a **bench** of optional seats (Performance, Cost/FinOps, Data & Migration, Accessibility, Compliance) — seat them only when the change warrants. See [`seats/bench.md`](seats/bench.md). Chairing and roster-choice guidance that doesn't fit here lives in [`reference.md`](reference.md).
37
37
 
38
38
  The **Chair** is not a sixth opinion. The Chair facilitates, finds the cruxes, and decides.
39
39
 
@@ -0,0 +1,46 @@
1
+ # Worked example — adversarial review of a just-written rate limiter
2
+
3
+ Input → output oracle for `devils-advocate`. Shows the four-lens sweep producing
4
+ severity-calibrated findings with `file:line` evidence and paste-able fixes — not a
5
+ generic "looks good, consider tests" pass.
6
+
7
+ ## Input (the "done" implementation)
8
+
9
+ > "Implemented the per-user rate limiter, tests pass, ready for review."
10
+
11
+ ```python
12
+ # ratelimit.py
13
+ _buckets: dict[str, tuple[float, float]] = {} # user_id -> (tokens, last_refill)
14
+
15
+ def allow(user_id: str, rate: float, burst: float) -> bool:
16
+ now = time.time()
17
+ tokens, last = _buckets.get(user_id, (burst, now))
18
+ tokens = min(burst, tokens + (now - last) * rate)
19
+ if tokens >= 1:
20
+ _buckets[user_id] = (tokens - 1, now)
21
+ return True
22
+ _buckets[user_id] = (tokens, now)
23
+ return False
24
+ ```
25
+
26
+ ## Output (the review)
27
+
28
+ **Verdict: not ready — 1 blocker, 1 major.** Four lenses swept; happy path is fine, the concurrency and growth paths are not.
29
+
30
+ 🟥 **Blocker — race on the shared dict (assumptions lens).** `ratelimit.py:6-11` reads then writes `_buckets[user_id]` with no lock. Two concurrent requests for the same user both read `tokens=1.0`, both pass, both write back `0.0` — the limiter leaks one token per race, so a burst of N parallel requests admits ~2× the intended rate. The "tests pass" because they're single-threaded. *Fix:* guard the read-modify-write with a per-user lock, or move to an atomic backend (Redis `INCR`+TTL). A dict-of-locks keyed by `user_id` is the minimal change.
31
+
32
+ 🟧 **Major — unbounded memory growth (edge-case lens).** `_buckets` never evicts (`:1`). Every distinct `user_id` ever seen stays forever; a service facing the open internet (or spoofable user ids) OOMs over time. *Fix:* cap with an LRU (`functools.lru_cache` won't fit the mutable value — use `cachetools.TTLCache(maxsize=…, ttl=…)`), evicting idle buckets.
33
+
34
+ 🟨 **Minor — first call gets a free full burst (edge-case lens).** A never-seen `user_id` starts at `(burst, now)` (`:6`), so a brand-new user can immediately spend the whole burst. If the intent is "warm up", seed at `min(burst, rate*window)` instead — flag for product, don't silently change.
35
+
36
+ ⚪ **Nit — `rate`/`burst` unvalidated (staff-engineer lens).** `rate<=0` freezes every user out; `burst<1` makes `allow` always false. Assert `rate>0 and burst>=1` at the boundary.
37
+
38
+ **Test-coverage gaps (the "tests pass" were happy-path only):**
39
+ - Concurrency: two threads hammering one `user_id` must not exceed `burst + rate*elapsed` admits.
40
+ - Refill: after exhausting tokens, `allow` returns True again only after `1/rate` seconds.
41
+ - Eviction: memory stays bounded under 10k distinct ids.
42
+ - Boundary: `tokens` sitting at exactly `1.0` admits; at `0.999…` denies.
43
+
44
+ ## Why this passes the quality bar
45
+
46
+ Severity is calibrated (one blocker, demoted the rest); every finding cites `file:line`, names the *lens* it came from, and gives a concrete fix or a specific missing test — not "add more tests."
@@ -0,0 +1,34 @@
1
+ # Worked example — critique of a design-doc excerpt
2
+
3
+ Input → output oracle for `doc-critique`. Shows local, doc-quoting findings with
4
+ paste-able fixes — reviewing whether the doc *made its case*, not re-debating the topic.
5
+
6
+ ## Input (excerpt of a design doc under review)
7
+
8
+ > ## TL;DR
9
+ > We will build an innovative, scalable notification service to leverage our
10
+ > existing infrastructure and deliver best-in-class user engagement.
11
+ >
12
+ > ## Approach
13
+ > The service consumes events and sends notifications. It will be highly
14
+ > available and performant. We considered several options and chose a
15
+ > queue-based design because it is the industry standard.
16
+ >
17
+ > ## Rollout
18
+ > We will roll it out to all users.
19
+
20
+ ## Output (the critique)
21
+
22
+ **Verdict: not ready to circulate — 1 blocker, 2 major, 1 minor.** The doc asserts conclusions it never earns; a reader can't tell what's being built or why this shape.
23
+
24
+ 🟥 **Blocker — the decision has no rationale (§ Approach).** Quoted: *"chose a queue-based design because it is the industry standard."* "Industry standard" is not a reason; it hides the actual tradeoff. *Fix:* replace with the decision's real driver — e.g. "chose a queue so a downstream outage buffers events instead of dropping them; the alternative (synchronous fan-out) loses notifications when a provider is down." Name the alternative and why it lost.
25
+
26
+ 🟧 **Major — TL;DR is adjectives, not content (§ TL;DR).** Quoted: *"innovative, scalable … leverage … best-in-class user engagement."* Five value-words, zero facts — a reader learns nothing about scope. *Fix:* state what it does and the one number that matters: "A queue-backed service that delivers email/push notifications from domain events, targeting < 5s p95 delivery for 1M events/day."
27
+
28
+ 🟧 **Major — unfalsifiable quality claims (§ Approach).** Quoted: *"highly available and performant."* No SLO, so nothing can be reviewed or later checked. *Fix:* commit numbers — availability target (e.g. 99.9%), p95 latency, throughput — or move them to an explicit "Open questions" list if unknown.
29
+
30
+ 🟨 **Minor — rollout has no stages or guardrail (§ Rollout).** Quoted: *"roll it out to all users."* No canary, no rollback trigger. *Fix:* a 2–3 line staged plan (1% → 10% → 100%) and the metric that halts it (delivery-failure rate > X%).
31
+
32
+ ## Why this passes the quality bar
33
+
34
+ Severity is calibrated (one blocker). Every finding is **local** and **quotes the doc verbatim** (the audit trail that it was actually read), the fixes are paste-able, and it critiques the *doc's* case-making — it does not re-argue whether a queue is the right architecture.
@@ -0,0 +1,42 @@
1
+ # Worked example — SWOT arriving as TOWS for a market-entry decision
2
+
3
+ Input → output oracle for `strategy-analysis`. Shows the framework justified in one
4
+ line, evidenced/consequential cells, the mandatory SWOT→TOWS crossings, ranked
5
+ action-shaped implications tied to the decision, and a verdict that takes a side.
6
+
7
+ ## Input
8
+
9
+ > "Should [Acme], a mid-market B2B analytics vendor, enter the SMB self-serve
10
+ > segment next year? Decision owner wants a go / no-go with conditions."
11
+
12
+ ## Framework fit (one line)
13
+
14
+ **SWOT→TOWS**, not Five Forces: the question is about *our* fit to a new segment (internal capabilities vs. external openings), not the structural attractiveness of the industry.
15
+
16
+ ## SWOT (every cell specific · evidenced · consequential)
17
+
18
+ | | Helpful | Harmful |
19
+ |---|---|---|
20
+ | **Internal** | **S1** Self-serve onboarding already built for mid-market trials (evidence: 40% of trials activate with zero sales touch) → *marginal cost to serve SMB is low.* | **W1** Pricing starts at $2k/mo (evidence: current floor plan) → *5–10× above SMB willingness-to-pay; no viable entry SKU.* |
21
+ | **External** | **O1** No incumbent owns SMB self-serve analytics in this niche (evidence: top 3 competitors are all sales-led, $10k+ ACV) → *an unserved segment with a wedge.* | **T1** Two horizontal BI tools added SMB free tiers this year (evidence: their changelogs) → *the window is closing; a free tier resets price expectations.* |
22
+
23
+ ## TOWS crossings (the strategy — inventory becomes moves)
24
+
25
+ - **S1 × O1 (invest):** Package the existing zero-touch onboarding as a low-price self-serve SKU to claim the unserved niche before it's contested.
26
+ - **W1 × T1 (defend/decide):** The $2k floor collides head-on with free tiers — a new SMB SKU is a *prerequisite*, not an option; without it, don't enter.
27
+ - **S1 × T1 (hedge):** Low cost-to-serve means an SMB tier can be near-free to run, so a defensive free/low tier is affordable if a competitor forces it.
28
+ - **W1 × O1 (fix-first):** The opportunity is real but unreachable until pricing is solved — so pricing is the gating workstream, not marketing.
29
+
30
+ ## Ranked implications (action-shaped, tied to the go/no-go)
31
+
32
+ 1. **Gate the decision on a validated SMB SKU** (target ≤ $99/mo, positive unit economics at self-serve volume). No SKU → no-go. *(from W1×T1, W1×O1)*
33
+ 2. **Run a 60-day self-serve pilot** on the existing onboarding to test activation without sales. *(S1×O1)*
34
+ 3. **Pre-commit a free-tier response** so a competitor's move doesn't catch us flat. *(S1×T1)*
35
+
36
+ ## Verdict (takes a side + what would change it)
37
+
38
+ **Conditional GO** — enter *only* after a sub-$100 SKU clears a unit-economics test in a 60-day pilot; the low cost-to-serve and the open niche make the upside real, but the pricing gap is disqualifying until fixed. **What flips it to no-go:** the pilot shows self-serve activation < 20% (the zero-touch advantage doesn't transfer), or a horizontal BI tool ships a *vertical* SMB tier first (the wedge closes).
39
+
40
+ ## Why this passes the quality bar
41
+
42
+ The framework choice is justified; every cell is specific, evidenced, and carries a "→ so what"; SWOT is delivered *as TOWS* with real crossings; implications are ranked and tied to the named decision; and the verdict commits with a falsifiable flip-condition instead of "it depends."
@@ -0,0 +1,41 @@
1
+ # Worked example — weighted comparison of message queues
2
+
3
+ Input → output oracle for `tech-comparison-matrix`. Shows shown weights, a one-line
4
+ justification per score, honest "rough" markers, and a one-sentence recommendation.
5
+
6
+ ## Input
7
+
8
+ > "We need a message queue for an order-processing pipeline: ~5k msg/s, must not
9
+ > lose messages, small team, already on AWS. Compare [managed-broker-A],
10
+ > [self-hosted-broker-B], and [cloud-queue-C]."
11
+
12
+ ## Output
13
+
14
+ **Weights** (sum to 100, set by the stated constraints — durability and ops-load dominate because the team is small and messages can't be lost):
15
+
16
+ | Criterion | Weight | Why this weight |
17
+ |---|--:|---|
18
+ | Durability / no message loss | 30 | Hard requirement — order data. |
19
+ | Operational load | 25 | Small team; running a broker is a tax. |
20
+ | Throughput headroom | 15 | 5k/s is modest; all three clear it, so it's not decisive. |
21
+ | Delivery semantics / ordering | 15 | Orders need per-key ordering. |
22
+ | Ecosystem fit (AWS) | 15 | Already on AWS; native integration saves glue. |
23
+
24
+ **Scores** (1–5, each justified; ties kept where real):
25
+
26
+ | Criterion | Wt | [managed-broker-A] | [self-hosted-broker-B] | [cloud-queue-C] |
27
+ |---|--:|--:|--:|--:|
28
+ | Durability | 30 | 5 — replicated, managed | 5 — replicated *if* configured right | 5 — replicated, managed |
29
+ | Ops load | 25 | 4 — managed, some tuning | 2 — you patch/scale/monitor it | 5 — fully serverless |
30
+ | Throughput (rough) | 15 | 4 — ~tens of k/s | 5 — highest ceiling | 4 — ample for 5k/s |
31
+ | Semantics/ordering | 15 | 4 — ordered per partition | 5 — most flexible | 3 — FIFO variant, lower quotas |
32
+ | AWS fit | 15 | 3 — runs on AWS, not native | 2 — self-run on EC2/EKS | 5 — native service |
33
+ | **Weighted total** | | **4.15** | **3.55** | **4.45** |
34
+
35
+ **Recommendation:** Pick **[cloud-queue-C]** — its serverless ops profile decisively fits a small team with a modest, durability-critical load, and the only real gap (ordering quotas) is manageable at 5k/s.
36
+
37
+ *Directional note:* throughput scores are rough (order-of-magnitude, not benchmarked); if load is likely to 10× within a year, re-weight throughput up and re-score — [self-hosted-broker-B]'s ceiling starts to matter.
38
+
39
+ ## Why this passes the quality bar
40
+
41
+ Weights are shown and tied to the question; every score carries a one-line justification; ties (durability 5/5/5) are left as ties; the guessed throughput numbers are flagged "rough"/"directional"; and the recommendation is one decisive sentence, not hedged.