opencode-skills-collection 4.1.1 → 4.1.3

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.

Potentially problematic release.


This version of opencode-skills-collection might be problematic. Click here for more details.

Files changed (274) hide show
  1. package/bundled-skills/.antigravity-install-manifest.json +133 -1
  2. package/bundled-skills/360-feedback-system/SKILL.md +481 -0
  3. package/bundled-skills/access-matrix/SKILL.md +338 -0
  4. package/bundled-skills/accounting-audit-system-builder/SKILL.md +302 -0
  5. package/bundled-skills/accounting-audit-system-builder/references/catalog.md +114 -0
  6. package/bundled-skills/accounting-software-selection/SKILL.md +427 -0
  7. package/bundled-skills/accounting-software-selection/references/build-artifacts.md +362 -0
  8. package/bundled-skills/accounting-software-selection/references/common-pitfalls.md +44 -0
  9. package/bundled-skills/accounting-software-selection/references/field-reference.md +93 -0
  10. package/bundled-skills/accounting-software-selection/references/select-options.md +202 -0
  11. package/bundled-skills/admin-access-register/SKILL.md +381 -0
  12. package/bundled-skills/advanced-analytics-dashboard/SKILL.md +318 -0
  13. package/bundled-skills/ai-image-generation-studio/SKILL.md +259 -0
  14. package/bundled-skills/ai-logo-maker/SKILL.md +259 -0
  15. package/bundled-skills/ai-multilingual-dubbing/SKILL.md +259 -0
  16. package/bundled-skills/ai-photo-restyler/SKILL.md +259 -0
  17. package/bundled-skills/ai-podcast-voiceover/SKILL.md +259 -0
  18. package/bundled-skills/alumni-re-hire-tracker/SKILL.md +314 -0
  19. package/bundled-skills/announcement-board/SKILL.md +336 -0
  20. package/bundled-skills/antigravity-maintainer-batch-release/SKILL.md +63 -4
  21. package/bundled-skills/asset-it-management/SKILL.md +407 -0
  22. package/bundled-skills/attendance/SKILL.md +331 -0
  23. package/bundled-skills/audit-log/SKILL.md +314 -0
  24. package/bundled-skills/audit-preparation/SKILL.md +416 -0
  25. package/bundled-skills/beatra/SKILL.md +260 -0
  26. package/bundled-skills/board-governance/SKILL.md +360 -0
  27. package/bundled-skills/brand-growth-system-builder/SKILL.md +360 -0
  28. package/bundled-skills/brand-kit-print-collateral/SKILL.md +498 -0
  29. package/bundled-skills/buddy-program-manager/SKILL.md +329 -0
  30. package/bundled-skills/budget-cash-flow/SKILL.md +352 -0
  31. package/bundled-skills/busabase/SKILL.md +118 -0
  32. package/bundled-skills/business-email-template/SKILL.md +480 -0
  33. package/bundled-skills/business-email-template/references/common-pitfalls.md +30 -0
  34. package/bundled-skills/business-website-setup/SKILL.md +489 -0
  35. package/bundled-skills/business-website-setup/references/common-pitfalls.md +32 -0
  36. package/bundled-skills/candidate-talent-pool/SKILL.md +359 -0
  37. package/bundled-skills/capacity-workload-planner/SKILL.md +354 -0
  38. package/bundled-skills/changelog-entry/SKILL.md +141 -0
  39. package/bundled-skills/clients-accounts/SKILL.md +398 -0
  40. package/bundled-skills/code-of-conduct/SKILL.md +488 -0
  41. package/bundled-skills/code-of-conduct/references/common-pitfalls.md +31 -0
  42. package/bundled-skills/company-email-accounts/SKILL.md +404 -0
  43. package/bundled-skills/competency-matrix/SKILL.md +335 -0
  44. package/bundled-skills/contract-document-renewal/SKILL.md +396 -0
  45. package/bundled-skills/course-upskilling-requests/SKILL.md +354 -0
  46. package/bundled-skills/credit-cycle-analysis/SKILL.md +303 -0
  47. package/bundled-skills/credit-cycle-analysis/references/best-practices.md +35 -0
  48. package/bundled-skills/credit-cycle-analysis/references/common-pitfalls.md +5 -0
  49. package/bundled-skills/credit-cycle-analysis/references/examples.md +34 -0
  50. package/bundled-skills/credit-cycle-analysis/references/field-reference.md +47 -0
  51. package/bundled-skills/credit-cycle-analysis/references/how-it-works.md +494 -0
  52. package/bundled-skills/credit-cycle-analysis/references/security-notes.md +16 -0
  53. package/bundled-skills/credit-cycle-analysis/references/select-options.md +32 -0
  54. package/bundled-skills/csv-manual-export/SKILL.md +499 -0
  55. package/bundled-skills/csv-manual-export/references/common-pitfalls.md +19 -0
  56. package/bundled-skills/culture-retention/SKILL.md +346 -0
  57. package/bundled-skills/data-export-engine/SKILL.md +308 -0
  58. package/bundled-skills/data-privacy-controls/SKILL.md +317 -0
  59. package/bundled-skills/day-book/SKILL.md +499 -0
  60. package/bundled-skills/day-book/references/best-practices.md +32 -0
  61. package/bundled-skills/day-book/references/common-pitfalls.md +58 -0
  62. package/bundled-skills/day-book/references/field-reference.md +45 -0
  63. package/bundled-skills/day-book/references/how-it-works.md +7 -0
  64. package/bundled-skills/day-book/references/related-skills.md +18 -0
  65. package/bundled-skills/day-book/references/relations.md +14 -0
  66. package/bundled-skills/day-book/references/reusable-prompt.md +50 -0
  67. package/bundled-skills/day-book/references/security-safety-notes.md +19 -0
  68. package/bundled-skills/day-book/references/select-options.md +38 -0
  69. package/bundled-skills/deep-research-framework/SKILL.md +81 -0
  70. package/bundled-skills/dei-dashboard/SKILL.md +307 -0
  71. package/bundled-skills/design-theme-guide/SKILL.md +472 -0
  72. package/bundled-skills/disciplinary-pip-tracker/SKILL.md +345 -0
  73. package/bundled-skills/document-management-system/SKILL.md +328 -0
  74. package/bundled-skills/ecommerce-listing-image-set/SKILL.md +259 -0
  75. package/bundled-skills/employee-suggestion-hub/SKILL.md +322 -0
  76. package/bundled-skills/esop-equity-tracker/SKILL.md +331 -0
  77. package/bundled-skills/events-activities/SKILL.md +355 -0
  78. package/bundled-skills/expense-accounting/SKILL.md +496 -0
  79. package/bundled-skills/expense-accounting/references/common-pitfalls.md +41 -0
  80. package/bundled-skills/expense-accounting/references/related-skills.md +11 -0
  81. package/bundled-skills/expense-accounting/references/reusable-prompt.md +36 -0
  82. package/bundled-skills/expense-management/SKILL.md +351 -0
  83. package/bundled-skills/five-axis-code-review/SKILL.md +78 -0
  84. package/bundled-skills/free-design-resources/SKILL.md +480 -0
  85. package/bundled-skills/free-design-resources/references/common-pitfalls.md +44 -0
  86. package/bundled-skills/free-design-resources/references/related-skills.md +24 -0
  87. package/bundled-skills/free-design-resources/references/reusable-prompt.md +12 -0
  88. package/bundled-skills/gamification-engine/SKILL.md +307 -0
  89. package/bundled-skills/gbp-local-seo-intent/SKILL.md +466 -0
  90. package/bundled-skills/gbp-local-seo-intent/references/best-practices.md +41 -0
  91. package/bundled-skills/gbp-local-seo-intent/references/common-pitfalls.md +40 -0
  92. package/bundled-skills/gbp-local-seo-intent/references/related-skills.md +17 -0
  93. package/bundled-skills/gbp-local-seo-intent/references/reusable-prompt.md +11 -0
  94. package/bundled-skills/gbp-local-seo-intent/references/security-safety-notes.md +27 -0
  95. package/bundled-skills/git-commit-message/SKILL.md +76 -0
  96. package/bundled-skills/health-wellness/SKILL.md +334 -0
  97. package/bundled-skills/idea-to-blueprint/LICENSE +21 -0
  98. package/bundled-skills/idea-to-blueprint/SKILL.md +260 -0
  99. package/bundled-skills/idea-to-blueprint/assets/AGENTS.md.template +38 -0
  100. package/bundled-skills/idea-to-blueprint/assets/CLAUDE.md.template +38 -0
  101. package/bundled-skills/idea-to-blueprint/assets/DECISIONS.md.template +14 -0
  102. package/bundled-skills/idea-to-blueprint/assets/PROGRESS.md.template +47 -0
  103. package/bundled-skills/idea-to-blueprint/assets/session-prompt.md +23 -0
  104. package/bundled-skills/idea-to-blueprint/references/architecture-decisions.md +202 -0
  105. package/bundled-skills/idea-to-blueprint/references/blueprint-template.md +259 -0
  106. package/bundled-skills/idea-to-blueprint/references/code-quality-and-review.md +216 -0
  107. package/bundled-skills/idea-to-blueprint/references/design-minimal.md +96 -0
  108. package/bundled-skills/idea-to-blueprint/references/edge-case-catalog.md +239 -0
  109. package/bundled-skills/idea-to-blueprint/references/intake-questions.md +105 -0
  110. package/bundled-skills/idea-to-blueprint/references/research-protocol.md +196 -0
  111. package/bundled-skills/idea-to-blueprint/references/session-protocol.md +133 -0
  112. package/bundled-skills/idea-to-blueprint/references/stories-ac-tests.md +194 -0
  113. package/bundled-skills/idea-to-blueprint/references/ux-writing-guide.md +128 -0
  114. package/bundled-skills/idea-to-blueprint/scripts/lint_blueprint.py +460 -0
  115. package/bundled-skills/intern-program/SKILL.md +354 -0
  116. package/bundled-skills/internal-communication/SKILL.md +318 -0
  117. package/bundled-skills/inventory-stock-reconciliation/SKILL.md +470 -0
  118. package/bundled-skills/inventory-stock-reconciliation/references/best-practices.md +18 -0
  119. package/bundled-skills/inventory-stock-reconciliation/references/common-pitfalls.md +42 -0
  120. package/bundled-skills/inventory-stock-reconciliation/references/related-skills.md +13 -0
  121. package/bundled-skills/inventory-stock-reconciliation/references/relations.md +8 -0
  122. package/bundled-skills/inventory-stock-reconciliation/references/reusable-prompt.md +31 -0
  123. package/bundled-skills/inventory-stock-reconciliation/references/security-safety-notes.md +17 -0
  124. package/bundled-skills/inventory-stock-reconciliation/references/select-options.md +45 -0
  125. package/bundled-skills/invoices-billing/SKILL.md +385 -0
  126. package/bundled-skills/issue-grievance-tracker/SKILL.md +400 -0
  127. package/bundled-skills/json-schema-manual/SKILL.md +309 -0
  128. package/bundled-skills/json-schema-manual/references/best-practices.md +9 -0
  129. package/bundled-skills/json-schema-manual/references/common-pitfalls.md +25 -0
  130. package/bundled-skills/json-schema-manual/references/input-modules.md +203 -0
  131. package/bundled-skills/json-schema-manual/references/related-skills.md +8 -0
  132. package/bundled-skills/json-schema-manual/references/reusable-prompt.md +10 -0
  133. package/bundled-skills/json-schema-manual/references/security-safety-notes.md +13 -0
  134. package/bundled-skills/knowledge-base/SKILL.md +318 -0
  135. package/bundled-skills/kpi-tracker/SKILL.md +345 -0
  136. package/bundled-skills/learning-career-development/SKILL.md +349 -0
  137. package/bundled-skills/leave-management/SKILL.md +341 -0
  138. package/bundled-skills/legal-compliance-vault/SKILL.md +324 -0
  139. package/bundled-skills/linktree-link-hub/SKILL.md +453 -0
  140. package/bundled-skills/liuguang-banlan-ui/SKILL.md +22 -18
  141. package/bundled-skills/liuguang-banlan-ui/assets/starter/launcher.css +2 -2
  142. package/bundled-skills/liuguang-banlan-ui/assets/starter/obsidian/index.html +5 -4
  143. package/bundled-skills/liuguang-banlan-ui/assets/starter/obsidian/theme-config.js +3 -10
  144. package/bundled-skills/liuguang-banlan-ui/assets/starter/obsidian/theme.css +48 -62
  145. package/bundled-skills/liuguang-banlan-ui/assets/starter/opal/index.html +5 -4
  146. package/bundled-skills/liuguang-banlan-ui/assets/starter/opal/theme-config.js +27 -35
  147. package/bundled-skills/liuguang-banlan-ui/assets/starter/opal/theme.css +48 -62
  148. package/bundled-skills/liuguang-banlan-ui/assets/starter/shared/spectral-field.js +135 -148
  149. package/bundled-skills/liuguang-banlan-ui/references/style-contract.md +26 -7
  150. package/bundled-skills/liuguang-banlan-ui/references/verification.md +19 -7
  151. package/bundled-skills/liuguang-banlan-ui/scripts/measure_preview.py +78 -47
  152. package/bundled-skills/liuguang-banlan-ui/scripts/serve_preview.py +35 -0
  153. package/bundled-skills/liuguang-banlan-ui/scripts/validate_manifest.py +34 -3
  154. package/bundled-skills/liuguang-banlan-ui/tests/test_measure_preview.py +119 -0
  155. package/bundled-skills/liuguang-banlan-ui/tests/test_serve_preview.py +38 -0
  156. package/bundled-skills/liuguang-banlan-ui/tests/test_validate_manifest.py +73 -0
  157. package/bundled-skills/logo-image-design/SKILL.md +459 -0
  158. package/bundled-skills/loki-mode/examples/todo-app-generated/frontend/package-lock.json +12 -12
  159. package/bundled-skills/loki-mode/examples/todo-app-generated/frontend/package.json +1 -1
  160. package/bundled-skills/meeting-notes/SKILL.md +80 -0
  161. package/bundled-skills/mentorship-program/SKILL.md +332 -0
  162. package/bundled-skills/mirrord/SKILL.md +90 -0
  163. package/bundled-skills/monthly-closing-statements/SKILL.md +488 -0
  164. package/bundled-skills/monthly-closing-statements/references/related-skills.md +17 -0
  165. package/bundled-skills/monthly-closing-statements/references/reusable-prompt.md +8 -0
  166. package/bundled-skills/music-generation-studio/SKILL.md +259 -0
  167. package/bundled-skills/notification-reminder-hub/SKILL.md +324 -0
  168. package/bundled-skills/notion-manual-import/SKILL.md +376 -0
  169. package/bundled-skills/notion-manual-import/references/best-practices.md +10 -0
  170. package/bundled-skills/notion-manual-import/references/common-pitfalls.md +26 -0
  171. package/bundled-skills/notion-manual-import/references/input-modules.md +203 -0
  172. package/bundled-skills/notion-manual-import/references/related-skills.md +7 -0
  173. package/bundled-skills/notion-manual-import/references/reusable-prompt.md +8 -0
  174. package/bundled-skills/notion-manual-import/references/security-safety-notes.md +15 -0
  175. package/bundled-skills/observability-cloud-planning/SKILL.md +487 -0
  176. package/bundled-skills/observability-cloud-planning/references/common-pitfalls.md +39 -0
  177. package/bundled-skills/observability-cloud-planning/references/related-skills.md +20 -0
  178. package/bundled-skills/observability-cloud-planning/references/reusable-prompt.md +12 -0
  179. package/bundled-skills/observability-cloud-planning/references/security-safety-notes.md +30 -0
  180. package/bundled-skills/offboarding-exit/SKILL.md +343 -0
  181. package/bundled-skills/offer-appointment/SKILL.md +351 -0
  182. package/bundled-skills/okr-system/SKILL.md +355 -0
  183. package/bundled-skills/onboarding-playbook/SKILL.md +292 -0
  184. package/bundled-skills/organization-design/SKILL.md +324 -0
  185. package/bundled-skills/party-ledger-reconciliation/SKILL.md +411 -0
  186. package/bundled-skills/payment-accounting/SKILL.md +421 -0
  187. package/bundled-skills/payments-received/SKILL.md +315 -0
  188. package/bundled-skills/payroll-finance/SKILL.md +351 -0
  189. package/bundled-skills/people-directory/SKILL.md +459 -0
  190. package/bundled-skills/performance-management/SKILL.md +367 -0
  191. package/bundled-skills/petty-cash-management/SKILL.md +448 -0
  192. package/bundled-skills/policy-acknowledgement/SKILL.md +314 -0
  193. package/bundled-skills/policy-library/SKILL.md +327 -0
  194. package/bundled-skills/poster-design-studio/SKILL.md +259 -0
  195. package/bundled-skills/pre-boarding/SKILL.md +326 -0
  196. package/bundled-skills/presentation-deck/SKILL.md +491 -0
  197. package/bundled-skills/presentation-deck/references/related-skills.md +19 -0
  198. package/bundled-skills/presentation-deck/references/reusable-prompt.md +11 -0
  199. package/bundled-skills/probation-tracker/SKILL.md +347 -0
  200. package/bundled-skills/product-photo-studio/SKILL.md +259 -0
  201. package/bundled-skills/project-based-performance/SKILL.md +323 -0
  202. package/bundled-skills/projects-work-management/SKILL.md +368 -0
  203. package/bundled-skills/promotion-upgrade-requests/SKILL.md +377 -0
  204. package/bundled-skills/purchase-accounting/SKILL.md +414 -0
  205. package/bundled-skills/receipt-accounting/SKILL.md +424 -0
  206. package/bundled-skills/recognition-rewards/SKILL.md +324 -0
  207. package/bundled-skills/recruitment-pipeline/SKILL.md +399 -0
  208. package/bundled-skills/remote-work-tracker/SKILL.md +306 -0
  209. package/bundled-skills/repo-foundation/SKILL.md +166 -0
  210. package/bundled-skills/repo-foundation/references/LICENSE.md +21 -0
  211. package/bundled-skills/repo-foundation/references/bootstrap.md +63 -0
  212. package/bundled-skills/repo-foundation/references/companion.md +9 -0
  213. package/bundled-skills/repo-foundation/references/continuity.md +50 -0
  214. package/bundled-skills/repo-foundation/references/evolution.md +60 -0
  215. package/bundled-skills/repo-foundation/references/migration-examples.md +53 -0
  216. package/bundled-skills/repo-foundation/references/shared-contracts.md +48 -0
  217. package/bundled-skills/repo-foundation/references/verification.md +50 -0
  218. package/bundled-skills/repo-native-refactor/SKILL.md +225 -0
  219. package/bundled-skills/repo-native-refactor/references/LICENSE.md +21 -0
  220. package/bundled-skills/repo-native-refactor/references/deterministic-tooling.md +101 -0
  221. package/bundled-skills/repo-native-refactor/references/error-reliability.md +117 -0
  222. package/bundled-skills/repo-native-refactor/references/finding-taxonomy.md +181 -0
  223. package/bundled-skills/repo-native-refactor/references/refactor-examples.md +77 -0
  224. package/bundled-skills/repo-native-refactor/references/repository-prose.md +157 -0
  225. package/bundled-skills/repo-native-refactor/references/repository-rehabilitation.md +94 -0
  226. package/bundled-skills/repo-native-refactor/references/semantic-risk.md +187 -0
  227. package/bundled-skills/repo-native-refactor/references/shared-contracts.md +48 -0
  228. package/bundled-skills/repo-native-refactor/references/testing-integrity.md +103 -0
  229. package/bundled-skills/reports-analytics/SKILL.md +320 -0
  230. package/bundled-skills/salary-benchmarking/SKILL.md +318 -0
  231. package/bundled-skills/salary-wage-accounting/SKILL.md +412 -0
  232. package/bundled-skills/sales-accounting/SKILL.md +494 -0
  233. package/bundled-skills/sales-accounting/references/common-pitfalls.md +28 -0
  234. package/bundled-skills/sales-accounting/references/related-skills.md +13 -0
  235. package/bundled-skills/sales-accounting/references/reusable-prompt.md +8 -0
  236. package/bundled-skills/seo-directory-backlinks/SKILL.md +484 -0
  237. package/bundled-skills/seo-directory-backlinks/references/common-pitfalls.md +36 -0
  238. package/bundled-skills/seo-directory-backlinks/references/related-skills.md +15 -0
  239. package/bundled-skills/seo-directory-backlinks/references/reusable-prompt.md +11 -0
  240. package/bundled-skills/skill-gap-analysis/SKILL.md +338 -0
  241. package/bundled-skills/social-media-setup/SKILL.md +477 -0
  242. package/bundled-skills/social-media-setup/references/common-pitfalls.md +34 -0
  243. package/bundled-skills/social-media-setup/references/related-skills.md +19 -0
  244. package/bundled-skills/social-media-setup/references/reusable-prompt.md +11 -0
  245. package/bundled-skills/social-media-setup/references/security-safety-notes.md +27 -0
  246. package/bundled-skills/sop-company-wiki/SKILL.md +324 -0
  247. package/bundled-skills/source-document-filing/SKILL.md +368 -0
  248. package/bundled-skills/spreadsheet-manual-build/SKILL.md +493 -0
  249. package/bundled-skills/spreadsheet-manual-build/references/best-practices.md +9 -0
  250. package/bundled-skills/spreadsheet-manual-build/references/common-pitfalls.md +22 -0
  251. package/bundled-skills/spreadsheet-manual-build/references/related-skills.md +8 -0
  252. package/bundled-skills/spreadsheet-manual-build/references/reusable-prompt.md +9 -0
  253. package/bundled-skills/spreadsheet-manual-build/references/security-safety-notes.md +16 -0
  254. package/bundled-skills/stakeholder-investor-reports/SKILL.md +303 -0
  255. package/bundled-skills/suno-lyrics-to-song/SKILL.md +259 -0
  256. package/bundled-skills/talking-avatar-video/SKILL.md +260 -0
  257. package/bundled-skills/tax-register/SKILL.md +363 -0
  258. package/bundled-skills/tds-booking-payment/SKILL.md +405 -0
  259. package/bundled-skills/team-calendar/SKILL.md +312 -0
  260. package/bundled-skills/tech-writing-proofread/SKILL.md +78 -0
  261. package/bundled-skills/telegram/assets/boilerplate/nodejs/package-lock.json +3 -3
  262. package/bundled-skills/telegram/assets/boilerplate/nodejs/package.json +1 -0
  263. package/bundled-skills/template-library/SKILL.md +304 -0
  264. package/bundled-skills/time-tracking/SKILL.md +353 -0
  265. package/bundled-skills/typescript-expert/scripts/ts_diagnostic.py +40 -19
  266. package/bundled-skills/vendor-contractor-management/SKILL.md +327 -0
  267. package/bundled-skills/viral-video-teardown-remake/SKILL.md +260 -0
  268. package/bundled-skills/voice-cloning-studio/SKILL.md +260 -0
  269. package/bundled-skills/voiceover-narration-studio/SKILL.md +259 -0
  270. package/bundled-skills/whatsapp-cloud-api/assets/boilerplate/nodejs/package-lock.json +3 -3
  271. package/bundled-skills/whatsapp-cloud-api/assets/boilerplate/nodejs/package.json +1 -0
  272. package/bundled-skills/youtube-summarizer/SKILL.md +3 -3
  273. package/package.json +1 -1
  274. package/skills_index.json +254 -0
@@ -0,0 +1,460 @@
1
+ #!/usr/bin/env python3
2
+ """Lint a generated blueprint (.md) for the structural guarantees the build sessions rely on.
3
+
4
+ Usage:
5
+ python3 lint_blueprint.py path/to/blueprint.md [--strict]
6
+
7
+ Exit code 0 = no errors (warnings may remain), 1 = errors found (or warnings with --strict).
8
+
9
+ What it checks (E = error, W = warning):
10
+ E required top-level sections present (by English anchor in a `## ` heading)
11
+ E no placeholder text (TODO, TBD, TBA, FIXME, XXX, lorem, ???, [insert, to be defined/decided)
12
+ E at least one `## Epic nn — Title` and Epic 00 present
13
+ E each epic has **Definition of Done**; W each epic has **Session handoff checklist**
14
+ E story headings `### Enn-Snn — Title` are unique and live inside the matching epic
15
+ E each story has **Acceptance Criteria**, **Edge cases**, **Tests**, at least one `AC-n`, and names a persona `P<n>`
16
+ W each story has **Story**, **Context**, **Scope**, **Tasks**, **Story DoD**
17
+ E no "As a user" stories
18
+ E every `[UNKNOWN → OQ-nn]` has a matching OQ-nn row in the Open Questions section; bare `[UNKNOWN]` without an OQ is an error
19
+ E every table body row in the Tech Stack section carries [VERIFIED / [ASSUMED / [STATED (or [UNVERIFIED], which also raises W)
20
+ E every S-nn cited in a [VERIFIED …] tag exists in the Sources section; W fewer than 5 URLs in Sources
21
+ E every defined persona P<n> is used by at least one story
22
+ W copy IDs (CP-…) referenced in stories are defined in the Copy section
23
+ W dangling story references (Enn-Snn mentioned but not defined)
24
+ W `## ` headings with non-ASCII text carry an ASCII anchor in parentheses
25
+ W vague adjectives inside AC lines (properly, appropriately, fast, quickly, easily, seamless, user-friendly, intuitive)
26
+ W Session Protocol section mentions an Amendments log; W an appendix with session prompts exists
27
+ E Architecture section defines drivers AD-n and mentions fitness functions; W <3 drivers, drivers
28
+ with no number in them, no explicit non-drivers
29
+ E every AD-n referenced outside the Architecture section is defined inside it
30
+ W Tech Stack table has a runner-up column (a choice with no stated cost was not a decision)
31
+ E Quality section names a `check` command and embeds >=10 review-checklist items of the form `[ ] …`
32
+ W Quality section names critical e2e paths, says something about mutation testing, has M-nn metric
33
+ rows, and lists anti-metrics
34
+ E no metric row defines an output-per-person metric (lines of code, commits/PRs/diffs per engineer,
35
+ story points as productivity); W coverage appearing as a metric without the word "floor"
36
+
37
+ Add `<!-- lint-ignore -->` at the end of a line to suppress placeholder/adjective findings on that line
38
+ (e.g., the rule sentence "No TODO or TBD anywhere" in the How-to-use section).
39
+ """
40
+ from __future__ import annotations
41
+
42
+ import re
43
+ import sys
44
+ from dataclasses import dataclass, field
45
+
46
+ REQUIRED_SECTIONS_ERROR = [
47
+ "How to use", "Executive summary", "Scope", "Research", "Assumptions", "Personas",
48
+ "Goals", "Architecture", "Tech Stack", "Quality", "Edge Cases", "Delivery Plan",
49
+ "Epics", "Session Protocol", "Risks", "Open Questions", "Glossary", "Sources",
50
+ ]
51
+ REQUIRED_SECTIONS_WARN = ["Flows", "Screens", "Design", "UX Writing", "Copy"]
52
+
53
+ PLACEHOLDER_RE = re.compile(
54
+ r"\bTODO\b|\bTBD\b|\bTBA\b|\bFIXME\b|\bXXX\b|lorem ipsum|\?\?\?|\[insert|to be defined|to be decided",
55
+ re.IGNORECASE,
56
+ )
57
+ EPIC_HEADING_RE = re.compile(r"^## Epic (\d{2})\s*[—–-]\s*(.+?)\s*$")
58
+ STORY_HEADING_RE = re.compile(r"^### (E(\d{2})-S(\d{2}))\s*[—–-]\s*(.+?)\s*$")
59
+ STORY_REF_RE = re.compile(r"\bE\d{2}-S\d{2}\b")
60
+ AC_LINE_RE = re.compile(r"^\s*[-*]\s*AC-\d+", re.IGNORECASE)
61
+ PERSONA_REF_RE = re.compile(r"(?<![A-Za-z])P(\d+)\b")
62
+ UNKNOWN_RE = re.compile(r"\[UNKNOWN([^\]]*)\]")
63
+ OQ_IN_UNKNOWN_RE = re.compile(r"OQ-(\d+)")
64
+ VERIFIED_SOURCE_RE = re.compile(r"\[VERIFIED[^\]]*?\bS-(\d+)")
65
+ SOURCE_ID_RE = re.compile(r"\bS-(\d+)\b")
66
+ URL_RE = re.compile(r"https?://\S+")
67
+ CP_ID_RE = re.compile(r"\bCP-[A-Za-z0-9]+-\d+\b")
68
+ EVIDENCE_TAG_RE = re.compile(r"\[(VERIFIED|ASSUMED|STATED|UNVERIFIED)\b")
69
+ UNVERIFIED_RE = re.compile(r"\[UNVERIFIED\]")
70
+ VAGUE_RE = re.compile(
71
+ r"\b(properly|appropriately|fast|quickly|easily|seamless(?:ly)?|user-friendly|intuitive(?:ly)?)\b",
72
+ re.IGNORECASE,
73
+ )
74
+ AS_A_USER_RE = re.compile(r"\bAs an? user\b", re.IGNORECASE)
75
+ AD_ID_RE = re.compile(r"\bAD-(\d+)\b")
76
+ DIGIT_RE = re.compile(r"\d")
77
+ FITNESS_RE = re.compile(r"fitness function", re.IGNORECASE)
78
+ CHECK_CMD_RE = re.compile(r"`[^`\n]*\bcheck\b[^`\n]*`")
79
+ CHECKLIST_ITEM_RE = re.compile(r"^\s*(?:[-*]\s*)?\[ \]\s+\S")
80
+ METRIC_ROW_RE = re.compile(r"\bM-\d+(?:\.\d+)?\b")
81
+ BANNED_METRIC_RE = re.compile(
82
+ r"lines of code|\bLOC\b|commits? per (?:engineer|developer|dev|person)"
83
+ r"|(?:pull requests?|PRs?|diffs?) per (?:engineer|developer|dev|person)"
84
+ r"|story points? (?:per|as a measure|completed per)|velocity per",
85
+ re.IGNORECASE,
86
+ )
87
+ COVERAGE_TARGET_RE = re.compile(r"coverage", re.IGNORECASE)
88
+ LINT_IGNORE = "<!-- lint-ignore -->"
89
+
90
+
91
+ @dataclass
92
+ class Findings:
93
+ errors: list[str] = field(default_factory=list)
94
+ warnings: list[str] = field(default_factory=list)
95
+
96
+ def err(self, line: int | None, msg: str) -> None:
97
+ self.errors.append(f"L{line}: {msg}" if line else msg)
98
+
99
+ def warn(self, line: int | None, msg: str) -> None:
100
+ self.warnings.append(f"L{line}: {msg}" if line else msg)
101
+
102
+
103
+ @dataclass
104
+ class Section:
105
+ title: str
106
+ start: int # 0-based index of heading line
107
+ end: int # exclusive
108
+
109
+
110
+ def level2_sections(lines: list[str]) -> list[Section]:
111
+ idx = [i for i, l in enumerate(lines) if l.startswith("## ")]
112
+ sections = []
113
+ for n, i in enumerate(idx):
114
+ end = idx[n + 1] if n + 1 < len(idx) else len(lines)
115
+ sections.append(Section(lines[i][3:].strip(), i, end))
116
+ return sections
117
+
118
+
119
+ def find_section(sections: list[Section], anchor: str) -> Section | None:
120
+ a = anchor.lower()
121
+ for s in sections:
122
+ if EPIC_HEADING_RE.match("## " + s.title):
123
+ continue
124
+ if a in s.title.lower():
125
+ return s
126
+ return None
127
+
128
+
129
+ def block_text(lines: list[str], start: int, end: int) -> str:
130
+ return "\n".join(lines[start:end])
131
+
132
+
133
+ def table_body_rows(lines: list[str], start: int, end: int) -> list[tuple[int, str]]:
134
+ """Return (line_no, row) for table rows that are neither header nor separator."""
135
+ rows = []
136
+ in_table = False
137
+ header_seen = False
138
+ for i in range(start, end):
139
+ l = lines[i].strip()
140
+ if l.startswith("|"):
141
+ if not in_table:
142
+ in_table, header_seen = True, True # first row of a table is its header
143
+ continue
144
+ if re.match(r"^\|[\s:\-|]+\|$", l):
145
+ continue # separator
146
+ rows.append((i + 1, l))
147
+ else:
148
+ in_table, header_seen = False, False
149
+ return rows
150
+
151
+
152
+ def main(argv: list[str]) -> int:
153
+ if len(argv) < 2 or argv[1] in {"-h", "--help"}:
154
+ print(__doc__)
155
+ return 0
156
+ path = argv[1]
157
+ strict = "--strict" in argv
158
+ with open(path, encoding="utf-8") as f:
159
+ lines = f.read().splitlines()
160
+ f_ = Findings()
161
+ sections = level2_sections(lines)
162
+
163
+ # 1. Required sections
164
+ for anchor in REQUIRED_SECTIONS_ERROR:
165
+ if not find_section(sections, anchor):
166
+ f_.err(None, f"Missing required section with anchor '{anchor}' in a '## ' heading")
167
+ for anchor in REQUIRED_SECTIONS_WARN:
168
+ if not find_section(sections, anchor):
169
+ f_.warn(None, f"No section with anchor '{anchor}' — fine only if it truly does not apply (say so in the doc)")
170
+
171
+ # 2. Placeholders + vague adjectives + "As a user"
172
+ for i, l in enumerate(lines, 1):
173
+ if LINT_IGNORE in l:
174
+ continue
175
+ m = PLACEHOLDER_RE.search(l)
176
+ if m:
177
+ f_.err(i, f"Placeholder text '{m.group(0)}' — decide it or route to an [UNKNOWN → OQ-nn]")
178
+ if AC_LINE_RE.match(l):
179
+ v = VAGUE_RE.search(l)
180
+ if v:
181
+ f_.warn(i, f"Vague word '{v.group(0)}' in an acceptance criterion — replace with a number or observable result")
182
+ if AS_A_USER_RE.search(l):
183
+ f_.err(i, "'As a user' — stories must name a persona ID and name (e.g. 'As **P2 (Owner)**')")
184
+
185
+ # 3. Epics and stories
186
+ epics: list[tuple[int, str, Section]] = [] # (epic_no, title, section)
187
+ for s in sections:
188
+ m = EPIC_HEADING_RE.match("## " + s.title)
189
+ if m:
190
+ epics.append((int(m.group(1)), m.group(2), s))
191
+ if not epics:
192
+ f_.err(None, "No epics found — expected headings like '## Epic 00 — Foundation'")
193
+ elif not any(n == 0 for n, _, _ in epics):
194
+ f_.err(None, "Epic 00 (Foundation) is missing")
195
+
196
+ story_ids: dict[str, int] = {}
197
+ story_blocks: list[tuple[str, int, int, int]] = [] # (id, epic_no, start, end)
198
+ for epic_no, epic_title, sec in epics:
199
+ text = block_text(lines, sec.start, sec.end)
200
+ if "**Definition of Done**" not in text:
201
+ f_.err(sec.start + 1, f"Epic {epic_no:02d} has no **Definition of Done**")
202
+ if "**Session handoff checklist**" not in text:
203
+ f_.warn(sec.start + 1, f"Epic {epic_no:02d} has no **Session handoff checklist**")
204
+ # stories inside this epic
205
+ heads = [i for i in range(sec.start + 1, sec.end) if lines[i].startswith("### ")]
206
+ if not heads:
207
+ f_.err(sec.start + 1, f"Epic {epic_no:02d} has no stories ('### Enn-Snn — Title')")
208
+ for n, i in enumerate(heads):
209
+ end = heads[n + 1] if n + 1 < len(heads) else sec.end
210
+ m = STORY_HEADING_RE.match(lines[i])
211
+ if not m:
212
+ f_.warn(i + 1, f"Level-3 heading inside Epic {epic_no:02d} is not a story heading: '{lines[i][4:60]}'")
213
+ continue
214
+ sid, e_no = m.group(1), int(m.group(2))
215
+ if sid in story_ids:
216
+ f_.err(i + 1, f"Duplicate story ID {sid} (first at L{story_ids[sid]})")
217
+ story_ids[sid] = i + 1
218
+ if e_no != epic_no:
219
+ f_.err(i + 1, f"Story {sid} is inside Epic {epic_no:02d} but its ID says E{e_no:02d}")
220
+ story_blocks.append((sid, epic_no, i, end))
221
+
222
+ all_story_text = ""
223
+ for sid, _, start, end in story_blocks:
224
+ text = block_text(lines, start, end)
225
+ all_story_text += "\n" + text
226
+ for label in ("**Acceptance Criteria**", "**Edge cases**", "**Tests**"):
227
+ if label not in text:
228
+ f_.err(start + 1, f"{sid} is missing {label}")
229
+ for label in ("**Story**", "**Context**", "**Scope**", "**Tasks**", "**Story DoD**"):
230
+ if label not in text:
231
+ f_.warn(start + 1, f"{sid} is missing {label}")
232
+ if not any(AC_LINE_RE.match(l) for l in lines[start:end]):
233
+ f_.err(start + 1, f"{sid} has no 'AC-n' lines")
234
+ if not PERSONA_REF_RE.search(text):
235
+ f_.err(start + 1, f"{sid} does not reference a persona ID (P1, P2, … or P0 for the builder)")
236
+
237
+ # dangling story references
238
+ defined = set(story_ids)
239
+ for i, l in enumerate(lines, 1):
240
+ for ref in STORY_REF_RE.findall(l):
241
+ if ref not in defined:
242
+ f_.warn(i, f"Reference to undefined story {ref}")
243
+
244
+ # 4. UNKNOWN → OQ
245
+ oq_sec = find_section(sections, "Open Questions")
246
+ oq_text = block_text(lines, oq_sec.start, oq_sec.end) if oq_sec else ""
247
+ for i, l in enumerate(lines, 1):
248
+ for m in UNKNOWN_RE.finditer(l):
249
+ oqs = OQ_IN_UNKNOWN_RE.findall(m.group(1))
250
+ if not oqs:
251
+ f_.err(i, "[UNKNOWN] without an OQ reference — use '[UNKNOWN → OQ-nn]'")
252
+ for q in oqs:
253
+ if oq_sec and not re.search(rf"\bOQ-{q}\b", oq_text):
254
+ f_.err(i, f"OQ-{q} referenced but not present in the Open Questions section")
255
+
256
+ # 5. Tech stack evidence
257
+ ts = find_section(sections, "Tech Stack")
258
+ if ts:
259
+ rows = table_body_rows(lines, ts.start, ts.end)
260
+ if not rows:
261
+ f_.err(ts.start + 1, "Tech Stack section has no table rows")
262
+ for ln, row in rows:
263
+ if not EVIDENCE_TAG_RE.search(row):
264
+ f_.err(ln, "Tech Stack table row without an evidence tag ([VERIFIED …] / [ASSUMED …] / [STATED])")
265
+
266
+ # 6. Sources
267
+ src = find_section(sections, "Sources")
268
+ if src:
269
+ src_text = block_text(lines, src.start, src.end)
270
+ defined_sources = set(SOURCE_ID_RE.findall(src_text))
271
+ urls = URL_RE.findall(src_text)
272
+ if len(urls) < 5:
273
+ f_.warn(src.start + 1, f"Only {len(urls)} URL(s) in Sources — deep research normally yields far more")
274
+ for i, l in enumerate(lines, 1):
275
+ if src.start < i - 1 < src.end:
276
+ continue
277
+ for s_id in VERIFIED_SOURCE_RE.findall(l):
278
+ if s_id not in defined_sources:
279
+ f_.err(i, f"[VERIFIED …] cites S-{s_id}, which is not in the Sources section")
280
+
281
+ # 7. Personas used
282
+ per = find_section(sections, "Personas")
283
+ if per:
284
+ per_text = block_text(lines, per.start, per.end)
285
+ defined_personas = sorted({int(x) for x in PERSONA_REF_RE.findall(per_text)})
286
+ if not defined_personas:
287
+ f_.err(per.start + 1, "Personas section defines no persona IDs (P1, P2, …)")
288
+ used = {int(x) for x in PERSONA_REF_RE.findall(all_story_text)}
289
+ for p in defined_personas:
290
+ if p not in used:
291
+ f_.err(per.start + 1, f"Persona P{p} is never referenced by any story — remove it or write its stories")
292
+
293
+ # 8. Copy IDs referenced vs defined
294
+ cp = find_section(sections, "Copy")
295
+ if cp:
296
+ cp_defined = set(CP_ID_RE.findall(block_text(lines, cp.start, cp.end)))
297
+ for sid, _, start, end in story_blocks:
298
+ for ref in set(CP_ID_RE.findall(block_text(lines, start, end))):
299
+ if ref not in cp_defined:
300
+ f_.warn(start + 1, f"{sid} references copy ID {ref} that is not defined in the Copy section")
301
+
302
+ # 9. Heading anchors
303
+ for s in sections:
304
+ if any(ord(ch) > 127 and ch.isalpha() for ch in s.title) and not re.search(r"\([A-Za-z][A-Za-z0-9 &/\-]*\)", s.title):
305
+ f_.warn(s.start + 1, f"Heading '{s.title[:40]}' has no ASCII anchor in parentheses")
306
+
307
+ # 10. Session protocol / appendix
308
+ sp = find_section(sections, "Session Protocol")
309
+ if sp and "amendment" not in block_text(lines, sp.start, sp.end).lower():
310
+ f_.warn(sp.start + 1, "Session Protocol section does not mention the Amendments log")
311
+ if not find_section(sections, "Session Prompts"):
312
+ f_.warn(None, "No appendix with 'Session Prompts' — the user needs one copy-paste prompt per epic")
313
+
314
+ # 11. UNVERIFIED tags (only legitimate when web tools were unavailable)
315
+ unverified = sum(len(UNVERIFIED_RE.findall(l)) for l in lines)
316
+ if unverified:
317
+ f_.warn(None, f"{unverified} [UNVERIFIED] tag(s) — acceptable only with the no-web-access warning on the cover; the first build session must re-verify each")
318
+
319
+ # 12. Architecture drivers and the style decision
320
+ arch = find_section(sections, "Architecture")
321
+ ad_defined: set[str] = set()
322
+ if arch:
323
+ arch_text = block_text(lines, arch.start, arch.end)
324
+ # A driver is *defined* where its ID opens the line (optionally after a list marker, bold
325
+ # marker or heading hashes) or opens a table row's first cell. Everywhere else is a reference.
326
+ for i in range(arch.start, min(arch.end, len(lines))):
327
+ l = lines[i]
328
+ head = l.lstrip().lstrip("#*->|").lstrip().lstrip("*_ ")
329
+ m = AD_ID_RE.match(head)
330
+ if m:
331
+ ad_defined.add(m.group(1))
332
+ if not ad_defined:
333
+ f_.err(
334
+ arch.start + 1,
335
+ "Architecture section defines no drivers (AD-1, AD-2, …) — the style decision has "
336
+ "nothing to be scored against, which is how a stack gets chosen first and justified after",
337
+ )
338
+ elif len(ad_defined) < 3:
339
+ f_.warn(arch.start + 1, f"Only {len(ad_defined)} architecture driver(s) — 5–8 ranked drivers is the target")
340
+ # Each driver definition line must carry a measurable target. Strip the AD-n IDs first:
341
+ # the digit in the ID itself does not make the driver measurable.
342
+ for i in range(arch.start, min(arch.end, len(lines))):
343
+ l = lines[i]
344
+ head = l.lstrip().lstrip("#*->|").lstrip().lstrip("*_ ")
345
+ if LINT_IGNORE in l or not AD_ID_RE.match(head):
346
+ continue
347
+ if not DIGIT_RE.search(AD_ID_RE.sub("", l)):
348
+ f_.warn(
349
+ i + 1,
350
+ "Architecture driver with no number in it — a driver without a measurable target "
351
+ "cannot decide anything ('scalable' is not a driver)",
352
+ )
353
+ if not FITNESS_RE.search(arch_text):
354
+ f_.err(
355
+ arch.start + 1,
356
+ "Architecture section never mentions fitness functions — boundaries that are described "
357
+ "but not enforced are gone within a few sessions",
358
+ )
359
+ if "non-driver" not in arch_text.lower() and "not optimis" not in arch_text.lower() and "not optimiz" not in arch_text.lower():
360
+ f_.warn(arch.start + 1, "No explicit non-drivers ('what we are NOT optimising for') in the Architecture section")
361
+
362
+ # Every AD-n referenced anywhere must be defined by a driver line in the Architecture section
363
+ if ad_defined:
364
+ for i, l in enumerate(lines, 1):
365
+ head = l.lstrip().lstrip("#*->|").lstrip().lstrip("*_ ")
366
+ if arch and arch.start < i - 1 < arch.end and AD_ID_RE.match(head):
367
+ continue # this is the definition line itself
368
+ for ad in AD_ID_RE.findall(l):
369
+ if ad not in ad_defined:
370
+ f_.err(i, f"AD-{ad} is referenced but never defined as a driver in the Architecture section")
371
+
372
+ # 13. Tech stack table shape — every row must name what the runner-up would have bought
373
+ if ts:
374
+ header = ""
375
+ for i in range(ts.start, min(ts.end, len(lines))):
376
+ if lines[i].lstrip().startswith("|") and "---" not in lines[i]:
377
+ header = lines[i].lower()
378
+ break
379
+ if header and "runner" not in header:
380
+ f_.warn(
381
+ ts.start + 1,
382
+ "Tech Stack table has no runner-up column — a choice with no stated cost was not a decision",
383
+ )
384
+
385
+ # 14. Quality section: the gate, the checklist, the critical paths
386
+ q = find_section(sections, "Quality")
387
+ if q:
388
+ q_lines = lines[q.start : q.end]
389
+ q_text = "\n".join(q_lines)
390
+ q_lower = q_text.lower()
391
+ if not CHECK_CMD_RE.search(q_text):
392
+ f_.err(
393
+ q.start + 1,
394
+ "Quality section names no `check` command in backticks — the build sessions have no "
395
+ "definition of green",
396
+ )
397
+ checklist_items = sum(1 for l in q_lines if CHECKLIST_ITEM_RE.match(l))
398
+ if checklist_items < 10:
399
+ f_.err(
400
+ q.start + 1,
401
+ f"Quality section contains {checklist_items} review-checklist item(s) of the form '[ ] …' — "
402
+ "embed the review checklist verbatim (code-quality-and-review.md §11) or the reviewer "
403
+ "invents a different standard every session",
404
+ )
405
+ if "e2e" not in q_lower and "end-to-end" not in q_lower:
406
+ f_.warn(q.start + 1, "Quality section does not name the critical e2e paths")
407
+ if "mutation" not in q_lower:
408
+ f_.warn(
409
+ q.start + 1,
410
+ "Quality section says nothing about mutation testing — name the tool for this stack, "
411
+ "or state that no maintained one exists",
412
+ )
413
+ if not METRIC_ROW_RE.search(q_text):
414
+ f_.warn(q.start + 1, "Quality section has no metrics table rows (M-nn) — nothing will be measured")
415
+ if "anti-metric" not in q_lower and "will not measure" not in q_lower and "not measure" not in q_lower:
416
+ f_.warn(
417
+ q.start + 1,
418
+ "Quality section lists no anti-metrics — say explicitly what will not be measured and why",
419
+ )
420
+
421
+ # 15. Banned productivity metrics inside metric definition rows
422
+ for i, l in enumerate(lines, 1):
423
+ if LINT_IGNORE in l or not METRIC_ROW_RE.search(l):
424
+ continue
425
+ m = BANNED_METRIC_RE.search(l)
426
+ if m:
427
+ f_.err(
428
+ i,
429
+ f"Metric row defines '{m.group(0)}' — output-per-person metrics are gamed the moment they "
430
+ "become targets; measure the system, not the author",
431
+ )
432
+ if COVERAGE_TARGET_RE.search(l) and "floor" not in l.lower():
433
+ f_.warn(
434
+ i,
435
+ "Coverage appears as a metric without the word 'floor' — state it as a regression floor, "
436
+ "never as a target to raise",
437
+ )
438
+
439
+ # 16. Report
440
+ print(f"Blueprint lint — {path}")
441
+ print(f" epics: {len(epics)} stories: {len(story_ids)} sections: {len(sections)}")
442
+ if f_.errors:
443
+ print(f"\nERRORS ({len(f_.errors)}):")
444
+ for e in f_.errors:
445
+ print(" ✘ " + e)
446
+ if f_.warnings:
447
+ print(f"\nWARNINGS ({len(f_.warnings)}):")
448
+ for w in f_.warnings:
449
+ print(" ! " + w)
450
+ if not f_.errors and not f_.warnings:
451
+ print("\nPASS — no findings.")
452
+ elif not f_.errors:
453
+ print("\nPASS with warnings — resolve or justify each warning in the document.")
454
+ else:
455
+ print("\nFAIL — fix every error before delivering the blueprint.")
456
+ return 1 if f_.errors or (strict and f_.warnings) else 0
457
+
458
+
459
+ if __name__ == "__main__":
460
+ sys.exit(main(sys.argv))