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,20 @@
1
+ from fastapi import APIRouter, WebSocket, WebSocketDisconnect, Depends
2
+ from <%= packageName %>.adapters.websocket_hub import WebSocketHub
3
+
4
+ # Instantiate hub (in a real app, bind to app state in lifespan)
5
+ hub = WebSocketHub()
6
+
7
+ router = APIRouter(prefix="/ws", tags=["websocket"])
8
+
9
+ @router.websocket("")
10
+ async def websocket_endpoint(websocket: WebSocket):
11
+ await hub.connect(websocket)
12
+ try:
13
+ # Subscribe to a default channel or read from query
14
+ await hub.subscribe("global")
15
+ while True:
16
+ data = await websocket.receive_text()
17
+ # Handle incoming data if needed
18
+ await hub.broadcast("global", {"echo": data})
19
+ except WebSocketDisconnect:
20
+ hub.disconnect(websocket)
@@ -0,0 +1,35 @@
1
+ import asyncio
2
+ import logging
3
+ from sqlalchemy.ext.asyncio import create_async_engine
4
+ from sqlalchemy import text
5
+ from <%= packageName %>.adapters.config import settings
6
+
7
+ logger = logging.getLogger(__name__)
8
+
9
+ async def cleanup_idempotency_keys():
10
+ """
11
+ Background worker to delete idempotency keys older than 24 hours.
12
+ Designed to be run as a cron job or Kubernetes CronJob.
13
+ """
14
+ logger.info("Starting idempotency key cleanup worker...")
15
+
16
+ if not settings.database_url:
17
+ logger.error("DATABASE_URL not set.")
18
+ return
19
+
20
+ engine = create_async_engine(settings.database_url)
21
+
22
+ try:
23
+ async with engine.begin() as conn:
24
+ result = await conn.execute(
25
+ text("DELETE FROM idempotency_keys WHERE created_at < NOW() - INTERVAL '24 hours'")
26
+ )
27
+ logger.info(f"Cleanup complete. Deleted {result.rowcount} expired idempotency keys.")
28
+ except Exception as e:
29
+ logger.error(f"Error during idempotency cleanup: {e}", exc_info=True)
30
+ finally:
31
+ await engine.dispose()
32
+
33
+ if __name__ == "__main__":
34
+ logging.basicConfig(level=logging.INFO)
35
+ asyncio.run(cleanup_idempotency_keys())
@@ -0,0 +1,28 @@
1
+ import runpod
2
+ from typing import Any, Dict
3
+
4
+ <% if (llm) { %>
5
+ from <%= packageName %>.adapters.llm import LLMClient
6
+ <% } %>
7
+ <% if (postgres) { %>
8
+ from <%= packageName %>.adapters.database import get_db_session
9
+ from <%= packageName %>.adapters.repository import PostgresExampleRepository
10
+ from <%= packageName %>.core.domain.entities import ExampleEntity
11
+ import uuid
12
+ import asyncio
13
+ <% } %>
14
+
15
+ def handler(job: Dict[str, Any]) -> Dict[str, Any]:
16
+ job_input = job['input']
17
+
18
+ # Example boundary validation
19
+ if 'prompt' not in job_input:
20
+ return {"error": "Missing required field 'prompt' in input"}
21
+
22
+ prompt = job_input['prompt']
23
+
24
+ # In a real app, initialize services here. For async, use asyncio.run
25
+ return {"status": "success", "echo": prompt}
26
+
27
+ if __name__ == '__main__':
28
+ runpod.serverless.start({'handler': handler})
@@ -0,0 +1,108 @@
1
+ from contextlib import asynccontextmanager
2
+ from fastapi import FastAPI, Request
3
+ from fastapi.middleware.cors import CORSMiddleware
4
+ import asyncio
5
+
6
+ from <%= packageName %>.adapters.config import settings
7
+ from <%= packageName %>.adapters.telemetry import setup_telemetry, setup_logging
8
+ <% if (rest) { %>
9
+ from <%= packageName %>.entrypoints.api.router import router as example_router
10
+ from <%= packageName %>.entrypoints.api.middleware import (
11
+ DomainExceptionHandlerMiddleware,
12
+ ConcurrencyLimitingMiddleware,
13
+ GlobalTimeoutMiddleware,
14
+ IdempotencyMiddleware
15
+ )
16
+ <% } %>
17
+ <% if (postgres) { %>
18
+ from <%= packageName %>.adapters.database import engine
19
+ from <%= packageName %>.adapters.repository import PostgresIdempotencyRepository
20
+ <% } %>
21
+
22
+ <% if (rest && websockets) { %>
23
+ from <%= packageName %>.entrypoints.api.websocket_handler import router as ws_router
24
+ <% } %>
25
+
26
+ @asynccontextmanager
27
+ async def lifespan(app: FastAPI):
28
+ # Initialize resources like Redis pools, DB connections
29
+ app.state.startup_failed = False
30
+ # Configure JSON logging with trace_id/span_id correlation. (Tracing itself is
31
+ # set up at module scope below — instrumenting the app must happen before
32
+ # Starlette builds its middleware stack, which is already done by the time the
33
+ # lifespan runs, so it cannot be done here.)
34
+ setup_logging()
35
+ try:
36
+ <% if (postgres) { %>
37
+ # Provide the repository for the idempotency middleware
38
+ # For simplicity, we just inject the class/engine. In a real app, DI container is better.
39
+ # But wait, PostgresIdempotencyRepository needs an AsyncSession which is bound to a request scope.
40
+ # For the middleware, we can bind an engine or sessionmaker to app.state.
41
+ app.state.db_engine = engine
42
+ <% } %>
43
+ pass
44
+ except Exception:
45
+ app.state.startup_failed = True
46
+
47
+ yield
48
+
49
+ # Cleanup resources gracefully
50
+ # Flush buffered spans before exit (BatchSpanProcessor flushes on shutdown).
51
+ _tracer_provider.shutdown()
52
+ <% if (postgres) { %>
53
+ await engine.dispose()
54
+ <% } %>
55
+
56
+ app = FastAPI(
57
+ title="<%= name %> API",
58
+ lifespan=lifespan
59
+ )
60
+ # Set up tracing + instrument the app at import time, BEFORE Starlette builds its
61
+ # middleware stack (which happens on first request / at startup). FastAPIInstrumentor
62
+ # adds an ASGI middleware; doing this inside the lifespan is too late and silently
63
+ # produces no spans. The provider is flushed on shutdown in the lifespan above.
64
+ _tracer_provider = setup_telemetry(app, settings.otel_exporter_otlp_endpoint)
65
+
66
+ <% if (rest) { %>
67
+ # Middlewares are executed in reverse order of addition
68
+ # 1. Exception Handler catches all
69
+ app.add_middleware(DomainExceptionHandlerMiddleware)
70
+ # 2. Timeout prevents hanging
71
+ app.add_middleware(GlobalTimeoutMiddleware, timeout=30.0)
72
+ # 3. Concurrency Limits protect from overload
73
+ app.add_middleware(ConcurrencyLimitingMiddleware, max_concurrent_requests=100)
74
+ # 5. Idempotency protects mutating endpoints
75
+ app.add_middleware(IdempotencyMiddleware)
76
+ <% } %>
77
+ # 4. CORS — always add
78
+ app.add_middleware(
79
+ CORSMiddleware,
80
+ allow_origins=["https://your-frontend.com"],
81
+ allow_credentials=True,
82
+ allow_methods=["GET", "POST", "PUT", "DELETE"],
83
+ allow_headers=["*"],
84
+ )
85
+ <% if (rest) { %>
86
+ app.include_router(example_router)
87
+ <% } %>
88
+ <% if (rest && websockets) { %>
89
+ app.include_router(ws_router)
90
+ <% } %>
91
+
92
+ @app.get("/health", status_code=200)
93
+ @app.get("/healthz", status_code=200)
94
+ async def liveness_probe():
95
+ """Liveness probe."""
96
+ return {"status": "alive"}
97
+
98
+ @app.get("/readyz")
99
+ async def readiness_probe(request: Request):
100
+ """Kubernetes readiness probe. Checks backing services."""
101
+ from fastapi.responses import JSONResponse
102
+ if getattr(request.app.state, "startup_failed", False):
103
+ return JSONResponse(status_code=503, content={"status": "not ready"})
104
+ return {"status": "ready"}
105
+
106
+ if __name__ == "__main__":
107
+ import uvicorn
108
+ uvicorn.run("<%= packageName %>.main:app", host="0.0.0.0", port=settings.server_port, reload=True)
@@ -0,0 +1,74 @@
1
+ import pytest
2
+ from httpx import AsyncClient, ASGITransport
3
+ import pytest_asyncio
4
+ <% if (rest) { %>
5
+ from <%= packageName %>.main import app
6
+ <% } %>
7
+
8
+ <% if (postgres) { %>
9
+ from testcontainers.postgres import PostgresContainer
10
+ import os
11
+
12
+ @pytest.fixture(scope="session", autouse=True)
13
+ def setup_postgres():
14
+ with PostgresContainer("postgres:15-alpine") as postgres:
15
+ os.environ["DB_HOST"] = postgres.get_container_host_ip()
16
+ os.environ["DB_PORT"] = postgres.get_exposed_port(5432)
17
+ os.environ["DB_USER"] = postgres.username
18
+ os.environ["DB_PASSWORD"] = postgres.password
19
+ os.environ["DB_NAME"] = postgres.dbname
20
+ yield
21
+ <% } %>
22
+
23
+ <% if (messaging === 'redis' || websockets) { %>
24
+ from testcontainers.redis import RedisContainer
25
+
26
+ @pytest.fixture(scope="session", autouse=True)
27
+ def setup_redis():
28
+ with RedisContainer("redis:7-alpine") as redis:
29
+ os.environ["REDIS_URL"] = f"redis://{redis.get_container_host_ip()}:{redis.get_exposed_port(6379)}"
30
+ yield
31
+ <% } %>
32
+
33
+ <% if (rest) { %>
34
+ @pytest_asyncio.fixture
35
+ async def async_client():
36
+ async with AsyncClient(
37
+ transport=ASGITransport(app=app), base_url="http://test"
38
+ ) as client:
39
+ yield client
40
+
41
+ @pytest.mark.asyncio
42
+ async def test_liveness_probe(async_client: AsyncClient):
43
+ response = await async_client.get("/healthz")
44
+ assert response.status_code == 200
45
+ assert response.json() == {"status": "alive"}
46
+
47
+ @pytest.mark.asyncio
48
+ async def test_readiness_probe(async_client: AsyncClient):
49
+ response = await async_client.get("/readyz")
50
+ assert response.status_code == 200
51
+ assert response.json() == {"status": "ready"}
52
+
53
+ @pytest.mark.asyncio
54
+ async def test_health_alias_reports_alive(async_client: AsyncClient):
55
+ # /health and /healthz are both wired to the liveness probe.
56
+ response = await async_client.get("/health")
57
+ assert response.status_code == 200
58
+ assert response.json() == {"status": "alive"}
59
+
60
+ @pytest.mark.asyncio
61
+ async def test_readyz_503_when_dependency_down(async_client: AsyncClient):
62
+ # Drives the real readiness 503 branch (main.py readiness_probe): when a
63
+ # backing dependency failed to start, /readyz must report not-ready.
64
+ # Phase 1-4 is expected to replace this flag with a live DB ping; tighten
65
+ # this test to exercise that ping once it lands.
66
+ app.state.startup_failed = True
67
+ try:
68
+ response = await async_client.get("/readyz")
69
+ assert response.status_code == 503
70
+ assert response.json() == {"status": "not ready"}
71
+ finally:
72
+ app.state.startup_failed = False
73
+
74
+ <% } %>
@@ -0,0 +1,109 @@
1
+ <% if (rest) { %>
2
+ import pytest
3
+ from httpx import AsyncClient, ASGITransport
4
+ import pytest_asyncio
5
+ from fastapi import FastAPI
6
+
7
+ from <%= packageName %>.entrypoints.api.middleware import (
8
+ IdempotencyMiddleware,
9
+ ConcurrencyLimitingMiddleware,
10
+ )
11
+ from <%= packageName %>.core.domain.entities import IdempotencyResponse
12
+
13
+
14
+ class InMemoryIdempotencyRepo:
15
+ """Real (non-mock) IdempotencyRepository implementation for tests."""
16
+
17
+ def __init__(self):
18
+ self.completed = {} # (key, user_id) -> IdempotencyResponse
19
+ self.in_progress = set()
20
+
21
+ async def get(self, key, user_id):
22
+ k = (key, user_id)
23
+ if k in self.completed:
24
+ return ("COMPLETED", self.completed[k])
25
+ if k in self.in_progress:
26
+ return ("IN_PROGRESS", None)
27
+ return None
28
+
29
+ async def lock(self, key, user_id):
30
+ k = (key, user_id)
31
+ if k in self.in_progress or k in self.completed:
32
+ return False
33
+ self.in_progress.add(k)
34
+ return True
35
+
36
+ async def save(self, key, user_id, response: IdempotencyResponse):
37
+ k = (key, user_id)
38
+ self.in_progress.discard(k)
39
+ self.completed[k] = response
40
+
41
+
42
+ def build_app_with_idempotency():
43
+ app = FastAPI()
44
+ app.add_middleware(IdempotencyMiddleware)
45
+ app.state.idempotency_repo = InMemoryIdempotencyRepo()
46
+ app.state.calls = 0
47
+
48
+ @app.post("/thing")
49
+ async def create_thing():
50
+ app.state.calls += 1
51
+ return {"created": True}
52
+
53
+ return app
54
+
55
+
56
+ @pytest_asyncio.fixture
57
+ async def idem_client():
58
+ app = build_app_with_idempotency()
59
+ async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client:
60
+ yield client, app
61
+
62
+
63
+ @pytest.mark.asyncio
64
+ async def test_idempotency_replays_cached_response(idem_client):
65
+ client, app = idem_client
66
+ headers = {"Idempotency-Key": "abc-123"}
67
+
68
+ r1 = await client.post("/thing", headers=headers)
69
+ assert r1.status_code == 200
70
+
71
+ r2 = await client.post("/thing", headers=headers)
72
+ # Second call replays the cached response; the handler runs exactly once.
73
+ assert r2.status_code == r1.status_code
74
+ assert app.state.calls == 1
75
+
76
+
77
+ @pytest.mark.asyncio
78
+ async def test_idempotency_get_is_not_deduplicated(idem_client):
79
+ client, app = idem_client
80
+ # GET bypasses the middleware entirely (no /thing GET route -> 405, never cached).
81
+ r = await client.get("/thing", headers={"Idempotency-Key": "abc-123"})
82
+ assert r.status_code in (404, 405)
83
+
84
+
85
+ @pytest.mark.asyncio
86
+ async def test_concurrency_limit_sheds_with_503():
87
+ import asyncio
88
+
89
+ app = FastAPI()
90
+ app.add_middleware(ConcurrencyLimitingMiddleware, max_concurrent_requests=1)
91
+ release = asyncio.Event()
92
+
93
+ @app.get("/slow")
94
+ async def slow():
95
+ await release.wait()
96
+ return {"ok": True}
97
+
98
+ transport = ASGITransport(app=app)
99
+ async with AsyncClient(transport=transport, base_url="http://test") as client:
100
+ # Hold the single slot, then fire a second request which must be shed (503).
101
+ first = asyncio.create_task(client.get("/slow"))
102
+ await asyncio.sleep(0.05)
103
+ second = await client.get("/slow")
104
+ assert second.status_code == 503
105
+ assert second.json()["detail"].startswith("Service overloaded")
106
+ release.set()
107
+ r1 = await first
108
+ assert r1.status_code == 200
109
+ <% } %>
@@ -0,0 +1,16 @@
1
+ <% if (runpod) { %>
2
+ from <%= packageName %>.entrypoints.worker.worker import handler
3
+
4
+
5
+ def test_worker_rejects_missing_prompt():
6
+ # Boundary validation: a job without 'prompt' must return a structured error,
7
+ # never raise an unhandled exception.
8
+ result = handler({"input": {}})
9
+ assert "error" in result
10
+ assert "prompt" in result["error"]
11
+
12
+
13
+ def test_worker_echoes_valid_prompt():
14
+ result = handler({"input": {"prompt": "hello"}})
15
+ assert result == {"status": "success", "echo": "hello"}
16
+ <% } %>
@@ -0,0 +1,286 @@
1
+ import {
2
+ formatFiles,
3
+ generateFiles,
4
+ Tree,
5
+ names,
6
+ } from '@nx/devkit';
7
+ import * as path from 'path';
8
+ import { recordGeneratorProvenance } from '../shared/provenance';
9
+ import {
10
+ promoteEngineerSkill,
11
+ deployStackDocs,
12
+ ensureOptionalInfra,
13
+ readProjectPrefix,
14
+ registerRunner,
15
+ } from '../shared/scaffold-helpers';
16
+ import { applyCapability } from '../shared/capabilities';
17
+
18
+ export interface PythonMicroserviceGeneratorSchema {
19
+ name: string;
20
+ rest: boolean;
21
+ postgres: boolean;
22
+ messaging: 'none' | 'redis' | 'kafka' | 'gcp-pubsub';
23
+ websockets: boolean;
24
+ runpod: boolean;
25
+ llm: boolean;
26
+ llmProvider: 'openai' | 'anthropic' | 'local' | 'none';
27
+ native?: boolean;
28
+ }
29
+
30
+ export default async function (tree: Tree, options: PythonMicroserviceGeneratorSchema) {
31
+ const serviceNames = names(options.name);
32
+ const projectRoot = `services/${serviceNames.fileName}`;
33
+ // src-layout: the importable package is `src/<packageName>` (PEP src-layout),
34
+ // so the package name is the service name in snake_case (a valid Python
35
+ // identifier). It names the `src/__packageName__/` template dir, every
36
+ // `from <pkg>.…` import, the hatch wheel package, and the import-linter root.
37
+ // Derive it from the kebab fileName (hyphens → underscores), NOT constantName:
38
+ // nx's constantName collapses single-char segments (`a-b1` → `AB1`), which would
39
+ // make the package name diverge from the intuitive `a_b1` a developer expects.
40
+ const packageName = serviceNames.fileName.replace(/-/g, '_');
41
+
42
+ let assignedPort = 8000;
43
+ let composeDoc: any = null;
44
+ if (tree.exists('docker-compose.yml')) {
45
+ try {
46
+ const yaml = require('yaml');
47
+ const composeContent = tree.read('docker-compose.yml', 'utf-8');
48
+ composeDoc = yaml.parseDocument(composeContent);
49
+
50
+ const usedPorts = new Set<number>();
51
+
52
+ // Collect ports from docker-compose.yml
53
+ const servicesMap = composeDoc.get('services');
54
+ if (servicesMap && servicesMap.items) {
55
+ for (const item of servicesMap.items) {
56
+ const service = item.value;
57
+ if (service && service.get) {
58
+ const ports = service.get('ports');
59
+ if (ports && ports.items) {
60
+ for (const pItem of ports.items) {
61
+ const portStr = String(pItem.value || pItem);
62
+ const match = portStr.match(/^(\d+):/);
63
+ if (match) {
64
+ usedPorts.add(parseInt(match[1], 10));
65
+ }
66
+ }
67
+ }
68
+ }
69
+ }
70
+ }
71
+
72
+ // Also collect ports from .env files of natively-run services (not in docker-compose)
73
+ if (tree.exists('services')) {
74
+ for (const svcName of tree.children('services') ?? []) {
75
+ const envPath = `services/${svcName}/.env`;
76
+ if (tree.exists(envPath)) {
77
+ const envContent = tree.read(envPath, 'utf-8') ?? '';
78
+ for (const line of envContent.split('\n')) {
79
+ const m = line.match(/^(?:PORT|SERVER_PORT)=(\d+)/);
80
+ if (m) usedPorts.add(parseInt(m[1], 10));
81
+ }
82
+ }
83
+ }
84
+ }
85
+
86
+ while (usedPorts.has(assignedPort)) {
87
+ assignedPort++;
88
+ }
89
+ } catch (e) {
90
+ console.warn('Failed to parse docker-compose.yml for port calculation:', e);
91
+ }
92
+ }
93
+
94
+ // Default the provider so programmatic callers (e.g. tests) that omit it get
95
+ // today's OpenAI behaviour unchanged. Only consumed inside `--llm` templates.
96
+ const llmProvider = options.llmProvider ?? 'openai';
97
+
98
+ const templateOptions = {
99
+ ...options,
100
+ ...serviceNames,
101
+ packageName,
102
+ assignedPort,
103
+ llmProvider,
104
+ tmpl: '' // required by generateFiles
105
+ };
106
+
107
+ generateFiles(
108
+ tree,
109
+ path.join(__dirname, '..', '..', '..', '..', 'src', 'generators', 'python-microservice', 'files'),
110
+ projectRoot,
111
+ templateOptions
112
+ );
113
+
114
+ deployStackDocs(tree, path.join(__dirname, '..', '..', '..', '..', 'src', 'generators', 'python-microservice', 'docs'));
115
+
116
+ // Auto-inject into docker-compose.yml if it exists
117
+ if (composeDoc) {
118
+ try {
119
+ if (!composeDoc.get('services')) {
120
+ // createNode so the result is a YAMLMap with .has/.set (a plain {} is not).
121
+ composeDoc.set('services', composeDoc.createNode({}));
122
+ }
123
+ const servicesMap = composeDoc.get('services');
124
+ // Only wire the infrastructure this service actually uses. Redis is needed
125
+ // for the WebSocket backplane or Redis pub/sub; the Pub/Sub emulator only
126
+ // for GCP Pub/Sub messaging. A plain --rest --postgres --llm service
127
+ // provisions neither.
128
+ const usesRedis = options.websockets || options.messaging === 'redis';
129
+ const usesPubSub = options.messaging === 'gcp-pubsub';
130
+ if (!options.native && !servicesMap.has(serviceNames.fileName)) {
131
+ const environment: string[] = [`SERVER_PORT=${assignedPort}`];
132
+ if (options.postgres) {
133
+ environment.push(
134
+ 'DB_HOST=db',
135
+ 'DB_PORT=5432',
136
+ 'DB_USER=${DB_USER:-postgres}',
137
+ 'DB_PASSWORD=${DB_PASSWORD:-postgres}',
138
+ `DB_NAME=\${DB_NAME:-${serviceNames.fileName}}`
139
+ );
140
+ }
141
+ if (usesRedis) {
142
+ environment.push('REDIS_URL=redis:6379');
143
+ }
144
+ if (usesPubSub) {
145
+ environment.push('PUBSUB_EMULATOR_HOST=pubsub:${PUBSUB_PORT:-8085}');
146
+ }
147
+ environment.push(
148
+ 'OTEL_EXPORTER_OTLP_ENDPOINT=http://jaeger:4317',
149
+ 'OTEL_EXPORTER_OTLP_PROTOCOL=grpc'
150
+ );
151
+
152
+ const dependsOn: Record<string, { condition: string }> = {};
153
+ if (options.postgres) {
154
+ dependsOn.db = { condition: 'service_healthy' };
155
+ }
156
+ if (usesRedis) {
157
+ dependsOn.redis = { condition: 'service_healthy' };
158
+ }
159
+
160
+ const newService: Record<string, unknown> = {
161
+ build: {
162
+ context: `./${projectRoot}`,
163
+ dockerfile: 'Dockerfile'
164
+ },
165
+ container_name: serviceNames.fileName,
166
+ restart: 'unless-stopped',
167
+ ports: [
168
+ `${assignedPort}:${assignedPort}`
169
+ ],
170
+ environment
171
+ };
172
+ // Only the REST entrypoint serves /healthz; the runpod worker image
173
+ // runs a background worker with no HTTP server, so it gets no probe.
174
+ if (options.rest && !options.runpod) {
175
+ // The python:slim runtime image has no curl, so probe the health
176
+ // endpoint with the interpreter that is guaranteed to be present.
177
+ newService.healthcheck = {
178
+ test: [
179
+ 'CMD-SHELL',
180
+ `python -c "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://localhost:${assignedPort}/healthz').status==200 else 1)"`
181
+ ],
182
+ interval: '10s',
183
+ timeout: '5s',
184
+ retries: 5,
185
+ start_period: '20s'
186
+ };
187
+ }
188
+ if (Object.keys(dependsOn).length > 0) {
189
+ newService.depends_on = dependsOn;
190
+ }
191
+ newService.networks = ['groundwork-net'];
192
+
193
+ servicesMap.set(serviceNames.fileName, newService);
194
+ // db only when this service uses Postgres; jaeger always for a
195
+ // containerized service (it exports OTLP). Neither is in the base compose.
196
+ ensureOptionalInfra(composeDoc, servicesMap, {
197
+ usesRedis,
198
+ usesPubSub,
199
+ usesDb: !!options.postgres,
200
+ usesTelemetry: true,
201
+ projectPrefix: readProjectPrefix(tree),
202
+ });
203
+ tree.write('docker-compose.yml', composeDoc.toString());
204
+ } else if (options.native && (options.postgres || usesRedis || usesPubSub)) {
205
+ // Native sidecar: no app container in compose, but provision the backing
206
+ // infra it connects to. A host process gets no forced tracing backend —
207
+ // telemetry is wired only if the project explicitly runs jaeger.
208
+ ensureOptionalInfra(composeDoc, servicesMap, {
209
+ usesRedis,
210
+ usesPubSub,
211
+ usesDb: !!options.postgres,
212
+ usesTelemetry: false,
213
+ projectPrefix: readProjectPrefix(tree),
214
+ });
215
+ tree.write('docker-compose.yml', composeDoc.toString());
216
+ }
217
+ } catch (e) {
218
+ console.warn('Failed to update docker-compose.yml:', e);
219
+ }
220
+ }
221
+
222
+ // Native mode: the service runs as a host process (e.g. it needs Metal/MPS that
223
+ // Docker on macOS can't provide), so register it as a sidecar runner instead of
224
+ // a compose service. `./dev start` launches it via `uv run`.
225
+ if (options.native) {
226
+ registerRunner(tree, {
227
+ name: serviceNames.fileName,
228
+ kind: 'sidecar',
229
+ cmd: `uv run python -m ${packageName}.main`,
230
+ cwd: projectRoot,
231
+ autostart: true,
232
+ });
233
+ }
234
+
235
+ const pkgRoot = `${projectRoot}/src/${packageName}`;
236
+
237
+ if (!options.rest) {
238
+ tree.delete(`${pkgRoot}/entrypoints/api`);
239
+ // Middleware tests import the API entrypoint, which only exists with --rest.
240
+ tree.delete(`${projectRoot}/tests/test_middleware.py`);
241
+ }
242
+
243
+ if (!options.postgres) {
244
+ tree.delete(`${pkgRoot}/adapters/database.py`);
245
+ tree.delete(`${pkgRoot}/adapters/repository.py`);
246
+ // Schema lives in db/ (parity with Go); migrate runs scripts/apply-schema.sh.
247
+ tree.delete(`${projectRoot}/db`);
248
+ tree.delete(`${projectRoot}/scripts/apply-schema.sh`);
249
+ }
250
+
251
+ if (!options.websockets) {
252
+ tree.delete(`${pkgRoot}/entrypoints/api/websocket_handler.py`);
253
+ tree.delete(`${pkgRoot}/adapters/websocket_hub.py`);
254
+ }
255
+
256
+ if (options.messaging === 'none') {
257
+ tree.delete(`${pkgRoot}/adapters/message_queue.py`);
258
+ }
259
+
260
+ if (!options.runpod) {
261
+ tree.delete(`${pkgRoot}/entrypoints/worker`);
262
+ tree.delete(`${pkgRoot}/adapters/comfyui.py`);
263
+ // Worker test imports the runpod worker handler, deleted above.
264
+ tree.delete(`${projectRoot}/tests/test_worker.py`);
265
+ }
266
+
267
+ // LLM is a composable capability port (plan WS-F). The chosen provider —
268
+ // anthropic | openai | local | none — selects the adapter; the port, the
269
+ // contract test, the provider dependency and its env footprint all come from
270
+ // the capability registry via one shared injector (no inline per-provider
271
+ // template here). `none` ships the bare port: the interface + a stub + a red bet.
272
+ if (options.llm) {
273
+ applyCapability(tree, {
274
+ capability: 'llm',
275
+ provider: llmProvider,
276
+ stack: 'python',
277
+ serviceRoot: projectRoot,
278
+ });
279
+ }
280
+
281
+ promoteEngineerSkill(tree, 'groundwork-python-engineer');
282
+
283
+ await formatFiles(tree);
284
+
285
+ recordGeneratorProvenance(tree, 'python-microservice', options as unknown as Record<string, unknown>);
286
+ }