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,162 @@
1
+ ---
2
+ name: void-cache-component-pattern
3
+ description: Use Next.js 16 Cache Components correctly — when to opt in ('use cache'), when to opt out ('use no cache'), cache key strategy, scoping by user/org. Default is cached; uncache deliberately.
4
+ ---
5
+
6
+ # cache-component-pattern
7
+
8
+ Use when writing or modifying any Next.js 16 Server Component, route handler, or fetch in `app/`. Cache Components is Next 16's default-cache model — flipping the previous default-dynamic stance. Getting this right is the difference between a page rendered in 30ms (cached) and 800ms (regenerated every request).
9
+
10
+ ## The default
11
+
12
+ Next 16 caches by default at the Server Component / fetch level. You opt out, not in. This is the inverse of Next 13/14.
13
+
14
+ ```tsx
15
+ // app/blog/[slug]/page.tsx — cached by default
16
+ export default async function Page({ params }: { params: { slug: string } }) {
17
+ const post = await db.query.posts.findFirst({ where: eq(posts.slug, params.slug) });
18
+ return <Article post={post} />;
19
+ }
20
+ ```
21
+
22
+ This page IS cached. The `params.slug` is the key. New slugs trigger a fresh render; existing slugs serve from cache.
23
+
24
+ ## When to opt OUT — `'use no cache'`
25
+
26
+ Some content cannot be cached. Tag the component or fetch:
27
+
28
+ ```tsx
29
+ // app/dashboard/page.tsx — user-specific
30
+ 'use no cache';
31
+
32
+ export default async function Page() {
33
+ const user = await getCurrentUser(); // session-dependent
34
+ return <Dashboard user={user} />;
35
+ }
36
+ ```
37
+
38
+ Use `'use no cache'` when the response depends on:
39
+
40
+ - Current user identity (`getCurrentUser`, `cookies()`, `headers()`)
41
+ - Live data with sub-minute staleness requirements (real-time dashboards, inbox)
42
+ - Random sampling, A/B tests at render time
43
+ - `Date.now()` or similar non-deterministic inputs you don't want to key
44
+
45
+ The rule: if the same URL could legitimately render two different responses to two different users, opt out.
46
+
47
+ ## Per-fetch opt-out
48
+
49
+ Inside a component that's MOSTLY cacheable but has one dynamic call:
50
+
51
+ ```tsx
52
+ export default async function Page() {
53
+ // Cached
54
+ const post = await db.query.posts.findFirst({ where: eq(posts.slug, slug) });
55
+
56
+ // Not cached — re-fetched every request
57
+ const liveViewerCount = await fetch('https://api/views', { cache: 'no-store' });
58
+
59
+ return <Article post={post} viewers={liveViewerCount} />;
60
+ }
61
+ ```
62
+
63
+ `{ cache: 'no-store' }` opts out one fetch. The page stays cached for the parts that can be.
64
+
65
+ ## Cache key strategy
66
+
67
+ The key for a cached component is **automatically derived** from:
68
+
69
+ - Route params (`[slug]`, `[id]`)
70
+ - Search params used in the component (only those READ; uses are tracked)
71
+ - Cookies / headers used (tracked similarly — but reading these usually opts you out automatically)
72
+
73
+ You influence the key by what you read. To cache one variant per locale:
74
+
75
+ ```tsx
76
+ // app/[locale]/page.tsx
77
+ export default async function Page({ params }: { params: { locale: string } }) {
78
+ return <Home locale={params.locale} />;
79
+ }
80
+ ```
81
+
82
+ `/en` and `/fr` are separate cache entries because `locale` is in the URL.
83
+
84
+ To cache one variant per org WITHOUT putting org in the URL: don't. Put it in the URL. Caching cross-cuts user scopes is a security accident waiting to happen.
85
+
86
+ ## The "shared cache across users" trap
87
+
88
+ ```tsx
89
+ // ✗ DANGEROUS — caches user-specific data under a route-only key
90
+ export default async function Page() {
91
+ const user = await getCurrentUser();
92
+ const posts = await db.query.posts.findMany({ where: eq(posts.authorId, user.id) });
93
+ return <PostList posts={posts} />;
94
+ }
95
+ ```
96
+
97
+ If Next caches this without realizing `user.id` is in play, user A could see user B's posts. The `getCurrentUser` call reads cookies, which marks the page dynamic — but only if Next is configured correctly. **Always add `'use no cache'` when the response depends on the user, even if Next "would have" detected it.** Belt and braces; the cost of being explicit is zero, the cost of a leak is unbounded.
98
+
99
+ ## `revalidate` for time-based freshness
100
+
101
+ Cached but with a maximum age:
102
+
103
+ ```tsx
104
+ export const revalidate = 60; // seconds
105
+
106
+ export default async function Page() { ... }
107
+ ```
108
+
109
+ Use cases: news headlines, leaderboards, dashboards updated every minute. The cache serves stale content for up to 60s, then re-renders on the next request.
110
+
111
+ For tag-based revalidation (invalidate specific entries after a mutation):
112
+
113
+ ```tsx
114
+ import { revalidateTag } from 'next/cache';
115
+
116
+ export async function publishPost() {
117
+ await db.insert(posts).values(...);
118
+ revalidateTag('posts-list');
119
+ }
120
+ ```
121
+
122
+ In the cached component: `fetch(url, { next: { tags: ['posts-list'] } })`. The tag links them.
123
+
124
+ ## `revalidatePath` vs `revalidateTag`
125
+
126
+ | Function | Use when | Scope |
127
+ |---|---|---|
128
+ | `revalidatePath('/blog/[slug]', 'page')` | One specific page invalidated after a mutation | Single path |
129
+ | `revalidatePath('/blog', 'layout')` | A whole subtree invalidated (rare) | Layout + all children |
130
+ | `revalidateTag('posts-list')` | Multiple pages share the same data | Every fetch with that tag |
131
+
132
+ Default to `revalidateTag`. Path-based revalidation is fragile (parameterized paths are tricky).
133
+
134
+ ## Anti-patterns
135
+
136
+ - ✗ **`'use no cache'` at the layout level** — blanket-opts-out the entire subtree. Use it on specific routes.
137
+ - ✗ **Caching `getCurrentUser()` results** — `cache(getCurrentUser)` is a request-scoped React `cache`, NOT a cross-request Next cache; don't confuse the two
138
+ - ✗ **`revalidate = 0`** — equivalent to `'use no cache'` but less explicit. Use the directive.
139
+ - ✗ **Broad `revalidatePath('/')` after every mutation** — kills cache hit rate; be surgical
140
+ - ✗ **Mixing `cache: 'no-store'` AND `next: { revalidate }` on the same fetch** — they conflict; pick one
141
+
142
+ ## Debug: "is this actually cached?"
143
+
144
+ Add a server-side `console.log(Date.now())` in the Server Component. Hit refresh. If the timestamp changes, the page is NOT cached. If it's stable across refreshes, it is.
145
+
146
+ Or use Next's built-in `?_cache-debug=1` (if available in your version) to inspect cache hit/miss per route in DevTools.
147
+
148
+ ## Workflow
149
+
150
+ 1. **Before writing the component**, ask: does the response depend on the user, on cookies, or on "right now"?
151
+ 2. **If yes**, top of the file: `'use no cache';`. Done.
152
+ 3. **If no**, leave it cached. No directive needed.
153
+ 4. **Per-fetch overrides** for surgical exceptions (one dynamic fetch in a mostly-cached page).
154
+ 5. **Tag your fetches** if they'll need invalidation after mutations (`next: { tags: [...] }`).
155
+ 6. **Invalidate from Server Actions** via `revalidateTag` after the mutation succeeds.
156
+
157
+ ## Composition
158
+
159
+ - `void-client-vs-server-component` — only Server Components participate in Cache Components.
160
+ - `void-server-action` — actions call `revalidateTag` / `revalidatePath` after mutations.
161
+ - `void-security-guidance` — explicit `'use no cache'` on user-scoped content is a security control, not just a perf one.
162
+ - `void-observability` — log cache misses on routes you expect cached; surface as a perf signal.
@@ -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,5 @@
1
+ Sources for `void-instrumentation-setup` skill (see `docs/plans/skill-audits/void-instrumentation-setup.md` for the full audit):
2
+
3
+ - No external source listed in the audit. Authored against the Next.js 16 instrumentation.ts mechanism (register() export, NEXT_RUNTIME edge/node split) and the Sentry + OpenTelemetry + pino composition.
4
+
5
+ Strategy: distill. Wiring pattern authored natively for Next 16; no upstream skill was adapted.
@@ -0,0 +1,161 @@
1
+ ---
2
+ name: void-instrumentation-setup
3
+ description: Wire instrumentation.ts in Next.js 16 — Sentry, pino logger, OpenTelemetry traces. Edge vs Node runtime split. The single place observability is bootstrapped.
4
+ ---
5
+
6
+ # instrumentation-setup
7
+
8
+ Use when setting up observability in a fresh Next.js app, OR when adding a new instrumentation tool (Sentry → +OTel, +Datadog, etc.). The pattern: ONE `instrumentation.ts` at the project root, conditionally initializes per runtime.
9
+
10
+ Composes with `void-observability` (the doctrine: pino, structured logs, Sentry user scope). This skill is the Next-specific wiring.
11
+
12
+ ## File location
13
+
14
+ ```
15
+ apps/<app>/
16
+ ├── instrumentation.ts # the bootstrap
17
+ ├── instrumentation-node.ts # Node-runtime-specific
18
+ ├── instrumentation-edge.ts # Edge-runtime-specific (optional)
19
+ └── src/
20
+ ```
21
+
22
+ Next 16 auto-loads `instrumentation.ts` at server startup (both runtimes). `instrumentation-{node,edge}.ts` are convention-driven splits.
23
+
24
+ ## Canonical bootstrap
25
+
26
+ ```ts
27
+ // apps/web/instrumentation.ts
28
+ export async function register() {
29
+ if (process.env.NEXT_RUNTIME === 'nodejs') {
30
+ await import('./instrumentation-node');
31
+ }
32
+ if (process.env.NEXT_RUNTIME === 'edge') {
33
+ await import('./instrumentation-edge');
34
+ }
35
+ }
36
+ ```
37
+
38
+ The dynamic imports keep edge bundles slim (Sentry's Node SDK doesn't ship to Edge runtime).
39
+
40
+ ## Node runtime setup
41
+
42
+ ```ts
43
+ // apps/web/instrumentation-node.ts
44
+ import * as Sentry from '@sentry/nextjs';
45
+ import { trace } from '@opentelemetry/api';
46
+ import { NodeSDK } from '@opentelemetry/sdk-node';
47
+ import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
48
+ import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
49
+ import { logger, env } from '@repo/core';
50
+
51
+ // 1. Sentry
52
+ Sentry.init({
53
+ dsn: env.SENTRY_DSN,
54
+ environment: env.NODE_ENV,
55
+ tracesSampleRate: env.NODE_ENV === 'production' ? 0.1 : 1.0,
56
+ beforeSend: (event) => {
57
+ if (event.user?.id) event.user.id = hash(event.user.id); // anonymize
58
+ return event;
59
+ },
60
+ });
61
+
62
+ // 2. OpenTelemetry (if you ship traces outside Sentry)
63
+ if (env.OTEL_EXPORTER_OTLP_ENDPOINT) {
64
+ const sdk = new NodeSDK({
65
+ traceExporter: new OTLPTraceExporter({
66
+ url: env.OTEL_EXPORTER_OTLP_ENDPOINT,
67
+ }),
68
+ instrumentations: [getNodeAutoInstrumentations()],
69
+ });
70
+ sdk.start();
71
+ }
72
+
73
+ // 3. pino is initialized eagerly in @repo/core/logger — nothing to do here.
74
+
75
+ logger.info({ event: 'app.boot', runtime: 'nodejs' });
76
+ ```
77
+
78
+ ## Edge runtime setup
79
+
80
+ ```ts
81
+ // apps/web/instrumentation-edge.ts
82
+ import * as Sentry from '@sentry/nextjs';
83
+ import { env } from '@repo/core';
84
+
85
+ Sentry.init({
86
+ dsn: env.SENTRY_DSN,
87
+ environment: env.NODE_ENV,
88
+ tracesSampleRate: 0.1,
89
+ transportOptions: { fetchOptions: { keepalive: true } }, // Edge fetch quirk
90
+ });
91
+
92
+ // No OTel, no pino — Edge runtime doesn't support them.
93
+ // Use Sentry.captureMessage / addBreadcrumb for structured-ish logs.
94
+ ```
95
+
96
+ Edge can't `fs.write`, can't load native modules, can't use Node `Buffer` outside polyfills. Keep instrumentation minimal.
97
+
98
+ ## What lives where (decision table)
99
+
100
+ | Concern | Where |
101
+ |---|---|
102
+ | Sentry init | `instrumentation-node.ts` AND `instrumentation-edge.ts` |
103
+ | OpenTelemetry | `instrumentation-node.ts` only |
104
+ | pino logger | `@repo/core/logger` (auto-initialized on import) |
105
+ | Sentry user scope per-request | Server Action / Route handler wrapper (`withTraceContext`) |
106
+ | Request-level traces | OTel auto-instrumentation (Node) |
107
+ | Client-side errors | `app/global-error.tsx` + `Sentry.init` in a `'use client'` provider |
108
+
109
+ ## Client-side Sentry
110
+
111
+ Server `instrumentation.ts` does NOT cover the browser. For client errors, add a separate provider:
112
+
113
+ ```tsx
114
+ // apps/web/src/app/sentry-provider.tsx
115
+ 'use client';
116
+
117
+ import * as Sentry from '@sentry/nextjs';
118
+ import { useEffect } from 'react';
119
+
120
+ let initialized = false;
121
+
122
+ export function SentryProvider({ children }: { children: React.ReactNode }) {
123
+ useEffect(() => {
124
+ if (initialized) return;
125
+ initialized = true;
126
+ Sentry.init({
127
+ dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
128
+ tracesSampleRate: 0.1,
129
+ replaysSessionSampleRate: 0.1,
130
+ });
131
+ }, []);
132
+ return <>{children}</>;
133
+ }
134
+ ```
135
+
136
+ Wire in `app/layout.tsx`. The `NEXT_PUBLIC_*` env is the only secret-ish value that's safe in the bundle.
137
+
138
+ ## Anti-patterns
139
+
140
+ - ✗ **Calling `Sentry.init` inside route handlers** — re-inits every request, leaks event listeners
141
+ - ✗ **Same Sentry sample rate in dev and prod** — at 1.0 prod you'll exhaust your event quota
142
+ - ✗ **Logging PII raw** — `beforeSend` should redact user.id, email, etc. Hash or strip.
143
+ - ✗ **OTel auto-instrumentation in Edge** — silently fails because Edge can't load Node native bindings
144
+ - ✗ **One instrumentation.ts that branches on runtime inline** — the dynamic-import pattern keeps bundles clean
145
+
146
+ ## Verification checklist
147
+
148
+ After setup, in dev:
149
+
150
+ 1. Throw in a Server Component — should surface in Sentry
151
+ 2. Throw in a Server Action — should surface
152
+ 3. Throw in a Client Component — should surface (client-side init)
153
+ 4. Check that user ID is hashed in Sentry events
154
+ 5. Check that NODE_ENV-conditional behavior (sample rate) actually differs
155
+
156
+ ## Composition
157
+
158
+ - `void-observability` — pino + Sentry doctrine (this skill is the Next wiring).
159
+ - `void-security-guidance` — Sentry user scope MUST be hashed; no PII in event payloads.
160
+ - `void-env-validation` — `SENTRY_DSN`, `OTEL_EXPORTER_OTLP_ENDPOINT` validated via Zod in `@repo/core/env`.
161
+ - `void-loading-error-boundaries` — `error.tsx` uses Sentry.captureException; this skill ensures Sentry is initialized when that fires.
@@ -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,5 @@
1
+ Sources for `void-loading-error-boundaries` skill (see `docs/plans/skill-audits/void-loading-error-boundaries.md` for the full audit):
2
+
3
+ - No external source listed in the audit. Authored against the App Router boundary file conventions (loading.tsx, error.tsx, not-found.tsx) and the Sentry capture point in error boundaries.
4
+
5
+ Strategy: distill. Placement rules authored natively for the App Router; no upstream skill was adapted.
@@ -0,0 +1,176 @@
1
+ ---
2
+ name: void-loading-error-boundaries
3
+ description: Place loading.tsx, error.tsx, not-found.tsx files at the right level — neither too high (poor UX) nor too low (unhandled errors). The skeleton matches the layout it replaces.
4
+ ---
5
+
6
+ # loading-error-boundaries
7
+
8
+ Use when adding or restructuring routes in `app/`. Next.js boundary files (`loading.tsx`, `error.tsx`, `not-found.tsx`) define UX during Server Component rendering, server failures, and missing-resource cases. Placement matters: too high = whole page flashes on partial load; too low = errors leak past the intended catch.
9
+
10
+ ## The 4 boundary files
11
+
12
+ | File | Wraps | Renders when |
13
+ |---|---|---|
14
+ | `loading.tsx` | Sibling `page.tsx` in a Suspense boundary | Async server work in progress |
15
+ | `error.tsx` | Sibling `page.tsx` + descendants in an Error Boundary | Server throws OR client error |
16
+ | `not-found.tsx` | Triggered by `notFound()` call | `notFound()` from a Server Component / handler |
17
+ | `global-error.tsx` | Wraps the root `app/layout.tsx` itself | Layout throws (rare) |
18
+
19
+ `error.tsx` and `global-error.tsx` MUST be Client Components (they catch React errors).
20
+
21
+ ## Placement: as low as practical
22
+
23
+ Place boundary files **at the segment that owns the unique loading state**, not at the root.
24
+
25
+ ```
26
+ app/
27
+ ├── (app)/
28
+ │ ├── layout.tsx # auth check, app shell
29
+ │ ├── dashboard/
30
+ │ │ ├── page.tsx
31
+ │ │ ├── loading.tsx # skeleton of dashboard widgets
32
+ │ │ └── error.tsx # error display in app shell context
33
+ │ └── settings/
34
+ │ ├── page.tsx
35
+ │ └── loading.tsx # skeleton of settings form
36
+ └── (marketing)/
37
+ ├── layout.tsx
38
+ └── blog/
39
+ ├── [slug]/
40
+ │ ├── page.tsx
41
+ │ ├── loading.tsx # article skeleton
42
+ │ └── error.tsx # "couldn't load article" message
43
+ └── page.tsx # blog index (no skeleton — small enough)
44
+ ```
45
+
46
+ Per-route boundaries mean a slow `/dashboard` doesn't blank out `/settings` when the user is on `/settings`. Each route streams in independently.
47
+
48
+ ## Skeleton design: match the final layout
49
+
50
+ A skeleton's job is to **reserve the space** the real content will occupy. The user's eye should not jump when the content arrives.
51
+
52
+ ```tsx
53
+ // app/(app)/dashboard/loading.tsx
54
+ export default function Loading() {
55
+ return (
56
+ <div className="grid grid-cols-3 gap-4 p-6">
57
+ <Skeleton className="h-32" /> {/* matches card height */}
58
+ <Skeleton className="h-32" />
59
+ <Skeleton className="h-32" />
60
+ <Skeleton className="col-span-3 h-64" />{/* matches chart */}
61
+ </div>
62
+ );
63
+ }
64
+ ```
65
+
66
+ - ✗ Spinner in the middle of the page — gives no spatial cue, content appearance is jarring
67
+ - ✗ Skeleton that's the wrong height — layout shift on content arrival = bad CLS
68
+ - ✓ Skeleton bricks matching the final layout shape, neutral gray fill, optional shimmer
69
+
70
+ For text content: 3-5 lines of skeleton bars at varying widths look more realistic than perfect rectangles.
71
+
72
+ ## `error.tsx`: handle, don't display the stack
73
+
74
+ Error boundary should:
75
+
76
+ - Hide the technical detail from end users
77
+ - Log to Sentry (composes with `void-observability`)
78
+ - Offer a recovery path (reset button, link back)
79
+
80
+ ```tsx
81
+ 'use client';
82
+
83
+ import { useEffect } from 'react';
84
+ import * as Sentry from '@sentry/nextjs';
85
+
86
+ export default function Error({ error, reset }: { error: Error & { digest?: string }; reset: () => void }) {
87
+ useEffect(() => {
88
+ Sentry.captureException(error);
89
+ }, [error]);
90
+
91
+ return (
92
+ <div className="p-6">
93
+ <h2>Quelque chose s'est mal passé.</h2>
94
+ <p>L'équipe est notifiée. Vous pouvez réessayer.</p>
95
+ <button onClick={() => reset()}>Réessayer</button>
96
+ </div>
97
+ );
98
+ }
99
+ ```
100
+
101
+ The `digest` prop is the server-side error ID — useful to correlate Sentry with the user report (display it discreetly: `<small>ID: {error.digest}</small>`).
102
+
103
+ ## `not-found.tsx` — the route's own 404
104
+
105
+ ```tsx
106
+ // app/(marketing)/blog/[slug]/not-found.tsx
107
+ export default function NotFound() {
108
+ return (
109
+ <div className="p-6 text-center">
110
+ <h1>Article introuvable</h1>
111
+ <p>Cet article n'existe pas ou a été supprimé.</p>
112
+ <Link href="/blog">← Retour aux articles</Link>
113
+ </div>
114
+ );
115
+ }
116
+ ```
117
+
118
+ Triggered from a Server Component:
119
+
120
+ ```tsx
121
+ import { notFound } from 'next/navigation';
122
+
123
+ export default async function Article({ params }) {
124
+ const post = await db.query.posts.findFirst({ where: eq(posts.slug, params.slug) });
125
+ if (!post) notFound();
126
+ return <ArticleView post={post} />;
127
+ }
128
+ ```
129
+
130
+ Without a `not-found.tsx` at the route, Next falls back to the nearest ancestor. Provide one at the level that knows the resource — a blog `not-found` is contextually richer than the root 404.
131
+
132
+ ## `global-error.tsx` — last resort
133
+
134
+ Catches errors in `app/layout.tsx` itself (and its providers). Rare; usually empty until needed.
135
+
136
+ ```tsx
137
+ // app/global-error.tsx
138
+ 'use client';
139
+
140
+ export default function GlobalError({ error, reset }) {
141
+ return (
142
+ <html>
143
+ <body>
144
+ <h1>Application non disponible.</h1>
145
+ <button onClick={() => reset()}>Recharger</button>
146
+ </body>
147
+ </html>
148
+ );
149
+ }
150
+ ```
151
+
152
+ Must render its own `<html>` and `<body>` because it replaces the root layout entirely.
153
+
154
+ ## Anti-patterns
155
+
156
+ - ✗ **One `loading.tsx` at app root** — every route shows the same skeleton; no granularity
157
+ - ✗ **Spinner-only loading** — no spatial cue, content appearance is jarring
158
+ - ✗ **Error boundary displaying the raw stack** — leaks internal info, scares users
159
+ - ✗ **`not-found.tsx` only at the root** — every "not found" looks the same; misses context
160
+ - ✗ **No `useEffect` Sentry capture in error.tsx** — errors swallowed silently
161
+ - ✗ **Catching errors in components via try/catch instead of `error.tsx`** — bypasses React's error boundary mechanism
162
+
163
+ ## Workflow
164
+
165
+ 1. **At each route segment**, ask: does this content need its own loading state?
166
+ 2. **If yes**, write a `loading.tsx` whose skeleton matches the final layout's shape.
167
+ 3. **For routes that fetch data**, write an `error.tsx` with Sentry capture + recovery action.
168
+ 4. **For routes with parameterized resources** ([slug], [id]), write a `not-found.tsx` and call `notFound()` when the resource is absent.
169
+ 5. **`global-error.tsx` only when** root layout starts having logic that can fail.
170
+
171
+ ## Composition
172
+
173
+ - `void-cache-component-pattern` — cached pages have predictable load times; loading.tsx is mostly for the cold cache case.
174
+ - `void-parallel-routes-slots` — each `@slot` can have its own `loading.tsx` / `error.tsx`.
175
+ - `void-observability` — `error.tsx` is the Sentry capture point for server errors.
176
+ - `void-accessibility-check` — skeletons should have `aria-busy` or `aria-live="polite"` regions.
@@ -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,5 @@
1
+ Sources for `void-parallel-routes-slots` skill (see `docs/plans/skill-audits/void-parallel-routes-slots.md` for the full audit):
2
+
3
+ - No external source listed in the audit. Authored against the Next.js routing primitives (parallel routes @slot, intercepting routes (.)foo) and their over-application traps.
4
+
5
+ Strategy: distill. WIN-vs-LOSE guidance authored natively for the Next routing primitives; no upstream skill was adapted.