skilldrop-cli 0.13.0 → 0.13.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,13 +3,13 @@
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 62 skills, filterable by outcome, pack, tag, and model tier.
6
+ **[Browse the catalogue →](https://sananthanarayan.github.io/skilldrop/)** — all 63 skills, filterable by outcome, pack, tag, and model tier.
7
7
 
8
- **62 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
+ **63 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
- npx skilldrop-cli install --pack product-manager # or: solution-architect, dev-team,
12
- npx skilldrop-cli list # sre-oncall, stakeholder-comms, ai-engineering, claude-api
11
+ npx skilldrop-cli install --pack product-manager # or: solution-architect, dev-team, sre-oncall,
12
+ npx skilldrop-cli list # stakeholder-comms, ai-engineering, claude-api (each brings core)
13
13
  ```
14
14
 
15
15
  Originally scoped to solution architects, now broadly useful to PMs, founders, consultants, engineering leaders, exec assistants — anyone who turns ideas into stakeholder-ready artifacts.
@@ -24,13 +24,14 @@ skilldrop ships **loops**, not just parts. A loop is a named sequence of stages
24
24
 
25
25
  A loop *sequences* skills — it never contains one. Every skill stays independently installable and runnable on its own, which is what keeps a single-folder copy working in Cursor, Kiro, or Aider.
26
26
 
27
- Four loops cover the lifecycle, and they are separated by **reversibility** — how expensive the mistake is to unwind — which is why each gets its own gate rather than folding into a neighbour:
27
+ Five loops cover the lifecycle, and they are separated by **reversibility** — how expensive the mistake is to unwind — which is why each gets its own gate rather than folding into a neighbour:
28
28
 
29
29
  | Loop | Takes | Gate | Produces | Mistake costs |
30
30
  |---|---|---|---|---|
31
31
  | [`discover`](loops/discover/LOOP.md) | interviews, journeys, a strategy question | **G0** human — a person ratifies the brief | a ratified requirement | a re-brief |
32
32
  | [`design`](loops/design/LOOP.md) | a ratified requirement | **G1** review — `council-review`'s panel | a recorded decision (ADR) | months, unwound in code |
33
33
  | [`build`](loops/build/LOOP.md) | an agreed requirement or triaged defect | **G2** mechanical — `pre-merge-review`'s gate script decides | merged code | a revert |
34
+ | [`release`](loops/release/LOOP.md) | merged code | **G2.5** review — `launch-readiness` on evidence; **G2.6** human go/no-go | a live, reversible rollout | users and data, often irreversible |
34
35
  | [`operate`](loops/operate/LOOP.md) | a shipped service | **G3** human — the incident is closed | a postmortem and runbook deltas | live users, irreversible |
35
36
 
36
37
  Plus one **wrapper**, which is not a lifecycle stage but the two passes either side of *any* generator:
@@ -144,6 +145,41 @@ flowchart LR
144
145
 
145
146
  <!-- loop:build:end -->
146
147
 
148
+ ### `release` — merged code to live users
149
+
150
+ Plan the rollout and the way back, judge readiness on evidence, draft the release notes, then a human makes the go/no-go call. The gap between a merge you can revert and a launch you often cannot.
151
+
152
+ <!-- loop:release:start -->
153
+
154
+ ```mermaid
155
+ %%{init: {'theme':'base','themeVariables':{'fontFamily':'Segoe UI, Helvetica, Arial','fontSize':'15px','lineColor':'#9AA5B1'},'flowchart':{'curve':'basis','rankSpacing':70,'nodeSpacing':50,'padding':16}}}%%
156
+ flowchart LR
157
+ classDef gen fill:#E8F0FE,stroke:#4C7DF0,stroke-width:1.5px,color:#1A3A8F;
158
+ classDef review fill:#FDEAEA,stroke:#E05B5B,stroke-width:1.5px,color:#8A1F1F;
159
+ classDef gate fill:#FBE3A2,stroke:#D9971E,stroke-width:2px,color:#6B4500,font-weight:bold;
160
+ classDef ship fill:#E6F7EC,stroke:#34A853,stroke-width:2px,color:#0F6B33,font-weight:bold;
161
+
162
+ plan["plan<br/><small>migration-plan</small>"]:::gen
163
+ ready["ready<br/><small>launch-readiness</small>"]:::review
164
+ announce["announce<br/><small>release-notes</small>"]:::gen
165
+ go["go<br/><small>council-review</small>"]:::gate
166
+ G2_5{"G2.5 · review"}:::gate
167
+ G2_6{"G2.6 · human"}:::gate
168
+ DONE(["complete"]):::ship
169
+
170
+ plan --> ready
171
+ ready --> G2_5
172
+ G2_5 == "PROCEED" ==> announce
173
+ announce --> go
174
+ go --> G2_6
175
+ G2_6 == "PROCEED" ==> DONE
176
+
177
+ G2_5 -- "REVISE (max 3)" --> plan
178
+ G2_6 -- "REVISE (max 3)" --> plan
179
+ ```
180
+
181
+ <!-- loop:release:end -->
182
+
147
183
  ### `operate` — a shipped service through detection and learning
148
184
 
149
185
  Instrument, write the runbook, communicate the incident, then feed the postmortem's runbook deltas straight back into the runbook. The one loop whose failures are live.
@@ -235,6 +271,7 @@ Skills for the SDLC steps around the code itself — turning raw requirements in
235
271
  | [`release-notes`](skills/release-notes/SKILL.md) | Turn git history between two refs (default: last tag → HEAD) into two artifacts: customer-facing release notes rewritten in reader benefits — no commit-speak, no ticket IDs, no "various improvements" — and an internal Keep-a-Changelog version with a commit hash on every line. Breaking changes hoisted to the top of both with an "Action required" line (detected via `!:` markers, removed public API, migration files, major bumps); internal noise (refactors, CI, deps) never leaks into customer notes; vague commits land in a "Needs review" list instead of being guessed at. |
236
272
  | [`bug-triage`](skills/bug-triage/SKILL.md) | Turn a vague bug report ("it's broken on mobile sometimes") into a ticket an engineer can start without contacting the reporter: searchable symptom-plus-condition title, numbered repro steps from a clean state (or an explicit "no repro yet" with the exact diagnostics to collect), expected-vs-actual with the verbatim error string, every claim tagged `[reported]` / `[verified]` / `[assumption]`, severity and priority judged independently (S4/P1 is a legitimate combination), ≤3 hypotheses each with a 5-minute check, and duplicate-search hints. One bug per ticket — multi-symptom reports get split. |
237
273
  | [`migration-plan`](skills/migration-plan/SKILL.md) | Phased migration/rollout plan (schema change with live backfill, API version, datastore/auth/platform swap) built on the parallel-change pattern: expand → migrate → contract. One change per phase (a failed phase implicates exactly one thing); every phase carries an observable gate with bake time, a tested rollback with an explicit data story, and a blast radius; at most one **named point of no return**; backfill specified idempotent + resumable + rate-limited with 3-depth parity checks; dual-write requires a named reconciler; the contract phase gets a date and an owner so "we'll remove the old path later" actually happens. |
274
+ | [`launch-readiness`](skills/launch-readiness/SKILL.md) | Go/no-go readiness report for a merged change before it reaches users. It lists the change's own failure modes first, then judges seven checks in order: rollback, detection, response, measured NFR targets, data & privacy, comms, staged exposure. Each row is met / not met / n/a-with-reason, with an evidence link and an owner role, and a row with no evidence is `not met`. The verdict (PROCEED / PROCEED WITH CONDITIONS / REVISE / BLOCKED) follows mechanically from the rows, and a missing rollback blocks on its own. Gaps go to `migration-plan`, `observability-plan` or `runbook-generator` instead of being drafted inline. The `ready` stage of the `release` loop. |
238
275
 
239
276
  ### Product strategy
240
277
 
@@ -388,17 +425,18 @@ Why not have an LLM pick the model live on every call? Because that pays tokens
388
425
 
389
426
  ## Skill packs — install a role's toolkit in one command
390
427
 
391
- Categories (above) say what a skill *is*; packs say *who needs it*. [`packs.json`](packs.json) defines six role-based bundles — packs overlap where a skill serves several roles, and every skill belongs to at least one:
428
+ Categories (above) say what a skill *is*; packs say *who needs it*. [`packs.json`](packs.json) gives every skill and every loop **exactly one home** ([RFC-0033](docs/rfcs/0033-core-pack-and-single-home-skills.md)). Skills every role uses live in **`core`**, and each role pack `requires` it, so installing a role pack installs `core` with it in the same command:
392
429
 
393
- | Pack | Skills | For |
394
- |---|---|---|
395
- | `solution-architect` | 17 | Design-phase artifacts: diagrams, ADRs, design docs, contracts, schemas, threat models, and the reviews that gate them |
396
- | `dev-team` | 14 | Build-and-ship loop: implementation with adversarial review, test plans, triage, migrations, release notes, quality gates, pre-ship hygiene |
397
- | `product-manager` | 13 | Direction to requirements: PR/FAQs, strategy frameworks, OKRs, PRDs, journey maps, story splitting, success measurement |
398
- | `ai-engineering` | 12 | Build and run AI systems: agent loop design, subagent orchestration, spend budgets, eval harnesses, usage reporting, data contracts |
399
- | `stakeholder-comms` | 9 | Non-technical audiences: audience profiling, deck outlines and real `.pptx` decks, exec summaries, decision logs, guides |
400
- | `sre-oncall` | 5 | Operate the service: runbooks, observability design, incident comms, postmortems, capacity/cost models |
401
- | `claude-api` | 4 | Build on the Anthropic API: prompt caching strategy, token budgeting, eval generation for skills, tool-use schema writing |
430
+ | Pack | Skills | Loops | For |
431
+ |---|---|---|---|
432
+ | `core` | 4 | `ship-a-draft` | Every role: structured intake, document critique, the review council, output hygiene. Comes with every role pack |
433
+ | `dev-team` | 14 + core | `build`, `release` | Build-and-ship: story splitting, implementation with adversarial review, test plans, triage, migrations, launch readiness, release notes, quality gates |
434
+ | `solution-architect` | 11 + core | `design` | Design-phase artifacts: diagrams, ADRs, design docs, contracts, schemas, threat models |
435
+ | `ai-engineering` | 11 + core | — | Adopt and build AI systems: readiness, use-case triage, rollout and policy, agent loop design, subagents, spend budgets, agent threat models, evals, usage reporting |
436
+ | `product-manager` | 8 + core | `discover` | Direction to requirements: PR/FAQs, strategy frameworks, OKRs, business cases, interviews, PRDs, journey maps, success measurement |
437
+ | `stakeholder-comms` | 6 + core | — | Non-technical audiences: audience profiling, deck outlines and real `.pptx` decks, exec summaries, decision logs, guides |
438
+ | `sre-oncall` | 5 + core | `operate` | Operate the service: runbooks, observability design, incident comms, postmortems, capacity/cost models |
439
+ | `claude-api` | 4 | — | Build on the Anthropic API: prompt caching strategy, token budgeting, eval generation for skills, tool-use schema writing. A specialist add-on; it does not bring core |
402
440
 
403
441
  ```bash
404
442
  python3 pack.py # list packs
@@ -408,7 +446,7 @@ python3 pack.py product-manager --install --project # into .claude/skills/
408
446
  python3 pack.py product-manager --install --dest .cursor/skills # any dir, for non-Claude IDEs
409
447
  ```
410
448
 
411
- For non-Claude IDEs, `--dest` drops the folders where your tool expects them; the per-IDE wiring steps below still apply. Packs are metadata only — skills stay in flat `skills/<name>` folders, so per-skill `cp -R` installs keep working unchanged ([RFC-0001](docs/rfcs/0001-skill-packs.md) records the design decision).
449
+ For non-Claude IDEs, `--dest` drops the folders where your tool expects them; the per-IDE wiring steps below still apply. Packs are metadata only — skills stay in flat `skills/<name>` folders, so per-skill `cp -R` installs keep working unchanged ([RFC-0001](docs/rfcs/0001-skill-packs.md) records the original decision; [RFC-0033](docs/rfcs/0033-core-pack-and-single-home-skills.md) replaced its overlapping packs with `core` and one home per skill).
412
450
 
413
451
  ## Outcomes — browse by why you're here
414
452
 
@@ -442,13 +480,13 @@ npx skilldrop-cli install --pack dev-team --project # .claude/skills — als
442
480
  npx skilldrop-cli install prfaq --ide cursor # + writes .cursor/rules/prfaq.mdc
443
481
  npx skilldrop-cli install --pack sre-oncall --ide kiro # .kiro/skills — Kiro IDE + Kiro CLI, discovered natively
444
482
  npx skilldrop-cli install adr-generator --dest .agents/skills # Codex + Copilot CLI (see below)
445
- npx skilldrop-cli loops # the five loops, their stages and gates
483
+ npx skilldrop-cli loops # the six loops, their stages and gates
446
484
  npx skilldrop-cli install --loop build # a loop + every stage skill it sequences (RFC-0028)
447
485
  npx skilldrop-cli install --loop --pack sre-oncall # every loop that pack declares
448
486
  npx skilldrop-cli agents # the reviewer subagents
449
487
  npx skilldrop-cli install --agent devils-advocate # -> ~/.claude/agents/ (RFC-0012)
450
488
  npx skilldrop-cli install --panel review # the whole review fleet: 3 subagents + the pre-merge-review orchestrator (RFC-0020)
451
- npx skilldrop-cli outdated && npx skilldrop-cli update # skills improve; cp -R never tells you
489
+ npx skilldrop-cli outdated && npx skilldrop-cli update # skills improve; files you edited are kept, new copy as <file>.upstream
452
490
  npx skilldrop-cli list | skilldrop info <skill> | skilldrop packs | skilldrop uninstall <skill>
453
491
  npx skilldrop-cli list --json # machine-readable: list/info/packs/agents/outdated (RFC-0021)
454
492
  ```
@@ -466,18 +504,20 @@ skilldrop is also a **Claude Code plugin marketplace** — one marketplace, seve
466
504
  Then take the whole catalogue, or just your role's pack:
467
505
 
468
506
  ```text
469
- /plugin install skilldrop@skilldrop # all 62 skills + 3 reviewer subagents
470
- /plugin install solution-architect@skilldrop # 17 skills
471
- /plugin install dev-team@skilldrop # 14 skills + the 3 reviewer subagents
472
- /plugin install product-manager@skilldrop # 13 skills
473
- /plugin install ai-engineering@skilldrop # 12 skills
474
- /plugin install stakeholder-comms@skilldrop # 9 skills
475
- /plugin install sre-oncall@skilldrop # 5 skills
507
+ /plugin install skilldrop@skilldrop # all 63 skills + 3 reviewer subagents
508
+ /plugin install dev-team@skilldrop # 18 skills (incl. core) + the 3 reviewer subagents
509
+ /plugin install solution-architect@skilldrop # 15 skills (incl. core)
510
+ /plugin install ai-engineering@skilldrop # 15 skills (incl. core)
511
+ /plugin install product-manager@skilldrop # 12 skills (incl. core)
512
+ /plugin install stakeholder-comms@skilldrop # 10 skills (incl. core)
513
+ /plugin install sre-oncall@skilldrop # 9 skills (incl. core)
514
+ /plugin install claude-api@skilldrop # 4 skills
515
+ /plugin install core@skilldrop # 4 skills, on their own
476
516
  ```
477
517
 
478
518
  Every skill then invokes as `/<plugin>:<name>` (e.g. `/skilldrop:prfaq`). The whole-catalogue plugin ships the flat `skills/` and `agents/` trees at the repo root unchanged — same copy-install premise, expressed in Claude's own plugin format.
479
519
 
480
- The six **pack plugins** work differently, because a plugin's skills have to sit in a `skills/` folder inside the plugin. Rather than duplicate every skill into six directories on `main` — physical packs, which [RFC-0001](docs/rfcs/0001-skill-packs.md) rejected — the marketplace entries use Claude's `git-subdir` source to point at `packs/<name>/` on a generated [`plugins`](https://github.com/sananthanarayan/skilldrop/tree/plugins) branch, rebuilt by CI on every push to main. Nothing moves in the source tree, and you still only ever type the one `marketplace add`. A pack carries the reviewer subagents its own skills delegate to, so `dev-team` brings the review panel and `sre-oncall` does not.
520
+ The eight **pack plugins** work differently, because a plugin's skills have to sit in a `skills/` folder inside the plugin. Rather than duplicate every skill into eight directories on `main` — physical packs, which [RFC-0001](docs/rfcs/0001-skill-packs.md) rejected — the marketplace entries use Claude's `git-subdir` source to point at `packs/<name>/` on a generated [`plugins`](https://github.com/sananthanarayan/skilldrop/tree/plugins) branch, rebuilt by CI on every push to main. Nothing moves in the source tree, and you still only ever type the one `marketplace add`. Each role pack's plugin also carries `core`'s skills and loops, since a plugin installs on its own. A pack carries the reviewer subagents its own skills delegate to, so `dev-team` brings the review panel and `sre-oncall` does not.
481
521
 
482
522
  `.claude-plugin/{marketplace,plugin}.json` are generated from `package.json` + `packs.json` by [`build_marketplace.py`](build_marketplace.py) (`--check` guards drift in CI; `--dist` renders the branch). Use the CLI above when you want per-skill granularity, another IDE, or hooks; use the marketplace when you're in Claude Code. Rationale: [RFC-0027](docs/rfcs/0027-retire-agentbundle-export.md).
483
523
 
package/bin/skilldrop.js CHANGED
@@ -13,6 +13,7 @@ const fs = require("fs");
13
13
  const path = require("path");
14
14
  const os = require("os");
15
15
  const { execFileSync } = require("child_process");
16
+ const crypto = require("crypto");
16
17
 
17
18
  const ROOT = path.resolve(__dirname, "..");
18
19
  const LEDGER = ".skilldrop.json";
@@ -48,7 +49,9 @@ Usage:
48
49
  (--no-skills for the loop alone) (RFC-0028)
49
50
  skilldrop install --panel review install the review panel — the 3 reviewer subagents +
50
51
  the pre-merge-review orchestrator that fires them (RFC-0020)
51
- skilldrop update re-copy installed skills whose version changed
52
+ skilldrop update [--force] re-copy installed skills whose version changed; files
53
+ you edited are kept and the new copy lands beside them
54
+ as <file>.upstream (--force overwrites) (RFC-0032)
52
55
  skilldrop outdated show installed vs current versions, change nothing
53
56
  skilldrop uninstall <skill...> remove skills (and wiring files this tool wrote)
54
57
  skilldrop uninstall --agent <name...> remove subagents
@@ -264,6 +267,15 @@ function packsOf(cat) {
264
267
  const p = path.join(cat.dir, "packs.json");
265
268
  return fs.existsSync(p) ? readJSON(p).packs : null;
266
269
  }
270
+ /* RFC-0033: a pack installs together with the packs it `requires` (in practice, core), so
271
+ one --pack still delivers a role's whole toolkit now that shared skills have one home. */
272
+ function packMembers(ps, name, key) {
273
+ const req = (ps[name].requires || []).filter((r) => ps[r]);
274
+ const out = [];
275
+ for (const n of [...req, name]) for (const x of ps[n][key] || []) if (!out.includes(x)) out.push(x);
276
+ if (req.length) console.log(`pack '${name}' includes ${req.join(", ")}`);
277
+ return out;
278
+ }
267
279
  function profilesOf(cat) {
268
280
  const p = path.join(cat.dir, "profiles.json");
269
281
  return fs.existsSync(p) ? readJSON(p).profiles : null;
@@ -709,7 +721,7 @@ function expandNames(args, cat) {
709
721
  if (!ps) die(`catalog '${cat.source}' has no packs.json — install skills by name`);
710
722
  const p = ps[args.flags.pack];
711
723
  if (!p) die(`unknown pack '${args.flags.pack}' in catalog '${cat.source}'`);
712
- return p.skills.slice();
724
+ return packMembers(ps, args.flags.pack, "skills");
713
725
  }
714
726
  if (!args._.length) die("nothing to install — pass skill names, --pack <name>, or --all");
715
727
  for (const s of args._) if (!skillExists(cat, s)) die(`unknown skill '${s}' in catalog '${cat.source}'`);
@@ -721,10 +733,64 @@ function copyOne(cat, s, dest, ide, l, notes) {
721
733
  fs.cpSync(skillDir(cat, s), path.join(dest, s), { recursive: true });
722
734
  const note = writeWiring(ide, dest, s, m.description);
723
735
  if (note && notes) notes.push(note);
724
- l.data[s] = { version: m.version, source: cat.source };
736
+ l.data[s] = { version: m.version, source: cat.source, files: fileHashes(skillDir(cat, s)) };
725
737
  return m;
726
738
  }
727
739
 
740
+ /* RFC-0032: per-file SHA-256 of a skill as the catalog shipped it, recorded in the ledger at
741
+ copy time. It is the baseline `update` compares against, so a file the user edited is never
742
+ overwritten. Paths are forward-slash relative; *.upstream files are this tool's output. */
743
+ function sha256(buf) { return crypto.createHash("sha256").update(buf).digest("hex"); }
744
+ function fileHashes(dir) {
745
+ const out = {};
746
+ (function walk(d, rel) {
747
+ for (const e of fs.readdirSync(d, { withFileTypes: true })) {
748
+ const r = rel ? `${rel}/${e.name}` : e.name;
749
+ if (e.isDirectory()) walk(path.join(d, e.name), r);
750
+ else if (e.isFile() && !e.name.endsWith(".upstream")) out[r] = sha256(fs.readFileSync(path.join(d, e.name)));
751
+ }
752
+ })(dir, "");
753
+ return out;
754
+ }
755
+
756
+ /* Update one skill file by file against the ledger baseline (RFC-0032):
757
+ upstream unchanged -> leave the local file alone, edited or not
758
+ local untouched, or new file -> take the new version
759
+ local edited, upstream moved -> keep the local file, write the new one as <file>.upstream
760
+ A file the catalog dropped is removed only if the user never touched it. The new baseline is
761
+ what the catalog ships now, so a kept edit stays "edited" until the user merges it. */
762
+ function mergeOne(cat, s, dest, ide, l, notes) {
763
+ const m = manifestOf(cat, s);
764
+ const src = skillDir(cat, s), dst = path.join(dest, s);
765
+ const base = l.data[s].files, next = fileHashes(src);
766
+ const kept = [], orphaned = [];
767
+ const at = (root, rel) => path.join(root, ...rel.split("/"));
768
+ const localHash = (rel) => { try { return sha256(fs.readFileSync(at(dst, rel))); } catch (e) { return null; } };
769
+ for (const [rel, h] of Object.entries(next)) {
770
+ const mine = localHash(rel), to = at(dst, rel);
771
+ if (mine === h) { fs.rmSync(to + ".upstream", { force: true }); continue; }
772
+ if (h === base[rel]) continue;
773
+ fs.mkdirSync(path.dirname(to), { recursive: true });
774
+ if (mine === null ? !(rel in base) : mine === base[rel]) {
775
+ fs.copyFileSync(at(src, rel), to);
776
+ fs.rmSync(to + ".upstream", { force: true });
777
+ } else {
778
+ fs.copyFileSync(at(src, rel), to + ".upstream");
779
+ kept.push(rel);
780
+ }
781
+ }
782
+ for (const rel of Object.keys(base)) {
783
+ if (rel in next) continue;
784
+ const mine = localHash(rel);
785
+ if (mine === base[rel]) fs.rmSync(at(dst, rel), { force: true });
786
+ else if (mine !== null) orphaned.push(rel);
787
+ }
788
+ const note = writeWiring(ide, dest, s, m.description);
789
+ if (note && notes) notes.push(note);
790
+ l.data[s] = { version: m.version, source: cat.source, files: next };
791
+ return { m, kept, orphaned };
792
+ }
793
+
728
794
  /* Install a whole review panel — the reviewer subagents + the orchestrator skill — in one
729
795
  command (RFC-0020). Needs a target with BOTH a subagent and a skill format, so it accepts
730
796
  the default (Claude Code), --project, --ide kiro, or --dest; other IDEs install the halves
@@ -874,18 +940,30 @@ function installedRows(flags) {
874
940
  function update(args) {
875
941
  const { dest, ide, l, rows } = installedRows(args.flags);
876
942
  if (!rows.length) return console.log(`nothing installed at ${dest}`);
877
- let n = 0;
943
+ let n = 0, conflicts = 0;
878
944
  for (const r of rows) {
879
945
  if (!r.current) { console.log(`skip ${r.s}: source '${r.src}' unreachable or skill gone from it`); continue; }
880
946
  if (r.current === r.installed) continue;
881
947
  const problems = checkSkill(r.cat, r.s);
882
948
  if (problems.length) { console.log(`skip ${r.s}: fails structural check in '${r.src}' (${problems[0]})`); continue; }
883
- copyOne(r.cat, r.s, dest, ide, l);
884
- console.log(`updated ${r.s} ${r.installed} -> ${r.current} (${r.src})`);
949
+ // No baseline (installed before RFC-0032) or --force: overwrite as before, and record one.
950
+ const entry = l.data[r.s];
951
+ if (args.flags.force || typeof entry !== "object" || !entry.files) {
952
+ copyOne(r.cat, r.s, dest, ide, l);
953
+ console.log(`updated ${r.s} ${r.installed} -> ${r.current} (${r.src})`);
954
+ } else {
955
+ const { kept, orphaned } = mergeOne(r.cat, r.s, dest, ide, l);
956
+ console.log(`updated ${r.s} ${r.installed} -> ${r.current} (${r.src})`);
957
+ for (const f of kept) console.log(` kept your edits in ${f} — new version at ${f}.upstream`);
958
+ for (const f of orphaned) console.log(` kept ${f} — dropped upstream, but you edited it`);
959
+ conflicts += kept.length;
960
+ }
885
961
  n++;
886
962
  }
887
963
  saveLedger(l);
888
964
  console.log(n ? `\n${n} skill(s) updated.` : "everything up to date.");
965
+ if (conflicts)
966
+ console.log(`${conflicts} file(s) kept your edits. Merge each <file>.upstream into its file, then delete it — or rerun with --force to take every new version.`);
889
967
  }
890
968
 
891
969
  function outdated(args) {
@@ -1013,7 +1091,7 @@ function installLoops(args) {
1013
1091
  if (!ps) die(`catalog '${cat.source}' has no packs.json`);
1014
1092
  const pk = ps[args.flags.pack];
1015
1093
  if (!pk) die(`unknown pack '${args.flags.pack}' in catalog '${cat.source}'`);
1016
- names = (pk.loops || []).slice();
1094
+ names = packMembers(ps, args.flags.pack, "loops");
1017
1095
  if (!names.length) die(`pack '${args.flags.pack}' declares no loops`);
1018
1096
  }
1019
1097
  if (!names.length && args.flags.all) names = available.slice();
@@ -1182,13 +1260,13 @@ function listPacks(args) {
1182
1260
  catalog: cat.source,
1183
1261
  count: ps ? Object.keys(ps).length : 0,
1184
1262
  packs: Object.entries(ps || {}).map(([name, p]) => ({
1185
- name, description: p.description || null, skills: p.skills || [],
1263
+ name, description: p.description || null, skills: p.skills || [], requires: p.requires || [],
1186
1264
  })),
1187
1265
  });
1188
1266
  if (!ps) return console.log(`catalog '${cat.source}' defines no packs.`);
1189
1267
  const w = Math.max(...Object.keys(ps).map((n) => n.length));
1190
1268
  for (const [n, p] of Object.entries(ps))
1191
- console.log(`${n.padEnd(w)} (${p.skills.length} skills) ${p.description}`);
1269
+ console.log(`${n.padEnd(w)} (${p.skills.length} skills${(p.requires || []).length ? ` + ${p.requires.join(", ")}` : ""}) ${p.description}`);
1192
1270
  console.log("\nInstall one: skilldrop install --pack <name>");
1193
1271
  }
1194
1272
 
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://github.com/sananthanarayan/skilldrop/contracts/pack.schema.json",
4
4
  "title": "skilldrop packs.json",
5
- "$comment": "RFC-0001 / RFC-0026 / RFC-0029. Packs and outcomes are METADATA ONLY — skills never move out of flat skills/<name> folders. Packs answer WHO needs a skill; outcomes answer WHY someone opened the catalogue. Both get the same two-way membership check in validate.py.",
5
+ "$comment": "RFC-0001 / RFC-0026 / RFC-0029 / RFC-0033. Packs and outcomes are METADATA ONLY — skills never move out of flat skills/<name> folders. RFC-0033: each skill and loop sits in exactly one pack; shared skills live in `core`, which other packs pull in via `requires`. Packs answer WHO needs a skill; outcomes answer WHY someone opened the catalogue. Both get the same two-way membership check in validate.py.",
6
6
  "type": "object",
7
7
  "additionalProperties": false,
8
8
  "required": ["version", "packs", "outcomes"],
@@ -20,7 +20,14 @@
20
20
  "description": { "type": "string", "description": "One line — who this pack is for." },
21
21
  "skills": { "type": "array", "items": { "type": "string" }, "minItems": 1,
22
22
  "description": "Real skill folders. Every skill must appear in at least one pack." },
23
- "loops": { "type": "array", "items": { "type": "string" },
23
+ "requires": {
24
+ "type": "array",
25
+ "items": {
26
+ "type": "string"
27
+ },
28
+ "description": "RFC-0033. Packs installed together with this one (in practice, `core`). One level only: a required pack may not itself require."
29
+ },
30
+ "loops": { "type": "array", "items": { "type": "string" },
24
31
  "description": "RFC-0028. Real loops/ folders. Every loop must appear in at least one pack." }
25
32
  }
26
33
  }
@@ -0,0 +1,76 @@
1
+ ---
2
+ name: release
3
+ description: Take merged code to live users through a planned, reversible rollout — plan the phases and the rollback, judge readiness on evidence, draft the release notes, then a human makes the go/no-go call. Use when the user has merged a change and asks how to roll it out, whether they are ready to launch, or for a go/no-go decision.
4
+ ---
5
+
6
+ # release
7
+
8
+ This loop covers the step between `build`, which ends when a human merges, and `operate`,
9
+ which assumes the service is already live. A merge can be undone with a revert. A launch that
10
+ has touched users or data often cannot be undone, so this loop gets its own gates instead of
11
+ being folded into either neighbour.
12
+
13
+ ## Stages
14
+
15
+ | # | Stage | Type | Skills | Gate |
16
+ |---|---|---|---|---|
17
+ | 1 | `plan` | generate | [`migration-plan`](../../skills/migration-plan/SKILL.md) | — |
18
+ | 2 | `ready` | verify | [`launch-readiness`](../../skills/launch-readiness/SKILL.md) | **G2.5** review |
19
+ | 3 | `announce` | generate | [`release-notes`](../../skills/release-notes/SKILL.md) | — |
20
+ | 4 | `go` | gate | [`council-review`](../../skills/council-review/SKILL.md) | **G2.6** human |
21
+
22
+ ## How to run this loop
23
+
24
+ 1. **Plan the rollout and the way back.** `migration-plan` sets out the phases, a tested
25
+ rollback for each one, and at most one named point of no return. For a code-only change
26
+ behind a flag, the plan can be short: the flag, the stages and how to turn it off. It still
27
+ has to exist.
28
+ 2. **Judge readiness at G2.5.** `launch-readiness` lists the change's own failure modes, then
29
+ checks rollback, detection, response, measured targets, data and privacy, comms and
30
+ exposure, each with evidence. `REVISE` returns to `plan`, and the report names which gap to
31
+ close and which skill closes it. A missing rollback is `BLOCKED` on its own.
32
+ 3. **Announce only once it is ready.** `release-notes` drafts the customer-facing and
33
+ internal notes from the git range. Writing them before G2.5 risks announcing a launch that
34
+ then does not happen.
35
+ 4. **A human decides at G2.6.** The release owner decides whether to ship *now*, given
36
+ timing, freeze windows and on-call coverage. When that decision is contested, use
37
+ `council-review`. `RECONSIDER` means it is ready but this is the wrong time, and the work
38
+ waits instead of going back to `plan`.
39
+
40
+ After `PROCEED`, the change is live and the work moves to `operate`. Gaps that G2.5 sent to
41
+ `observability-plan` or `runbook-generator` are the first things `operate` picks up.
42
+
43
+ ## Verdicts
44
+
45
+ Defined in [`contracts/terminals.json`](../../contracts/terminals.json). G2.5 emits `PROCEED`,
46
+ `PROCEED WITH CONDITIONS`, `REVISE` or `BLOCKED`. G2.6 adds `RECONSIDER`. `PROCEED WITH
47
+ CONDITIONS` at G2.5 is allowed only when the open rows are comms or exposure. A detection or
48
+ response gap is always `REVISE`.
49
+
50
+ ## Non-interactive runs
51
+
52
+ Never invent evidence such as rehearsal logs, load-test numbers, dashboards or sign-offs.
53
+ When the change being released cannot be identified, emit `BLOCKED: need <the PR, tag, or
54
+ feature name>`. G2.6 is a human gate. A headless run stops after `announce` and reports the
55
+ G2.5 verdict for a person to act on.
56
+
57
+ ## When a stage's skill is not installed
58
+
59
+ Name the missing skill and skilldrop as its source, do the minimal inline version of that
60
+ stage, and record the stage as degraded. For `ready`, the minimal version is the seven checks
61
+ written as a list, each marked met, not met or n/a with a reason. Skipping it is never the
62
+ minimal version.
63
+
64
+ ## Quality bar
65
+
66
+ - **Rollback exists before readiness is judged.** A plan with no way back is the one thing that cannot be fixed after launch.
67
+ - **Readiness rests on evidence.** Every check links to something; "we're good" is `not met`.
68
+ - **Can and should are separate gates.** G2.5 says whether it can ship; G2.6 says whether it should ship now.
69
+ - **Detection gaps leave this loop as hand-offs.** `operate` picks them up first, rather than discovering them during the first incident.
70
+
71
+ ## Anti-patterns to avoid
72
+
73
+ - ❌ **Jumping from merge to "instrument a running service".** That skips this loop entirely, which is the gap it exists to close.
74
+ - ❌ **Announcing before G2.5.** Customers hear about a launch that is then pulled.
75
+ - ❌ **Treating flag-off as a rollback without a data story.** If dual-write or a backfill has run, turning the flag off does not undo the data.
76
+ - ❌ **Letting G2.6 overrule a G2.5 `BLOCKED`.** A human can delay a ready launch; they cannot make an unready one ready by deciding to go.
@@ -0,0 +1,47 @@
1
+ {
2
+ "$comment": "RFC-0031. Covers the step between build (ends at merge, G2.1) and operate (starts at instrument). The gate ids sit between G2 and G3 to match where the loop sits in the lifecycle.",
3
+ "name": "release",
4
+ "version": "0.1.0",
5
+ "description": "Take merged code to live users through a planned, reversible rollout — plan the phases and the rollback, judge readiness on evidence, draft the release notes, then a human makes the go/no-go call. Use when the user has merged a change and asks how to roll it out, whether they are ready to launch, or for a go/no-go decision.",
6
+ "entrypoint": "LOOP.md",
7
+ "kind": "loop",
8
+ "cap": 3,
9
+ "stages": [
10
+ {
11
+ "id": "plan",
12
+ "type": "generate",
13
+ "intent": "Decide the rollout phases, the rollback for each, and the one point of no return, before anything reaches users.",
14
+ "skills": ["migration-plan"]
15
+ },
16
+ {
17
+ "id": "ready",
18
+ "type": "verify",
19
+ "intent": "Judge on evidence whether the change can go live: rollback, detection, response, measured targets, data, comms, exposure.",
20
+ "skills": ["launch-readiness"],
21
+ "gate": {
22
+ "id": "G2.5",
23
+ "kind": "review",
24
+ "verdicts": ["PROCEED", "PROCEED WITH CONDITIONS", "REVISE", "BLOCKED"],
25
+ "revise_to": "plan"
26
+ }
27
+ },
28
+ {
29
+ "id": "announce",
30
+ "type": "generate",
31
+ "intent": "Write what users and the team are told. Only after readiness, so nobody announces a launch that then fails the check.",
32
+ "skills": ["release-notes"]
33
+ },
34
+ {
35
+ "id": "go",
36
+ "type": "gate",
37
+ "intent": "A human decides whether it should ship now. Readiness says it can; this decides timing, freeze windows, and who is on call.",
38
+ "skills": ["council-review"],
39
+ "gate": {
40
+ "id": "G2.6",
41
+ "kind": "human",
42
+ "verdicts": ["PROCEED", "PROCEED WITH CONDITIONS", "REVISE", "RECONSIDER", "BLOCKED"],
43
+ "revise_to": "plan"
44
+ }
45
+ }
46
+ ]
47
+ }
@@ -146,6 +146,10 @@
146
146
  "tier": "standard",
147
147
  "rationale": "Extracts architecture from code/IaC. Escalate to heavy on large codebases where cross-file inference is heavy."
148
148
  },
149
+ "launch-readiness": {
150
+ "tier": "standard",
151
+ "rationale": "Checks evidence against a fixed checklist. Bounded synthesis, not adversarial review."
152
+ },
149
153
  "runbook-generator": {
150
154
  "tier": "standard",
151
155
  "rationale": "Operational doc from service facts. Bounded synthesis."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skilldrop-cli",
3
- "version": "0.13.0",
3
+ "version": "0.13.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
5
  "author": {
6
6
  "name": "Sanjay Ananthanarayan",
package/packs.json CHANGED
@@ -1,12 +1,22 @@
1
1
  {
2
- "$comment": "Virtual skill packs — role-based bundles for one-command install. Packs are METADATA ONLY: skills stay in flat skills/<name> folders (golden rule: skills are discovered by path), a skill may belong to several packs, and every skill must belong to at least one (validate.py enforces both directions). Install a pack with `python3 pack.py <pack> --install`; see README. Rationale: docs/rfcs/0001-skill-packs.md. `outcomes` (RFC-0026) is the second browse axis: packs say WHO needs a skill, outcomes say WHY someone opens the catalogue. It is the README's nine categories restated as seven outcomes and made machine-readable so the site cannot drift from them. Outcomes are a browse aid only — not an install unit — and validate.py enforces the same two-way check packs get.",
3
- "version": "0.1.0",
2
+ "$comment": "Virtual skill packs — role-based bundles for one-command install. Packs are METADATA ONLY: skills stay in flat skills/<name> folders (golden rule: skills are discovered by path), every skill and every loop belongs to exactly one pack (RFC-0033 — the shape a later physical packs/<name>/ layout needs), and a pack may `requires` the `core` pack, which every installer then installs with it. validate.py enforces all of this. Install a pack with `python3 pack.py <pack> --install`; see README. Rationale: docs/rfcs/0001-skill-packs.md. `outcomes` (RFC-0026) is the second browse axis: packs say WHO needs a skill, outcomes say WHY someone opens the catalogue. It is the README's nine categories restated as seven outcomes and made machine-readable so the site cannot drift from them. Outcomes are a browse aid only — not an install unit — and validate.py enforces the same two-way check packs get.",
3
+ "version": "0.2.0",
4
4
  "packs": {
5
+ "core": {
6
+ "description": "The cross-role toolkit every pack builds on: structured intake, document critique, the review council, and output hygiene, plus the ship-a-draft wrapper. Installed automatically with every role pack.",
7
+ "loops": ["ship-a-draft"],
8
+ "skills": [
9
+ "brief-intake",
10
+ "doc-critique",
11
+ "output-hygiene",
12
+ "council-review"
13
+ ]
14
+ },
5
15
  "solution-architect": {
6
16
  "description": "Design-phase artifacts: diagrams, decision records, design docs, contracts, schemas, threat models, and the reviews that gate them.",
7
- "loops": ["design", "ship-a-draft"],
17
+ "requires": ["core"],
18
+ "loops": ["design"],
8
19
  "skills": [
9
- "brief-intake",
10
20
  "architecture-diagrams",
11
21
  "reverse-architecture",
12
22
  "figma-diagrams",
@@ -14,22 +24,17 @@
14
24
  "design-doc",
15
25
  "tech-comparison-matrix",
16
26
  "threat-model",
17
- "agent-threat-model",
18
- "agents-md-generator",
19
27
  "api-contract-draft",
20
28
  "data-contract",
21
29
  "db-schema-design",
22
- "nfr-spec",
23
- "capacity-cost-model",
24
- "council-review",
25
- "doc-critique"
30
+ "nfr-spec"
26
31
  ]
27
32
  },
28
33
  "product-manager": {
29
- "description": "Direction to requirements: PR/FAQs, strategy frameworks, OKRs, PRDs, journey maps, story splitting, and success measurement.",
30
- "loops": ["discover", "ship-a-draft"],
34
+ "description": "Direction to requirements: PR/FAQs, strategy frameworks, OKRs, business cases, interviews, PRDs, journey maps, and success measurement.",
35
+ "requires": ["core"],
36
+ "loops": ["discover"],
31
37
  "skills": [
32
- "brief-intake",
33
38
  "prfaq",
34
39
  "strategy-analysis",
35
40
  "okr-cascade",
@@ -37,23 +42,19 @@
37
42
  "requirements-interview",
38
43
  "prd-draft",
39
44
  "user-journey-map",
40
- "user-story-splitter",
41
- "success-metrics",
42
- "exec-summary",
43
- "doc-critique",
44
- "ai-use-case-triage"
45
+ "success-metrics"
45
46
  ]
46
47
  },
47
48
  "dev-team": {
48
- "description": "Build-and-ship loop: story implementation with adversarial review, test plans, triage, migrations, release notes, agent-policy files, and code-quality gates.",
49
- "loops": ["build", "ship-a-draft"],
49
+ "description": "Build-and-ship: story splitting, implementation with adversarial review, test plans, triage, migrations, launch readiness, release notes, agent-policy files, and code-quality gates.",
50
+ "requires": ["core"],
51
+ "loops": ["build", "release"],
50
52
  "skills": [
51
53
  "agents-md-generator",
52
54
  "user-story-splitter",
53
55
  "feature-implement-loop",
54
56
  "pre-merge-review",
55
57
  "devils-advocate",
56
- "council-review",
57
58
  "test-plan-generator",
58
59
  "bug-triage",
59
60
  "migration-plan",
@@ -61,12 +62,13 @@
61
62
  "sonar-onboard",
62
63
  "sonar-review",
63
64
  "accessibility-audit",
64
- "output-hygiene",
65
- "contribution-wizard"
65
+ "contribution-wizard",
66
+ "launch-readiness"
66
67
  ]
67
68
  },
68
69
  "sre-oncall": {
69
70
  "description": "Operate the service: runbooks, observability design, incident communications, postmortems, and capacity/cost models.",
71
+ "requires": ["core"],
70
72
  "loops": ["operate"],
71
73
  "skills": [
72
74
  "runbook-generator",
@@ -78,22 +80,21 @@
78
80
  },
79
81
  "stakeholder-comms": {
80
82
  "description": "Non-technical audiences: audience profiling, deck outlines and real .pptx decks, exec summaries, decision logs, and guides.",
81
- "loops": ["ship-a-draft"],
83
+ "requires": ["core"],
84
+ "loops": [],
82
85
  "skills": [
83
- "brief-intake",
84
86
  "audience-profile",
85
87
  "slide-outliner",
86
88
  "deck-builder",
87
89
  "exec-summary",
88
90
  "decision-log",
89
- "guide-builder",
90
- "doc-critique",
91
- "output-hygiene"
91
+ "guide-builder"
92
92
  ]
93
93
  },
94
94
  "ai-engineering": {
95
- "description": "Adopt and build AI systems: readiness assessment, use-case triage, rollout and acceptable-use policy, plus agent loop design, subagent orchestration, spend budgets, agent security review, eval harnesses, AI-usage reporting, and the data contracts AI pipelines depend on.",
96
- "loops": ["design", "build"],
95
+ "description": "Adopt and build AI systems: readiness assessment, use-case triage, rollout and acceptable-use policy, plus agent loop design, subagent orchestration, spend budgets, agent security review, eval harnesses, and AI-usage reporting.",
96
+ "requires": ["core"],
97
+ "loops": [],
97
98
  "skills": [
98
99
  "agent-loop-design",
99
100
  "subagent-design",
@@ -101,7 +102,6 @@
101
102
  "agent-threat-model",
102
103
  "llm-eval-harness",
103
104
  "ai-usage-report",
104
- "data-contract",
105
105
  "ai-readiness-assessment",
106
106
  "ai-use-case-triage",
107
107
  "ai-adoption-rollout",
@@ -191,7 +191,8 @@
191
191
  "observability-plan",
192
192
  "release-notes",
193
193
  "incident-comms",
194
- "postmortem-generator"
194
+ "postmortem-generator",
195
+ "launch-readiness"
195
196
  ]
196
197
  },
197
198
  "explain-it-to-decision-makers": {
@@ -0,0 +1,95 @@
1
+ ---
2
+ name: launch-readiness
3
+ description: Produce a go/no-go launch readiness report for a merged change before it goes live — one row per check (rollback path, alert and runbook per new failure mode, NFR targets measured, comms drafted, data/privacy sign-off), each with an owner, evidence link, and met / not met / n/a-because status, ending in a PROCEED / PROCEED WITH CONDITIONS / REVISE / BLOCKED verdict. Use when the user asks "are we ready to launch", "go/no-go", "production readiness review", "launch checklist", or "can we ship this to users".
4
+ ---
5
+
6
+ # launch-readiness
7
+
8
+ You judge whether a change that is already merged *can* go live, using evidence rather than
9
+ reassurance. The output is a readiness report a release owner can act on in five minutes.
10
+ Whether it *should* go live now (timing, freeze windows, who is on call) is a separate human
11
+ decision. That belongs to `council-review` or the release owner, not to this report.
12
+
13
+ ## How to respond
14
+
15
+ 1. **Pin down what is launching.** You need: the change (a PR, a release tag, or a feature
16
+ name), who it reaches (internal, a percentage, everyone), and the release owner. If the
17
+ change itself is unknown, ask. You may ask at most 2 questions. A missing reach or owner
18
+ becomes an `[assumption]` to confirm. Everything else becomes a row that is `not met`
19
+ because evidence is missing.
20
+
21
+ 2. **List the new failure modes first.** Before any checklist, write 3–5 ways this specific
22
+ change could hurt users or data once it is live. Read them from the diff, the design doc or
23
+ the migration plan. Each later check is judged against this list. A generic checklist with
24
+ no failure modes is a ritual.
25
+
26
+ 3. **Fill [`templates/readiness-report.md`](templates/readiness-report.md).** It has one row
27
+ per check, and every row carries:
28
+ - **Status:** `met`, `not met`, or `n/a — <reason>`. `n/a` without a reason counts as `not met`.
29
+ - **Evidence:** a link, a command output, or a file path. A row with no evidence counts as
30
+ `not met`, however confident the user sounds. Evidence must cover the path the failure
31
+ mode touches; if it is unclear what it covered (which endpoint a load test hit), tag it
32
+ `[assumption]`.
33
+ - **Owner:** a role, not a person's name.
34
+
35
+ 4. **Apply the checks in this order.** The order matters: the first ones are the costliest to
36
+ discover after launch.
37
+ 1. **Rollback.** It must be a tested path back, with its data story stated. If a data or
38
+ schema change is involved and no plan exists, hand off to `migration-plan`.
39
+ 2. **Detection.** Each new failure mode needs an alert that fires before users complain. If
40
+ one is missing, hand off to `observability-plan`.
41
+ 3. **Response.** Each such alert needs a runbook entry. If one is missing, hand off to
42
+ `runbook-generator`.
43
+ 4. **Quality targets.** Every target in `nfr-spec` (latency, availability, scale) must be
44
+ *measured*, for example by a load test or canary result. A target that is only asserted
45
+ does not count.
46
+ 5. **Data and privacy.** New personal data, retention changes or new processors need a
47
+ named sign-off, or `n/a — <reason>`.
48
+ 6. **Comms.** User-facing notes are drafted (see `release-notes`), support is briefed, and
49
+ the status page owner is known if the launch is risky.
50
+ 7. **Exposure.** The first exposure is staged (flag, percentage or cohort), or there is a
51
+ stated reason why all-at-once is safe.
52
+
53
+ 5. **Give the verdict.** It is the last line, with exactly one reason:
54
+ - `PROCEED`: every row is `met` or `n/a — <reason>`.
55
+ - `PROCEED WITH CONDITIONS`: only rows 6–7 are open, and each open row has an owner and a
56
+ date. The open rows travel with the release.
57
+ - `REVISE`: any row 2–5 is `not met`. Name the row and the hand-off that fixes it.
58
+ - `BLOCKED`: rollback is `not met`, or the change or its reach is unknown. A missing
59
+ rollback blocks on its own, whatever else passes.
60
+
61
+ **Non-interactive runs** (CI, subagent, headless): never invent evidence such as test results,
62
+ dashboards or sign-offs. Tag a guessed fact `[assumption]` and list it first. If the change
63
+ being launched cannot be identified, emit `BLOCKED: need <the PR, tag, or feature name>`.
64
+
65
+ ## Useful references in this skill
66
+
67
+ - [`templates/readiness-report.md`](templates/readiness-report.md) — the report skeleton, one row per check.
68
+ - [`examples/schema-change-revise.md`](examples/schema-change-revise.md) — a worked report for a schema change that comes out `REVISE`.
69
+
70
+ ## Quality bar
71
+
72
+ - **Every row has evidence or is `not met`.** Readiness asserted is not readiness.
73
+ - **The failure modes are specific to this change.** "The service could go down" is true of everything and checks nothing.
74
+ - **Rollback is judged first and can block alone.** Every other gap can be fixed while live; an irreversible launch with no way back cannot.
75
+ - **The verdict follows mechanically from the rows.** Two reviewers given the same rows reach the same verdict.
76
+ - **Owners are roles.** "Payments on-call", not a person who will change teams.
77
+
78
+ ## When to use this skill
79
+
80
+ - ✅ A merged change is about to reach users and someone asks "are we ready?"
81
+ - ✅ A production readiness review needs a written go/no-go record.
82
+ - ✅ The `ready` stage of the `release` loop.
83
+
84
+ ## When NOT to use this skill
85
+
86
+ - ❌ Deciding whether to *merge*. That is `pre-merge-review`'s gate, which happens earlier.
87
+ - ❌ Planning the rollout phases themselves. That is `migration-plan`; this skill checks that the plan exists and has been rehearsed.
88
+ - ❌ Choosing *when* to launch. Timing and freeze windows are the release owner's call, or `council-review`'s if they are contested.
89
+
90
+ ## Anti-patterns to avoid
91
+
92
+ - ❌ **A generic checklist with every box ticked.** If no row is `not met` on a non-trivial launch, the evidence was not checked.
93
+ - ❌ **`n/a` as a way out.** Data and privacy marked `n/a` with no reason is the most common way a launch skips a review it needed.
94
+ - ❌ **Letting a strong row offset a missing rollback.** Great dashboards do not make an irreversible launch safe.
95
+ - ❌ **Writing the runbook or the alert inside this report.** Name the gap and hand it off; a readiness report that also drafts fixes becomes too long to read.
@@ -0,0 +1,10 @@
1
+ [
2
+ { "query": "Are we ready to launch this to users on Monday?", "should_trigger": true },
3
+ { "query": "Run a go/no-go check on the checkout redesign before we turn it on", "should_trigger": true },
4
+ { "query": "Do a production readiness review for the new search service", "should_trigger": true },
5
+ { "query": "Give me a launch checklist for this release and tell me what's missing", "should_trigger": true },
6
+ { "query": "Is this PR safe to merge?", "should_trigger": false },
7
+ { "query": "Plan the phased rollout and backfill for moving users to the new auth provider", "should_trigger": false },
8
+ { "query": "Write the release notes for everything since v2.3", "should_trigger": false },
9
+ { "query": "Write the runbook for the payments service", "should_trigger": false }
10
+ ]
@@ -0,0 +1,19 @@
1
+ {
2
+ "skill_name": "launch-readiness",
3
+ "evals": [
4
+ {
5
+ "id": 1,
6
+ "prompt": "Are we ready to launch? PR #412 adds a `loyalty_points` column to `customers`, backfills it from order history, and shows points on the checkout page. Going to 100% of users Thursday. Load test hit p99 180ms against a 250ms target (link: grafana/d/lt-412). We have a dashboard but haven't added alerts yet. Support hasn't been told.",
7
+ "assertions": [
8
+ "Lists 3-5 failure modes specific to this change (e.g. backfill load on customers, wrong point totals shown at checkout) before the checklist",
9
+ "Every check row has a status of met, not met, or n/a with a reason, plus an evidence column and an owner expressed as a role",
10
+ "Rollback is the first row and is not met, because no tested rollback or data story was supplied",
11
+ "Detection is not met because no alerts exist, and the report hands off to observability-plan rather than drafting the alert inline",
12
+ "The quality-targets row is met and cites the supplied load-test link as evidence",
13
+ "Exposure is flagged because a 100% launch is not staged and no reason is given for why all-at-once is safe",
14
+ "The verdict is BLOCKED, and the reason given is the missing rollback",
15
+ "No dashboards, test results, or sign-offs are invented beyond what the prompt supplied"
16
+ ]
17
+ }
18
+ ]
19
+ }
@@ -0,0 +1,54 @@
1
+ # Worked example — schema change that comes out REVISE
2
+
3
+ ## Input given to the skill
4
+
5
+ > Go/no-go for release `orders-v4.2`. It splits `orders.address` into `shipping_address_id`
6
+ > pointing at a new `addresses` table. We followed the migration plan
7
+ > (docs/migrations/orders-address.md): expand and backfill are done in staging, and dual-write
8
+ > is behind the flag `orders.address_split`. Rollback is "turn the flag off". It was rehearsed
9
+ > in staging on 2026-09-28 (log: ci/run/88213). The p99 target for order reads is 120ms, and
10
+ > the canary at 5% shows 96ms (grafana/d/orders-canary). The existing `orders-5xx` alert
11
+ > covers this. Release notes are drafted in PR #977. Plan is 5% → 50% → 100% over three days.
12
+
13
+ ---
14
+
15
+ # Launch readiness — orders-v4.2 (address split)
16
+
17
+ **Change:** release `orders-v4.2` · **Reach:** 5% → 50% → 100% over 3 days · **Release owner:** Orders tech lead
18
+ **Assessed:** 2026-10-01 · **Inputs:** migration plan, staging rollback log, canary dashboard, PR #977
19
+
20
+ ## New failure modes
21
+
22
+ | # | Failure mode | Who is hurt | Reversible? |
23
+ |---|---|---|---|
24
+ | F1 | Dual-write diverges: an order is saved with an `addresses` row that doesn't match `orders.address` | Customers shipped to the wrong address | Partly. Data can be fixed, parcels already sent cannot |
25
+ | F2 | The read path picks the new column before the backfill is complete for that tenant | Customers who see a blank address at checkout | Yes, by turning the flag off |
26
+ | F3 | The extra join pushes order reads past p99 under full load | All checkout users | Yes, by turning the flag off |
27
+
28
+ ## Checks
29
+
30
+ | # | Check | Covers | Status | Evidence | Owner |
31
+ |---|---|---|---|---|---|
32
+ | 1 | Rollback | all | met | Flag-off rehearsed in staging, ci/run/88213. While the old column is still written, flag-off loses no data | Orders on-call |
33
+ | 2 | Detection | F1–F3 | **not met** | `orders-5xx` catches F3 errors only. Nothing detects F1 divergence or F2 blank reads, because both return 200 | Orders on-call |
34
+ | 3 | Response | F1–F3 | **not met** | There is no runbook entry for divergence. `orders-5xx` has a runbook entry, but it does not mention the flag | Orders on-call |
35
+ | 4 | Quality targets | F3 | met | Canary p99 96ms against a 120ms target at 5%, grafana/d/orders-canary | Orders tech lead |
36
+ | 5 | Data & privacy | — | n/a — no new personal data. Address data moves between tables, and retention and processors are unchanged | Migration plan §2 | Data protection lead |
37
+ | 6 | Comms | — | met | Release notes drafted in PR #977. No customer-visible change | Orders tech lead |
38
+ | 7 | Exposure | — | met | Staged 5% → 50% → 100% behind `orders.address_split` | Release owner |
39
+
40
+ ## Open items
41
+
42
+ - Row 2: add a reconciliation metric for dual-write divergence, and an alert on any non-zero count, plus an alert on blank-address reads. Orders on-call, before the 5% → 50% step. Hand off to `observability-plan`.
43
+ - Row 3: add a runbook entry for "divergence alert fires" (flag off, then run the reconciler), and add the flag to the `orders-5xx` entry. Orders on-call, same deadline. Hand off to `runbook-generator`.
44
+
45
+ ## Verdict
46
+
47
+ **REVISE.** Row 2 is not met: the two failure modes that do lasting damage (F1, F2) return 200, so nothing would detect them. Fix rows 2 and 3, then run readiness again.
48
+
49
+ ---
50
+
51
+ **Why this is a good output:** the rollback is genuinely in place, so the verdict is REVISE and
52
+ not BLOCKED. The report notices that an existing alert covering the change only catches the
53
+ failure that is easiest to undo. It does not draft the alert or runbook itself; it names the
54
+ gap, the owner and the hand-off.
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "launch-readiness",
3
+ "version": "0.1.0",
4
+ "description": "Produce a go/no-go launch readiness report for a merged change before it goes live — one row per check (rollback path, alert and runbook per new failure mode, NFR targets measured, comms drafted, data/privacy sign-off), each with an owner, evidence link, and met / not met / n/a-because status, ending in a PROCEED / PROCEED WITH CONDITIONS / REVISE / BLOCKED verdict. Use when the user asks \"are we ready to launch\", \"go/no-go\", \"production readiness review\", \"launch checklist\", or \"can we ship this to users\".",
5
+ "entrypoint": "SKILL.md",
6
+ "deps": { "npm": [], "pip": [] },
7
+ "env": { "required": [], "optional": [] },
8
+ "related": [
9
+ "migration-plan",
10
+ "observability-plan",
11
+ "runbook-generator",
12
+ "nfr-spec",
13
+ "release-notes",
14
+ "council-review",
15
+ "pre-merge-review"
16
+ ],
17
+ "handoff": [
18
+ { "to": "migration-plan", "when": "the change has no tested rollback path", "purpose": "Plan the phases and the rollback, and name the point of no return, before readiness is judged again.", "fallback": "If migration-plan is absent, write the rollback as numbered steps with its data story inline, and mark the row not met until someone has rehearsed it." },
19
+ { "to": "observability-plan", "when": "a new failure mode has no alert", "purpose": "Define the SLI and the burn-rate alert that would detect it.", "fallback": "If observability-plan is absent, name the symptom, the metric that shows it, and a threshold inline, tagged [assumption] for the owner to confirm." },
20
+ { "to": "runbook-generator", "when": "an alert exists but has no runbook entry", "purpose": "Write the procedure the on-call follows when that alert fires.", "fallback": "If runbook-generator is absent, write recognise / mitigate / escalate as three lines under the row, and keep the row not met until the on-call owner has reviewed them." }
21
+ ],
22
+ "tags": ["launch", "release", "readiness", "go-no-go", "production-readiness"],
23
+ "model": { "tier": "standard", "rationale": "Checks evidence against a fixed checklist. Bounded synthesis, not adversarial review." }
24
+ }
@@ -0,0 +1,41 @@
1
+ # Launch readiness — {change name}
2
+
3
+ **Change:** {PR / tag / feature} · **Reach:** {internal / N% / cohort / everyone} · **Release owner:** {role}
4
+ **Assessed:** {YYYY-MM-DD} · **Inputs:** {what was read — diff, design doc, migration plan, dashboards}
5
+
6
+ > **Assumptions to confirm first** (omit if none)
7
+ > - `[assumption]` {fact guessed rather than given}
8
+
9
+ ## New failure modes
10
+
11
+ What this change, specifically, could do to users or data once live.
12
+
13
+ | # | Failure mode | Who is hurt | Reversible? |
14
+ |---|---|---|---|
15
+ | F1 | {e.g. backfill locks `orders` table under peak write load} | {checkout users} | {yes / no / partly} |
16
+ | F2 | | | |
17
+ | F3 | | | |
18
+
19
+ ## Checks
20
+
21
+ Status is `met`, `not met`, or `n/a — <reason>`. No evidence means `not met`.
22
+
23
+ | # | Check | Covers | Status | Evidence | Owner |
24
+ |---|---|---|---|---|---|
25
+ | 1 | **Rollback** — tested path back, data story stated | all | | {link / command output} | {role} |
26
+ | 2 | **Detection** — an alert per failure mode, fires before users complain | F1–F3 | | | |
27
+ | 3 | **Response** — a runbook entry per alert in row 2 | F1–F3 | | | |
28
+ | 4 | **Quality targets** — each NFR target measured, not asserted | | | | |
29
+ | 5 | **Data & privacy** — sign-off for new personal data, retention, or processors | | | | |
30
+ | 6 | **Comms** — release notes drafted, support briefed, status-page owner known | | | | |
31
+ | 7 | **Exposure** — first exposure staged, or why all-at-once is safe | | | | |
32
+
33
+ ## Open items
34
+
35
+ One line per `not met` row: what closes it, who, by when, and the hand-off if any.
36
+
37
+ - Row {n}: {what closes it} — {owner role}, {date} → {`migration-plan` / `observability-plan` / `runbook-generator` / none}
38
+
39
+ ## Verdict
40
+
41
+ **{PROCEED | PROCEED WITH CONDITIONS | REVISE | BLOCKED}** — {the one reason, naming the row}.