voidmachine 0.0.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (341) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +123 -4
  3. package/bin/void-harness.mjs +12 -0
  4. package/bin/void-machine.mjs +12 -0
  5. package/core-assets/.claude-plugin/plugin.json +253 -0
  6. package/core-assets/.gitkeep +0 -0
  7. package/core-assets/PHILOSOPHY.md +218 -0
  8. package/core-assets/PROJECT-DOCTRINE.template.md +14 -0
  9. package/core-assets/adapters/security/manifest.yaml +96 -0
  10. package/core-assets/agents/.gitkeep +0 -0
  11. package/core-assets/agents/accessibility-specialist.md +59 -0
  12. package/core-assets/agents/api-integration-engineer.md +59 -0
  13. package/core-assets/agents/code-explorer.md +94 -0
  14. package/core-assets/agents/code-explorer.source +7 -0
  15. package/core-assets/agents/data-migration-engineer.md +59 -0
  16. package/core-assets/agents/devex-docs-engineer.md +57 -0
  17. package/core-assets/agents/doctrine-critic.md +91 -0
  18. package/core-assets/agents/doctrine-critic.source +11 -0
  19. package/core-assets/agents/domain-architect.md +56 -0
  20. package/core-assets/agents/experience-designer.md +59 -0
  21. package/core-assets/agents/frontend-engineer.md +60 -0
  22. package/core-assets/agents/independent-code-reviewer.md +61 -0
  23. package/core-assets/agents/migration-planner.md +97 -0
  24. package/core-assets/agents/migration-planner.source +7 -0
  25. package/core-assets/agents/observability-sre-engineer.md +59 -0
  26. package/core-assets/agents/pdf-specialist.md +58 -0
  27. package/core-assets/agents/performance-engineer.md +58 -0
  28. package/core-assets/agents/product-challenger.md +55 -0
  29. package/core-assets/agents/security-engineer.md +66 -0
  30. package/core-assets/agents/silent-failure-hunter.md +94 -0
  31. package/core-assets/agents/silent-failure-hunter.source +8 -0
  32. package/core-assets/agents/solution-architect.md +57 -0
  33. package/core-assets/agents/test-qa-engineer.md +60 -0
  34. package/core-assets/agents/type-design-analyzer.md +93 -0
  35. package/core-assets/agents/type-design-analyzer.source +8 -0
  36. package/core-assets/agents/visual-craft-director.md +62 -0
  37. package/core-assets/codex/hooks.json +157 -0
  38. package/core-assets/contract-history/visual-craft-director/v2.yaml +43 -0
  39. package/core-assets/data/catalog.v3.json +10479 -0
  40. package/core-assets/data/certification.json +1800 -0
  41. package/core-assets/data/identity.json +8 -0
  42. package/core-assets/data/model.json +4226 -0
  43. package/core-assets/enforce/ci-enforce.sh +183 -0
  44. package/core-assets/hooks/_checks.sh +145 -0
  45. package/core-assets/hooks/_hooklib.sh +163 -0
  46. package/core-assets/hooks/_syntax-worker.cjs +503 -0
  47. package/core-assets/hooks/_void-hook.mjs +5459 -0
  48. package/core-assets/hooks/activation-meter.sh +13 -0
  49. package/core-assets/hooks/anti-ai-slop-grep.sh +38 -0
  50. package/core-assets/hooks/auto-format.sh +9 -0
  51. package/core-assets/hooks/axe-precommit.sh +35 -0
  52. package/core-assets/hooks/block-dangerous-bash.sh +10 -0
  53. package/core-assets/hooks/block-protected-push.sh +81 -0
  54. package/core-assets/hooks/boundary-direction-check.sh +10 -0
  55. package/core-assets/hooks/control-character-grep.sh +10 -0
  56. package/core-assets/hooks/fowler-refactors.txt +71 -0
  57. package/core-assets/hooks/large-cl-grep.sh +9 -0
  58. package/core-assets/hooks/llm-cost-precommit.sh +55 -0
  59. package/core-assets/hooks/migration-lint.sh +58 -0
  60. package/core-assets/hooks/migration-pr-template.sh +55 -0
  61. package/core-assets/hooks/no-ai-design-slop.sh +10 -0
  62. package/core-assets/hooks/no-any-grep.sh +10 -0
  63. package/core-assets/hooks/no-as-cast-grep.sh +10 -0
  64. package/core-assets/hooks/no-console-log-grep.sh +10 -0
  65. package/core-assets/hooks/no-null-grep.sh +10 -0
  66. package/core-assets/hooks/no-only-no-skip.sh +10 -0
  67. package/core-assets/hooks/outcome-meter.sh +13 -0
  68. package/core-assets/hooks/pre-PR-review-evidence.sh +47 -0
  69. package/core-assets/hooks/protect-sensitive-files.sh +10 -0
  70. package/core-assets/hooks/refactor-named-grep.sh +49 -0
  71. package/core-assets/hooks/secret-in-content.sh +10 -0
  72. package/core-assets/hooks/sessionstart-context.sh +9 -0
  73. package/core-assets/hooks/stop-typecheck.sh +9 -0
  74. package/core-assets/hooks/tdd-guard.md +90 -0
  75. package/core-assets/hooks/tdd-guard.sh +10 -0
  76. package/core-assets/hooks/test-name-lint.sh +10 -0
  77. package/core-assets/hooks/tidying-commit-prefix.sh +37 -0
  78. package/core-assets/hooks/trim-large-output.sh +9 -0
  79. package/core-assets/hooks/tsc-noemit-precommit.sh +22 -0
  80. package/core-assets/hooks/ubiquitous-language-lint.sh +58 -0
  81. package/core-assets/hooks/viewport-screenshot-gate.sh +48 -0
  82. package/core-assets/modules/.gitkeep +0 -0
  83. package/core-assets/packs/pack-mobile/skills/void-eas-build-profile/.source +7 -0
  84. package/core-assets/packs/pack-mobile/skills/void-eas-build-profile/SKILL.md +164 -0
  85. package/core-assets/packs/pack-mobile/skills/void-eas-build-profile/harness.yaml +14 -0
  86. package/core-assets/packs/pack-mobile/skills/void-expo-config-plugins/.source +7 -0
  87. package/core-assets/packs/pack-mobile/skills/void-expo-config-plugins/SKILL.md +178 -0
  88. package/core-assets/packs/pack-mobile/skills/void-expo-config-plugins/harness.yaml +14 -0
  89. package/core-assets/packs/pack-mobile/skills/void-expo-router-pattern/.source +8 -0
  90. package/core-assets/packs/pack-mobile/skills/void-expo-router-pattern/SKILL.md +209 -0
  91. package/core-assets/packs/pack-mobile/skills/void-expo-router-pattern/harness.yaml +14 -0
  92. package/core-assets/packs/pack-mobile/skills/void-ota-update-strategy/.source +7 -0
  93. package/core-assets/packs/pack-mobile/skills/void-ota-update-strategy/SKILL.md +194 -0
  94. package/core-assets/packs/pack-mobile/skills/void-ota-update-strategy/harness.yaml +14 -0
  95. package/core-assets/packs/pack-monorepo/skills/void-dependency-direction/.source +5 -0
  96. package/core-assets/packs/pack-monorepo/skills/void-dependency-direction/SKILL.md +160 -0
  97. package/core-assets/packs/pack-monorepo/skills/void-dependency-direction/harness.yaml +14 -0
  98. package/core-assets/packs/pack-monorepo/skills/void-package-extraction/.source +5 -0
  99. package/core-assets/packs/pack-monorepo/skills/void-package-extraction/SKILL.md +70 -0
  100. package/core-assets/packs/pack-monorepo/skills/void-package-extraction/harness.yaml +14 -0
  101. package/core-assets/packs/pack-monorepo/skills/void-service-package/.source +5 -0
  102. package/core-assets/packs/pack-monorepo/skills/void-service-package/SKILL.md +122 -0
  103. package/core-assets/packs/pack-monorepo/skills/void-service-package/harness.yaml +14 -0
  104. package/core-assets/packs/pack-monorepo/skills/void-turbo-pipeline-tuning/.source +7 -0
  105. package/core-assets/packs/pack-monorepo/skills/void-turbo-pipeline-tuning/SKILL.md +116 -0
  106. package/core-assets/packs/pack-monorepo/skills/void-turbo-pipeline-tuning/harness.yaml +14 -0
  107. package/core-assets/packs/pack-nextjs/skills/void-cache-component-pattern/.source +5 -0
  108. package/core-assets/packs/pack-nextjs/skills/void-cache-component-pattern/SKILL.md +162 -0
  109. package/core-assets/packs/pack-nextjs/skills/void-cache-component-pattern/harness.yaml +14 -0
  110. package/core-assets/packs/pack-nextjs/skills/void-instrumentation-setup/.source +5 -0
  111. package/core-assets/packs/pack-nextjs/skills/void-instrumentation-setup/SKILL.md +161 -0
  112. package/core-assets/packs/pack-nextjs/skills/void-instrumentation-setup/harness.yaml +14 -0
  113. package/core-assets/packs/pack-nextjs/skills/void-loading-error-boundaries/.source +5 -0
  114. package/core-assets/packs/pack-nextjs/skills/void-loading-error-boundaries/SKILL.md +176 -0
  115. package/core-assets/packs/pack-nextjs/skills/void-loading-error-boundaries/harness.yaml +14 -0
  116. package/core-assets/packs/pack-nextjs/skills/void-parallel-routes-slots/.source +5 -0
  117. package/core-assets/packs/pack-nextjs/skills/void-parallel-routes-slots/SKILL.md +129 -0
  118. package/core-assets/packs/pack-nextjs/skills/void-parallel-routes-slots/harness.yaml +14 -0
  119. package/core-assets/packs/pack-nextjs/skills/void-route-group-decision/.source +5 -0
  120. package/core-assets/packs/pack-nextjs/skills/void-route-group-decision/SKILL.md +107 -0
  121. package/core-assets/packs/pack-nextjs/skills/void-route-group-decision/harness.yaml +14 -0
  122. package/core-assets/packs/pack-pwa/skills/void-install-prompt-ux/.source +5 -0
  123. package/core-assets/packs/pack-pwa/skills/void-install-prompt-ux/SKILL.md +153 -0
  124. package/core-assets/packs/pack-pwa/skills/void-install-prompt-ux/harness.yaml +14 -0
  125. package/core-assets/packs/pack-pwa/skills/void-manifest-checklist/.source +5 -0
  126. package/core-assets/packs/pack-pwa/skills/void-manifest-checklist/SKILL.md +204 -0
  127. package/core-assets/packs/pack-pwa/skills/void-manifest-checklist/harness.yaml +14 -0
  128. package/core-assets/packs/pack-pwa/skills/void-offline-first-mutation/.source +8 -0
  129. package/core-assets/packs/pack-pwa/skills/void-offline-first-mutation/SKILL.md +266 -0
  130. package/core-assets/packs/pack-pwa/skills/void-offline-first-mutation/harness.yaml +14 -0
  131. package/core-assets/packs/pack-pwa/skills/void-service-worker-strategy/.source +5 -0
  132. package/core-assets/packs/pack-pwa/skills/void-service-worker-strategy/SKILL.md +178 -0
  133. package/core-assets/packs/pack-pwa/skills/void-service-worker-strategy/harness.yaml +14 -0
  134. package/core-assets/packs/pack-react/skills/void-accessibility-check/.source +8 -0
  135. package/core-assets/packs/pack-react/skills/void-accessibility-check/SKILL.md +136 -0
  136. package/core-assets/packs/pack-react/skills/void-accessibility-check/harness.yaml +14 -0
  137. package/core-assets/packs/pack-react/skills/void-client-vs-server-component/.source +5 -0
  138. package/core-assets/packs/pack-react/skills/void-client-vs-server-component/SKILL.md +116 -0
  139. package/core-assets/packs/pack-react/skills/void-client-vs-server-component/harness.yaml +14 -0
  140. package/core-assets/packs/pack-react/skills/void-form-pattern/.source +7 -0
  141. package/core-assets/packs/pack-react/skills/void-form-pattern/SKILL.md +157 -0
  142. package/core-assets/packs/pack-react/skills/void-form-pattern/harness.yaml +14 -0
  143. package/core-assets/packs/pack-react/skills/void-state-architecture/.source +5 -0
  144. package/core-assets/packs/pack-react/skills/void-state-architecture/SKILL.md +160 -0
  145. package/core-assets/packs/pack-react/skills/void-state-architecture/harness.yaml +14 -0
  146. package/core-assets/packs/pack-server/skills/void-background-job-pattern/.source +6 -0
  147. package/core-assets/packs/pack-server/skills/void-background-job-pattern/SKILL.md +214 -0
  148. package/core-assets/packs/pack-server/skills/void-background-job-pattern/harness.yaml +14 -0
  149. package/core-assets/packs/pack-server/skills/void-drizzle-migration-safe/.source +6 -0
  150. package/core-assets/packs/pack-server/skills/void-drizzle-migration-safe/SKILL.md +168 -0
  151. package/core-assets/packs/pack-server/skills/void-drizzle-migration-safe/harness.yaml +14 -0
  152. package/core-assets/packs/pack-server/skills/void-env-validation/.source +6 -0
  153. package/core-assets/packs/pack-server/skills/void-env-validation/SKILL.md +131 -0
  154. package/core-assets/packs/pack-server/skills/void-env-validation/harness.yaml +14 -0
  155. package/core-assets/packs/pack-server/skills/void-rate-limit-strategy/.source +6 -0
  156. package/core-assets/packs/pack-server/skills/void-rate-limit-strategy/SKILL.md +149 -0
  157. package/core-assets/packs/pack-server/skills/void-rate-limit-strategy/harness.yaml +14 -0
  158. package/core-assets/packs/pack-server/skills/void-server-action/.source +7 -0
  159. package/core-assets/packs/pack-server/skills/void-server-action/SKILL.md +181 -0
  160. package/core-assets/packs/pack-server/skills/void-server-action/harness.yaml +14 -0
  161. package/core-assets/packs/pack-server/skills/void-testing-server-modules/.source +7 -0
  162. package/core-assets/packs/pack-server/skills/void-testing-server-modules/SKILL.md +73 -0
  163. package/core-assets/packs/pack-server/skills/void-testing-server-modules/harness.yaml +14 -0
  164. package/core-assets/packs/pack-server/skills/void-webhook-handler-pattern/.source +7 -0
  165. package/core-assets/packs/pack-server/skills/void-webhook-handler-pattern/SKILL.md +205 -0
  166. package/core-assets/packs/pack-server/skills/void-webhook-handler-pattern/harness.yaml +14 -0
  167. package/core-assets/policies/core.yaml +95 -0
  168. package/core-assets/policies/ui.yaml +23 -0
  169. package/core-assets/profiles/base.yaml +29 -0
  170. package/core-assets/profiles/expo-config.yaml +36 -0
  171. package/core-assets/profiles/expo.yaml +35 -0
  172. package/core-assets/profiles/monorepo.yaml +33 -0
  173. package/core-assets/profiles/nextjs-config.yaml +31 -0
  174. package/core-assets/profiles/nextjs.yaml +31 -0
  175. package/core-assets/profiles/node-server.yaml +31 -0
  176. package/core-assets/profiles/pwa.yaml +33 -0
  177. package/core-assets/profiles/react.yaml +39 -0
  178. package/core-assets/profiles/sql.yaml +39 -0
  179. package/core-assets/profiles/typescript.yaml +39 -0
  180. package/core-assets/skills/.gitkeep +0 -0
  181. package/core-assets/skills/void-accessibility/.source +15 -0
  182. package/core-assets/skills/void-accessibility/SKILL.md +275 -0
  183. package/core-assets/skills/void-accessibility/harness.yaml +17 -0
  184. package/core-assets/skills/void-api-and-interface-design/.source +13 -0
  185. package/core-assets/skills/void-api-and-interface-design/SKILL.md +231 -0
  186. package/core-assets/skills/void-api-and-interface-design/harness.yaml +16 -0
  187. package/core-assets/skills/void-async-safety/.source +13 -0
  188. package/core-assets/skills/void-async-safety/SKILL.md +287 -0
  189. package/core-assets/skills/void-async-safety/harness.yaml +16 -0
  190. package/core-assets/skills/void-audit/.source +15 -0
  191. package/core-assets/skills/void-audit/SKILL.md +83 -0
  192. package/core-assets/skills/void-audit/harness.yaml +14 -0
  193. package/core-assets/skills/void-autopilot/.source +21 -0
  194. package/core-assets/skills/void-autopilot/SKILL.md +358 -0
  195. package/core-assets/skills/void-autopilot/harness.yaml +14 -0
  196. package/core-assets/skills/void-brainstorm/.source +14 -0
  197. package/core-assets/skills/void-brainstorm/SKILL.md +271 -0
  198. package/core-assets/skills/void-brainstorm/harness.yaml +14 -0
  199. package/core-assets/skills/void-checkpoint/.source +39 -0
  200. package/core-assets/skills/void-checkpoint/SKILL.md +227 -0
  201. package/core-assets/skills/void-checkpoint/harness.yaml +14 -0
  202. package/core-assets/skills/void-claude-md/.source +15 -0
  203. package/core-assets/skills/void-claude-md/SKILL.md +180 -0
  204. package/core-assets/skills/void-claude-md/harness.yaml +14 -0
  205. package/core-assets/skills/void-code-review/.source +14 -0
  206. package/core-assets/skills/void-code-review/SKILL.md +232 -0
  207. package/core-assets/skills/void-code-review/harness.yaml +15 -0
  208. package/core-assets/skills/void-commit-discipline/.source +9 -0
  209. package/core-assets/skills/void-commit-discipline/SKILL.md +211 -0
  210. package/core-assets/skills/void-commit-discipline/harness.yaml +15 -0
  211. package/core-assets/skills/void-context/.source +15 -0
  212. package/core-assets/skills/void-context/SKILL.md +167 -0
  213. package/core-assets/skills/void-context/harness.yaml +14 -0
  214. package/core-assets/skills/void-debug/.source +11 -0
  215. package/core-assets/skills/void-debug/SKILL.md +211 -0
  216. package/core-assets/skills/void-debug/harness.yaml +14 -0
  217. package/core-assets/skills/void-decide/.source +9 -0
  218. package/core-assets/skills/void-decide/SKILL.md +147 -0
  219. package/core-assets/skills/void-decide/harness.yaml +14 -0
  220. package/core-assets/skills/void-devex-audit/.source +8 -0
  221. package/core-assets/skills/void-devex-audit/SKILL.md +113 -0
  222. package/core-assets/skills/void-devex-audit/harness.yaml +15 -0
  223. package/core-assets/skills/void-doctor/.source +15 -0
  224. package/core-assets/skills/void-doctor/SKILL.md +83 -0
  225. package/core-assets/skills/void-doctor/harness.yaml +14 -0
  226. package/core-assets/skills/void-domain-driven-design/.source +13 -0
  227. package/core-assets/skills/void-domain-driven-design/SKILL.md +292 -0
  228. package/core-assets/skills/void-domain-driven-design/harness.yaml +15 -0
  229. package/core-assets/skills/void-frontend-design/.source +19 -0
  230. package/core-assets/skills/void-frontend-design/SKILL.md +274 -0
  231. package/core-assets/skills/void-frontend-design/harness.yaml +17 -0
  232. package/core-assets/skills/void-functional/.source +14 -0
  233. package/core-assets/skills/void-functional/SKILL.md +312 -0
  234. package/core-assets/skills/void-functional/harness.yaml +15 -0
  235. package/core-assets/skills/void-graph/.source +15 -0
  236. package/core-assets/skills/void-graph/SKILL.md +80 -0
  237. package/core-assets/skills/void-graph/harness.yaml +14 -0
  238. package/core-assets/skills/void-hexagonal-architecture/.source +12 -0
  239. package/core-assets/skills/void-hexagonal-architecture/SKILL.md +276 -0
  240. package/core-assets/skills/void-hexagonal-architecture/harness.yaml +15 -0
  241. package/core-assets/skills/void-implement/.source +39 -0
  242. package/core-assets/skills/void-implement/SKILL.md +183 -0
  243. package/core-assets/skills/void-implement/harness.yaml +14 -0
  244. package/core-assets/skills/void-learn/.source +13 -0
  245. package/core-assets/skills/void-learn/SKILL.md +226 -0
  246. package/core-assets/skills/void-learn/harness.yaml +14 -0
  247. package/core-assets/skills/void-llm-cost-discipline/.source +13 -0
  248. package/core-assets/skills/void-llm-cost-discipline/SKILL.md +299 -0
  249. package/core-assets/skills/void-llm-cost-discipline/harness.yaml +15 -0
  250. package/core-assets/skills/void-make-pdf/.source +9 -0
  251. package/core-assets/skills/void-make-pdf/SKILL.md +52 -0
  252. package/core-assets/skills/void-make-pdf/harness.yaml +15 -0
  253. package/core-assets/skills/void-merge/.source +8 -0
  254. package/core-assets/skills/void-merge/SKILL.md +111 -0
  255. package/core-assets/skills/void-merge/harness.yaml +14 -0
  256. package/core-assets/skills/void-migrations/.source +13 -0
  257. package/core-assets/skills/void-migrations/SKILL.md +264 -0
  258. package/core-assets/skills/void-migrations/harness.yaml +17 -0
  259. package/core-assets/skills/void-observability/.source +12 -0
  260. package/core-assets/skills/void-observability/SKILL.md +245 -0
  261. package/core-assets/skills/void-observability/harness.yaml +15 -0
  262. package/core-assets/skills/void-plan/.source +15 -0
  263. package/core-assets/skills/void-plan/SKILL.md +239 -0
  264. package/core-assets/skills/void-plan/harness.yaml +14 -0
  265. package/core-assets/skills/void-plan-review/.source +12 -0
  266. package/core-assets/skills/void-plan-review/SKILL.md +128 -0
  267. package/core-assets/skills/void-plan-review/harness.yaml +15 -0
  268. package/core-assets/skills/void-qa/.source +15 -0
  269. package/core-assets/skills/void-qa/SKILL.md +103 -0
  270. package/core-assets/skills/void-qa/harness.yaml +15 -0
  271. package/core-assets/skills/void-refactor/.source +9 -0
  272. package/core-assets/skills/void-refactor/SKILL.md +220 -0
  273. package/core-assets/skills/void-refactor/harness.yaml +15 -0
  274. package/core-assets/skills/void-retrospective/.source +9 -0
  275. package/core-assets/skills/void-retrospective/SKILL.md +71 -0
  276. package/core-assets/skills/void-retrospective/harness.yaml +15 -0
  277. package/core-assets/skills/void-security-audit/.source +12 -0
  278. package/core-assets/skills/void-security-audit/SKILL.md +138 -0
  279. package/core-assets/skills/void-security-audit/harness.yaml +15 -0
  280. package/core-assets/skills/void-security-guidance/.source +12 -0
  281. package/core-assets/skills/void-security-guidance/SKILL.md +255 -0
  282. package/core-assets/skills/void-security-guidance/harness.yaml +15 -0
  283. package/core-assets/skills/void-source-driven-development/.source +12 -0
  284. package/core-assets/skills/void-source-driven-development/SKILL.md +158 -0
  285. package/core-assets/skills/void-source-driven-development/harness.yaml +15 -0
  286. package/core-assets/skills/void-tdd/.source +15 -0
  287. package/core-assets/skills/void-tdd/SKILL.md +394 -0
  288. package/core-assets/skills/void-tdd/harness.yaml +15 -0
  289. package/core-assets/skills/void-testing/.source +19 -0
  290. package/core-assets/skills/void-testing/SKILL.md +301 -0
  291. package/core-assets/skills/void-testing/harness.yaml +17 -0
  292. package/core-assets/skills/void-ticket/.source +18 -0
  293. package/core-assets/skills/void-ticket/SKILL.md +239 -0
  294. package/core-assets/skills/void-ticket/harness.yaml +14 -0
  295. package/core-assets/skills/void-typescript-strict/.source +10 -0
  296. package/core-assets/skills/void-typescript-strict/SKILL.md +294 -0
  297. package/core-assets/skills/void-typescript-strict/harness.yaml +17 -0
  298. package/core-assets/skills/void-ui-review/.source +12 -0
  299. package/core-assets/skills/void-ui-review/SKILL.md +97 -0
  300. package/core-assets/skills/void-ui-review/harness.yaml +15 -0
  301. package/core-assets/skills/void-verify/.source +12 -0
  302. package/core-assets/skills/void-verify/SKILL.md +184 -0
  303. package/core-assets/skills/void-verify/harness.yaml +15 -0
  304. package/core-assets/specialists/accessibility-specialist.source +11 -0
  305. package/core-assets/specialists/accessibility-specialist.yaml +30 -0
  306. package/core-assets/specialists/api-integration-engineer.source +11 -0
  307. package/core-assets/specialists/api-integration-engineer.yaml +30 -0
  308. package/core-assets/specialists/data-migration-engineer.source +11 -0
  309. package/core-assets/specialists/data-migration-engineer.yaml +30 -0
  310. package/core-assets/specialists/devex-docs-engineer.source +11 -0
  311. package/core-assets/specialists/devex-docs-engineer.yaml +29 -0
  312. package/core-assets/specialists/domain-architect.source +11 -0
  313. package/core-assets/specialists/domain-architect.yaml +28 -0
  314. package/core-assets/specialists/experience-designer.source +15 -0
  315. package/core-assets/specialists/experience-designer.yaml +38 -0
  316. package/core-assets/specialists/frontend-engineer.source +11 -0
  317. package/core-assets/specialists/frontend-engineer.yaml +32 -0
  318. package/core-assets/specialists/independent-code-reviewer.source +10 -0
  319. package/core-assets/specialists/independent-code-reviewer.yaml +37 -0
  320. package/core-assets/specialists/migrations.json +15 -0
  321. package/core-assets/specialists/observability-sre-engineer.source +11 -0
  322. package/core-assets/specialists/observability-sre-engineer.yaml +30 -0
  323. package/core-assets/specialists/pdf-specialist.source +11 -0
  324. package/core-assets/specialists/pdf-specialist.yaml +29 -0
  325. package/core-assets/specialists/performance-engineer.source +11 -0
  326. package/core-assets/specialists/performance-engineer.yaml +29 -0
  327. package/core-assets/specialists/product-challenger.source +10 -0
  328. package/core-assets/specialists/product-challenger.yaml +27 -0
  329. package/core-assets/specialists/security-engineer.source +13 -0
  330. package/core-assets/specialists/security-engineer.yaml +41 -0
  331. package/core-assets/specialists/solution-architect.source +13 -0
  332. package/core-assets/specialists/solution-architect.yaml +32 -0
  333. package/core-assets/specialists/test-qa-engineer.source +14 -0
  334. package/core-assets/specialists/test-qa-engineer.yaml +35 -0
  335. package/core-assets/specialists/visual-craft-director.source +17 -0
  336. package/core-assets/specialists/visual-craft-director.yaml +60 -0
  337. package/core-assets/templates/github/dependency-audit.mjs +54 -0
  338. package/core-assets/templates/github/void-dependency-audit.yml +35 -0
  339. package/core-assets/templates/github/void-security.yml +85 -0
  340. package/dist/main.js +57001 -0
  341. package/package.json +66 -4
@@ -0,0 +1,149 @@
1
+ ---
2
+ name: void-rate-limit-strategy
3
+ description: Choose rate limit window, max, and key strategy per action class. Per-user for authed, per-IP for public, escalation for auth-adjacent. Default values + when to deviate.
4
+ ---
5
+
6
+ # rate-limit-strategy
7
+
8
+ Use when applying a rate limit to a Server Action, route handler, or webhook. Rate limits are mandatory at every trust boundary (per `void-security-guidance`); this skill says HOW to choose the right window/max/key per use case.
9
+
10
+ If you're tempted to skip rate limit "because it's internal" — wrong. The trust boundary is the URL. Anything reachable from a browser is rate-limited.
11
+
12
+ ## The 3 parameters
13
+
14
+ ```ts
15
+ { window: '1 min', max: 10, key: 'user:${user.id}:contact-form' }
16
+ ```
17
+
18
+ - `window` — time window (1 min, 1 hour, 24 hours)
19
+ - `max` — number of requests allowed in the window
20
+ - `key` — what gets counted (per user? per IP? per action?)
21
+
22
+ ## Default presets
23
+
24
+ Per action class, here are the void-machine defaults. Deviate with explicit justification in a code comment.
25
+
26
+ | Action class | Window / Max | Key | Why |
27
+ |---|---|---|---|
28
+ | Standard read (data fetch, list) | 1 min / 100 | `user:${id}` | Generous; reads are cheap |
29
+ | Standard write (create, update) | 1 min / 30 | `user:${id}` | Conservative; writes are expensive |
30
+ | Search / filter | 1 min / 60 | `user:${id}` OR `ip:${ip}` | Mid |
31
+ | Auth: login | 5 min / 5 | `ip:${ip}` + `email:${email}` (BOTH) | Credential stuffing |
32
+ | Auth: password reset | 1 hour / 3 | `ip:${ip}` + `email:${email}` | Account enumeration |
33
+ | Auth: 2FA verify | 5 min / 5 | `user:${id}` | Brute force |
34
+ | Auth: 2FA resend | 5 min / 1 | `user:${id}` | SMS cost |
35
+ | LLM call | 1 hour / 50 | `user:${id}` | Cost control |
36
+ | File upload | 1 hour / 20 | `user:${id}` | Bandwidth + disk |
37
+ | Webhook receiver | 1 min / 1000 | `source:${source}` | Permissive; senders should self-throttle |
38
+ | Public form (contact, signup) | 5 min / 3 | `ip:${ip}` | Anti-spam |
39
+
40
+ These are **starting points**. If your traffic patterns show 1 min / 30 is too tight for a specific write that users do legitimately 50 times/min (e.g., batch import), document the deviation and raise.
41
+
42
+ ## Key strategy: `user:` vs `ip:`
43
+
44
+ - **Per-user (`user:${id}`)** — for authenticated actions. User is the right scope; one user shouldn't tank another user's quota by sharing an IP (office NAT, mobile carrier CGN).
45
+ - **Per-IP (`ip:${ip}`)** — for unauthenticated actions where user identity doesn't exist yet (login, public form, signup).
46
+ - **Both (`user:${id}` AND `ip:${ip}`)** — for auth-adjacent flows (login, password reset, 2FA). One attacker can rotate emails on one IP; one IP can host one stolen credential. Block on either limit.
47
+
48
+ When using BOTH, configure the rate limiter to use `Math.max` semantics: the more restrictive limit wins.
49
+
50
+ ## Sliding window vs token bucket vs fixed window
51
+
52
+ Pick one strategy per app, stick with it. The differences in practice:
53
+
54
+ - **Fixed window**: simple, off-by-one at boundary (user makes 30 in second 59, then 30 more in second 1 of next window = 60 in 2s). Use for non-security limits.
55
+ - **Sliding window**: smoother, no boundary spike. Use for cost-sensitive limits (LLM, uploads).
56
+ - **Token bucket**: allows burst then refill. Use when "burst is OK but sustained is not" (search-as-you-type, real-time API).
57
+
58
+ The void-machine default is **sliding window** via Upstash Redis or Vercel KV (`@upstash/ratelimit`). Token bucket only when burst is the intended UX.
59
+
60
+ ## Implementation (Upstash example, no wrapper)
61
+
62
+ ```ts
63
+ // apps/web/src/adapters/ratelimit.ts
64
+ import { Ratelimit } from '@upstash/ratelimit';
65
+ import { Redis } from '@upstash/redis';
66
+ import { env } from '@repo/core';
67
+
68
+ const redis = Redis.fromEnv();
69
+
70
+ export const ratelimit = {
71
+ perUser: new Ratelimit({
72
+ redis,
73
+ limiter: Ratelimit.slidingWindow(30, '1 m'),
74
+ prefix: 'rl:user',
75
+ }),
76
+ perIp: new Ratelimit({
77
+ redis,
78
+ limiter: Ratelimit.slidingWindow(5, '5 m'),
79
+ prefix: 'rl:ip',
80
+ }),
81
+ auth: new Ratelimit({
82
+ redis,
83
+ limiter: Ratelimit.slidingWindow(5, '5 m'),
84
+ prefix: 'rl:auth',
85
+ }),
86
+ };
87
+ ```
88
+
89
+ Use in a Server Action:
90
+
91
+ ```ts
92
+ // inside an action handler, after auth resolves session
93
+ const { success } = await ratelimit.perUser.limit(`${session.userId}:note.create`);
94
+ if (!success) return { ok: false as const, error: 'rate-limited' };
95
+ ```
96
+
97
+ For per-IP or composite keys (login: both IP and email):
98
+
99
+ ```ts
100
+ const ip = headers().get('x-forwarded-for')?.split(',')[0] ?? 'unknown';
101
+ const { success: ipOk } = await ratelimit.auth.limit(`ip:${ip}:login`);
102
+ const { success: emailOk } = await ratelimit.auth.limit(`email:${input.email}:login`);
103
+ if (!ipOk || !emailOk) return { ok: false as const, error: 'rate-limited' };
104
+ ```
105
+
106
+ Webhook handlers rate-limit per-source:
107
+
108
+ ```ts
109
+ const { success } = await ratelimit.perUser.limit(`webhook:stripe`);
110
+ if (!success) return NextResponse.json({ error: 'rate-limited' }, { status: 429 });
111
+ ```
112
+
113
+ If you DRY this into a `defineAction` helper (recommended once the pattern repeats), the helper accepts a `rateLimit` option and applies the same primitive under the hood.
114
+
115
+ ## Escalation: progressive lockout
116
+
117
+ For high-stakes auth flows, ramp the cost of repeated failures:
118
+
119
+ ```ts
120
+ {
121
+ window: '5 min',
122
+ max: 5,
123
+ // After 5 failures, escalate: 1 hour cooldown
124
+ escalate: { afterFails: 5, lockoutMin: 60 },
125
+ }
126
+ ```
127
+
128
+ Not all limiters support this natively; if your stack doesn't, implement at the service layer: count failures in a separate counter, when threshold crossed, return 403 with a lockout response.
129
+
130
+ ## Anti-patterns
131
+
132
+ - ✗ **No rate limit on Server Actions because "we'll add it later"** — every action ships with one or doesn't ship
133
+ - ✗ **Same limit for reads and writes** — wastes capacity OR makes writes too easy to abuse
134
+ - ✗ **IP-only limit on authed actions** — office NAT or carrier CGN punishes legit users; use user key
135
+ - ✗ **No rate limit on webhook receivers** — a buggy sender can flood you
136
+ - ✗ **Rate limit at the database query level** — too late; the request already consumed compute. Rate limit at the boundary.
137
+ - ✗ **Identical message for "rate limited" and "denied"** — leaks "your credentials are valid, just slow down" (info disclosure). For auth flows, return a generic 429.
138
+
139
+ ## Monitoring
140
+
141
+ Surface 429 responses in your dashboard. Sudden spikes = either an attack OR a UX bug (unintended retries from the client). Both need attention.
142
+
143
+ ## Composition (informational)
144
+
145
+ - `void-security-guidance` — rate limit is a security control; Zod is the schema control; both at every boundary.
146
+ - `void-async-safety` — webhook + background-job retry semantics interact with rate limits.
147
+ - `void-server-action` — actions apply rate limit before service call (layer 3 of 5).
148
+ - `void-webhook-handler-pattern` — webhook rate limits use a per-source key.
149
+ - `void-llm-cost-discipline` — LLM call rate limits are cost-control, more conservative than CPU-control limits.
@@ -0,0 +1,14 @@
1
+ # Harness metadata for this skill. Not part of the Agent Skills
2
+ # specification, and never copied into a consumer project: the SKILL.md
3
+ # beside it stays portable and validates against the official six fields.
4
+ # Read by this repository's graph, and by the installer for `runtimes`.
5
+ kind: standard
6
+ owner: folpe
7
+ runtimes: [claude, codex]
8
+ enforcement:
9
+ floor: ci
10
+ inline:
11
+ claude: active
12
+ codex: active
13
+ hermes: ci-only
14
+ eval_targets: [claude/anthropic/opus]
@@ -0,0 +1,7 @@
1
+ Sources for `void-server-action` skill (see `docs/plans/skill-audits/void-server-action.md` for the full audit):
2
+
3
+ - Next.js 16 docs — `'use server'` and defineAction semantics — distilled, not copied.
4
+ - Vercel security guidance — trust-boundary obligations for Server Actions.
5
+ - Solaar's webhook safety implementation — real-world source for withWebhookSafety / defineAction / defineFormAction patterns.
6
+
7
+ Strategy: native. Distilled from the three sources above and adapted to the void-machine convention where services own domain logic and actions are pure trust-boundary wrappers.
@@ -0,0 +1,181 @@
1
+ ---
2
+ name: void-server-action
3
+ description: "Create a Next.js 16 Server Action with the void trust-boundary checklist: Zod ingress, auth, rate limit, observability, structured errors. Composes with security-guidance, async-safety."
4
+ ---
5
+
6
+ # server-action
7
+
8
+ Use when adding any `'use server'` function (in Next.js, Hono, or any Server Action-capable runtime) following the void-machine `pack-server` conventions. Server Actions cross a trust boundary — the input came from a browser. Treat them like HTTP handlers, not like internal function calls.
9
+
10
+ If the function is **not** marked `'use server'` (it's a normal service function in `src/services/`), use `void-tdd` directly and skip this skill.
11
+
12
+ ## When this skill triggers
13
+
14
+ - "Add a Server Action for X"
15
+ - "Create the action that handles the contact form"
16
+ - "Wire this button to a mutation"
17
+ - Any new file or function exporting `'use server'`
18
+
19
+ ## Location (mandatory)
20
+
21
+ ```
22
+ apps/<app>/src/
23
+ ├── actions/<feature>/<verb>.ts # preferred: typed Server Actions
24
+ └── app/<route>/_actions.ts # only if tightly coupled to one route
25
+ ```
26
+
27
+ Server Actions **never** live inside `packages/`. Packages own services (pure-by-default); apps own actions (the trust boundary).
28
+
29
+ ## The five non-negotiable layers (in order)
30
+
31
+ Every Server Action goes through these layers, top to bottom, **always**:
32
+
33
+ ```
34
+ 1. Auth — verify session; reject unauthenticated requests
35
+ 2. Zod ingress — schema validates the input object (no untyped formData)
36
+ 3. Rate limit — per-user or per-IP (see rate-limit-strategy)
37
+ 4. Observability — trace ID, Sentry user scope (anonymized via hash)
38
+ 5. Service call — pure domain logic in src/services/<feature>/
39
+ ```
40
+
41
+ Skipping any of these is a security or operability bug. There are no "internal" Server Actions — anything `'use server'` is reachable from the public internet via a forged request.
42
+
43
+ ## Canonical skeleton (vanilla — no wrapper assumed)
44
+
45
+ ```ts
46
+ // apps/web/src/actions/billing/cancel-subscription.ts
47
+ 'use server';
48
+
49
+ import { z } from 'zod';
50
+ import { cookies } from 'next/headers';
51
+ import { logger, env } from '@repo/core';
52
+ import * as Sentry from '@sentry/nextjs';
53
+ import { ratelimit } from '@/adapters/ratelimit';
54
+ import { getSession } from '@/services/auth';
55
+ import { cancelSubscription as cancelSubscriptionService } from '@/services/billing/cancel';
56
+
57
+ const Input = z.object({
58
+ subscriptionId: z.string().uuid(),
59
+ reason: z.string().min(1).max(500).optional(),
60
+ });
61
+
62
+ export async function cancelSubscription(raw: unknown) {
63
+ // 1. Auth
64
+ const session = await getSession(cookies());
65
+ if (!session) return { ok: false as const, error: 'unauthenticated' };
66
+
67
+ // 2. Zod ingress
68
+ const parsed = Input.safeParse(raw);
69
+ if (!parsed.success) return { ok: false as const, error: 'invalid-input' };
70
+ const input = parsed.data;
71
+
72
+ // 3. Rate limit (per-user)
73
+ const rl = await ratelimit.check(`user:${session.userId}:billing.cancel`, { window: '1 min', max: 5 });
74
+ if (!rl.ok) return { ok: false as const, error: 'rate-limited' };
75
+
76
+ // 4. Observability — trace context + Sentry scope (hashed user)
77
+ Sentry.setUser({ id: hashUserId(session.userId) });
78
+ const traceId = crypto.randomUUID();
79
+ logger.info({ traceId, userId: session.userId, action: 'billing.cancelSubscription' }, 'start');
80
+
81
+ // 5. Service call — pure
82
+ const result = await cancelSubscriptionService({
83
+ subscriptionId: input.subscriptionId,
84
+ userId: session.userId,
85
+ reason: input.reason,
86
+ });
87
+
88
+ if (!result.ok) {
89
+ logger.warn({ traceId, error: result.error }, 'cancelSubscription failed');
90
+ return { ok: false as const, error: result.error.code };
91
+ }
92
+ return { ok: true as const, data: result.value };
93
+ }
94
+ ```
95
+
96
+ 40 lines. The 5 layers are explicit and a reviewer can audit at a glance.
97
+
98
+ ## Optional: `defineAction` helper
99
+
100
+ If your project repeats the 5 layers in every action (it will), DRY them into a `defineAction` helper. This is a project-side convention many void-machine monorepos add in `@repo/auth` or `@repo/server`:
101
+
102
+ ```ts
103
+ // Equivalent action using a project-side defineAction helper
104
+ export const cancelSubscription = defineAction({
105
+ name: 'billing.cancelSubscription',
106
+ auth: 'required',
107
+ input: Input,
108
+ rateLimit: { window: '1 min', max: 5 },
109
+ handler: async ({ input, user, traceId }) => {
110
+ /* just the service call + result mapping */
111
+ },
112
+ });
113
+ ```
114
+
115
+ The helper is convenience — the 5 layers below it are the substance. Build it once when the pattern repeats 3+ times; not before.
116
+
117
+ ## Return type discipline
118
+
119
+ Server Actions return a **discriminated union**, never throw to the client:
120
+
121
+ ```ts
122
+ type ActionResult<T> =
123
+ | { ok: true; data: T }
124
+ | { ok: false; error: string }; // error is a stable, human-readable code
125
+ ```
126
+
127
+ - ✗ Don't return raw domain objects — they leak schema. Pick a DTO.
128
+ - ✗ Don't `throw new Error('...')` — Next swallows the message and the client sees a 500 with no actionable info. Use the Result type.
129
+ - ✗ Don't return Date or BigInt — they don't serialize across the action boundary. Convert in the handler.
130
+
131
+ ## Forbidden
132
+
133
+ - `db.query(...)` directly in the action — call a service. The service calls a repository.
134
+ - `process.env.STRIPE_KEY` — use `@repo/core/env`.
135
+ - Inline `fetch('https://external/...')` — go through an adapter behind a port.
136
+ - `revalidatePath('/')` without scope — pass the specific path you mutated; broad revalidation kills cache hit rate.
137
+ - `redirect('...')` from inside a `try/catch` — Next.js `redirect()` throws on purpose; catching it breaks navigation.
138
+
139
+ ## Forms vs. typed actions
140
+
141
+ Two flavors, pick by use case:
142
+
143
+ | Use | Action signature | Input source |
144
+ |---|---|---|
145
+ | Submit-on-click button / typed payload | `async function(input: T)` | Object (Zod object schema) |
146
+ | HTML form with `<form action={action}>` | `async function(formData: FormData)` | FormData (Zod parses entries; `getAll` for repeated fields) |
147
+
148
+ For the FormData variant, always parse via Zod — never reach into FormData manually with raw `.get()` casts. But `Object.fromEntries(formData)` is **not** a safe default: it keeps only the **last** value of a repeated field, so a multi-select, a checkbox group, or `<input multiple>` is silently truncated to one entry. Read any field that can repeat with `getAll` and validate it as an array:
149
+
150
+ ```ts
151
+ const schema = z.object({
152
+ title: z.string().min(1),
153
+ tagIds: z.array(z.string()).default([]), // repeated field
154
+ });
155
+ // Single-value fields via .get(); repeated fields via .getAll().
156
+ const input = schema.parse({
157
+ title: formData.get('title'),
158
+ tagIds: formData.getAll('tagId'),
159
+ });
160
+ ```
161
+
162
+ `Object.fromEntries(formData)` is fine only when every field is known-single-valued — and that assumption breaks the day someone adds a multi-select. Prefer the explicit shape above for any form with a repeatable input.
163
+
164
+ ## Workflow
165
+
166
+ 1. **Define the service first**, in `src/services/<feature>/<verb>.ts`. Pure-by-default; deps injected; tested in strict TDD mode.
167
+ 2. **Write the Zod input schema** in the action file. Aim for the smallest possible surface; reject unknown keys.
168
+ 3. **Pick the action shape**: object input (typed payload) or FormData input (HTML form). Parse FormData via Zod; use `getAll` + `z.array` for any repeatable field (never `Object.fromEntries`, which drops all but the last value).
169
+ 4. **Decide auth posture**: logged-in required, optional, or public (`public` requires explicit justification in a comment).
170
+ 5. **Set the rate limit**. Default per-user 30/min for mutations, 100/min for reads. Stricter on auth-adjacent actions (see `void-rate-limit-strategy`).
171
+ 6. **Wire trace + Sentry scope** explicitly in the handler (until you extract a `defineAction` helper).
172
+ 7. **Write the action test** in `<verb>.test.ts` next to the action — assert auth, validation, rate limit, and happy path. Service tests already cover the domain.
173
+
174
+ ## Composition (informational)
175
+
176
+ - `void-security-guidance` — Zod at every ingress; sensitive data redacted from logs; no PII in error messages returned to client.
177
+ - `void-webhook-handler-pattern` — webhooks share the 5-layer pattern; same Zod discipline, different transport.
178
+ - `void-rate-limit-strategy` — preset windows/max per action class.
179
+ - `void-observability` — trace ID + Sentry user scope (hashed); same pattern across actions, webhooks, jobs.
180
+ - `void-tdd` — souple mode on the action (boundary), strict on the underlying service.
181
+ - `void-service-package` — when the service grows enough to deserve its own package, extract it (rare, but the path is there).
@@ -0,0 +1,14 @@
1
+ # Harness metadata for this skill. Not part of the Agent Skills
2
+ # specification, and never copied into a consumer project: the SKILL.md
3
+ # beside it stays portable and validates against the official six fields.
4
+ # Read by this repository's graph, and by the installer for `runtimes`.
5
+ kind: standard
6
+ owner: folpe
7
+ runtimes: [claude, codex]
8
+ enforcement:
9
+ floor: ci
10
+ inline:
11
+ claude: active
12
+ codex: active
13
+ hermes: ci-only
14
+ eval_targets: [claude/anthropic/opus]
@@ -0,0 +1,7 @@
1
+ Sources for `void-testing-server-modules` skill (see `docs/plans/skill-audits/void-testing-server-modules.md` for the full audit):
2
+
3
+ - Next.js docs — `server-only` / `client-only` packages and their import-time throw semantics (poisoning the wrong bundle). Distilled, not copied.
4
+ - Vitest docs — `test.alias` / `resolve.alias` resolution for replacing a module at test time. Version-matched to the installed Vitest.
5
+ - Real-world friction from a consumer project (issue #17 cluster B / B3): a server-only import chain crashed the Vitest run before any assertion.
6
+
7
+ Strategy: native. The "alias to an empty stub, keep the boundary real" framing is the void-machine adaptation — it deliberately refuses to let a test-time convenience erode the build-time server/client boundary.
@@ -0,0 +1,73 @@
1
+ ---
2
+ name: void-testing-server-modules
3
+ description: Unit-test modules guarded by server-only / client-only under Vitest by aliasing those packages to an empty stub. Test-time only; never a substitute for the real build-time boundary.
4
+ ---
5
+
6
+ # testing-server-modules
7
+
8
+ `server-only` and `client-only` are import-time tripwires: they exist to **throw** the moment a server module is pulled into a client bundle (or vice-versa). That is exactly what you want at build time — and exactly what breaks Vitest, which runs neither in an RSC server graph nor in a browser. Importing any module whose chain reaches `server-only` crashes the test run with a cryptic `"This module cannot be imported from a Client Component module"` before a single assertion runs.
9
+
10
+ **Attribution**: see `.source`.
11
+
12
+ ---
13
+
14
+ ## The fix — alias the tripwire to an empty stub in the Vitest config
15
+
16
+ The tripwire's only job is to throw outside its runtime. Tests are outside its runtime by design, so the correct test-time substitute is an **empty module** — not a mock, not a partial.
17
+
18
+ ```ts
19
+ // vitest.base.ts (shared config in the monorepo — extend it per package)
20
+ import { defineConfig } from 'vitest/config';
21
+
22
+ export default defineConfig({
23
+ test: {
24
+ alias: {
25
+ 'server-only': new URL('./test/stubs/empty.ts', import.meta.url).pathname,
26
+ 'client-only': new URL('./test/stubs/empty.ts', import.meta.url).pathname,
27
+ },
28
+ },
29
+ });
30
+ ```
31
+
32
+ ```ts
33
+ // test/stubs/empty.ts
34
+ export {}; // server-only / client-only export nothing; their side effect is the throw.
35
+ ```
36
+
37
+ A single shared stub serves both. In a monorepo, put the alias in the `vitest.base` config every package extends, so no package re-discovers the gotcha (composes with `void-turbo-pipeline-tuning` and the shared `@repo/config`).
38
+
39
+ ---
40
+
41
+ ## What the alias does and does NOT buy you
42
+
43
+ - **Does**: lets you unit-test the *pure logic* inside a server module (the service, the mapper, the validation) without standing up an RSC runtime.
44
+ - **Does NOT**: make the module safe to import from a Client Component. The real server/client boundary still holds at build time — the alias is **test-only**. If a client component genuinely imports a server module, that is a real boundary violation the build will (correctly) reject; do not "fix" it by widening the alias. Keep the pure, testable logic in a runtime-agnostic `services/` module and let the thin server wrapper carry the `server-only` import (composes with `void-env-validation`, which keeps server-only env access out of the edge/client chain).
45
+
46
+ ---
47
+
48
+ ## When this applies
49
+
50
+ - A Vitest run fails on import with a `server-only` / `client-only` error before any test body executes.
51
+ - You are setting up the shared test config for a Next.js / RSC monorepo and want every package to inherit the alias once.
52
+
53
+ ## When it does NOT
54
+
55
+ - Pure modules with no `server-only` import need no alias — prefer keeping domain logic runtime-agnostic so the question never arises.
56
+ - Integration/e2e runners that DO execute in the real runtime (Playwright, the Next.js test runtime) must NOT stub these — there the tripwire is meaningful.
57
+
58
+ ---
59
+
60
+ ## Anti-rules
61
+
62
+ - MUST NOT mock `server-only` with anything but an empty module — it has no API to mock, only a side effect to neutralize.
63
+ - MUST NOT use the alias to import a server module from client code in production — the alias is test-only; the boundary is real.
64
+ - MUST NOT scatter the alias per-test-file — define it once in the shared Vitest config.
65
+
66
+ ---
67
+
68
+ ## Final rule
69
+
70
+ ```
71
+ server-only/client-only break Vitest → alias to an empty stub in the shared config, test the pure logic.
72
+ The build-time boundary stays real → never let the alias paper over a true client/server violation.
73
+ ```
@@ -0,0 +1,14 @@
1
+ # Harness metadata for this skill. Not part of the Agent Skills
2
+ # specification, and never copied into a consumer project: the SKILL.md
3
+ # beside it stays portable and validates against the official six fields.
4
+ # Read by this repository's graph, and by the installer for `runtimes`.
5
+ kind: standard
6
+ owner: folpe
7
+ runtimes: [claude, codex]
8
+ enforcement:
9
+ floor: ci
10
+ inline:
11
+ claude: active
12
+ codex: active
13
+ hermes: ci-only
14
+ eval_targets: [claude/anthropic/opus]
@@ -0,0 +1,7 @@
1
+ Sources for `void-webhook-handler-pattern` skill (see `docs/plans/skill-audits/void-webhook-handler-pattern.md` for the full audit):
2
+
3
+ - No external source audited — native distillation of canonical per-source webhook patterns.
4
+ - Per-source patterns referenced (not vendored): Stripe, Resend, GitHub signature/idempotency/retry semantics.
5
+ - Doctrine referenced: `void-async-safety` (stack-agnostic retry/idempotency/dead-letter).
6
+
7
+ Strategy: distill. Per-source handler patterns distilled into the 5 non-negotiable layers; no upstream skill was copied.