groundwork-method 0.0.1 → 0.11.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 (647) hide show
  1. package/CHANGELOG.md +823 -0
  2. package/LICENSE +21 -0
  3. package/README.md +44 -29
  4. package/bin/groundwork.js +1723 -0
  5. package/dist/src/generators/add-capability/generator.d.ts +8 -0
  6. package/dist/src/generators/add-capability/generator.js +60 -0
  7. package/dist/src/generators/add-capability/generator.js.map +1 -0
  8. package/dist/src/generators/cli-app/generator.d.ts +9 -0
  9. package/dist/src/generators/cli-app/generator.js +140 -0
  10. package/dist/src/generators/cli-app/generator.js.map +1 -0
  11. package/dist/src/generators/docs-site/generator.d.ts +5 -0
  12. package/dist/src/generators/docs-site/generator.js +441 -0
  13. package/dist/src/generators/docs-site/generator.js.map +1 -0
  14. package/dist/src/generators/electron-app/generator.d.ts +6 -0
  15. package/dist/src/generators/electron-app/generator.js +261 -0
  16. package/dist/src/generators/electron-app/generator.js.map +1 -0
  17. package/dist/src/generators/flutter-app/generator.d.ts +6 -0
  18. package/dist/src/generators/flutter-app/generator.js +314 -0
  19. package/dist/src/generators/flutter-app/generator.js.map +1 -0
  20. package/dist/src/generators/go-microservice/generator.d.ts +8 -0
  21. package/dist/src/generators/go-microservice/generator.js +232 -0
  22. package/dist/src/generators/go-microservice/generator.js.map +1 -0
  23. package/dist/src/generators/nextjs-app/generator.d.ts +8 -0
  24. package/dist/src/generators/nextjs-app/generator.js +294 -0
  25. package/dist/src/generators/nextjs-app/generator.js.map +1 -0
  26. package/dist/src/generators/python-microservice/generator.d.ts +13 -0
  27. package/dist/src/generators/python-microservice/generator.js +265 -0
  28. package/dist/src/generators/python-microservice/generator.js.map +1 -0
  29. package/dist/src/generators/shared/brand-tokens.d.ts +89 -0
  30. package/dist/src/generators/shared/brand-tokens.js +308 -0
  31. package/dist/src/generators/shared/brand-tokens.js.map +1 -0
  32. package/dist/src/generators/shared/capabilities.d.ts +101 -0
  33. package/dist/src/generators/shared/capabilities.js +279 -0
  34. package/dist/src/generators/shared/capabilities.js.map +1 -0
  35. package/dist/src/generators/shared/provenance.d.ts +2 -0
  36. package/dist/src/generators/shared/provenance.js +85 -0
  37. package/dist/src/generators/shared/provenance.js.map +1 -0
  38. package/dist/src/generators/shared/scaffold-helpers.d.ts +72 -0
  39. package/dist/src/generators/shared/scaffold-helpers.js +309 -0
  40. package/dist/src/generators/shared/scaffold-helpers.js.map +1 -0
  41. package/dist/src/generators/system-test-runner/generator.d.ts +23 -0
  42. package/dist/src/generators/system-test-runner/generator.js +173 -0
  43. package/dist/src/generators/system-test-runner/generator.js.map +1 -0
  44. package/dist/src/generators/workspace-dev-cli/generator.d.ts +7 -0
  45. package/dist/src/generators/workspace-dev-cli/generator.js +138 -0
  46. package/dist/src/generators/workspace-dev-cli/generator.js.map +1 -0
  47. package/generators.json +57 -0
  48. package/lib/repo-map/grammars/tree-sitter-c.wasm +0 -0
  49. package/lib/repo-map/grammars/tree-sitter-cpp.wasm +0 -0
  50. package/lib/repo-map/grammars/tree-sitter-csharp.wasm +0 -0
  51. package/lib/repo-map/grammars/tree-sitter-dart.wasm +0 -0
  52. package/lib/repo-map/grammars/tree-sitter-go.wasm +0 -0
  53. package/lib/repo-map/grammars/tree-sitter-java.wasm +0 -0
  54. package/lib/repo-map/grammars/tree-sitter-javascript.wasm +0 -0
  55. package/lib/repo-map/grammars/tree-sitter-kotlin.wasm +0 -0
  56. package/lib/repo-map/grammars/tree-sitter-lua.wasm +0 -0
  57. package/lib/repo-map/grammars/tree-sitter-php.wasm +0 -0
  58. package/lib/repo-map/grammars/tree-sitter-python.wasm +0 -0
  59. package/lib/repo-map/grammars/tree-sitter-ruby.wasm +0 -0
  60. package/lib/repo-map/grammars/tree-sitter-rust.wasm +0 -0
  61. package/lib/repo-map/grammars/tree-sitter-scala.wasm +0 -0
  62. package/lib/repo-map/grammars/tree-sitter-swift.wasm +0 -0
  63. package/lib/repo-map/grammars/tree-sitter-tsx.wasm +0 -0
  64. package/lib/repo-map/grammars/tree-sitter-typescript.wasm +0 -0
  65. package/lib/repo-map/index.js +386 -0
  66. package/lib/repo-map/languages.js +514 -0
  67. package/lib/repo-map/pagerank.js +59 -0
  68. package/migrations/README.md +60 -0
  69. package/migrations/_template/cli-migration.js +27 -0
  70. package/migrations/gw-bet-prose-redesign.js +105 -0
  71. package/migrations/gw-drop-test-manifest.js +37 -0
  72. package/migrations/gw-register-serena-mcp.js +42 -0
  73. package/migrations/gw-relocate-hidden-skills.js +40 -0
  74. package/migrations/gw-seed-config-toml.js +24 -0
  75. package/migrations/index.json +40 -0
  76. package/package.json +70 -6
  77. package/src/AGENTS.md +36 -0
  78. package/src/config/config.toml +30 -0
  79. package/src/config/groundwork-state.json +5 -0
  80. package/src/docs/llms.txt +72 -0
  81. package/src/docs/principles/ai-native/agent-native-systems.md +90 -0
  82. package/src/docs/principles/ai-native/agentic-systems.md +78 -0
  83. package/src/docs/principles/ai-native/ai-engineering.md +100 -0
  84. package/src/docs/principles/ai-native/ai-native-product.md +76 -0
  85. package/src/docs/principles/delivery/cost-engineering.md +89 -0
  86. package/src/docs/principles/delivery/day-2-operational-baseline.md +57 -0
  87. package/src/docs/principles/delivery/devex.md +88 -0
  88. package/src/docs/principles/delivery/platform.md +101 -0
  89. package/src/docs/principles/delivery/progressive-delivery.md +92 -0
  90. package/src/docs/principles/design/ai-native-design.md +73 -0
  91. package/src/docs/principles/design/design-foundations.md +80 -0
  92. package/src/docs/principles/design/design-systems-and-tokens.md +72 -0
  93. package/src/docs/principles/design/interaction-and-motion.md +69 -0
  94. package/src/docs/principles/design/layout-and-space.md +72 -0
  95. package/src/docs/principles/design/usability-and-ux.md +79 -0
  96. package/src/docs/principles/design/visual-design.md +84 -0
  97. package/src/docs/principles/foundations/code-craft.md +86 -0
  98. package/src/docs/principles/foundations/continuous-discovery.md +75 -0
  99. package/src/docs/principles/foundations/documentation.md +102 -0
  100. package/src/docs/principles/foundations/prioritization-and-appetite.md +78 -0
  101. package/src/docs/principles/foundations/product-engineering.md +90 -0
  102. package/src/docs/principles/foundations/product-risks.md +89 -0
  103. package/src/docs/principles/foundations/requirements-and-specs.md +80 -0
  104. package/src/docs/principles/foundations/success-metrics.md +66 -0
  105. package/src/docs/principles/foundations/testing.md +108 -0
  106. package/src/docs/principles/index.md +24 -0
  107. package/src/docs/principles/quality/accessibility.md +88 -0
  108. package/src/docs/principles/quality/observability.md +84 -0
  109. package/src/docs/principles/quality/performance.md +84 -0
  110. package/src/docs/principles/quality/privacy.md +92 -0
  111. package/src/docs/principles/quality/reliability.md +89 -0
  112. package/src/docs/principles/quality/security.md +78 -0
  113. package/src/docs/principles/stack/postgres.md +100 -0
  114. package/src/docs/principles/system-design/api-design.md +86 -0
  115. package/src/docs/principles/system-design/architecture-decisions.md +81 -0
  116. package/src/docs/principles/system-design/code-structure.md +104 -0
  117. package/src/docs/principles/system-design/data-engineering.md +87 -0
  118. package/src/docs/principles/system-design/durable-execution.md +89 -0
  119. package/src/docs/principles/system-design/evolutionary-architecture.md +81 -0
  120. package/src/docs/principles/system-design/identity-and-access.md +76 -0
  121. package/src/docs/principles/system-design/integration-patterns.md +84 -0
  122. package/src/docs/principles/system-design/real-time.md +83 -0
  123. package/src/docs/principles/system-design/surface-architecture.md +74 -0
  124. package/src/docs/ways-of-working/documentation.md +69 -0
  125. package/src/docs/ways-of-working/how-we-work.md +76 -0
  126. package/src/docs/ways-of-working/units-of-work.md +40 -0
  127. package/src/engineer-skills/groundwork-electron-engineer/SKILL.md +123 -0
  128. package/src/engineer-skills/groundwork-electron-engineer/references/documentation.md +126 -0
  129. package/src/engineer-skills/groundwork-electron-engineer/references/ipc-contracts.md +138 -0
  130. package/src/engineer-skills/groundwork-electron-engineer/references/observability.md +37 -0
  131. package/src/engineer-skills/groundwork-electron-engineer/references/packaging-and-updates.md +82 -0
  132. package/src/engineer-skills/groundwork-electron-engineer/references/performance-and-reliability.md +80 -0
  133. package/src/engineer-skills/groundwork-electron-engineer/references/process-model.md +94 -0
  134. package/src/engineer-skills/groundwork-electron-engineer/references/security.md +107 -0
  135. package/src/engineer-skills/groundwork-electron-engineer/references/testing-and-smoke.md +129 -0
  136. package/src/engineer-skills/groundwork-electron-engineer/references/theming-and-tokens.md +74 -0
  137. package/src/engineer-skills/groundwork-electron-engineer/sync-anchor.md +22 -0
  138. package/src/engineer-skills/groundwork-flutter-engineer/SKILL.md +114 -0
  139. package/src/engineer-skills/groundwork-flutter-engineer/references/accessibility.md +92 -0
  140. package/src/engineer-skills/groundwork-flutter-engineer/references/architecture.md +189 -0
  141. package/src/engineer-skills/groundwork-flutter-engineer/references/data-and-contracts.md +136 -0
  142. package/src/engineer-skills/groundwork-flutter-engineer/references/documentation.md +122 -0
  143. package/src/engineer-skills/groundwork-flutter-engineer/references/navigation.md +122 -0
  144. package/src/engineer-skills/groundwork-flutter-engineer/references/observability.md +37 -0
  145. package/src/engineer-skills/groundwork-flutter-engineer/references/performance-and-reliability.md +100 -0
  146. package/src/engineer-skills/groundwork-flutter-engineer/references/platform-channels.md +93 -0
  147. package/src/engineer-skills/groundwork-flutter-engineer/references/releases-and-distribution.md +84 -0
  148. package/src/engineer-skills/groundwork-flutter-engineer/references/security.md +96 -0
  149. package/src/engineer-skills/groundwork-flutter-engineer/references/state-management.md +166 -0
  150. package/src/engineer-skills/groundwork-flutter-engineer/references/testing.md +160 -0
  151. package/src/engineer-skills/groundwork-flutter-engineer/references/theming-and-design-tokens.md +109 -0
  152. package/src/engineer-skills/groundwork-flutter-engineer/references/widgets-and-composition.md +123 -0
  153. package/src/engineer-skills/groundwork-flutter-engineer/sync-anchor.md +24 -0
  154. package/src/engineer-skills/groundwork-go-engineer/SKILL.md +174 -0
  155. package/src/engineer-skills/groundwork-go-engineer/references/api-design.md +82 -0
  156. package/src/engineer-skills/groundwork-go-engineer/references/architecture.md +42 -0
  157. package/src/engineer-skills/groundwork-go-engineer/references/capability-ports.md +50 -0
  158. package/src/engineer-skills/groundwork-go-engineer/references/code-craft-security.md +34 -0
  159. package/src/engineer-skills/groundwork-go-engineer/references/concurrency.md +108 -0
  160. package/src/engineer-skills/groundwork-go-engineer/references/documentation.md +130 -0
  161. package/src/engineer-skills/groundwork-go-engineer/references/go-services.md +77 -0
  162. package/src/engineer-skills/groundwork-go-engineer/references/http-handlers.md +172 -0
  163. package/src/engineer-skills/groundwork-go-engineer/references/implementation-patterns.md +156 -0
  164. package/src/engineer-skills/groundwork-go-engineer/references/integration-realtime-data.md +57 -0
  165. package/src/engineer-skills/groundwork-go-engineer/references/observability.md +49 -0
  166. package/src/engineer-skills/groundwork-go-engineer/references/postgres.md +41 -0
  167. package/src/engineer-skills/groundwork-go-engineer/references/reliability-performance.md +105 -0
  168. package/src/engineer-skills/groundwork-go-engineer/references/testing.md +201 -0
  169. package/src/engineer-skills/groundwork-go-engineer/sync-anchor.md +20 -0
  170. package/src/engineer-skills/groundwork-nextjs-engineer/SKILL.md +112 -0
  171. package/src/engineer-skills/groundwork-nextjs-engineer/references/accessibility.md +111 -0
  172. package/src/engineer-skills/groundwork-nextjs-engineer/references/architecture.md +323 -0
  173. package/src/engineer-skills/groundwork-nextjs-engineer/references/data-fetching.md +458 -0
  174. package/src/engineer-skills/groundwork-nextjs-engineer/references/documentation.md +324 -0
  175. package/src/engineer-skills/groundwork-nextjs-engineer/references/error-boundaries.md +383 -0
  176. package/src/engineer-skills/groundwork-nextjs-engineer/references/mutations-and-forms.md +396 -0
  177. package/src/engineer-skills/groundwork-nextjs-engineer/references/observability.md +48 -0
  178. package/src/engineer-skills/groundwork-nextjs-engineer/references/performance-and-deployment.md +947 -0
  179. package/src/engineer-skills/groundwork-nextjs-engineer/references/routing-and-navigation.md +405 -0
  180. package/src/engineer-skills/groundwork-nextjs-engineer/references/security.md +131 -0
  181. package/src/engineer-skills/groundwork-nextjs-engineer/references/server-components.md +394 -0
  182. package/src/engineer-skills/groundwork-nextjs-engineer/references/tailwind-and-styling.md +134 -0
  183. package/src/engineer-skills/groundwork-nextjs-engineer/references/testing.md +491 -0
  184. package/src/engineer-skills/groundwork-nextjs-engineer/references/type-system.md +368 -0
  185. package/src/engineer-skills/groundwork-nextjs-engineer/references/ux-principles.md +230 -0
  186. package/src/engineer-skills/groundwork-nextjs-engineer/references/visual-language.md +69 -0
  187. package/src/engineer-skills/groundwork-nextjs-engineer/sync-anchor.md +16 -0
  188. package/src/engineer-skills/groundwork-python-engineer/SKILL.md +199 -0
  189. package/src/engineer-skills/groundwork-python-engineer/references/api-standards.md +88 -0
  190. package/src/engineer-skills/groundwork-python-engineer/references/architecture.md +57 -0
  191. package/src/engineer-skills/groundwork-python-engineer/references/async-patterns.md +103 -0
  192. package/src/engineer-skills/groundwork-python-engineer/references/capability-ports.md +44 -0
  193. package/src/engineer-skills/groundwork-python-engineer/references/database.md +88 -0
  194. package/src/engineer-skills/groundwork-python-engineer/references/documentation-mcp.md +167 -0
  195. package/src/engineer-skills/groundwork-python-engineer/references/implementation-patterns.md +166 -0
  196. package/src/engineer-skills/groundwork-python-engineer/references/ml-pipelines.md +119 -0
  197. package/src/engineer-skills/groundwork-python-engineer/references/ml-systems-ai-engineering.md +74 -0
  198. package/src/engineer-skills/groundwork-python-engineer/references/observability.md +57 -0
  199. package/src/engineer-skills/groundwork-python-engineer/references/resilience.md +126 -0
  200. package/src/engineer-skills/groundwork-python-engineer/references/security.md +148 -0
  201. package/src/engineer-skills/groundwork-python-engineer/references/testing.md +216 -0
  202. package/src/engineer-skills/groundwork-python-engineer/sync-anchor.md +20 -0
  203. package/src/generators/add-capability/generator.ts +70 -0
  204. package/src/generators/add-capability/schema.json +30 -0
  205. package/src/generators/capabilities/llm/capability.json +28 -0
  206. package/src/generators/capabilities/llm/providers/anthropic/footprint.json +13 -0
  207. package/src/generators/capabilities/llm/providers/anthropic/stacks/go/internal/llm/llm.go.template +102 -0
  208. package/src/generators/capabilities/llm/providers/anthropic/stacks/python/src/__packageName__/adapters/llm.py.template +61 -0
  209. package/src/generators/capabilities/llm/providers/local/footprint.json +13 -0
  210. package/src/generators/capabilities/llm/providers/local/stacks/go/internal/llm/llm.go.template +102 -0
  211. package/src/generators/capabilities/llm/providers/local/stacks/python/src/__packageName__/adapters/llm.py.template +53 -0
  212. package/src/generators/capabilities/llm/providers/localai/footprint.json +29 -0
  213. package/src/generators/capabilities/llm/providers/localai/stacks/go/internal/llm/llm.go.template +102 -0
  214. package/src/generators/capabilities/llm/providers/localai/stacks/python/src/__packageName__/adapters/llm.py.template +53 -0
  215. package/src/generators/capabilities/llm/providers/none/footprint.json +9 -0
  216. package/src/generators/capabilities/llm/providers/none/stacks/go/internal/llm/llm.go.template +35 -0
  217. package/src/generators/capabilities/llm/providers/none/stacks/python/src/__packageName__/adapters/llm.py.template +25 -0
  218. package/src/generators/capabilities/llm/providers/ollama/footprint.json +20 -0
  219. package/src/generators/capabilities/llm/providers/ollama/stacks/go/internal/llm/llm.go.template +102 -0
  220. package/src/generators/capabilities/llm/providers/ollama/stacks/python/src/__packageName__/adapters/llm.py.template +53 -0
  221. package/src/generators/capabilities/llm/providers/openai/footprint.json +13 -0
  222. package/src/generators/capabilities/llm/providers/openai/stacks/go/internal/llm/llm.go.template +98 -0
  223. package/src/generators/capabilities/llm/providers/openai/stacks/python/src/__packageName__/adapters/llm.py.template +60 -0
  224. package/src/generators/capabilities/llm/stacks/go/internal/core/service/llm.go.template +12 -0
  225. package/src/generators/capabilities/llm/stacks/go/internal/llm/llm_test.go.template +33 -0
  226. package/src/generators/capabilities/llm/stacks/python/src/__packageName__/core/llm.py.template +15 -0
  227. package/src/generators/capabilities/llm/stacks/python/tests/contracts/test_llm.py.template +37 -0
  228. package/src/generators/cli-app/files/README.md.template +76 -0
  229. package/src/generators/cli-app/files/build.mjs.template +15 -0
  230. package/src/generators/cli-app/files/package.json.template +21 -0
  231. package/src/generators/cli-app/files/src/cli.ts.template +67 -0
  232. package/src/generators/cli-app/files/src/commands/hello.ts.template +17 -0
  233. package/src/generators/cli-app/files/src/commands/status.ts.template +23 -0
  234. package/src/generators/cli-app/files/src/core/client.test.ts.template +80 -0
  235. package/src/generators/cli-app/files/src/core/client.ts.template +64 -0
  236. package/src/generators/cli-app/files/src/registry.test.ts.template +35 -0
  237. package/src/generators/cli-app/files/src/registry.ts.template +31 -0
  238. package/src/generators/cli-app/files/tsconfig.json.template +16 -0
  239. package/src/generators/cli-app/files/tsconfig.test.json.template +11 -0
  240. package/src/generators/cli-app/generator.ts +138 -0
  241. package/src/generators/cli-app/schema.json +24 -0
  242. package/src/generators/docs-site/files/.gitignore.ejs +40 -0
  243. package/src/generators/docs-site/files/app/docs/__slug__/page.tsx +101 -0
  244. package/src/generators/docs-site/files/app/docs/layout.tsx +14 -0
  245. package/src/generators/docs-site/files/app/docs.css +43 -0
  246. package/src/generators/docs-site/files/app/layout.tsx +24 -0
  247. package/src/generators/docs-site/files/app/page.tsx +135 -0
  248. package/src/generators/docs-site/files/app/source.ts +8 -0
  249. package/src/generators/docs-site/files/components/mermaid.tsx +67 -0
  250. package/src/generators/docs-site/files/next.config.mjs +10 -0
  251. package/src/generators/docs-site/files/package.json +32 -0
  252. package/src/generators/docs-site/files/pnpm-workspace.yaml +7 -0
  253. package/src/generators/docs-site/files/postcss.config.mjs +6 -0
  254. package/src/generators/docs-site/files/source.config.ts +77 -0
  255. package/src/generators/docs-site/files/tailwind.config.js +10 -0
  256. package/src/generators/docs-site/files/tsconfig.json +27 -0
  257. package/src/generators/docs-site/generator.ts +476 -0
  258. package/src/generators/docs-site/schema.json +17 -0
  259. package/src/generators/electron-app/docs/principles/stack/electron/index.md +49 -0
  260. package/src/generators/electron-app/docs/principles/stack/electron/ipc-contracts.md +71 -0
  261. package/src/generators/electron-app/docs/principles/stack/electron/packaging-and-updates.md +59 -0
  262. package/src/generators/electron-app/docs/principles/stack/electron/process-model.md +53 -0
  263. package/src/generators/electron-app/docs/principles/stack/electron/security.md +70 -0
  264. package/src/generators/electron-app/docs/principles/stack/typescript/frontend.md +65 -0
  265. package/src/generators/electron-app/files/.gitignore.template +20 -0
  266. package/src/generators/electron-app/files/README.md.template +125 -0
  267. package/src/generators/electron-app/files/electron.vite.config.ts +31 -0
  268. package/src/generators/electron-app/files/eslint.config.mjs +92 -0
  269. package/src/generators/electron-app/files/forge.config.ts.template +44 -0
  270. package/src/generators/electron-app/files/package.json.template +54 -0
  271. package/src/generators/electron-app/files/playwright.config.ts +18 -0
  272. package/src/generators/electron-app/files/project.json.template +65 -0
  273. package/src/generators/electron-app/files/src/main/core-client.test.ts +81 -0
  274. package/src/generators/electron-app/files/src/main/core-client.ts +55 -0
  275. package/src/generators/electron-app/files/src/main/index.ts +157 -0
  276. package/src/generators/electron-app/files/src/main/ipc.ts +52 -0
  277. package/src/generators/electron-app/files/src/main/policy.test.ts +71 -0
  278. package/src/generators/electron-app/files/src/main/policy.ts +73 -0
  279. package/src/generators/electron-app/files/src/preload/index.ts +23 -0
  280. package/src/generators/electron-app/files/src/renderer/index.html.template +20 -0
  281. package/src/generators/electron-app/files/src/renderer/src/App.test.tsx +61 -0
  282. package/src/generators/electron-app/files/src/renderer/src/App.tsx.template +43 -0
  283. package/src/generators/electron-app/files/src/renderer/src/assets/main.css +40 -0
  284. package/src/generators/electron-app/files/src/renderer/src/env.d.ts +14 -0
  285. package/src/generators/electron-app/files/src/renderer/src/main.tsx +25 -0
  286. package/src/generators/electron-app/files/src/shared/ipc.ts +54 -0
  287. package/src/generators/electron-app/files/tests/smoke/app.spec.ts.template +133 -0
  288. package/src/generators/electron-app/files/tool/electron_exec.sh.template +83 -0
  289. package/src/generators/electron-app/files/tsconfig.json +7 -0
  290. package/src/generators/electron-app/files/tsconfig.node.json +27 -0
  291. package/src/generators/electron-app/files/tsconfig.web.json +22 -0
  292. package/src/generators/electron-app/files/vitest.config.ts +32 -0
  293. package/src/generators/electron-app/files/vitest.setup.ts +1 -0
  294. package/src/generators/electron-app/generator.ts +288 -0
  295. package/src/generators/electron-app/schema.json +23 -0
  296. package/src/generators/flutter-app/docs/principles/stack/flutter/architecture.md +78 -0
  297. package/src/generators/flutter-app/docs/principles/stack/flutter/index.md +38 -0
  298. package/src/generators/flutter-app/docs/principles/stack/flutter/platform-channels.md +51 -0
  299. package/src/generators/flutter-app/docs/principles/stack/flutter/releases-and-distribution.md +59 -0
  300. package/src/generators/flutter-app/docs/principles/stack/flutter/state-management.md +85 -0
  301. package/src/generators/flutter-app/docs/principles/stack/flutter/testing.md +86 -0
  302. package/src/generators/flutter-app/docs/principles/stack/flutter/widgets-and-composition.md +69 -0
  303. package/src/generators/flutter-app/files/.gitignore.template +30 -0
  304. package/src/generators/flutter-app/files/README.md.template +100 -0
  305. package/src/generators/flutter-app/files/analysis_options.yaml.template +18 -0
  306. package/src/generators/flutter-app/files/integration_test/app_test.dart.template +64 -0
  307. package/src/generators/flutter-app/files/lib/app.dart.template +24 -0
  308. package/src/generators/flutter-app/files/lib/config/app_config.dart +15 -0
  309. package/src/generators/flutter-app/files/lib/data/repositories/status_repository.dart +36 -0
  310. package/src/generators/flutter-app/files/lib/data/services/api_client.dart +71 -0
  311. package/src/generators/flutter-app/files/lib/domain/models/health_status.dart +23 -0
  312. package/src/generators/flutter-app/files/lib/main.dart +11 -0
  313. package/src/generators/flutter-app/files/lib/router.dart +23 -0
  314. package/src/generators/flutter-app/files/lib/ui/core/theme/app_theme.dart +110 -0
  315. package/src/generators/flutter-app/files/lib/ui/home/home_view.dart +89 -0
  316. package/src/generators/flutter-app/files/lib/ui/home/home_view_model.dart.template +38 -0
  317. package/src/generators/flutter-app/files/project.json.template +51 -0
  318. package/src/generators/flutter-app/files/pubspec.yaml.template +47 -0
  319. package/src/generators/flutter-app/files/test/api_client_test.dart.template +63 -0
  320. package/src/generators/flutter-app/files/test/fakes/fake_status_repository.dart.template +19 -0
  321. package/src/generators/flutter-app/files/test/home_view_test.dart.template +58 -0
  322. package/src/generators/flutter-app/files/tool/flutter_exec.sh.template +60 -0
  323. package/src/generators/flutter-app/generator.ts +362 -0
  324. package/src/generators/flutter-app/schema.json +23 -0
  325. package/src/generators/go-microservice/docs/principles/stack/go/concurrency.md +123 -0
  326. package/src/generators/go-microservice/docs/principles/stack/go/index.md +70 -0
  327. package/src/generators/go-microservice/docs/principles/stack/go/testing.md +168 -0
  328. package/src/generators/go-microservice/files/.air.toml.template +38 -0
  329. package/src/generators/go-microservice/files/.env.template +4 -0
  330. package/src/generators/go-microservice/files/.golangci.yml.template +82 -0
  331. package/src/generators/go-microservice/files/Dockerfile.dev.template +12 -0
  332. package/src/generators/go-microservice/files/asyncapi-pubsub.yaml.template +33 -0
  333. package/src/generators/go-microservice/files/asyncapi-ws.yaml.template +34 -0
  334. package/src/generators/go-microservice/files/cmd/api/main.go.template +149 -0
  335. package/src/generators/go-microservice/files/cmd/api/main_test.go.template +99 -0
  336. package/src/generators/go-microservice/files/cmd/worker/cleanup/main.go.template +39 -0
  337. package/src/generators/go-microservice/files/db/schema.sql.template +24 -0
  338. package/src/generators/go-microservice/files/go.mod.template +39 -0
  339. package/src/generators/go-microservice/files/internal/config/config.go.template +52 -0
  340. package/src/generators/go-microservice/files/internal/config/otel.go.template +93 -0
  341. package/src/generators/go-microservice/files/internal/core/domain/errors.go.template +16 -0
  342. package/src/generators/go-microservice/files/internal/core/domain/model.go.template +28 -0
  343. package/src/generators/go-microservice/files/internal/core/domain/user.go.template +13 -0
  344. package/src/generators/go-microservice/files/internal/core/pagination.go.template +16 -0
  345. package/src/generators/go-microservice/files/internal/core/service/app_service.go.template +79 -0
  346. package/src/generators/go-microservice/files/internal/core/service/event_hub.go.template +9 -0
  347. package/src/generators/go-microservice/files/internal/core/service/message_queue.go.template +10 -0
  348. package/src/generators/go-microservice/files/internal/core/service/outbox_repository.go.template +31 -0
  349. package/src/generators/go-microservice/files/internal/core/service/repository.go.template +23 -0
  350. package/src/generators/go-microservice/files/internal/core/service/user_repository.go.template +15 -0
  351. package/src/generators/go-microservice/files/internal/core/service/user_service.go.template +43 -0
  352. package/src/generators/go-microservice/files/internal/entrypoints/api/app_handler.go.template +108 -0
  353. package/src/generators/go-microservice/files/internal/entrypoints/api/auth_middleware_test.go.template +52 -0
  354. package/src/generators/go-microservice/files/internal/entrypoints/api/clerk_webhook.go.template +202 -0
  355. package/src/generators/go-microservice/files/internal/entrypoints/api/clerk_webhook_test.go.template +82 -0
  356. package/src/generators/go-microservice/files/internal/entrypoints/api/health_handler.go.template +80 -0
  357. package/src/generators/go-microservice/files/internal/entrypoints/api/idempotency/middleware.go.template +87 -0
  358. package/src/generators/go-microservice/files/internal/entrypoints/api/idempotency/middleware_test.go.template +76 -0
  359. package/src/generators/go-microservice/files/internal/entrypoints/api/idempotency/repository.go.template +37 -0
  360. package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_auth.go.template +40 -0
  361. package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_loadshed.go.template +38 -0
  362. package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_logging.go.template +40 -0
  363. package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_ratelimit.go.template +48 -0
  364. package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_test.go.template +81 -0
  365. package/src/generators/go-microservice/files/internal/entrypoints/api/router.go.template +105 -0
  366. package/src/generators/go-microservice/files/internal/entrypoints/api/types.go.template +70 -0
  367. package/src/generators/go-microservice/files/internal/entrypoints/api/websocket_handler.go.template +39 -0
  368. package/src/generators/go-microservice/files/internal/httpclient/http_client.go.template +87 -0
  369. package/src/generators/go-microservice/files/internal/kafka/kafka.go.template +34 -0
  370. package/src/generators/go-microservice/files/internal/postgres/postgres.go.template +195 -0
  371. package/src/generators/go-microservice/files/internal/postgres/postgres_test.go.template +156 -0
  372. package/src/generators/go-microservice/files/internal/postgres/user_repository.go.template +56 -0
  373. package/src/generators/go-microservice/files/internal/pubsub/gcp_pubsub.go.template +35 -0
  374. package/src/generators/go-microservice/files/internal/websocket/client.go.template +151 -0
  375. package/src/generators/go-microservice/files/internal/websocket/hub.go.template +261 -0
  376. package/src/generators/go-microservice/files/scripts/apply-schema.sh.template +21 -0
  377. package/src/generators/go-microservice/files/tools/tools.go.template +10 -0
  378. package/src/generators/go-microservice/generator.ts +240 -0
  379. package/src/generators/go-microservice/schema.json +63 -0
  380. package/src/generators/nextjs-app/docs/principles/stack/typescript/frontend.md +65 -0
  381. package/src/generators/nextjs-app/files/.dockerignore.template +7 -0
  382. package/src/generators/nextjs-app/files/.env.example.template +24 -0
  383. package/src/generators/nextjs-app/files/.gitignore.template +5 -0
  384. package/src/generators/nextjs-app/files/Dockerfile +53 -0
  385. package/src/generators/nextjs-app/files/app/(auth)/sign-in/__sign-in__/page.tsx.template +9 -0
  386. package/src/generators/nextjs-app/files/app/(auth)/sign-up/__sign-up__/page.tsx.template +9 -0
  387. package/src/generators/nextjs-app/files/app/api/config/route.ts.template +39 -0
  388. package/src/generators/nextjs-app/files/app/api/healthz/route.test.ts +15 -0
  389. package/src/generators/nextjs-app/files/app/api/healthz/route.ts +5 -0
  390. package/src/generators/nextjs-app/files/app/api/proxy/__path__/route.test.ts.template +55 -0
  391. package/src/generators/nextjs-app/files/app/api/proxy/__path__/route.ts.template +126 -0
  392. package/src/generators/nextjs-app/files/app/error.tsx +39 -0
  393. package/src/generators/nextjs-app/files/app/global-error.tsx +68 -0
  394. package/src/generators/nextjs-app/files/app/globals.css +105 -0
  395. package/src/generators/nextjs-app/files/app/layout.tsx +59 -0
  396. package/src/generators/nextjs-app/files/app/loading.tsx +13 -0
  397. package/src/generators/nextjs-app/files/app/not-found.tsx +30 -0
  398. package/src/generators/nextjs-app/files/app/page.tsx +20 -0
  399. package/src/generators/nextjs-app/files/components/providers/default.tsx +19 -0
  400. package/src/generators/nextjs-app/files/components/providers/production.tsx +32 -0
  401. package/src/generators/nextjs-app/files/components/providers/telemetry.tsx +76 -0
  402. package/src/generators/nextjs-app/files/components/render-smoke.test.tsx +29 -0
  403. package/src/generators/nextjs-app/files/components/theme-provider.tsx +11 -0
  404. package/src/generators/nextjs-app/files/components.json +21 -0
  405. package/src/generators/nextjs-app/files/eslint.config.mjs +120 -0
  406. package/src/generators/nextjs-app/files/hooks/use-toast.ts +7 -0
  407. package/src/generators/nextjs-app/files/instrumentation.ts +90 -0
  408. package/src/generators/nextjs-app/files/lib/api/fetcher.ts.template +130 -0
  409. package/src/generators/nextjs-app/files/lib/config.ts +21 -0
  410. package/src/generators/nextjs-app/files/lib/logger.ts +29 -0
  411. package/src/generators/nextjs-app/files/lib/schemas/index.ts +19 -0
  412. package/src/generators/nextjs-app/files/lib/utils.ts +6 -0
  413. package/src/generators/nextjs-app/files/next.config.mjs +9 -0
  414. package/src/generators/nextjs-app/files/package.json +70 -0
  415. package/src/generators/nextjs-app/files/postcss.config.mjs +8 -0
  416. package/src/generators/nextjs-app/files/proxy.test.ts.template +30 -0
  417. package/src/generators/nextjs-app/files/proxy.ts +31 -0
  418. package/src/generators/nextjs-app/files/public/.gitkeep +1 -0
  419. package/src/generators/nextjs-app/files/tsconfig.json +42 -0
  420. package/src/generators/nextjs-app/files/vitest.config.mts +15 -0
  421. package/src/generators/nextjs-app/files/vitest.setup.ts +7 -0
  422. package/src/generators/nextjs-app/generator.ts +307 -0
  423. package/src/generators/nextjs-app/schema.json +44 -0
  424. package/src/generators/python-microservice/docs/principles/stack/python/async.md +168 -0
  425. package/src/generators/python-microservice/docs/principles/stack/python/documentation.md +240 -0
  426. package/src/generators/python-microservice/docs/principles/stack/python/mcp.md +147 -0
  427. package/src/generators/python-microservice/docs/principles/stack/python/resilience.md +193 -0
  428. package/src/generators/python-microservice/docs/principles/stack/python/testing.md +322 -0
  429. package/src/generators/python-microservice/files/.env.example.template +30 -0
  430. package/src/generators/python-microservice/files/Dockerfile.template +36 -0
  431. package/src/generators/python-microservice/files/db/schema.sql.template +19 -0
  432. package/src/generators/python-microservice/files/pyproject.toml.template +76 -0
  433. package/src/generators/python-microservice/files/scripts/apply-schema.sh.template +25 -0
  434. package/src/generators/python-microservice/files/src/__packageName__/adapters/comfyui.py.template +87 -0
  435. package/src/generators/python-microservice/files/src/__packageName__/adapters/config.py.template +48 -0
  436. package/src/generators/python-microservice/files/src/__packageName__/adapters/database.py.template +21 -0
  437. package/src/generators/python-microservice/files/src/__packageName__/adapters/message_queue.py.template +29 -0
  438. package/src/generators/python-microservice/files/src/__packageName__/adapters/repository.py.template +130 -0
  439. package/src/generators/python-microservice/files/src/__packageName__/adapters/telemetry.py.template +68 -0
  440. package/src/generators/python-microservice/files/src/__packageName__/adapters/websocket_hub.py.template +36 -0
  441. package/src/generators/python-microservice/files/src/__packageName__/core/domain/entities.py.template +22 -0
  442. package/src/generators/python-microservice/files/src/__packageName__/core/domain/exceptions.py.template +43 -0
  443. package/src/generators/python-microservice/files/src/__packageName__/core/ports.py.template +42 -0
  444. package/src/generators/python-microservice/files/src/__packageName__/core/service/example_service.py.template +68 -0
  445. package/src/generators/python-microservice/files/src/__packageName__/entrypoints/api/dependencies.py.template +50 -0
  446. package/src/generators/python-microservice/files/src/__packageName__/entrypoints/api/middleware.py.template +131 -0
  447. package/src/generators/python-microservice/files/src/__packageName__/entrypoints/api/router.py.template +37 -0
  448. package/src/generators/python-microservice/files/src/__packageName__/entrypoints/api/websocket_handler.py.template +20 -0
  449. package/src/generators/python-microservice/files/src/__packageName__/entrypoints/worker/cleanup.py.template +35 -0
  450. package/src/generators/python-microservice/files/src/__packageName__/entrypoints/worker/worker.py.template +28 -0
  451. package/src/generators/python-microservice/files/src/__packageName__/main.py.template +108 -0
  452. package/src/generators/python-microservice/files/tests/test_main.py.template +74 -0
  453. package/src/generators/python-microservice/files/tests/test_middleware.py.template +109 -0
  454. package/src/generators/python-microservice/files/tests/test_worker.py.template +16 -0
  455. package/src/generators/python-microservice/generator.ts +286 -0
  456. package/src/generators/python-microservice/schema.json +86 -0
  457. package/src/generators/shared/brand-tokens.ts +301 -0
  458. package/src/generators/shared/capabilities.ts +349 -0
  459. package/src/generators/shared/provenance.ts +61 -0
  460. package/src/generators/shared/scaffold-helpers.ts +309 -0
  461. package/src/generators/system-test-runner/NATIVE-CHECK-CONTRACT.md +20 -0
  462. package/src/generators/system-test-runner/files/tests/bets/.gitkeep +0 -0
  463. package/src/generators/system-test-runner/files/tests/bets/_archive/.gitkeep +0 -0
  464. package/src/generators/system-test-runner/files/tests/conftest.py.template +503 -0
  465. package/src/generators/system-test-runner/files/tests/pyproject.toml.template +20 -0
  466. package/src/generators/system-test-runner/files/tests/system/pages/__init__.py.template +9 -0
  467. package/src/generators/system-test-runner/files/tests/system/pages/base_page.py.template +36 -0
  468. package/src/generators/system-test-runner/files/tests/system/test_a11y_smoke.py.template +132 -0
  469. package/src/generators/system-test-runner/files/tests/system/test_contract_conformance.py.template +140 -0
  470. package/src/generators/system-test-runner/files/tests/system/test_layout_geometry.py.template +109 -0
  471. package/src/generators/system-test-runner/files/tests/system/test_render_smoke.py.template +257 -0
  472. package/src/generators/system-test-runner/files/tests/system/test_system.py.template +158 -0
  473. package/src/generators/system-test-runner/files/tests/system/test_token_conformance.py.template +206 -0
  474. package/src/generators/system-test-runner/files/tests/system/test_visual_regression.py.template +104 -0
  475. package/src/generators/system-test-runner/generator.ts +196 -0
  476. package/src/generators/system-test-runner/schema.json +24 -0
  477. package/src/generators/workspace-dev-cli/cli-src/build.mjs +42 -0
  478. package/src/generators/workspace-dev-cli/cli-src/dist/dev-bundle.js +2168 -0
  479. package/src/generators/workspace-dev-cli/cli-src/src/commands/bet.ts +442 -0
  480. package/src/generators/workspace-dev-cli/cli-src/src/commands/completion.ts +87 -0
  481. package/src/generators/workspace-dev-cli/cli-src/src/commands/doctor.ts +139 -0
  482. package/src/generators/workspace-dev-cli/cli-src/src/commands/lifecycle.ts +548 -0
  483. package/src/generators/workspace-dev-cli/cli-src/src/commands/quality.ts +127 -0
  484. package/src/generators/workspace-dev-cli/cli-src/src/commands/surface.ts +214 -0
  485. package/src/generators/workspace-dev-cli/cli-src/src/index.ts +127 -0
  486. package/src/generators/workspace-dev-cli/cli-src/src/registry.ts +194 -0
  487. package/src/generators/workspace-dev-cli/cli-src/src/theme/color.ts +130 -0
  488. package/src/generators/workspace-dev-cli/cli-src/src/theme/render.ts +158 -0
  489. package/src/generators/workspace-dev-cli/cli-src/src/theme/tokens.ts +122 -0
  490. package/src/generators/workspace-dev-cli/cli-src/src/util/context.ts +43 -0
  491. package/src/generators/workspace-dev-cli/cli-src/src/util/extensions.ts +99 -0
  492. package/src/generators/workspace-dev-cli/cli-src/src/util/paths.ts +46 -0
  493. package/src/generators/workspace-dev-cli/cli-src/src/util/proc.ts +106 -0
  494. package/src/generators/workspace-dev-cli/cli-src/src/util/prompt.ts +108 -0
  495. package/src/generators/workspace-dev-cli/cli-src/src/util/runners.ts +70 -0
  496. package/src/generators/workspace-dev-cli/cli-src/src/util/services.ts +221 -0
  497. package/src/generators/workspace-dev-cli/cli-src/src/util/version.ts +21 -0
  498. package/src/generators/workspace-dev-cli/cli-src/tsconfig.json +16 -0
  499. package/src/generators/workspace-dev-cli/files/.agents/skills/workspace-cli/SKILL.md.template +74 -0
  500. package/src/generators/workspace-dev-cli/files/dev.template +16 -0
  501. package/src/generators/workspace-dev-cli/files/docker-compose.yml.template +20 -0
  502. package/src/generators/workspace-dev-cli/files/scripts/cli/templates/milestone-test.pytmpl.template +46 -0
  503. package/src/generators/workspace-dev-cli/files/scripts/cli/templates/slice-test.pytmpl.template +38 -0
  504. package/src/generators/workspace-dev-cli/generator.ts +136 -0
  505. package/src/generators/workspace-dev-cli/schema.json +22 -0
  506. package/src/hidden-skills/code-intelligence.md +135 -0
  507. package/src/hidden-skills/groundwork-architect/SKILL.md +114 -0
  508. package/src/hidden-skills/groundwork-architect/references/agentic-systems.md +44 -0
  509. package/src/hidden-skills/groundwork-architect/references/ai-native-architecture.md +37 -0
  510. package/src/hidden-skills/groundwork-architect/references/api-and-contracts.md +45 -0
  511. package/src/hidden-skills/groundwork-architect/references/core-and-boundaries.md +45 -0
  512. package/src/hidden-skills/groundwork-architect/references/data-architecture.md +33 -0
  513. package/src/hidden-skills/groundwork-architect/references/decision-records.md +34 -0
  514. package/src/hidden-skills/groundwork-architect/references/durable-execution.md +45 -0
  515. package/src/hidden-skills/groundwork-architect/references/evolutionary-architecture.md +37 -0
  516. package/src/hidden-skills/groundwork-architect/references/identity-and-access.md +41 -0
  517. package/src/hidden-skills/groundwork-architect/references/integration-patterns.md +39 -0
  518. package/src/hidden-skills/groundwork-architect/references/observability.md +36 -0
  519. package/src/hidden-skills/groundwork-architect/references/performance-and-scale.md +41 -0
  520. package/src/hidden-skills/groundwork-architect/references/platform-and-delivery.md +47 -0
  521. package/src/hidden-skills/groundwork-architect/references/realtime-and-async.md +28 -0
  522. package/src/hidden-skills/groundwork-architect/references/reliability.md +31 -0
  523. package/src/hidden-skills/groundwork-architect/references/security-and-trust.md +47 -0
  524. package/src/hidden-skills/groundwork-architect/references/surface-architecture.md +40 -0
  525. package/src/hidden-skills/groundwork-architect/sync-anchor.md +34 -0
  526. package/src/hidden-skills/groundwork-architecture/architecture-template.md +50 -0
  527. package/src/hidden-skills/groundwork-architecture/instructions.md +139 -0
  528. package/src/hidden-skills/groundwork-architecture/phases/01-context-ingestion.md +18 -0
  529. package/src/hidden-skills/groundwork-architecture/phases/02-technical-constraints.md +27 -0
  530. package/src/hidden-skills/groundwork-architecture/phases/03-service-design.md +19 -0
  531. package/src/hidden-skills/groundwork-architecture/phases/04-data-flow-communication.md +23 -0
  532. package/src/hidden-skills/groundwork-architecture/phases/05-component-boundaries-contracts.md +17 -0
  533. package/src/hidden-skills/groundwork-architecture/phases/06-draft-review-present.md +38 -0
  534. package/src/hidden-skills/groundwork-architecture/phases/07-commit.md +33 -0
  535. package/src/hidden-skills/groundwork-architecture/templates/architecture-cache.md +43 -0
  536. package/src/hidden-skills/groundwork-architecture-extract/instructions.md +163 -0
  537. package/src/hidden-skills/groundwork-architecture-extract/templates/architecture-extract-cache.md +21 -0
  538. package/src/hidden-skills/groundwork-bet/briefs/acceptance-auditor.md +68 -0
  539. package/src/hidden-skills/groundwork-bet/briefs/blind-reviewer.md +56 -0
  540. package/src/hidden-skills/groundwork-bet/briefs/coverage-auditor.md +95 -0
  541. package/src/hidden-skills/groundwork-bet/briefs/edge-case-tracer.md +64 -0
  542. package/src/hidden-skills/groundwork-bet/briefs/experience-auditor.md +83 -0
  543. package/src/hidden-skills/groundwork-bet/briefs/slice-worker.md +257 -0
  544. package/src/hidden-skills/groundwork-bet/instructions.md +88 -0
  545. package/src/hidden-skills/groundwork-bet/templates/bet-progress-test.md +115 -0
  546. package/src/hidden-skills/groundwork-bet/templates/change-proposal.md +38 -0
  547. package/src/hidden-skills/groundwork-bet/templates/decomposition/meta.json +4 -0
  548. package/src/hidden-skills/groundwork-bet/templates/decomposition/milestone-index.md +31 -0
  549. package/src/hidden-skills/groundwork-bet/templates/decomposition/slice.md +31 -0
  550. package/src/hidden-skills/groundwork-bet/templates/pitch.md +45 -0
  551. package/src/hidden-skills/groundwork-bet/templates/technical-design/01-ui-design.md +51 -0
  552. package/src/hidden-skills/groundwork-bet/templates/technical-design/02-data-flows.md +36 -0
  553. package/src/hidden-skills/groundwork-bet/templates/technical-design/03-api-design.md +90 -0
  554. package/src/hidden-skills/groundwork-bet/templates/technical-design/04-data-design.md +29 -0
  555. package/src/hidden-skills/groundwork-bet/workflows/01-discovery.md +200 -0
  556. package/src/hidden-skills/groundwork-bet/workflows/02-design.md +178 -0
  557. package/src/hidden-skills/groundwork-bet/workflows/03-decomposition.md +242 -0
  558. package/src/hidden-skills/groundwork-bet/workflows/04-delivery.md +226 -0
  559. package/src/hidden-skills/groundwork-bet/workflows/05-validation.md +210 -0
  560. package/src/hidden-skills/groundwork-design-system/instructions.md +125 -0
  561. package/src/hidden-skills/groundwork-design-system/templates/brand-tokens.md +182 -0
  562. package/src/hidden-skills/groundwork-design-system/templates/design-system-cache.md +64 -0
  563. package/src/hidden-skills/groundwork-design-system/tracks/_foundation.md +136 -0
  564. package/src/hidden-skills/groundwork-design-system/tracks/agentic-protocol.md +269 -0
  565. package/src/hidden-skills/groundwork-design-system/tracks/cli.md +355 -0
  566. package/src/hidden-skills/groundwork-design-system/tracks/graphical-ui.md +330 -0
  567. package/src/hidden-skills/groundwork-design-system-extract/instructions.md +124 -0
  568. package/src/hidden-skills/groundwork-design-system-extract/templates/design-system-extract-cache.md +19 -0
  569. package/src/hidden-skills/groundwork-designer/SKILL.md +108 -0
  570. package/src/hidden-skills/groundwork-designer/references/accessibility.md +33 -0
  571. package/src/hidden-skills/groundwork-designer/references/ai-native-design.md +37 -0
  572. package/src/hidden-skills/groundwork-designer/references/design-review.md +29 -0
  573. package/src/hidden-skills/groundwork-designer/references/design-systems-and-tokens.md +33 -0
  574. package/src/hidden-skills/groundwork-designer/references/interaction-and-motion.md +37 -0
  575. package/src/hidden-skills/groundwork-designer/references/layout-and-space.md +33 -0
  576. package/src/hidden-skills/groundwork-designer/references/usability-and-ux.md +33 -0
  577. package/src/hidden-skills/groundwork-designer/references/visual-craft.md +49 -0
  578. package/src/hidden-skills/groundwork-designer/sync-anchor.md +20 -0
  579. package/src/hidden-skills/groundwork-doc-sync/instructions.md +100 -0
  580. package/src/hidden-skills/groundwork-elicit/instructions.md +66 -0
  581. package/src/hidden-skills/groundwork-elicit/methods.md +65 -0
  582. package/src/hidden-skills/groundwork-infra-adopt/instructions.md +168 -0
  583. package/src/hidden-skills/groundwork-infra-adopt/templates/infra-adopt-cache.md +21 -0
  584. package/src/hidden-skills/groundwork-mvp/instructions.md +223 -0
  585. package/src/hidden-skills/groundwork-mvp/templates/mvp-cache.md +9 -0
  586. package/src/hidden-skills/groundwork-patch/instructions.md +40 -0
  587. package/src/hidden-skills/groundwork-persona/instructions.md +65 -0
  588. package/src/hidden-skills/groundwork-product/SKILL.md +102 -0
  589. package/src/hidden-skills/groundwork-product/references/ai-native-product.md +45 -0
  590. package/src/hidden-skills/groundwork-product/references/discovery-and-opportunity.md +38 -0
  591. package/src/hidden-skills/groundwork-product/references/product-risks.md +52 -0
  592. package/src/hidden-skills/groundwork-product/references/requirements-and-specs.md +39 -0
  593. package/src/hidden-skills/groundwork-product/references/scope-and-sequencing.md +35 -0
  594. package/src/hidden-skills/groundwork-product/references/shaping-and-appetite.md +48 -0
  595. package/src/hidden-skills/groundwork-product/references/success-metrics-and-signals.md +37 -0
  596. package/src/hidden-skills/groundwork-product/sync-anchor.md +19 -0
  597. package/src/hidden-skills/groundwork-product-brief/instructions.md +231 -0
  598. package/src/hidden-skills/groundwork-product-brief-extract/instructions.md +139 -0
  599. package/src/hidden-skills/groundwork-product-brief-extract/templates/product-brief-extract-cache.md +17 -0
  600. package/src/hidden-skills/groundwork-review/checklists/architecture.md +93 -0
  601. package/src/hidden-skills/groundwork-review/checklists/bet-pitch.md +94 -0
  602. package/src/hidden-skills/groundwork-review/checklists/decomposition.md +135 -0
  603. package/src/hidden-skills/groundwork-review/checklists/design-system.md +85 -0
  604. package/src/hidden-skills/groundwork-review/checklists/domain-entity.md +66 -0
  605. package/src/hidden-skills/groundwork-review/checklists/implementation-readiness.md +47 -0
  606. package/src/hidden-skills/groundwork-review/checklists/infrastructure.md +68 -0
  607. package/src/hidden-skills/groundwork-review/checklists/maturity.md +71 -0
  608. package/src/hidden-skills/groundwork-review/checklists/product-brief.md +69 -0
  609. package/src/hidden-skills/groundwork-review/checklists/technical-design.md +112 -0
  610. package/src/hidden-skills/groundwork-review/instructions.md +181 -0
  611. package/src/hidden-skills/groundwork-scaffold/instructions.md +254 -0
  612. package/src/hidden-skills/groundwork-scaffold/phases/01-ingestion-service-mapping.md +87 -0
  613. package/src/hidden-skills/groundwork-scaffold/phases/02-scaffolding-execution.md +15 -0
  614. package/src/hidden-skills/groundwork-scaffold/phases/03-service-documentation-api-stubs.md +100 -0
  615. package/src/hidden-skills/groundwork-scaffold/phases/04-infrastructure-verification.md +17 -0
  616. package/src/hidden-skills/groundwork-scaffold/phases/05-draft-review.md +19 -0
  617. package/src/hidden-skills/groundwork-scaffold/phases/06-commit.md +19 -0
  618. package/src/hidden-skills/groundwork-scaffold/templates/scaffold-cache.md +23 -0
  619. package/src/hidden-skills/groundwork-scan/instructions.md +164 -0
  620. package/src/hidden-skills/groundwork-scan/references/digest-schema.md +66 -0
  621. package/src/hidden-skills/groundwork-scan/references/exclusions.md +44 -0
  622. package/src/hidden-skills/groundwork-scan/templates/architecture-findings.md +42 -0
  623. package/src/hidden-skills/groundwork-scan/templates/design-findings.md +23 -0
  624. package/src/hidden-skills/groundwork-scan/templates/overview.md +26 -0
  625. package/src/hidden-skills/groundwork-scan/templates/product-findings.md +23 -0
  626. package/src/hidden-skills/groundwork-scan/templates/scan-state.json +19 -0
  627. package/src/hidden-skills/groundwork-stack-forge/instructions.md +150 -0
  628. package/src/hidden-skills/groundwork-stack-forge/references/authoring-engineer-skills.md +107 -0
  629. package/src/hidden-skills/groundwork-surface-activation/instructions.md +138 -0
  630. package/src/hidden-skills/groundwork-update/briefs/reconcile-worker.md +196 -0
  631. package/src/hidden-skills/groundwork-update/instructions.md +200 -0
  632. package/src/hidden-skills/groundwork-writer/SKILL.md +278 -0
  633. package/src/hidden-skills/maturity-model.md +125 -0
  634. package/src/hidden-skills/operating-contract.md +400 -0
  635. package/src/hidden-skills/repo-map-schema.md +90 -0
  636. package/src/hidden-skills/templates/adr.md +57 -0
  637. package/src/hidden-skills/templates/capability-ports.md +71 -0
  638. package/src/hidden-skills/templates/discovery-notes.md +33 -0
  639. package/src/hidden-skills/templates/domain-entity.md +80 -0
  640. package/src/hidden-skills/templates/gap-ledger.md +21 -0
  641. package/src/hidden-skills/templates/handoff.md +37 -0
  642. package/src/hidden-skills/templates/maturity.md +39 -0
  643. package/src/hidden-skills/templates/surfaces.md +207 -0
  644. package/src/skills/groundwork-check/SKILL.md +56 -0
  645. package/src/skills/groundwork-check/instructions.md +70 -0
  646. package/src/skills/groundwork-orchestrator/SKILL.md +176 -0
  647. package/src/skills/groundwork-orchestrator/workflow-index.md +50 -0
@@ -0,0 +1,158 @@
1
+ """Real, discovery-driven system tests. Parametrized over every APP service
2
+ found in the workspace docker-compose.yml (see conftest.services_manifest).
3
+
4
+ FAIL LOUD: the span tests are gated by GROUNDWORK_REQUIRE_TRACES=1. When that
5
+ flag is set (CI, `./dev test integration`), an unreachable backend or a
6
+ missing span is a FAILURE, not a skip.
7
+ """
8
+
9
+ import os
10
+ import time
11
+ import uuid
12
+
13
+ import httpx
14
+ import pytest
15
+
16
+ from conftest import JAEGER_URL, _base_url, _discover_services
17
+
18
+ REQUIRE_TRACES = os.environ.get("GROUNDWORK_REQUIRE_TRACES") == "1"
19
+ # BatchSpanProcessor flushes ~every 5s; give spans time to land.
20
+ EXPORT_TIMEOUT_S = 30
21
+
22
+ # Build params at import time so pytest can show one case per service. An empty
23
+ # workspace yields zero params (and the suite is a no-op, which is correct).
24
+ _SERVICES = _discover_services()
25
+ _PARAMS = [pytest.param(s, id=s["name"]) for s in _SERVICES]
26
+
27
+
28
+ def _fetch_trace(trace_id: str) -> dict | None:
29
+ deadline = time.time() + EXPORT_TIMEOUT_S
30
+ while time.time() < deadline:
31
+ resp = httpx.get(f"{JAEGER_URL}/api/traces/{trace_id}", timeout=3.0)
32
+ if resp.status_code == 200 and resp.json().get("data"):
33
+ return resp.json()["data"][0]
34
+ time.sleep(1)
35
+ return None
36
+
37
+
38
+ @pytest.mark.parametrize("svc", _PARAMS)
39
+ def test_every_service_is_healthy(cluster, svc):
40
+ """Each discovered service answers its health endpoint. Synchronous on
41
+ purpose (like the trace probes below): a plain GET needs no event loop, and
42
+ avoiding an async fixture keeps the suite robust across pytest-asyncio /
43
+ Python versions."""
44
+ if svc["host_port"] is None:
45
+ pytest.skip(f"{svc['name']} has no published host port")
46
+ url = f"{_base_url(svc)}{svc['health_path']}"
47
+ resp = httpx.get(url, timeout=5.0)
48
+ assert resp.status_code == 200, f"{url} -> {resp.status_code}"
49
+ data = resp.json()
50
+ if svc["type"] == "go":
51
+ assert data.get("status") == "ok", f"{svc['name']} status: {data}"
52
+ assert data.get("checks", {}).get("db") == "ok", f"{svc['name']} db: {data}"
53
+ else:
54
+ # Python FastAPI returns {"status": "alive"}; Next returns its own shape.
55
+ assert data.get("status") in {"ok", "alive", "ready", "healthy"}, f"{svc['name']}: {data}"
56
+
57
+
58
+ @pytest.mark.parametrize("svc", _PARAMS)
59
+ def test_instrumented_get_exports_span(cluster, svc):
60
+ """A traced GET to an instrumented route produces a span that reaches jaeger.
61
+
62
+ Go and Python both export spans over OTLP: Go via otel.go, Python via the
63
+ FastAPI instrumentation wired in adapters/telemetry.py. Next.js server-side
64
+ tracing is unverified through this harness (no domain GET route to probe),
65
+ so it xfails here.
66
+ """
67
+ if svc["type"] not in ("go", "python"):
68
+ pytest.xfail(f"{svc['type']} trace export not verified through this harness (TODO)")
69
+ if svc["host_port"] is None:
70
+ pytest.skip(f"{svc['name']} has no published host port")
71
+
72
+ trace_id = uuid.uuid4().hex
73
+ span_id = uuid.uuid4().hex[:16]
74
+ # The trailing -01 (sampled) flag is load-bearing: ParentBased(AlwaysSample)
75
+ # inherits it. -00 exports nothing.
76
+ traceparent = f"00-{trace_id}-{span_id}-01"
77
+ # /health is excluded from tracing by the otelhttp middleware; use a real
78
+ # route. Default is per-service-type (Go /api/v1/entities, Python /examples);
79
+ # TRACE_PROBE_PATH overrides for ad-hoc runs.
80
+ probe = os.environ.get("TRACE_PROBE_PATH", svc["probe_path"])
81
+
82
+ # Warm up: a just-booted service can serve liveness before its DB-backed routes
83
+ # are ready (e.g. a schema migration is still settling), so the first requests
84
+ # may transiently 5xx. Retry until the route is ready so this asserts span
85
+ # export, not startup ordering (test_every_service_is_healthy covers liveness).
86
+ resp = None
87
+ for attempt in range(8):
88
+ resp = httpx.get(
89
+ f"{_base_url(svc)}{probe}",
90
+ headers={"traceparent": traceparent},
91
+ timeout=5.0,
92
+ )
93
+ if resp.status_code == 200:
94
+ break
95
+ time.sleep(2)
96
+ assert resp.status_code == 200, f"probe failed after warmup retries: {resp.status_code}"
97
+
98
+ trace = _fetch_trace(trace_id)
99
+ if trace is None:
100
+ msg = (
101
+ f"no span with trace_id={trace_id} reached jaeger within "
102
+ f"{EXPORT_TIMEOUT_S}s — the OTLP export pipeline is broken"
103
+ )
104
+ if REQUIRE_TRACES:
105
+ pytest.fail(msg)
106
+ pytest.skip(msg)
107
+
108
+ services = {p["serviceName"] for p in trace["processes"].values()}
109
+ assert svc["otel_name"] in services, (
110
+ f"expected span from '{svc['otel_name']}', got {services}"
111
+ )
112
+ assert trace["spans"], "trace arrived but contains no spans"
113
+
114
+
115
+ @pytest.mark.parametrize("svc", _PARAMS)
116
+ def test_trace_context_propagates_unchanged(cluster, svc):
117
+ """The service continues the incoming trace id rather than starting a new one."""
118
+ if svc["type"] not in ("go", "python"):
119
+ pytest.xfail(f"{svc['type']} trace export not verified through this harness (TODO)")
120
+ if svc["host_port"] is None:
121
+ pytest.skip(f"{svc['name']} has no published host port")
122
+
123
+ trace_id = uuid.uuid4().hex
124
+ span_id = uuid.uuid4().hex[:16]
125
+ traceparent = f"00-{trace_id}-{span_id}-01"
126
+ probe = os.environ.get("TRACE_PROBE_PATH", svc["probe_path"])
127
+
128
+ httpx.get(
129
+ f"{_base_url(svc)}{probe}",
130
+ headers={"traceparent": traceparent},
131
+ timeout=5.0,
132
+ )
133
+ trace = _fetch_trace(trace_id)
134
+ if trace is None:
135
+ msg = "injected trace context was not propagated/exported"
136
+ if REQUIRE_TRACES:
137
+ pytest.fail(msg)
138
+ pytest.skip(msg)
139
+ # Compare numerically so leading-zero normalisation doesn't cause a false fail.
140
+ assert int(trace["traceID"], 16) == int(trace_id, 16)
141
+
142
+
143
+ @pytest.mark.skip(reason="real CRUD lands in Phase 4")
144
+ @pytest.mark.asyncio
145
+ @pytest.mark.parametrize("svc", _PARAMS)
146
+ async def test_crud_round_trip(cluster, api_client: httpx.AsyncClient, svc):
147
+ """POST then GET an entity and assert the round-trip through the real DB."""
148
+ if svc["type"] != "go":
149
+ pytest.skip("CRUD round-trip targets Go services for now")
150
+ base = _base_url(svc)
151
+ payload = {"name": "phase0-roundtrip"}
152
+ created = await api_client.post(f"{base}/api/v1/entities", json=payload, timeout=5.0)
153
+ assert created.status_code in (200, 201), created.text
154
+ entity_id = created.json().get("id")
155
+ assert entity_id, "POST did not return an id"
156
+ fetched = await api_client.get(f"{base}/api/v1/entities/{entity_id}", timeout=5.0)
157
+ assert fetched.status_code == 200
158
+ assert fetched.json().get("name") == payload["name"]
@@ -0,0 +1,206 @@
1
+ <% if (!surfaces) { -%>
2
+ """Token-conformance gate — Tier 1 of the visual verification loop.
3
+
4
+ The deterministic answer to "did the polish actually land?" A behavioural test
5
+ passes while the atmosphere has silently degraded to a flat default — the build
6
+ dropped the design system's surface treatment, or the projected tokens never
7
+ reached the page. This gate reads computed styles and asserts the opposite:
8
+ the atmosphere tokens resolve, the elevation is a multi-layer stack (not one
9
+ default drop shadow), and any surface treatment in the DOM renders with its
10
+ backdrop blur and layered shadow rather than collapsing to a framework default.
11
+
12
+ It is deliberately structural, not aesthetic: it cannot judge taste (that is the
13
+ designer's spec-conformance pass), but it makes "the tokens are applied" a fact,
14
+ not an opinion. Skips cleanly when no frontend service is discovered.
15
+ """
16
+
17
+ import json
18
+ import pathlib
19
+
20
+ from playwright.sync_api import Page
21
+
22
+ # Atmosphere tokens the nextjs-app generator projects into brand.css from the
23
+ # design system's visual block. Their presence proves the projection landed.
24
+ _PROBE = """
25
+ () => {
26
+ const root = getComputedStyle(document.documentElement);
27
+ const tok = (n) => (root.getPropertyValue(n) || '').trim();
28
+ const countLayers = (s) => {
29
+ s = (s || '').trim();
30
+ if (!s || s === 'none') return 0;
31
+ let depth = 0, n = 1;
32
+ for (const ch of s) {
33
+ if (ch === '(') depth++;
34
+ else if (ch === ')') depth--;
35
+ else if (ch === ',' && depth === 0) n++;
36
+ }
37
+ return n;
38
+ };
39
+ const surfaces = [];
40
+ for (const el of document.querySelectorAll('.surface-glass, .surface-elevated, .surface-hero')) {
41
+ const cs = getComputedStyle(el);
42
+ const bf = (cs.backdropFilter || cs.webkitBackdropFilter || '').trim();
43
+ surfaces.push({
44
+ cls: el.className,
45
+ hasBlur: /blur\\(/.test(bf),
46
+ shadowLayers: countLayers(cs.boxShadow),
47
+ });
48
+ }
49
+ return {
50
+ shadowMid: tok('--gw-shadow-mid'),
51
+ shadowMidLayers: countLayers(tok('--gw-shadow-mid')),
52
+ blurStandard: tok('--gw-blur-standard'),
53
+ surfaces,
54
+ };
55
+ }
56
+ """
57
+
58
+
59
+ def _load_routes() -> tuple[str, ...]:
60
+ manifest = pathlib.Path("tests/system/routes.json")
61
+ if manifest.exists():
62
+ try:
63
+ routes = json.loads(manifest.read_text())
64
+ if isinstance(routes, list) and routes:
65
+ return tuple(routes)
66
+ except Exception: # noqa: BLE001 — a malformed manifest falls back to root
67
+ pass
68
+ return ("/",)
69
+
70
+
71
+ ROUTES = _load_routes()
72
+
73
+
74
+ def _assert_token_conformance(page: Page, surface_slug: str, base_url: str | None) -> None:
75
+ for route in ROUTES:
76
+ target = (base_url.rstrip("/") + route) if base_url else route
77
+ page.goto(target, wait_until="load")
78
+ page.wait_for_load_state("networkidle")
79
+ r = page.evaluate(_PROBE)
80
+
81
+ # The atmosphere layer projected into :root.
82
+ assert r["shadowMid"], (
83
+ f"{surface_slug} {route}: --gw-shadow-mid is undefined — the brand.css "
84
+ f"projection did not reach the page (atmosphere tokens missing)."
85
+ )
86
+ assert r["blurStandard"], (
87
+ f"{surface_slug} {route}: --gw-blur-standard is undefined — blur tokens "
88
+ f"did not project."
89
+ )
90
+ assert r["shadowMidLayers"] >= 2, (
91
+ f"{surface_slug} {route}: --gw-shadow-mid is a single-layer shadow "
92
+ f"({r['shadowMidLayers']} layer) — the multi-layer elevation stack "
93
+ f"degraded to a default drop shadow."
94
+ )
95
+
96
+ # Any surface treatment in the DOM rendered its atmosphere, not a flat default.
97
+ for s in r["surfaces"]:
98
+ assert s["hasBlur"], (
99
+ f"{surface_slug} {route}: '{s['cls']}' rendered with no backdrop "
100
+ f"blur — the glass treatment was stripped to a flat fill."
101
+ )
102
+ assert s["shadowLayers"] >= 2, (
103
+ f"{surface_slug} {route}: '{s['cls']}' rendered with "
104
+ f"{s['shadowLayers']} shadow layer(s) — the elevation stack was lost."
105
+ )
106
+
107
+
108
+ def test_frontend_token_conformance(cluster, frontend_base_url, page: Page):
109
+ _assert_token_conformance(page, "frontend", frontend_base_url)
110
+ <% } else { -%>
111
+ """Token-conformance gate, one test per graphical surface — Tier 1 of the visual loop.
112
+
113
+ The deterministic answer to "did the polish actually land?" A behavioural test
114
+ passes while the atmosphere has silently degraded to a flat default. This gate
115
+ reads computed styles and asserts the atmosphere tokens resolve, the elevation is
116
+ a multi-layer stack, and any surface treatment in the DOM renders with its
117
+ backdrop blur and layered shadow rather than a framework default. Structural, not
118
+ aesthetic — taste is the designer's spec-conformance pass. Skips cleanly when a
119
+ surface is not reachable.
120
+ """
121
+
122
+ import json
123
+ import pathlib
124
+
125
+ from playwright.sync_api import Page
126
+
127
+ _PROBE = """
128
+ () => {
129
+ const root = getComputedStyle(document.documentElement);
130
+ const tok = (n) => (root.getPropertyValue(n) || '').trim();
131
+ const countLayers = (s) => {
132
+ s = (s || '').trim();
133
+ if (!s || s === 'none') return 0;
134
+ let depth = 0, n = 1;
135
+ for (const ch of s) {
136
+ if (ch === '(') depth++;
137
+ else if (ch === ')') depth--;
138
+ else if (ch === ',' && depth === 0) n++;
139
+ }
140
+ return n;
141
+ };
142
+ const surfaces = [];
143
+ for (const el of document.querySelectorAll('.surface-glass, .surface-elevated, .surface-hero')) {
144
+ const cs = getComputedStyle(el);
145
+ const bf = (cs.backdropFilter || cs.webkitBackdropFilter || '').trim();
146
+ surfaces.push({
147
+ cls: el.className,
148
+ hasBlur: /blur\\(/.test(bf),
149
+ shadowLayers: countLayers(cs.boxShadow),
150
+ });
151
+ }
152
+ return {
153
+ shadowMid: tok('--gw-shadow-mid'),
154
+ shadowMidLayers: countLayers(tok('--gw-shadow-mid')),
155
+ blurStandard: tok('--gw-blur-standard'),
156
+ surfaces,
157
+ };
158
+ }
159
+ """
160
+
161
+
162
+ def _load_routes() -> tuple[str, ...]:
163
+ manifest = pathlib.Path("tests/system/routes.json")
164
+ if manifest.exists():
165
+ try:
166
+ routes = json.loads(manifest.read_text())
167
+ if isinstance(routes, list) and routes:
168
+ return tuple(routes)
169
+ except Exception: # noqa: BLE001 — a malformed manifest falls back to root
170
+ pass
171
+ return ("/",)
172
+
173
+
174
+ ROUTES = _load_routes()
175
+
176
+
177
+ def _assert_token_conformance(page: Page, surface_slug: str) -> None:
178
+ for route in ROUTES:
179
+ page.goto(route, wait_until="load")
180
+ page.wait_for_load_state("networkidle")
181
+ r = page.evaluate(_PROBE)
182
+
183
+ assert r["shadowMid"], (
184
+ f"{surface_slug} {route}: --gw-shadow-mid is undefined — the brand.css "
185
+ f"projection did not reach the page."
186
+ )
187
+ assert r["blurStandard"], (
188
+ f"{surface_slug} {route}: --gw-blur-standard is undefined."
189
+ )
190
+ assert r["shadowMidLayers"] >= 2, (
191
+ f"{surface_slug} {route}: --gw-shadow-mid degraded to a single-layer "
192
+ f"shadow ({r['shadowMidLayers']} layer)."
193
+ )
194
+ for s in r["surfaces"]:
195
+ assert s["hasBlur"], (
196
+ f"{surface_slug} {route}: '{s['cls']}' rendered with no backdrop blur."
197
+ )
198
+ assert s["shadowLayers"] >= 2, (
199
+ f"{surface_slug} {route}: '{s['cls']}' rendered with "
200
+ f"{s['shadowLayers']} shadow layer(s) — elevation stack lost."
201
+ )
202
+ <% graphicalSurfaces.forEach((s) => { %>
203
+
204
+ def test_<%= s.ident %>_token_conformance(cluster, <%= s.ident %>_page: Page):
205
+ _assert_token_conformance(<%= s.ident %>_page, "<%= s.slug %>")
206
+ <% }) %><% } -%>
@@ -0,0 +1,104 @@
1
+ """Visual regression gate — Tier 1 of the visual verification loop, OPT-IN.
2
+
3
+ Screenshot-baseline diffing catches *unintended* visual change against a known-good
4
+ baseline. It is off by default (decision D8): it carries real baseline-management and
5
+ flakiness cost, and it does nothing for a screen's *first* render — that is what the
6
+ render-smoke, a11y, and geometry gates plus the agent's own inspection cover. Turn it
7
+ on only once a surface is visually stable and worth pinning.
8
+
9
+ Enable: set GROUNDWORK_VISUAL_REGRESSION=1. Baselines live in
10
+ tests/system/visual-baselines/<surface>/<route>.png and are committed to the repo.
11
+ Update protocol: review the diff, then re-run with GROUNDWORK_VISUAL_REGRESSION=update
12
+ to overwrite the baseline deliberately — never auto-update in CI.
13
+
14
+ Determinism note: when enabled the gate pins the viewport, disables animations, and
15
+ masks nothing by default; add per-project masks for dynamic regions (timestamps,
16
+ avatars) before trusting it. Requires Pillow for the pixel diff; skips if absent.
17
+ """
18
+
19
+ import json
20
+ import os
21
+ import pathlib
22
+
23
+ import pytest
24
+ from playwright.sync_api import Page
25
+
26
+ _MODE = os.environ.get("GROUNDWORK_VISUAL_REGRESSION", "")
27
+ _BASELINE_DIR = pathlib.Path("tests/system/visual-baselines")
28
+ # Fraction of differing pixels tolerated before a route is considered changed.
29
+ _DIFF_THRESHOLD = 0.01
30
+ DESKTOP = (1280, 800)
31
+
32
+
33
+ def _load_routes() -> tuple[str, ...]:
34
+ manifest = pathlib.Path("tests/system/routes.json")
35
+ if manifest.exists():
36
+ try:
37
+ routes = json.loads(manifest.read_text())
38
+ if isinstance(routes, list) and routes:
39
+ return tuple(routes)
40
+ except Exception: # noqa: BLE001 — a malformed manifest falls back to root
41
+ pass
42
+ return ("/",)
43
+
44
+
45
+ ROUTES = _load_routes()
46
+
47
+
48
+ def _diff_fraction(a_bytes: bytes, b_bytes: bytes) -> float:
49
+ from io import BytesIO
50
+
51
+ from PIL import Image, ImageChops
52
+
53
+ a = Image.open(BytesIO(a_bytes)).convert("RGB")
54
+ b = Image.open(BytesIO(b_bytes)).convert("RGB")
55
+ if a.size != b.size:
56
+ return 1.0
57
+ diff = ImageChops.difference(a, b)
58
+ bbox = diff.getbbox()
59
+ if bbox is None:
60
+ return 0.0
61
+ changed = sum(1 for px in diff.crop(bbox).getdata() if any(px))
62
+ return changed / float(a.size[0] * a.size[1])
63
+
64
+
65
+ def _visual_regression(page: Page, surface_slug: str, base_url: str | None) -> None:
66
+ if not _MODE:
67
+ pytest.skip("visual regression is opt-in; set GROUNDWORK_VISUAL_REGRESSION=1")
68
+ try:
69
+ import PIL # noqa: F401
70
+ except ImportError:
71
+ pytest.skip("visual regression needs Pillow (pip install Pillow)")
72
+
73
+ page.set_viewport_size({"width": DESKTOP[0], "height": DESKTOP[1]})
74
+ out_dir = _BASELINE_DIR / surface_slug
75
+ for route in ROUTES:
76
+ target = (base_url.rstrip("/") + route) if base_url else route
77
+ page.goto(target, wait_until="load")
78
+ page.wait_for_load_state("networkidle")
79
+ shot = page.screenshot(animations="disabled", full_page=True)
80
+
81
+ slug = route.strip("/").replace("/", "_") or "root"
82
+ baseline = out_dir / f"{slug}.png"
83
+ if _MODE == "update" or not baseline.exists():
84
+ out_dir.mkdir(parents=True, exist_ok=True)
85
+ baseline.write_bytes(shot)
86
+ if _MODE != "update":
87
+ pytest.skip(f"no baseline for {surface_slug} {route}; wrote one — review and commit it")
88
+ continue
89
+
90
+ frac = _diff_fraction(baseline.read_bytes(), shot)
91
+ assert frac <= _DIFF_THRESHOLD, (
92
+ f"{surface_slug} {route} changed visually: {frac:.1%} of pixels differ "
93
+ f"from the baseline (threshold {_DIFF_THRESHOLD:.0%}). Review the change; "
94
+ f"re-run with GROUNDWORK_VISUAL_REGRESSION=update to accept it."
95
+ )
96
+ <% if (!surfaces) { -%>
97
+
98
+ def test_frontend_visual_regression(cluster, frontend_base_url, page: Page):
99
+ _visual_regression(page, "frontend", frontend_base_url)
100
+ <% } else { -%><% graphicalSurfaces.forEach((s) => { %>
101
+
102
+ def test_<%= s.ident %>_visual_regression(cluster, <%= s.ident %>_page: Page):
103
+ _visual_regression(<%= s.ident %>_page, "<%= s.slug %>", None)
104
+ <% }) %><% } -%>
@@ -0,0 +1,196 @@
1
+ import {
2
+ formatFiles,
3
+ generateFiles,
4
+ Tree,
5
+ } from '@nx/devkit';
6
+ import * as path from 'path';
7
+ import { recordGeneratorProvenance } from '../shared/provenance';
8
+
9
+ /** One surface from the registry (`.groundwork/surfaces.json`). The slug is the
10
+ * join key everywhere — ledger cells, fixture map keys, generated fixture
11
+ * names. `medium` is the registry's `testMedium`; `reach` is an optional
12
+ * static base URL (playwright / protocol-client), launch command
13
+ * (subprocess-cli), or test-harness command (flutter-integration /
14
+ * playwright-electron) — omitted, URL mediums are discovered at test time
15
+ * from the docker-compose service named after the slug, and harness mediums
16
+ * resolve to `npx nx run <slug>:<target>` when services/<slug> exists. */
17
+ export interface SurfaceSpec {
18
+ slug: string;
19
+ medium: string;
20
+ reach?: string;
21
+ }
22
+
23
+ export interface SystemTestRunnerGeneratorSchema {
24
+ projectPrefix?: string;
25
+ /** Deprecated single-surface alias — `surfaces` supersedes it. */
26
+ interfaceMedium?: 'graphical-ui' | 'cli' | 'agentic-protocol';
27
+ /** JSON array of SurfaceSpec (string form when invoked from the CLI). */
28
+ surfaces?: string | SurfaceSpec[];
29
+ }
30
+
31
+ /** Parsed spec plus the python-identifier form of the slug, for fixture names. */
32
+ interface SurfaceTemplateSpec extends SurfaceSpec {
33
+ ident: string;
34
+ }
35
+
36
+ function parseSurfaces(
37
+ raw: string | SurfaceSpec[] | undefined
38
+ ): SurfaceTemplateSpec[] | null {
39
+ if (raw === undefined || raw === null || raw === '') {
40
+ return null;
41
+ }
42
+ let specs: unknown;
43
+ if (typeof raw === 'string') {
44
+ try {
45
+ specs = JSON.parse(raw);
46
+ } catch (e) {
47
+ throw new Error(`--surfaces is not valid JSON: ${(e as Error).message}`);
48
+ }
49
+ } else {
50
+ specs = raw;
51
+ }
52
+ if (!Array.isArray(specs) || specs.length === 0) {
53
+ throw new Error(
54
+ '--surfaces must be a non-empty JSON array of {slug, medium, reach?} objects'
55
+ );
56
+ }
57
+ for (const spec of specs as SurfaceSpec[]) {
58
+ if (
59
+ !spec ||
60
+ typeof spec.slug !== 'string' ||
61
+ spec.slug.length === 0 ||
62
+ typeof spec.medium !== 'string' ||
63
+ spec.medium.length === 0
64
+ ) {
65
+ throw new Error(
66
+ `every --surfaces entry needs a slug and a medium: ${JSON.stringify(spec)}`
67
+ );
68
+ }
69
+ }
70
+ return (specs as SurfaceSpec[]).map((s) => ({
71
+ ...s,
72
+ ident: s.slug.replace(/-/g, '_'),
73
+ }));
74
+ }
75
+
76
+ /** A fail-closed pytest stub for a graphical surface with no runnable UI check.
77
+ * It fails (never skips) so the surface's UI proof is an honest red until a
78
+ * platform check is implemented per NATIVE-CHECK-CONTRACT.md. Deleting it to go
79
+ * green is the silent-skip this exists to prevent. */
80
+ function uiCheckPlaceholder(s: SurfaceTemplateSpec): string {
81
+ return `import pytest
82
+
83
+ # AUTO-GENERATED fail-closed placeholder — do not delete to go green.
84
+ # Surface "${s.slug}" (test medium "${s.medium}") is a surface GroundWork has no
85
+ # UI check runner for. A milestone cannot be proven on a surface nothing checks,
86
+ # so this placeholder FAILS until a platform UI check is implemented for it per
87
+ # src/generators/system-test-runner/NATIVE-CHECK-CONTRACT.md (render,
88
+ # navigation / no dead ends, the named states, design-system token match).
89
+
90
+
91
+ def test_${s.ident}_ui_check_not_implemented():
92
+ pytest.fail(
93
+ "No UI check runner for surface '${s.slug}' (medium '${s.medium}'). "
94
+ "Implement a platform UI check per "
95
+ "system-test-runner/NATIVE-CHECK-CONTRACT.md, then replace this "
96
+ "fail-closed placeholder. A graphical surface must not ship unverified."
97
+ )
98
+ `;
99
+ }
100
+
101
+ export async function systemTestRunnerGenerator(
102
+ tree: Tree,
103
+ options: SystemTestRunnerGeneratorSchema
104
+ ) {
105
+ const projectPrefix = options.projectPrefix || 'groundwork';
106
+ const interfaceMedium = options.interfaceMedium || 'graphical-ui';
107
+ // Registry mode: `surfaces` carries the full set of test mediums and wins
108
+ // over the deprecated single-medium alias when both are given.
109
+ const surfaces = parseSurfaces(options.surfaces);
110
+
111
+ const graphicalSurfaces = (surfaces ?? []).filter((s) => s.medium === 'playwright');
112
+ const cliSurfaces = (surfaces ?? []).filter((s) => s.medium === 'subprocess-cli');
113
+ const protocolSurfaces = (surfaces ?? []).filter((s) => s.medium === 'protocol-client');
114
+ // App-harness mediums: the surface ships its own test harness (Flutter
115
+ // integration_test / Playwright _electron smoke); the runner fixture drives
116
+ // it as a subprocess through the app's Nx target.
117
+ const flutterSurfaces = (surfaces ?? []).filter((s) => s.medium === 'flutter-integration');
118
+ const electronSurfaces = (surfaces ?? []).filter((s) => s.medium === 'playwright-electron');
119
+
120
+ // Every test medium GroundWork knows how to run a check for. A graphical
121
+ // surface registered with a medium outside this set has no UI check runner —
122
+ // and a milestone cannot be proven on a surface nothing checks. We refuse to
123
+ // silently leave it unverified: each such surface gets a fail-closed
124
+ // placeholder check (below) naming the gap, never a silent no-op.
125
+ const KNOWN_MEDIA = new Set([
126
+ 'playwright',
127
+ 'subprocess-cli',
128
+ 'protocol-client',
129
+ 'flutter-integration',
130
+ 'playwright-electron',
131
+ ]);
132
+ const unsupportedSurfaces = (surfaces ?? []).filter((s) => !KNOWN_MEDIA.has(s.medium));
133
+
134
+ // Playwright structure follows graphical surfaces: any playwright surface in
135
+ // registry mode, the graphical-ui value in single-medium mode. pexpect ships
136
+ // alongside the subprocess runners so interactive (REPL) CLI flows are testable.
137
+ const includePlaywright = surfaces
138
+ ? graphicalSurfaces.length > 0
139
+ : interfaceMedium === 'graphical-ui';
140
+ const includePexpect = cliSurfaces.length > 0;
141
+
142
+ // Generate files into the workspace root
143
+ generateFiles(
144
+ tree,
145
+ path.join(__dirname, '..', '..', '..', '..', 'src', 'generators', 'system-test-runner', 'files'),
146
+ '.',
147
+ {
148
+ ...options,
149
+ projectPrefix,
150
+ interfaceMedium,
151
+ surfaces,
152
+ graphicalSurfaces,
153
+ cliSurfaces,
154
+ protocolSurfaces,
155
+ flutterSurfaces,
156
+ electronSurfaces,
157
+ includePlaywright,
158
+ includePexpect,
159
+ tmpl: ''
160
+ }
161
+ );
162
+
163
+ // Playwright structure ships only with a graphical web surface: the
164
+ // page-object package, the axe-core a11y smoke, and the render-smoke gate
165
+ // depend on pytest-playwright, which the pyproject template declares only when
166
+ // includePlaywright is set. Removing the web-specific gates here is correct —
167
+ // they genuinely cannot run without a web surface. What must never happen is a
168
+ // graphical surface left with no check at all; the placeholder below closes
169
+ // that gap fail-closed instead of silently.
170
+ if (!includePlaywright) {
171
+ tree.delete('tests/system/pages');
172
+ tree.delete('tests/system/test_a11y_smoke.py');
173
+ tree.delete('tests/system/test_render_smoke.py');
174
+ tree.delete('tests/system/test_layout_geometry.py');
175
+ tree.delete('tests/system/test_visual_regression.py');
176
+ tree.delete('tests/system/test_token_conformance.py');
177
+ }
178
+
179
+ // Fail-closed: a graphical surface whose test medium GroundWork cannot run a
180
+ // check for gets a placeholder that FAILS naming the gap, never a silent skip.
181
+ // The scaffold still generates and its other tests run; this surface's UI
182
+ // proof is an honest red until a platform check is implemented per
183
+ // NATIVE-CHECK-CONTRACT.md — the follow-on that turns it green.
184
+ for (const s of unsupportedSurfaces) {
185
+ tree.write(
186
+ `tests/system/test_${s.ident}_ui_check_missing.py`,
187
+ uiCheckPlaceholder(s)
188
+ );
189
+ }
190
+
191
+ await formatFiles(tree);
192
+
193
+ recordGeneratorProvenance(tree, 'system-test-runner', options as unknown as Record<string, unknown>);
194
+ }
195
+
196
+ export default systemTestRunnerGenerator;