@haus-tech/haus-workflow 0.17.1 → 0.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +14 -3
  3. package/dist/cli.js +80 -19
  4. package/library/catalog/manifest.json +2 -2
  5. package/library/catalog/validation-rules.json +2 -3
  6. package/package.json +1 -1
  7. package/tests/fixtures/catalog/skills/auth-oidc-azure-bankid-patterns/SKILL.md +6 -1
  8. package/tests/fixtures/catalog/skills/bullmq-patterns/SKILL.md +6 -1
  9. package/tests/fixtures/catalog/skills/database-patterns/SKILL.md +6 -1
  10. package/tests/fixtures/catalog/skills/dotnet-patterns/SKILL.md +6 -1
  11. package/tests/fixtures/catalog/skills/dotnet-service-patterns/SKILL.md +6 -1
  12. package/tests/fixtures/catalog/skills/eslint-setup/SKILL.md +6 -1
  13. package/tests/fixtures/catalog/skills/expo-react-native-patterns/SKILL.md +6 -1
  14. package/tests/fixtures/catalog/skills/global-engineering-rules/SKILL.md +6 -1
  15. package/tests/fixtures/catalog/skills/i18next-patterns/SKILL.md +6 -1
  16. package/tests/fixtures/catalog/skills/jest-patterns/SKILL.md +6 -1
  17. package/tests/fixtures/catalog/skills/laravel-nova-patterns/SKILL.md +6 -1
  18. package/tests/fixtures/catalog/skills/laravel-patterns/SKILL.md +6 -1
  19. package/tests/fixtures/catalog/skills/nestjs-graphql-patterns/SKILL.md +6 -1
  20. package/tests/fixtures/catalog/skills/nextauth-patterns/SKILL.md +6 -1
  21. package/tests/fixtures/catalog/skills/nextjs-patterns/SKILL.md +6 -1
  22. package/tests/fixtures/catalog/skills/nx21-monorepo-patterns/SKILL.md +6 -1
  23. package/tests/fixtures/catalog/skills/package-manager-yarn4-pnpm89/SKILL.md +6 -1
  24. package/tests/fixtures/catalog/skills/phpunit-patterns/SKILL.md +6 -1
  25. package/tests/fixtures/catalog/skills/playwright-patterns/SKILL.md +6 -1
  26. package/tests/fixtures/catalog/skills/prettier-setup/SKILL.md +6 -1
  27. package/tests/fixtures/catalog/skills/prisma-patterns/SKILL.md +6 -1
  28. package/tests/fixtures/catalog/skills/production-readiness-review/SKILL.md +6 -1
  29. package/tests/fixtures/catalog/skills/qliro-patterns/SKILL.md +6 -1
  30. package/tests/fixtures/catalog/skills/radix-shadcn-patterns/SKILL.md +6 -1
  31. package/tests/fixtures/catalog/skills/react-router-v7-patterns/SKILL.md +6 -1
  32. package/tests/fixtures/catalog/skills/react19-patterns/SKILL.md +6 -1
  33. package/tests/fixtures/catalog/skills/sanity-patterns/SKILL.md +6 -1
  34. package/tests/fixtures/catalog/skills/security-review/SKILL.md +6 -1
  35. package/tests/fixtures/catalog/skills/sentry-patterns/SKILL.md +6 -1
  36. package/tests/fixtures/catalog/skills/storybook-patterns/SKILL.md +6 -1
  37. package/tests/fixtures/catalog/skills/strapi-patterns/SKILL.md +6 -1
  38. package/tests/fixtures/catalog/skills/stripe-patterns/SKILL.md +6 -1
  39. package/tests/fixtures/catalog/skills/supabase-patterns/SKILL.md +6 -1
  40. package/tests/fixtures/catalog/skills/tailwind-scss-patterns/SKILL.md +6 -1
  41. package/tests/fixtures/catalog/skills/tanstack-query-router-patterns/SKILL.md +6 -1
  42. package/tests/fixtures/catalog/skills/testing-library-patterns/SKILL.md +6 -1
  43. package/tests/fixtures/catalog/skills/turbo-monorepo-patterns/SKILL.md +6 -1
  44. package/tests/fixtures/catalog/skills/typescript5-patterns/SKILL.md +6 -1
  45. package/tests/fixtures/catalog/skills/vendure-app-patterns/SKILL.md +6 -1
  46. package/tests/fixtures/catalog/skills/vendure-plugin-patterns/SKILL.md +6 -1
  47. package/tests/fixtures/catalog/skills/vite8-patterns/SKILL.md +6 -1
  48. package/tests/fixtures/catalog/skills/vitest-patterns/SKILL.md +6 -1
  49. package/tests/fixtures/catalog/skills/vue-patterns/SKILL.md +6 -1
  50. package/tests/fixtures/catalog/skills/wordpress-acf-elementor-jetengine-patterns/SKILL.md +6 -1
  51. package/tests/fixtures/catalog/skills/wordpress-bedrock-patterns/SKILL.md +6 -1
  52. package/tests/fixtures/catalog/skills/wordpress-patterns/SKILL.md +6 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.18.1](https://github.com/WeAreHausTech/haus-workflow/compare/v0.18.0...v0.18.1) (2026-06-09)
4
+
5
+ ### Bug Fixes
6
+
7
+ - **ci:** improve PR creation logic in sync-catalog-fixture workflow ([d7717d6](https://github.com/WeAreHausTech/haus-workflow/commit/d7717d6024bb400b02f3254ff7f2d33b6e1fb4c6))
8
+
9
+ ## [0.18.0](https://github.com/WeAreHausTech/haus-workflow/compare/v0.17.1...v0.18.0) (2026-06-09)
10
+
11
+ ### Features
12
+
13
+ - prune stale catalog copies and simplify validators ([#83](https://github.com/WeAreHausTech/haus-workflow/issues/83)) ([f87541c](https://github.com/WeAreHausTech/haus-workflow/commit/f87541cc182e9cf2461ba6b388dc227aba88900e))
14
+
15
+ ### Bug Fixes
16
+
17
+ - **validate:** parse folded YAML description frontmatter ([#84](https://github.com/WeAreHausTech/haus-workflow/issues/84)) ([677d7de](https://github.com/WeAreHausTech/haus-workflow/commit/677d7def4e838c4e5381f34c870a5525c4614073))
18
+
3
19
  ## [0.17.1](https://github.com/WeAreHausTech/haus-workflow/compare/v0.17.0...v0.17.1) (2026-06-09)
4
20
 
5
21
  ### Bug Fixes
package/README.md CHANGED
@@ -66,12 +66,13 @@ haus setup-project # re-run setup on existing project
66
66
  haus scan # scan repo and write context-map
67
67
  haus recommend # recommend catalog items (binary eligibility)
68
68
  haus apply --dry-run # preview what would be written
69
- haus apply --write # write .claude/ files
69
+ haus apply --write # write .claude/ files (skills, agents, commands, templates)
70
+ haus apply --select # interactively choose which recommended items to install
70
71
  haus apply --refill-config # fill still-blank workflow-config.md fields, keep edits
71
72
  haus context --task "<task>" # select context rules for a task (token-budgeted)
72
- haus update # sync remote catalog + refresh lockfile
73
+ haus update # sync remote catalog + re-apply project files
73
74
  haus update --check # check for updates without applying
74
- haus undo # undo last applied changes
75
+ haus undo # remove haus-managed project files (lock-tracked paths)
75
76
  haus doctor # health check: hooks, CLAUDE.md, imports, catalog cache
76
77
  haus config # manage hook configuration
77
78
  haus guard # test bash/file-access guards
@@ -91,9 +92,19 @@ yarn verify # typecheck + lint + build + test
91
92
  yarn dev <cmd> # run CLI without building (tsx)
92
93
  ```
93
94
 
95
+ ### Catalog
96
+
97
+ Content lives in [`haus-workflow-catalog`](https://github.com/WeAreHausTech/haus-workflow-catalog)
98
+ (71 items at v2.5.0). Fetched at runtime from `main` (override with `HAUS_CATALOG_REF`).
99
+ Validation rules sync from catalog → `library/catalog/validation-rules.json` (ADR-0001).
100
+
101
+ On `haus apply` / `haus update`, items **removed from the catalog** are pruned from the
102
+ project when their on-disk copy still matches the lock hash; user-edited copies are kept.
103
+
94
104
  ### Internal docs
95
105
 
96
106
  - [Architecture](docs/architecture.md)
97
107
  - [CLI reference](docs/cli.md)
98
108
  - [Security](docs/security.md)
99
109
  - [Developer scripts](docs/dev.md)
110
+ - [Runbook](docs/runbook.md)
package/dist/cli.js CHANGED
@@ -1262,6 +1262,7 @@ async function writeClaudeFiles(root, dryRun, selectedIds, opts = {}) {
1262
1262
  );
1263
1263
  }
1264
1264
  }
1265
+ await cleanupStaleCatalogItems(root, new Set(manifestById.keys()), dryRun);
1265
1266
  if (dryRun) return [...new Set(files)];
1266
1267
  const installedItems = catalogItems.filter((r) => installedIds.has(r.id));
1267
1268
  await writeManagedJson(
@@ -1304,6 +1305,50 @@ async function writeClaudeFiles(root, dryRun, selectedIds, opts = {}) {
1304
1305
  await writeManagedJson(root, hausPath(root, "haus.lock.json"), lock, false);
1305
1306
  return [...new Set(files)];
1306
1307
  }
1308
+ async function cleanupStaleCatalogItems(root, knownIds, dryRun) {
1309
+ const prevLock = await readJson(hausPath(root, "haus.lock.json"));
1310
+ if (!prevLock?.length) return;
1311
+ for (const entry of prevLock) {
1312
+ if (!entry.id || knownIds.has(entry.id)) continue;
1313
+ const relPaths = entry.paths ?? [];
1314
+ if (relPaths.length === 0) continue;
1315
+ const existing = [];
1316
+ for (const rel of relPaths) {
1317
+ if (await fs10.pathExists(path12.join(root, rel))) existing.push(rel);
1318
+ }
1319
+ if (existing.length === 0) continue;
1320
+ if (entry.hash === void 0) {
1321
+ warn(
1322
+ `Stale catalog item ${entry.id} has no lock hash \u2014 leaving in place: ${existing.join(", ")}`
1323
+ );
1324
+ continue;
1325
+ }
1326
+ const currentHash = await hashInstalledPaths(root, relPaths);
1327
+ if (currentHash !== entry.hash) {
1328
+ warn(
1329
+ `Stale catalog item ${entry.id} was modified locally \u2014 leaving in place: ${existing.join(", ")}`
1330
+ );
1331
+ continue;
1332
+ }
1333
+ for (const rel of existing) {
1334
+ const abs = path12.join(root, rel);
1335
+ if (dryRun) {
1336
+ log(`[dry-run] would remove stale ${displayPath(root, abs)} (${entry.id})`);
1337
+ continue;
1338
+ }
1339
+ await fs10.remove(abs);
1340
+ await pruneEmptyDir(path12.dirname(abs));
1341
+ log(`Removed stale ${displayPath(root, abs)} (${entry.id})`);
1342
+ }
1343
+ }
1344
+ }
1345
+ async function pruneEmptyDir(dir) {
1346
+ try {
1347
+ const entries = await fs10.readdir(dir);
1348
+ if (entries.length === 0) await fs10.remove(dir);
1349
+ } catch {
1350
+ }
1351
+ }
1307
1352
  async function writeManagedText(root, filePath, nextText, dryRun) {
1308
1353
  const prev = await fs10.pathExists(filePath) ? await fs10.readFile(filePath, "utf8") : "";
1309
1354
  const printable = displayPath(root, filePath);
@@ -1424,7 +1469,7 @@ var validation_rules_default = {
1424
1469
  "trading"
1425
1470
  ],
1426
1471
  bannedAgentPhrases: ["autonomous", "swarm", "delegate", "orchestrat", "marketplace"],
1427
- requiredSkillSections: ["## Use when", "## Do not use when"],
1472
+ requiredSkillFrontmatter: ["description"],
1428
1473
  requiredAgentSections: ["## Use when", "## Do not use when", "## Verification"],
1429
1474
  riskyInstallPatterns: [
1430
1475
  { source: "\\bnpx\\s+-y\\b", flags: "i" },
@@ -1549,19 +1594,14 @@ var validation_rules_default = {
1549
1594
  "baseline",
1550
1595
  "project-instructions"
1551
1596
  ],
1552
- patternTagSuffixes: ["-patterns"],
1553
- skillSectionExemptSources: ["curated"]
1597
+ patternTagSuffixes: ["-patterns"]
1554
1598
  };
1555
1599
 
1556
1600
  // src/catalog/validation-rules.ts
1557
1601
  var toRegExp = (r) => new RegExp(r.source, r.flags);
1558
1602
  var FORBIDDEN_TAGS = validation_rules_default.forbiddenTags;
1559
1603
  var BANNED_AGENT_PHRASES = validation_rules_default.bannedAgentPhrases;
1560
- var REQUIRED_SKILL_SECTIONS = validation_rules_default.requiredSkillSections;
1561
- var SKILL_SECTION_EXEMPT_SOURCES = validation_rules_default.skillSectionExemptSources;
1562
- function isVerbatimSuperpowersMarkdownPath(rel) {
1563
- return rel.replace(/\\/g, "/").includes("/superpowers/");
1564
- }
1604
+ var REQUIRED_SKILL_FRONTMATTER = validation_rules_default.requiredSkillFrontmatter;
1565
1605
  var REQUIRED_AGENT_SECTIONS = validation_rules_default.requiredAgentSections;
1566
1606
  var RISKY_INSTALL_PATTERNS = validation_rules_default.riskyInstallPatterns.map(toRegExp);
1567
1607
  var ALLOWED_NPX_PATTERN = toRegExp(validation_rules_default.allowedNpxPattern);
@@ -3819,7 +3859,7 @@ async function runUninstall(options = {}) {
3819
3859
  continue;
3820
3860
  }
3821
3861
  await fs17.remove(entry.destPath);
3822
- await pruneEmptyDir(path23.dirname(entry.destPath));
3862
+ await pruneEmptyDir2(path23.dirname(entry.destPath));
3823
3863
  result.deleted.push(entry.destPath);
3824
3864
  }
3825
3865
  const settings = await readSettings();
@@ -3850,7 +3890,7 @@ function printUninstallResult(result) {
3850
3890
  log("Haus hook entries removed from ~/.claude/settings.json");
3851
3891
  }
3852
3892
  }
3853
- async function pruneEmptyDir(dir) {
3893
+ async function pruneEmptyDir2(dir) {
3854
3894
  try {
3855
3895
  const entries = await fs17.readdir(dir);
3856
3896
  if (entries.length === 0) await fs17.remove(dir);
@@ -4086,8 +4126,33 @@ function extractUseWhenSection(text) {
4086
4126
  const next = tail.search(/\n##\s+/);
4087
4127
  return next < 0 ? tail : tail.slice(0, next);
4088
4128
  }
4129
+ function isYamlBlockScalarHeader(rest) {
4130
+ return /^[>|][-+]?(\d+)?(?:\s+#.*)?$/.test(rest);
4131
+ }
4132
+ function extractFrontmatterDescription(text) {
4133
+ const m = text.match(/^---\r?\n([\s\S]*?)\r?\n---/);
4134
+ if (!m) return "";
4135
+ const lines = m[1].split(/\r?\n/);
4136
+ const idx = lines.findIndex((l) => /^description:[ \t]*/.test(l));
4137
+ if (idx < 0) return "";
4138
+ const rest = lines[idx].replace(/^description:[ \t]*/, "").trim();
4139
+ if (!rest) return "";
4140
+ if (!isYamlBlockScalarHeader(rest)) {
4141
+ return rest.replace(/^["']|["']$/g, "").trim();
4142
+ }
4143
+ const body = [];
4144
+ for (let j = idx + 1; j < lines.length; j++) {
4145
+ const line2 = lines[j];
4146
+ if (/^[a-zA-Z_][\w.-]*:[ \t]/.test(line2)) break;
4147
+ if (line2.trim() === "") continue;
4148
+ if (/^\s+/.test(line2)) body.push(line2.trimStart());
4149
+ else break;
4150
+ }
4151
+ return body.join(" ").replace(/\s+/g, " ").trim();
4152
+ }
4089
4153
  function auditForbiddenTagsInText(text, label) {
4090
- const body = extractUseWhenSection(text);
4154
+ const body = `${extractFrontmatterDescription(text)}
4155
+ ${extractUseWhenSection(text)}`;
4091
4156
  if (!body.trim()) return [];
4092
4157
  const failures = [];
4093
4158
  for (const word of PROSE_FORBIDDEN_TAGS) {
@@ -4173,10 +4238,10 @@ function auditShippedFiles(manifestDir, items) {
4173
4238
  continue;
4174
4239
  }
4175
4240
  const text = fs18.readFileSync(skillMd, "utf8");
4176
- const skillSectionExempt = SKILL_SECTION_EXEMPT_SOURCES.includes(item.source) && item.whenToUse && item.whenNotToUse;
4177
- if (!skillSectionExempt) {
4178
- for (const section of REQUIRED_SKILL_SECTIONS) {
4179
- if (!text.includes(section)) failures.push(`${item.id}: SKILL.md missing ${section}`);
4241
+ const description = extractFrontmatterDescription(text);
4242
+ for (const key of REQUIRED_SKILL_FRONTMATTER) {
4243
+ if (key === "description" && !description) {
4244
+ failures.push(`${item.id}: SKILL.md missing non-empty frontmatter 'description:'`);
4180
4245
  }
4181
4246
  }
4182
4247
  failures.push(
@@ -4245,13 +4310,9 @@ function auditMarkdownContent(manifestDir) {
4245
4310
  walkMd(abs, (file) => {
4246
4311
  const text = fs18.readFileSync(file, "utf8");
4247
4312
  const rel = path26.relative(manifestDir, file);
4248
- if (isVerbatimSuperpowersMarkdownPath(rel)) return;
4249
4313
  const lines = text.split(/\r?\n/);
4250
4314
  for (let i = 0; i < lines.length; i++) {
4251
4315
  const line2 = lines[i] ?? "";
4252
- if (PLACEHOLDER_PATTERN.test(line2)) {
4253
- failures.push(`${rel}:${i + 1}: TODO or placeholder in shipped content`);
4254
- }
4255
4316
  if (RISKY_INSTALL_PATTERNS.some((re) => re.test(line2))) {
4256
4317
  failures.push(`${rel}:${i + 1}: risky install pattern`);
4257
4318
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.5.0",
2
+ "version": "2.6.1",
3
3
  "items": [
4
4
  {
5
5
  "id": "haus.nextjs-patterns",
@@ -1650,7 +1650,7 @@
1650
1650
  },
1651
1651
  {
1652
1652
  "id": "haus.superpowers-brainstorming",
1653
- "version": "1.0.1",
1653
+ "version": "1.0.2",
1654
1654
  "source": "curated",
1655
1655
  "type": "skill",
1656
1656
  "path": "skills/superpowers/brainstorming",
@@ -17,7 +17,7 @@
17
17
  "trading"
18
18
  ],
19
19
  "bannedAgentPhrases": ["autonomous", "swarm", "delegate", "orchestrat", "marketplace"],
20
- "requiredSkillSections": ["## Use when", "## Do not use when"],
20
+ "requiredSkillFrontmatter": ["description"],
21
21
  "requiredAgentSections": ["## Use when", "## Do not use when", "## Verification"],
22
22
  "riskyInstallPatterns": [
23
23
  { "source": "\\bnpx\\s+-y\\b", "flags": "i" },
@@ -142,6 +142,5 @@
142
142
  "baseline",
143
143
  "project-instructions"
144
144
  ],
145
- "patternTagSuffixes": ["-patterns"],
146
- "skillSectionExemptSources": ["curated"]
145
+ "patternTagSuffixes": ["-patterns"]
147
146
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haus-tech/haus-workflow",
3
- "version": "0.17.1",
3
+ "version": "0.18.1",
4
4
  "description": "Haus AI workflow CLI for Claude Code.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9
 
@@ -1,4 +1,9 @@
1
- <!-- Fixture stub — minimal valid SKILL.md for CLI tests. -->
1
+ ---
2
+ name: fixture-stub
3
+ description: Fixture stub — minimal valid SKILL.md for CLI tests.
4
+ ---
5
+
6
+ # Fixture stub
2
7
 
3
8
  ## Use when
4
9