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,178 @@
1
+ ---
2
+ name: void-expo-config-plugins
3
+ description: Add native functionality to an Expo app via config plugins, never by ejecting. Pick existing Expo modules first, write a custom plugin only when none fits. Document everything in app.config.ts.
4
+ ---
5
+
6
+ # expo-config-plugins
7
+
8
+ Use when an Expo app needs functionality not available in JS — push notifications, camera, haptics, secure storage, or any native iOS/Android API. The Expo way: config plugins + Expo Modules. Ejecting to bare React Native is a one-way door — almost never the right answer.
9
+
10
+ ## The decision tree
11
+
12
+ ```
13
+ 1. Is there an `expo-X` package on npm? → use it (e.g., expo-camera, expo-haptics)
14
+ 2. Is there a community config plugin? → use it (search "expo-plugin" + your need)
15
+ 3. Does it just need a Podfile / Manifest tweak? → write a custom config plugin (~30 lines)
16
+ 4. Does it need new Swift/Kotlin code? → write an Expo Module
17
+ 5. Truly nothing fits? → reconsider the requirement; ejecting last resort
18
+ ```
19
+
20
+ Most teams hit (1) for 80% of needs and never go past (3).
21
+
22
+ ## What a config plugin is
23
+
24
+ A function that mutates the native iOS/Android project files at build time. It does not run in the app — it runs in EAS Build / `expo prebuild`.
25
+
26
+ ```ts
27
+ // app.config.ts
28
+ import { ConfigContext, ExpoConfig } from 'expo/config';
29
+
30
+ export default ({ config }: ConfigContext): ExpoConfig => ({
31
+ ...config,
32
+ name: 'Solaar',
33
+ slug: 'solaar',
34
+ plugins: [
35
+ 'expo-router',
36
+ 'expo-secure-store',
37
+ [
38
+ 'expo-build-properties',
39
+ {
40
+ ios: { deploymentTarget: '15.1', useFrameworks: 'static' },
41
+ android: { compileSdkVersion: 34, targetSdkVersion: 34 },
42
+ },
43
+ ],
44
+ './plugins/my-custom-plugin', // local plugin
45
+ ],
46
+ });
47
+ ```
48
+
49
+ Each entry is either:
50
+
51
+ - A string: package name; uses the package's default plugin
52
+ - A tuple `[name, props]`: passes config to the plugin
53
+
54
+ ## Common Expo modules
55
+
56
+ Pin the ones below mentally — they handle 80% of native needs:
57
+
58
+ | Need | Package |
59
+ |---|---|
60
+ | Camera | `expo-camera` |
61
+ | Push notifications | `expo-notifications` |
62
+ | Haptics (vibrate, tap feedback) | `expo-haptics` |
63
+ | Secure storage (keychain / keystore) | `expo-secure-store` |
64
+ | File system | `expo-file-system` |
65
+ | Local notifications | `expo-notifications` |
66
+ | Authentication (OAuth, biometrics) | `expo-auth-session`, `expo-local-authentication` |
67
+ | Location | `expo-location` |
68
+ | Linking (deep links) | `expo-linking` |
69
+ | Updates | `expo-updates` |
70
+ | Sharing | `expo-sharing` |
71
+ | WebView | `expo-webview` (or `react-native-webview`) |
72
+ | Storage (key-value) | `expo-sqlite` or `react-native-mmkv` |
73
+
74
+ For each: install, add to `plugins` array if it needs prebuild config, use the JS API in your code.
75
+
76
+ ## When to write a custom plugin
77
+
78
+ Two cases:
79
+
80
+ ### A. Config-only (Info.plist, AndroidManifest tweaks)
81
+
82
+ ```ts
83
+ // plugins/with-app-tracking.ts
84
+ import { ConfigPlugin, withInfoPlist } from 'expo/config-plugins';
85
+
86
+ const withAppTracking: ConfigPlugin<{ reason: string }> = (config, { reason }) => {
87
+ return withInfoPlist(config, (cfg) => {
88
+ cfg.modResults.NSUserTrackingUsageDescription = reason;
89
+ return cfg;
90
+ });
91
+ };
92
+
93
+ export default withAppTracking;
94
+ ```
95
+
96
+ Usage:
97
+
98
+ ```ts
99
+ // app.config.ts
100
+ plugins: [
101
+ ['./plugins/with-app-tracking', { reason: 'Personalize your experience' }],
102
+ ];
103
+ ```
104
+
105
+ This pattern handles: permission strings, URL schemes, custom Info.plist keys, AndroidManifest entries, build settings.
106
+
107
+ ### B. Native code (Swift / Kotlin)
108
+
109
+ If you need actual native code, write an **Expo Module**, not a config plugin. Expo Modules are first-class native modules with auto-linking + TS bindings.
110
+
111
+ ```bash
112
+ npx create-expo-module@latest --local my-native-module
113
+ ```
114
+
115
+ The generated package has `ios/`, `android/`, and `src/` (TS bindings). Build runs `expo prebuild` automatically.
116
+
117
+ ## When NOT to do native
118
+
119
+ Most "I need a native feature" turns out to be solvable in JS:
120
+
121
+ - **"I need to read the file system"** → `expo-file-system`, no native code
122
+ - **"I need biometric auth"** → `expo-local-authentication`
123
+ - **"I need to detect device type"** → `expo-device` provides everything
124
+
125
+ Try the JS path first. Native is overhead: build complexity, EAS Build minutes, debugging hardness.
126
+
127
+ ## `app.config.ts` vs `app.json`
128
+
129
+ Use `app.config.ts`. Reasons:
130
+
131
+ - TypeScript = typo-safe
132
+ - Dynamic values (env vars, computed flags) supported
133
+ - One source of truth for dev/staging/prod variants
134
+
135
+ Example:
136
+
137
+ ```ts
138
+ // app.config.ts
139
+ import { ConfigContext, ExpoConfig } from 'expo/config';
140
+
141
+ const variant = process.env.APP_VARIANT ?? 'dev';
142
+
143
+ export default ({ config }: ConfigContext): ExpoConfig => ({
144
+ ...config,
145
+ name: variant === 'prod' ? 'Solaar' : `Solaar (${variant})`,
146
+ slug: 'solaar',
147
+ ios: {
148
+ bundleIdentifier: `io.voidcorp.solaar.${variant}`,
149
+ },
150
+ android: {
151
+ package: `io.voidcorp.solaar.${variant}`,
152
+ },
153
+ extra: {
154
+ apiUrl: process.env.EXPO_PUBLIC_API_URL,
155
+ },
156
+ });
157
+ ```
158
+
159
+ Dev + staging + prod variants installed side-by-side on a single device thanks to bundle ID variation.
160
+
161
+ ## Anti-patterns
162
+
163
+ - ✗ **Ejecting on first sign of native need** — almost always reversible to "use an Expo module"
164
+ - ✗ **Hand-editing `ios/` or `android/`** after prebuild — gets nuked on next `expo prebuild`; bad merges between repo and prebuild
165
+ - ✗ **Mixing `app.json` and `app.config.ts`** — pick one, delete the other; precedence is unclear
166
+ - ✗ **`extra` field used for secrets** — `extra` ships in the JS bundle, visible to anyone
167
+ - ✗ **Plugin order matters and you ignored it** — some plugins must come before others (e.g., expo-router before any router consumer); follow plugin docs
168
+
169
+ ## Verification
170
+
171
+ `npx expo prebuild --no-install --clean` — runs the plugin pipeline locally, generates `ios/` and `android/` you can inspect. If something's broken at native level, you'll see it before EAS.
172
+
173
+ ## Composition
174
+
175
+ - `void-eas-build-profile` — config plugins + build profiles together define what binary ships
176
+ - `void-ota-update-strategy` — JS-only changes don't need a rebuild; native config changes do
177
+ - `void-state-architecture` — share state architecture with web siblings; only native deps differ
178
+ - `void-env-validation` — env reaches the app via `extra` or EAS Build env; validate with same schema discipline
@@ -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,8 @@
1
+ Sources for `void-expo-router-pattern` skill (see `docs/plans/skill-audits/void-expo-router-pattern.md` for the full audit):
2
+
3
+ - expo-router official documentation — no URL recorded in the audit — distilled the file-based routing conventions (`(tabs)/`, `(modal)/`, `(auth)/`, per-group `_layout.tsx`, typed routes via `experiments.typedRoutes`, deep-link auto-config).
4
+ - Next.js App Router conventions — no URL recorded in the audit — used as the shared mental model expo-router mirrors by design, so a monorepo keeps one routing model across web and mobile.
5
+
6
+ No external skill ships this verbatim; authored by distilling the expo-router docs and aligning them to the Next.js App Router convention.
7
+
8
+ Strategy: distill. Lean on the deliberate Next.js parity so devs do not reinvent React Navigation patterns.
@@ -0,0 +1,209 @@
1
+ ---
2
+ name: void-expo-router-pattern
3
+ description: File-based routing in Expo via expo-router — layouts, tabs, modals, deep links. Mirrors Next.js App Router so monorepos can share mental model. Stack-aware navigation patterns.
4
+ ---
5
+
6
+ # expo-router-pattern
7
+
8
+ Use when adding screens / navigation to an Expo app using `expo-router`. The convention mirrors Next.js App Router by design — same `(group)/`, `_layout.tsx`, `[param]`, dynamic segments — so a monorepo sharing web + mobile keeps one routing mental model.
9
+
10
+ If your app uses React Navigation directly (not expo-router), this skill does not apply (different API entirely).
11
+
12
+ ## File layout (Solaar archetype)
13
+
14
+ ```
15
+ apps/mobile/app/
16
+ ├── _layout.tsx # root layout: providers, Stack navigator
17
+ ├── (tabs)/ # tab navigation root
18
+ │ ├── _layout.tsx # tab bar config
19
+ │ ├── index.tsx # / → Home tab
20
+ │ ├── contacts/
21
+ │ │ ├── index.tsx # /contacts
22
+ │ │ └── [id].tsx # /contacts/123
23
+ │ ├── notes.tsx
24
+ │ └── settings.tsx
25
+ ├── (modal)/ # modal-presented screens
26
+ │ ├── _layout.tsx # presentation: 'modal'
27
+ │ ├── new-contact.tsx # /new-contact (slides up)
28
+ │ └── share.tsx
29
+ ├── (auth)/ # auth flow (no tabs)
30
+ │ ├── _layout.tsx # presentation: stack, no tab bar
31
+ │ ├── sign-in.tsx
32
+ │ └── sign-up.tsx
33
+ └── +not-found.tsx # 404
34
+ ```
35
+
36
+ ## Layouts: what each `_layout.tsx` does
37
+
38
+ ### Root `app/_layout.tsx`
39
+
40
+ - Wraps `<Stack />` (or `<Slot />` for layoutless)
41
+ - Provides global Providers (Auth, Query Client, Theme, i18n)
42
+ - Initializes Sentry, fonts, splash hide
43
+ - Owns navigation theme (`DarkTheme` / `DefaultTheme`)
44
+
45
+ ```tsx
46
+ // app/_layout.tsx
47
+ import { Stack } from 'expo-router';
48
+ import { Providers } from '@/providers';
49
+ import { useFonts } from 'expo-font';
50
+ import * as SplashScreen from 'expo-splash-screen';
51
+
52
+ SplashScreen.preventAutoHideAsync();
53
+
54
+ export default function RootLayout() {
55
+ const [loaded] = useFonts({ /* ... */ });
56
+ if (!loaded) return null;
57
+
58
+ return (
59
+ <Providers>
60
+ <Stack screenOptions={{ headerShown: false }}>
61
+ <Stack.Screen name="(tabs)" />
62
+ <Stack.Screen name="(modal)" options={{ presentation: 'modal' }} />
63
+ <Stack.Screen name="(auth)" />
64
+ </Stack>
65
+ </Providers>
66
+ );
67
+ }
68
+ ```
69
+
70
+ ### `(tabs)/_layout.tsx`
71
+
72
+ ```tsx
73
+ import { Tabs } from 'expo-router';
74
+
75
+ export default function TabsLayout() {
76
+ return (
77
+ <Tabs screenOptions={{ tabBarActiveTintColor: 'gold' }}>
78
+ <Tabs.Screen name="index" options={{ title: 'Accueil' }} />
79
+ <Tabs.Screen name="contacts" options={{ title: 'Contacts' }} />
80
+ <Tabs.Screen name="notes" options={{ title: 'Notes' }} />
81
+ <Tabs.Screen name="settings" options={{ title: 'Réglages' }} />
82
+ </Tabs>
83
+ );
84
+ }
85
+ ```
86
+
87
+ ### `(modal)/_layout.tsx`
88
+
89
+ ```tsx
90
+ import { Stack } from 'expo-router';
91
+
92
+ export default function ModalLayout() {
93
+ return <Stack screenOptions={{ presentation: 'modal' }} />;
94
+ }
95
+ ```
96
+
97
+ ## Navigation primitives
98
+
99
+ ```tsx
100
+ import { useRouter, Link } from 'expo-router';
101
+
102
+ function ContactCard({ id }: { id: string }) {
103
+ const router = useRouter();
104
+ return (
105
+ <>
106
+ {/* Imperative */}
107
+ <Pressable onPress={() => router.push(`/contacts/${id}`)} />
108
+
109
+ {/* Declarative — composes with Tappable from @repo/ui */}
110
+ <Link href={{ pathname: '/contacts/[id]', params: { id } }} asChild>
111
+ <Tappable>{children}</Tappable>
112
+ </Link>
113
+ </>
114
+ );
115
+ }
116
+ ```
117
+
118
+ Prefer `<Link>` over `router.push` — typed params, better a11y (renders an actual touchable surface), works with deep links.
119
+
120
+ ## Dynamic segments + typed routes
121
+
122
+ ```
123
+ app/(tabs)/contacts/[id].tsx → /contacts/:id
124
+ app/(tabs)/contacts/[...rest].tsx → /contacts/* (catch-all)
125
+ ```
126
+
127
+ Access params:
128
+
129
+ ```tsx
130
+ import { useLocalSearchParams } from 'expo-router';
131
+
132
+ export default function Contact() {
133
+ const { id } = useLocalSearchParams<{ id: string }>();
134
+ return <ContactView id={id} />;
135
+ }
136
+ ```
137
+
138
+ Enable **typed routes** in `app.config.ts`:
139
+
140
+ ```ts
141
+ experiments: { typedRoutes: true }
142
+ ```
143
+
144
+ Then `<Link href="/contacts/xyz" />` is type-checked at build time.
145
+
146
+ ## Deep links
147
+
148
+ `expo-router` automatically configures deep links from the file structure. To open the app at `/contacts/123` from outside:
149
+
150
+ ```
151
+ iOS: yourscheme://contacts/123
152
+ Android: same
153
+ Universal Link / App Link: https://app.solaar.com/contacts/123
154
+ ```
155
+
156
+ `scheme` in `app.config.ts`:
157
+
158
+ ```ts
159
+ scheme: 'solaar',
160
+ ```
161
+
162
+ Universal Links need additional setup (`apple-app-site-association`, `assetlinks.json` on the web).
163
+
164
+ ## Modals
165
+
166
+ Two patterns:
167
+
168
+ ### A. Modal as a route (`(modal)/` group)
169
+
170
+ Stack-based modal presentation, full route URL, supports deep linking. Use for screens that ARE work — new-contact form, share sheet, settings detail.
171
+
172
+ ### B. Modal as local state
173
+
174
+ `useState` + a `<Modal>` component from React Native or Radix-ish mobile library. Use for transient UI — confirmation dialog, toast.
175
+
176
+ Same rule as web: if the modal should be shareable / deep-linkable / browser-backable, it's a route. Otherwise local state.
177
+
178
+ ## Auth flow
179
+
180
+ `(auth)/` group with its own layout, no tab bar. Root layout redirects unauthenticated users:
181
+
182
+ ```tsx
183
+ // app/_layout.tsx
184
+ import { Redirect } from 'expo-router';
185
+ import { useAuth } from '@/auth';
186
+
187
+ export default function RootLayout() {
188
+ const { user, loading } = useAuth();
189
+ if (loading) return null;
190
+ if (!user) return <Redirect href="/sign-in" />;
191
+ return <Stack>...</Stack>;
192
+ }
193
+ ```
194
+
195
+ ## Anti-patterns
196
+
197
+ - ✗ **Mixing `react-navigation` directly with `expo-router`** — they conflict; pick one
198
+ - ✗ **One mega `_layout.tsx` at root with all logic** — push down to per-group layouts
199
+ - ✗ **Dynamic `useEffect` to redirect** — use `<Redirect>` or middleware-like guards in `_layout.tsx`
200
+ - ✗ **`router.replace` in render** — only call navigation actions in effects/handlers
201
+ - ✗ **Hardcoded path strings everywhere** — enable typedRoutes; centralize destinations in a constants file otherwise
202
+
203
+ ## Composition
204
+
205
+ - `void-expo-config-plugins` — `expo-router` is itself a config plugin (`plugins: ['expo-router']`)
206
+ - `void-eas-build-profile` — dev profile must have `developmentClient: true` for expo-router to work in dev
207
+ - `void-route-group-decision` — same `(group)/` convention; same WHY (group by trust posture)
208
+ - `void-state-architecture` — modal-as-route vs modal-as-state decision
209
+ - `void-accessibility-check` — touch targets, focus management apply identically
@@ -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-ota-update-strategy` skill (see `docs/plans/skill-audits/void-ota-update-strategy.md` for the full audit):
2
+
3
+ - EAS Update official documentation — no URL recorded in the audit — distilled the runtime-version model (fingerprint vs appVersion policy), the JS-only-vs-rebuild boundary, channels, and rollback into a change-type table plus an explicit "what CAN'T go in OTA" list, with a strong recommendation toward the fingerprint policy.
4
+
5
+ No external skill ships this verbatim; authored by distilling the official EAS Update docs into the void-machine "when can I OTA vs when do I rebuild" decision.
6
+
7
+ Strategy: distill. Surface the quiet runtime-version footgun explicitly rather than leave it scattered across the docs.
@@ -0,0 +1,194 @@
1
+ ---
2
+ name: void-ota-update-strategy
3
+ description: Ship JS-only fixes via EAS Update; full rebuild via EAS Build. Runtime versions, channels, rollback. The "when can I OTA vs when do I rebuild" decision.
4
+ ---
5
+
6
+ # ota-update-strategy
7
+
8
+ Use when planning to ship a change to an Expo app already in users' hands. The fundamental choice: **JS-only change** → EAS Update (minutes); **native change** → EAS Build + store submit (hours/days). Getting this wrong means either users running broken apps or unnecessary store rejections.
9
+
10
+ ## The fundamental rule
11
+
12
+ | Change type | Path | Speed |
13
+ |---|---|---|
14
+ | JS bug fix (logic, UI text, layout) | EAS Update | Minutes |
15
+ | Adding a new screen (no new native dep) | EAS Update | Minutes |
16
+ | Changing a string in `app.config.ts` env | EAS Update if same plugins | Minutes |
17
+ | New `expo-X` package added to plugins | EAS Build + submit | Hours + store review days |
18
+ | Native config changes (Info.plist, permissions) | EAS Build + submit | Hours + store review |
19
+ | New native module | EAS Build + submit | Hours + store review |
20
+ | Bump SDK version | EAS Build + submit | Hours + store review |
21
+
22
+ When in doubt: if the change touches `plugins:` or `ios:`/`android:` config in `app.config.ts`, it needs a rebuild.
23
+
24
+ ## Branches and channels (mental model)
25
+
26
+ EAS Update splits the publishing target in two layers:
27
+
28
+ - **Branch** — where you PUBLISH an update (`eas update --branch production`)
29
+ - **Channel** — what the BUILD reads from (declared in `eas.json` per profile)
30
+
31
+ Builds read from a channel; channels point at branches; you publish to branches.
32
+
33
+ ```jsonc
34
+ // eas.json
35
+ "production": {
36
+ "channel": "production",
37
+ // ...
38
+ }
39
+ ```
40
+
41
+ This build is on channel `production`. By default, channel `production` points at branch `production`. To re-point: `eas channel:edit production --branch <other>`.
42
+
43
+ Publish to the production branch (so the production channel picks it up):
44
+
45
+ ```bash
46
+ eas update --branch production --message "Fix avatar crash on iOS"
47
+ ```
48
+
49
+ A user with a production-channel build pulls this update on next app launch.
50
+
51
+ Pre-launch / staging:
52
+
53
+ ```bash
54
+ eas update --branch preview --message "..."
55
+ ```
56
+
57
+ Users with a preview-channel build get this update; production users don't see it (different channel → different branch).
58
+
59
+ ## Runtime versions — the critical detail
60
+
61
+ `expo-updates` checks **runtime version** before applying an update. If the update's runtime version doesn't match the build's, the update is silently skipped.
62
+
63
+ ```ts
64
+ // app.config.ts
65
+ runtimeVersion: { policy: 'fingerprint' },
66
+ ```
67
+
68
+ `'fingerprint'` is the modern policy: SDK + every native plugin + every native dep contribute to a hash. Add a native plugin → fingerprint changes → new builds have new runtime version → old builds won't accept new updates (which is correct: old build can't run the new code anyway).
69
+
70
+ Other policies:
71
+
72
+ - `'appVersion'` — uses `version` field (manual; you remember to bump it when adding native)
73
+ - `'sdkVersion'` — every SDK bump = new runtime (coarse; native changes within an SDK rev don't trigger)
74
+
75
+ `fingerprint` is the right default; the others are legacy. Don't use them on new apps.
76
+
77
+ ## Update strategy: when does the user actually see the update
78
+
79
+ `expo-updates` config:
80
+
81
+ ```ts
82
+ // app.config.ts (extra section or via expo-updates config block)
83
+ updates: {
84
+ enabled: true,
85
+ checkAutomatically: 'ON_LOAD', // check on every cold start
86
+ fallbackToCacheTimeout: 0, // 0 = use cache instantly, check in background
87
+ }
88
+ ```
89
+
90
+ | `checkAutomatically` | When checks happen |
91
+ |---|---|
92
+ | `ON_LOAD` | Every cold start |
93
+ | `ON_ERROR_RECOVERY` | Only after a crash |
94
+ | `NEVER` | Manual only (call `Updates.checkForUpdateAsync()` yourself) |
95
+
96
+ For most apps, `ON_LOAD` + `fallbackToCacheTimeout: 0` is right: instant launch with cached code, update applied silently on next launch.
97
+
98
+ If you need immediate apply (critical security fix), code-call:
99
+
100
+ ```ts
101
+ import * as Updates from 'expo-updates';
102
+
103
+ async function applyUpdateIfAvailable() {
104
+ const update = await Updates.checkForUpdateAsync();
105
+ if (update.isAvailable) {
106
+ await Updates.fetchUpdateAsync();
107
+ await Updates.reloadAsync(); // forces immediate reload
108
+ }
109
+ }
110
+ ```
111
+
112
+ Show a confirmation UI before forced reload — don't yank the user out of their current task.
113
+
114
+ ## Rollback
115
+
116
+ If an update is broken, deploy a fixed one — there's no "delete" for OTA updates, but newer wins.
117
+
118
+ ```bash
119
+ eas update --branch production --message "Revert: avatar crash fix had its own bug"
120
+ ```
121
+
122
+ The new update reverts the change in code. Users get it on next check.
123
+
124
+ For a hard halt of bad updates, republish a known-good update at the head of the branch:
125
+
126
+ ```bash
127
+ eas update:republish --branch production --group <previous-good-update-id>
128
+ ```
129
+
130
+ Or re-point the production channel at a known-good branch:
131
+
132
+ ```bash
133
+ eas channel:edit production --branch production-stable
134
+ ```
135
+
136
+ This shifts every production-channel build to read the alternate branch.
137
+
138
+ ## Testing updates before production
139
+
140
+ `eas channel:edit` lets you point a channel at any branch:
141
+
142
+ ```bash
143
+ # Build was on production, but you want to test an update from "experimental" branch
144
+ eas channel:edit production --branch experimental
145
+ ```
146
+
147
+ Test on real production-channel builds → switch back to production branch when validated:
148
+
149
+ ```bash
150
+ eas channel:edit production --branch production
151
+ ```
152
+
153
+ ## What CAN'T go in an OTA update
154
+
155
+ - Anything touching native code (SDK bump, new module, config plugin change)
156
+ - Adding new permissions
157
+ - Changing the bundle ID, name, icon
158
+ - Splash screen image change (it's pre-bundled in the native shell)
159
+
160
+ These all require EAS Build + store submission. Plan ahead.
161
+
162
+ ## Anti-patterns
163
+
164
+ - ✗ **`'appVersion'` runtime policy** — silently skips updates when devs forget to bump version. `fingerprint` removes this trap.
165
+ - ✗ **OTA-ing a native dep change** — update silently doesn't apply (different runtime version). Confusing for hours of debugging.
166
+ - ✗ **`Updates.reloadAsync()` without warning** — yanks user mid-task; bad UX
167
+ - ✗ **Same channel for staging + prod** — staging users get prod updates; prod users get unfinished work
168
+ - ✗ **No `extra` field for update metadata** — can't tell "which build is this user on" in Sentry / analytics
169
+
170
+ ## Verification
171
+
172
+ After deploying an update:
173
+
174
+ ```bash
175
+ eas update:list --branch production --limit 5
176
+ ```
177
+
178
+ Shows recent updates with IDs, messages, runtime versions, dates. Spot the new one.
179
+
180
+ In the app, check:
181
+
182
+ ```ts
183
+ import * as Updates from 'expo-updates';
184
+ console.log(Updates.updateId, Updates.createdAt);
185
+ ```
186
+
187
+ This logs which update the user is currently on. Useful in a debug screen for QA.
188
+
189
+ ## Composition
190
+
191
+ - `void-eas-build-profile` — channel names map to build profile names
192
+ - `void-expo-config-plugins` — plugin changes invalidate runtime versions
193
+ - `void-observability` — log `Updates.updateId` in every Sentry event so you can correlate "which JS is running"
194
+ - `void-async-safety` — `Updates.checkForUpdateAsync()` failures should not block app launch; timeout + fallback to cached
@@ -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-dependency-direction` skill (see `docs/plans/skill-audits/void-dependency-direction.md` for the full audit):
2
+
3
+ - No external source. Native concretization of the `01-monorepo-layout.md` module's abstract `@repo/*` import rules into worked examples.
4
+
5
+ Strategy: native. Distills the module topology into concrete violation-plus-fix examples; core `void-hexagonal-architecture` is the generic doctrine, this is the monorepo-specific operational guide.