@turri-dev/cli 0.0.0-stage → 0.1.2-next.48dacfc

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 (315) hide show
  1. package/.pi/themes/turri-dark.json +80 -0
  2. package/.pi/themes/turri-light.json +82 -0
  3. package/LICENSE +21 -0
  4. package/README.md +272 -2
  5. package/assets/jellyfish/dark-00.png +0 -0
  6. package/assets/jellyfish/dark-01.png +0 -0
  7. package/assets/jellyfish/dark-02.png +0 -0
  8. package/assets/jellyfish/dark-03.png +0 -0
  9. package/assets/jellyfish/dark-04.png +0 -0
  10. package/assets/jellyfish/dark-05.png +0 -0
  11. package/assets/jellyfish/dark-06.png +0 -0
  12. package/assets/jellyfish/dark-07.png +0 -0
  13. package/assets/jellyfish/dark-08.png +0 -0
  14. package/assets/jellyfish/dark-09.png +0 -0
  15. package/assets/jellyfish/dark-10.png +0 -0
  16. package/assets/jellyfish/dark-11.png +0 -0
  17. package/assets/jellyfish/dark-12.png +0 -0
  18. package/assets/jellyfish/dark-13.png +0 -0
  19. package/assets/jellyfish/dark-14.png +0 -0
  20. package/assets/jellyfish/fallback.txt +252 -0
  21. package/assets/jellyfish/light-00.png +0 -0
  22. package/assets/jellyfish/light-01.png +0 -0
  23. package/assets/jellyfish/light-02.png +0 -0
  24. package/assets/jellyfish/light-03.png +0 -0
  25. package/assets/jellyfish/light-04.png +0 -0
  26. package/assets/jellyfish/light-05.png +0 -0
  27. package/assets/jellyfish/light-06.png +0 -0
  28. package/assets/jellyfish/light-07.png +0 -0
  29. package/assets/jellyfish/light-08.png +0 -0
  30. package/assets/jellyfish/light-09.png +0 -0
  31. package/assets/jellyfish/light-10.png +0 -0
  32. package/assets/jellyfish/light-11.png +0 -0
  33. package/assets/jellyfish/light-12.png +0 -0
  34. package/assets/jellyfish/light-13.png +0 -0
  35. package/assets/jellyfish/light-14.png +0 -0
  36. package/bin/turri.mjs +29 -0
  37. package/dist/ask.js +149 -0
  38. package/dist/brand.js +50 -0
  39. package/dist/btw.js +174 -0
  40. package/dist/chat-models.js +37 -0
  41. package/dist/chat-skills.js +18 -0
  42. package/dist/cli.js +178 -0
  43. package/dist/config-command.js +197 -0
  44. package/dist/config-edit.js +367 -0
  45. package/dist/config.js +489 -0
  46. package/dist/conform-cli.js +29 -0
  47. package/dist/cultivate-cli.js +110 -0
  48. package/dist/drift-cli.js +25 -0
  49. package/dist/environment.js +70 -0
  50. package/dist/extension.js +2372 -0
  51. package/dist/genome.js +301 -0
  52. package/dist/graph.js +246 -0
  53. package/dist/identity.js +35 -0
  54. package/dist/init-config.js +511 -0
  55. package/dist/judge.js +62 -0
  56. package/dist/lineage-cli.js +13 -0
  57. package/dist/loop-cli.js +132 -0
  58. package/dist/loop-tools.js +225 -0
  59. package/dist/mature-tools.js +193 -0
  60. package/dist/model-check.js +117 -0
  61. package/dist/module-report.js +9 -0
  62. package/dist/pi-launch.js +31 -0
  63. package/dist/pi.js +813 -0
  64. package/dist/plain/check.js +76 -0
  65. package/dist/plain/concepts.js +213 -0
  66. package/dist/plain/errors.js +43 -0
  67. package/dist/plain/files.js +57 -0
  68. package/dist/plain/highlight.js +195 -0
  69. package/dist/plain/index.js +15 -0
  70. package/dist/plain/liquid.js +129 -0
  71. package/dist/plain/markdown.js +208 -0
  72. package/dist/plain/parser.js +752 -0
  73. package/dist/plain/plain.tmLanguage.json +124 -0
  74. package/dist/plain/spec.js +291 -0
  75. package/dist/plain/stdlib.js +44 -0
  76. package/dist/question-dialog.js +125 -0
  77. package/dist/questioning.js +109 -0
  78. package/dist/quiet.js +125 -0
  79. package/dist/regenerate/activity.js +187 -0
  80. package/dist/regenerate/agent-env.js +190 -0
  81. package/dist/regenerate/agent-shell.js +114 -0
  82. package/dist/regenerate/arbiter.js +133 -0
  83. package/dist/regenerate/audit.js +203 -0
  84. package/dist/regenerate/cases.js +83 -0
  85. package/dist/regenerate/change-view.js +102 -0
  86. package/dist/regenerate/choose-conformance.js +117 -0
  87. package/dist/regenerate/chunk-plan.js +625 -0
  88. package/dist/regenerate/codebase.js +75 -0
  89. package/dist/regenerate/command-check.js +312 -0
  90. package/dist/regenerate/compaction.js +20 -0
  91. package/dist/regenerate/confine.js +310 -0
  92. package/dist/regenerate/conform.js +133 -0
  93. package/dist/regenerate/conformance-agents.js +955 -0
  94. package/dist/regenerate/conformance.js +936 -0
  95. package/dist/regenerate/conversation-writes.js +100 -0
  96. package/dist/regenerate/credentials.js +88 -0
  97. package/dist/regenerate/debug-log.js +228 -0
  98. package/dist/regenerate/debugger.js +90 -0
  99. package/dist/regenerate/delivery.js +19 -0
  100. package/dist/regenerate/diagnose-job.js +40 -0
  101. package/dist/regenerate/diagnose.js +81 -0
  102. package/dist/regenerate/diff-view.js +240 -0
  103. package/dist/regenerate/drift.js +194 -0
  104. package/dist/regenerate/engine.js +118 -0
  105. package/dist/regenerate/environment-error.js +220 -0
  106. package/dist/regenerate/job-log.js +102 -0
  107. package/dist/regenerate/job-panel.js +336 -0
  108. package/dist/regenerate/jobs-tree.js +300 -0
  109. package/dist/regenerate/jobs.js +427 -0
  110. package/dist/regenerate/lanes.js +32 -0
  111. package/dist/regenerate/lineage.js +384 -0
  112. package/dist/regenerate/loop.js +1435 -0
  113. package/dist/regenerate/masking.js +95 -0
  114. package/dist/regenerate/notes.js +397 -0
  115. package/dist/regenerate/os-sandbox.js +243 -0
  116. package/dist/regenerate/paths.js +165 -0
  117. package/dist/regenerate/plain-palette.js +83 -0
  118. package/dist/regenerate/prompt.js +704 -0
  119. package/dist/regenerate/records.js +294 -0
  120. package/dist/regenerate/regenerate.js +598 -0
  121. package/dist/regenerate/regression.js +181 -0
  122. package/dist/regenerate/release.js +262 -0
  123. package/dist/regenerate/requires.js +241 -0
  124. package/dist/regenerate/resources.js +164 -0
  125. package/dist/regenerate/self-check.js +111 -0
  126. package/dist/regenerate/services.js +155 -0
  127. package/dist/regenerate/shell.js +320 -0
  128. package/dist/regenerate/side-panel.js +278 -0
  129. package/dist/regenerate/spec-map-view.js +574 -0
  130. package/dist/regenerate/spec-map.js +561 -0
  131. package/dist/regenerate/spec-steps.js +527 -0
  132. package/dist/regenerate/state.js +10 -0
  133. package/dist/regenerate/steer.js +91 -0
  134. package/dist/regenerate/steering.js +119 -0
  135. package/dist/regenerate/stop-report.js +161 -0
  136. package/dist/regenerate/submit-work.js +71 -0
  137. package/dist/regenerate/test-kinds.js +124 -0
  138. package/dist/regenerate/test-scripts.js +695 -0
  139. package/dist/regenerate/testing.js +406 -0
  140. package/dist/regenerate/transcript-view.js +1 -0
  141. package/dist/regenerate/unit-gate.js +20 -0
  142. package/dist/regenerate/unit-review.js +347 -0
  143. package/dist/regenerate/web.js +256 -0
  144. package/dist/regenerate/workspace.js +99 -0
  145. package/dist/regenerate-cli.js +68 -0
  146. package/dist/release-agent.js +114 -0
  147. package/dist/release-cli.js +131 -0
  148. package/dist/release-tools.js +148 -0
  149. package/dist/review/live.js +165 -0
  150. package/dist/rules.js +47 -0
  151. package/dist/self-invocation.js +110 -0
  152. package/dist/setup.js +245 -0
  153. package/dist/skill-progress.js +78 -0
  154. package/dist/skill.js +149 -0
  155. package/dist/skills.js +74 -0
  156. package/dist/spec-diff-cli.js +37 -0
  157. package/dist/spec-tools.js +155 -0
  158. package/dist/stack.js +158 -0
  159. package/dist/stacks.js +97 -0
  160. package/dist/stdlib.js +100 -0
  161. package/dist/terminal-images.js +46 -0
  162. package/dist/tools.js +242 -0
  163. package/dist/validate-cli.js +52 -0
  164. package/docs/README.md +58 -0
  165. package/docs/authoring-plain.md +245 -0
  166. package/docs/config.md +353 -0
  167. package/docs/deploy.md +109 -0
  168. package/docs/development.md +88 -0
  169. package/docs/headless.md +148 -0
  170. package/docs/images/how-turri-works.svg +50 -0
  171. package/docs/images/turri-banner.png +0 -0
  172. package/docs/installation.md +119 -0
  173. package/docs/parser.md +108 -0
  174. package/docs/regenerating.md +1116 -0
  175. package/docs/sandbox.md +233 -0
  176. package/docs/skills-and-gates.md +254 -0
  177. package/docs/theming.md +76 -0
  178. package/docs/using.md +454 -0
  179. package/genome/rules/bullet-continuation.md +69 -0
  180. package/genome/rules/concise-specs-examples.md +431 -0
  181. package/genome/rules/concise-specs-integration-examples.md +270 -0
  182. package/genome/rules/concise-specs.md +80 -0
  183. package/genome/rules/definitions.md +107 -0
  184. package/genome/rules/examples/integration-embedded-testing/run_conformance_tests_java.sh +163 -0
  185. package/genome/rules/examples/integration-embedded-testing/run_unittests_java.sh +51 -0
  186. package/genome/rules/exported-concepts.md +39 -0
  187. package/genome/rules/func-specs.md +129 -0
  188. package/genome/rules/impl-reqs.md +68 -0
  189. package/genome/rules/import-modules.md +48 -0
  190. package/genome/rules/integration-embedded-testing.md +276 -0
  191. package/genome/rules/integration-embedded.md +171 -0
  192. package/genome/rules/integration-standalone.md +135 -0
  193. package/genome/rules/integrations.md +137 -0
  194. package/genome/rules/linked-resources.md +69 -0
  195. package/genome/rules/module-structure.md +105 -0
  196. package/genome/rules/project-model.md +88 -0
  197. package/genome/rules/required-concepts.md +44 -0
  198. package/genome/rules/requires-modules.md +80 -0
  199. package/genome/rules/stdlib.md +73 -0
  200. package/genome/rules/test-reqs.md +57 -0
  201. package/genome/skills/add-acceptance-test/SKILL.md +100 -0
  202. package/genome/skills/add-concept/SKILL.md +71 -0
  203. package/genome/skills/add-functional-spec/SKILL.md +84 -0
  204. package/genome/skills/add-functional-specs/SKILL.md +118 -0
  205. package/genome/skills/add-implementation-requirement/SKILL.md +86 -0
  206. package/genome/skills/add-resource/SKILL.md +105 -0
  207. package/genome/skills/add-template/SKILL.md +64 -0
  208. package/genome/skills/add-test-requirement/SKILL.md +73 -0
  209. package/genome/skills/analyze-2-func-specs/SKILL.md +101 -0
  210. package/genome/skills/analyze-func-specs/SKILL.md +123 -0
  211. package/genome/skills/analyze-if-func-spec-too-complex/SKILL.md +211 -0
  212. package/genome/skills/break-down-func-spec/SKILL.md +205 -0
  213. package/genome/skills/brood/SKILL.md +229 -0
  214. package/genome/skills/brood/references/intent.md +35 -0
  215. package/genome/skills/brood/references/product.md +101 -0
  216. package/genome/skills/brood/references/stack.md +61 -0
  217. package/genome/skills/brood/references/testing.md +56 -0
  218. package/genome/skills/bud/SKILL.md +148 -0
  219. package/genome/skills/bud/references/checklist.md +44 -0
  220. package/genome/skills/bud/references/intent.md +30 -0
  221. package/genome/skills/check-plain-env/SKILL.md +285 -0
  222. package/genome/skills/consolidate-concepts/SKILL.md +192 -0
  223. package/genome/skills/create-import-module/SKILL.md +104 -0
  224. package/genome/skills/create-requires-module/SKILL.md +109 -0
  225. package/genome/skills/debug-specs/SKILL.md +188 -0
  226. package/genome/skills/implement-conformance-testing-script/SKILL.md +238 -0
  227. package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_cypress.ps1 +337 -0
  228. package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_golang.ps1 +111 -0
  229. package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_java.sh +136 -0
  230. package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_python.ps1 +103 -0
  231. package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_python.sh +150 -0
  232. package/genome/skills/implement-unit-testing-script/SKILL.md +160 -0
  233. package/genome/skills/implement-unit-testing-script/assets/run_unittests_flutter.ps1 +87 -0
  234. package/genome/skills/implement-unit-testing-script/assets/run_unittests_golang.ps1 +73 -0
  235. package/genome/skills/implement-unit-testing-script/assets/run_unittests_java.sh +72 -0
  236. package/genome/skills/implement-unit-testing-script/assets/run_unittests_python.ps1 +81 -0
  237. package/genome/skills/implement-unit-testing-script/assets/run_unittests_python.sh +98 -0
  238. package/genome/skills/implement-unit-testing-script/assets/run_unittests_react.ps1 +87 -0
  239. package/genome/skills/init-plain-project/SKILL.md +117 -0
  240. package/genome/skills/init-plain-project/references/checklist.md +30 -0
  241. package/genome/skills/mature/SKILL.md +126 -0
  242. package/genome/skills/refactor-module/SKILL.md +196 -0
  243. package/genome/skills/resolve-section-ownership/SKILL.md +64 -0
  244. package/genome/skills/resolve-spec-conflict/SKILL.md +96 -0
  245. package/genome/skills/spawn/SKILL.md +163 -0
  246. package/package.json +68 -4
  247. package/stdlib/backend/common.plain +25 -0
  248. package/stdlib/backend/conformance/common.plain +12 -0
  249. package/stdlib/backend/conformance/go-gin.plain +9 -0
  250. package/stdlib/backend/conformance/go-nethttp.plain +9 -0
  251. package/stdlib/backend/conformance/java-springboot.plain +9 -0
  252. package/stdlib/backend/conformance/python-django.plain +9 -0
  253. package/stdlib/backend/conformance/python-fastapi.plain +9 -0
  254. package/stdlib/backend/conformance/python-flask.plain +9 -0
  255. package/stdlib/backend/conformance/rust-axum.plain +9 -0
  256. package/stdlib/backend/conformance/typescript-express.plain +9 -0
  257. package/stdlib/backend/conformance/typescript-fastify.plain +9 -0
  258. package/stdlib/backend/conformance/typescript-nestjs.plain +9 -0
  259. package/stdlib/backend/go-gin.plain +18 -0
  260. package/stdlib/backend/go-nethttp.plain +18 -0
  261. package/stdlib/backend/java-springboot.plain +19 -0
  262. package/stdlib/backend/python-django.plain +19 -0
  263. package/stdlib/backend/python-fastapi.plain +23 -0
  264. package/stdlib/backend/python-flask.plain +23 -0
  265. package/stdlib/backend/rust-axum.plain +17 -0
  266. package/stdlib/backend/typescript-express.plain +19 -0
  267. package/stdlib/backend/typescript-fastify.plain +19 -0
  268. package/stdlib/backend/typescript-nestjs.plain +19 -0
  269. package/stdlib/cli/common.plain +17 -0
  270. package/stdlib/cli/conformance/common.plain +11 -0
  271. package/stdlib/cli/conformance/go-cobra.plain +9 -0
  272. package/stdlib/cli/conformance/go-flag.plain +9 -0
  273. package/stdlib/cli/conformance/java-picocli.plain +9 -0
  274. package/stdlib/cli/conformance/python-argparse.plain +9 -0
  275. package/stdlib/cli/conformance/python-click.plain +9 -0
  276. package/stdlib/cli/conformance/python-typer.plain +9 -0
  277. package/stdlib/cli/conformance/rust-clap.plain +9 -0
  278. package/stdlib/cli/conformance/typescript-commander.plain +9 -0
  279. package/stdlib/cli/go-cobra.plain +14 -0
  280. package/stdlib/cli/go-flag.plain +14 -0
  281. package/stdlib/cli/java-picocli.plain +15 -0
  282. package/stdlib/cli/python-argparse.plain +18 -0
  283. package/stdlib/cli/python-click.plain +16 -0
  284. package/stdlib/cli/python-typer.plain +16 -0
  285. package/stdlib/cli/rust-clap.plain +14 -0
  286. package/stdlib/cli/typescript-commander.plain +17 -0
  287. package/stdlib/frontend/angular.plain +17 -0
  288. package/stdlib/frontend/common.plain +17 -0
  289. package/stdlib/frontend/conformance/angular.plain +5 -0
  290. package/stdlib/frontend/conformance/common.plain +11 -0
  291. package/stdlib/frontend/conformance/react-vite.plain +5 -0
  292. package/stdlib/frontend/conformance/sveltekit-spa.plain +5 -0
  293. package/stdlib/frontend/conformance/vue-vite.plain +5 -0
  294. package/stdlib/frontend/react-vite.plain +16 -0
  295. package/stdlib/frontend/sveltekit-spa.plain +16 -0
  296. package/stdlib/frontend/vue-vite.plain +16 -0
  297. package/stdlib/lang/go.plain +13 -0
  298. package/stdlib/lang/java.plain +12 -0
  299. package/stdlib/lang/python.plain +18 -0
  300. package/stdlib/lang/rust.plain +12 -0
  301. package/stdlib/lang/typescript.plain +13 -0
  302. package/stdlib/library/common.plain +15 -0
  303. package/stdlib/library/conformance/common.plain +9 -0
  304. package/stdlib/library/conformance/go.plain +9 -0
  305. package/stdlib/library/conformance/java-gradle.plain +9 -0
  306. package/stdlib/library/conformance/java-maven.plain +9 -0
  307. package/stdlib/library/conformance/python.plain +9 -0
  308. package/stdlib/library/conformance/rust.plain +9 -0
  309. package/stdlib/library/conformance/typescript.plain +9 -0
  310. package/stdlib/library/go.plain +12 -0
  311. package/stdlib/library/java-gradle.plain +13 -0
  312. package/stdlib/library/java-maven.plain +13 -0
  313. package/stdlib/library/python.plain +13 -0
  314. package/stdlib/library/rust.plain +12 -0
  315. package/stdlib/library/typescript.plain +15 -0
@@ -0,0 +1,109 @@
1
+ ---
2
+ name: create-requires-module
3
+ description: >-
4
+ Create a ***plain module that uses requires to depend on another module in
5
+ the build chain. Use when the user wants to create a new .plain file that
6
+ builds on top of a previously built module, inheriting its functional specs
7
+ and generated code as a starting point.
8
+ allowed-tools: [read, write, edit, bash, ls, grep, find]
9
+ ---
10
+
11
+ # Create Requires Module
12
+
13
+ ## What Requires Does
14
+
15
+ `requires` attaches the current module to the project's build chain. The required module is built **before** the current one, and its generated code — the accumulated output of that module and all its ancestors — is copied as the starting point. The current module does not need to functionally extend the required module, but their outputs are never independent: the current module's code physically contains the required module's.
16
+
17
+ When this module is rendered:
18
+ - The required module's generated code (`plain_modules/<required_module>/code`) is copied as the starting point.
19
+ - The `***functional specs***` of the required module **and all its ancestors** become visible as **previous functional specs**.
20
+ - Of the required module's definitions, only the concepts in its `exported_concepts` are visible, each with its full definition text. Export visibility is **not** transitive — to see an ancestor's exports, list that ancestor in `requires` too.
21
+
22
+ All modules connected by `requires` form a single tree with a common root. **Diamond joins are prohibited**: multiple `requires` entries must lie on one root-to-tip ancestor path. The deepest entry is the attachment point; the other entries exist only to make those ancestors' exports visible.
23
+
24
+ Use `requires` for:
25
+ - Building on top of an existing module's functionality
26
+ - Attaching a module at the right point in the build chain, even when it addresses a different concern
27
+
28
+ If you only need shared definitions and reqs (no functional specs, no generated code), use `import` instead — see the `create-import-module` skill.
29
+
30
+ ## Workflow
31
+
32
+ 1. **Identify the attachment point.** Determine which existing module this new module attaches after in the build chain. That module must already exist and be renderable. If listing additional modules, verify each is an ancestor of the attachment point — no diamond joins.
33
+ 2. **Create the `.plain` file at the repository root** with YAML frontmatter containing the `requires` field. Modules with functional specs live at the root, not in `template/`.
34
+ 3. **Review the functional specs of the whole ancestor chain** — they will be treated as previous requirements. Your new functional specs must not conflict with any of them.
35
+ 4. **Review each listed module's `exported_concepts`** — only those concepts are available to reference; an ancestor's exports require listing that ancestor.
36
+ 5. **Add module-specific content** — definitions, implementation reqs, test reqs, and functional specs unique to this module.
37
+ 6. **Check for conflicts** between your new functional specs and any spec in the ancestor chain.
38
+
39
+ ## Format
40
+
41
+ The `requires` field is a list of module paths in the YAML frontmatter:
42
+
43
+ ```plain
44
+ ---
45
+ requires:
46
+ - base_module
47
+ import:
48
+ - shared_template
49
+ description: Extended module that builds on base_module
50
+ ---
51
+
52
+ ***definitions***
53
+
54
+ - :NewFeature: is a feature added by this module.
55
+
56
+ ***functional specs***
57
+
58
+ - :NewFeature: is available.
59
+ ```
60
+
61
+ A module can use both `requires` and `import` together. `requires` points to other root-level modules; `import` resolves from the default `template/` directory (no prefix needed).
62
+
63
+ Multiple `requires` entries are legal only when they lie on one ancestor path (e.g., `requires: [auth, messaging]` where `messaging` itself requires `auth`). The deepest entry (`messaging`) is the attachment point; `auth` is listed only to make its exports visible.
64
+
65
+ ## Exported Concepts
66
+
67
+ The required module controls what concepts are visible via `exported_concepts`:
68
+
69
+ ```plain
70
+ > In the required module's frontmatter:
71
+ ---
72
+ exported_concepts: [":StorageClient:", ":BackupResult:"]
73
+ ---
74
+ ```
75
+
76
+ Only `:StorageClient:` and `:BackupResult:` would be available to modules that `require` this one, each with its full definition text. All other concepts from the required module are internal.
77
+
78
+ ## Chronological Ordering with Requires
79
+
80
+ Functional specs from the whole `requires` ancestor chain are considered **previous functional specs**. This means:
81
+ - They are already rendered and their code exists.
82
+ - Your new specs are rendered after them, with full awareness of what they defined.
83
+ - Your new specs must not conflict with any spec in the ancestor chain.
84
+ - The renderer sees the chain's functional specs as context when rendering yours.
85
+
86
+ The current module may or may not be functionally related to the required module — `requires` places it at the right point in the accumulating build chain either way.
87
+
88
+ ## Import vs Requires
89
+
90
+ | Aspect | `import` | `requires` |
91
+ |--------|----------|------------|
92
+ | Pulls in definitions | Yes | No (only `exported_concepts`) |
93
+ | Pulls in implementation reqs | Yes | No |
94
+ | Pulls in test reqs | Yes | No |
95
+ | Pulls in functional specs | No | Yes (as previous requirements, transitively) |
96
+ | Copies generated code | No | Yes (accumulated ancestor chain) |
97
+ | Typical use | Templates, shared definitions | Attaching a module to the build chain |
98
+
99
+ ## Validation Checklist
100
+
101
+ - [ ] Module file is at the repository root (not in `template/`)
102
+ - [ ] Required module exists and is renderable
103
+ - [ ] All `requires` entries lie on one ancestor path — no diamond joins
104
+ - [ ] The deepest `requires` entry is the intended attachment point
105
+ - [ ] Every listed module's `exported_concepts` provide the concepts you need
106
+ - [ ] New functional specs do not conflict with any spec in the ancestor chain
107
+ - [ ] Module has at least one functional spec and one implementation req
108
+ - [ ] Both `requires` and `import` are used correctly (not mixed up)
109
+ - [ ] YAML frontmatter is correctly formatted between `---` markers
@@ -0,0 +1,188 @@
1
+ ---
2
+ name: debug-specs
3
+ description: >-
4
+ Investigate a bug observed in the running application by reading the generated
5
+ code in plain_modules/, tracing the issue back to the specs, and fixing only
6
+ the .plain files. Generated code is never modified. Use when the user reports
7
+ unexpected behavior, visual glitches, crashes, or incorrect logic in the app.
8
+ allowed-tools: [read, write, edit, bash, ls, grep, find]
9
+ ---
10
+
11
+ # Debug Specs
12
+
13
+ ## When to Use
14
+
15
+ - The user observes a bug in the running application (visual, behavioral, crash, performance).
16
+ - A conformance test or unit test is failing.
17
+ - The generated code does something unexpected or incorrect.
18
+ - The user points to a specific functional spec that seems wrong.
19
+
20
+ ## Guiding Principle
21
+
22
+ Generated code in `plain_modules/<module>/code/` and `plain_modules/<module>/tests/` is **read-only** — it exists solely as evidence for diagnosis. All fixes are applied exclusively to the `.plain` spec files. The workflow is: observe → read generated code → trace to spec → fix the spec.
23
+
24
+ ## Input
25
+
26
+ 1. **The module name** — identifies the `plain_modules/<module_name>/` directory (`code/` and `tests/`) and the corresponding `.plain` file(s).
27
+ 2. **The user's observation** — what is wrong? This can be a bug description, a screenshot, a test failure, an error message, or a general "this doesn't work right."
28
+ 3. **Optional: a specific functional spec** — if the user suspects a particular spec, start there. Otherwise, investigate broadly.
29
+
30
+ ## Phase 1 — Understand the Context
31
+
32
+ 1. **Read the `.plain` file(s)** for the module — frontmatter, definitions, implementation reqs, test reqs, and all functional specs. Also read `import` and `requires` chains.
33
+ 2. **Read the user's observation carefully.** Rephrase it back to confirm understanding. Identify:
34
+ - What is the expected behavior?
35
+ - What is the actual behavior?
36
+ - Is this a visual issue, a logic issue, a crash, or a data issue?
37
+
38
+ ## Phase 2 — Investigate the Generated Code
39
+
40
+ Read files in `plain_modules/<module_name>/code/` to understand what the renderer produced. **Do not modify any generated files.**
41
+
42
+ ### 2a. Narrow the search
43
+
44
+ If the user pointed to a specific spec or area:
45
+ - Identify which generated files implement that spec's behavior.
46
+ - Read those files to understand the current implementation.
47
+
48
+ If the investigation is broad:
49
+ - Start from the entry point and follow the execution path related to the observed bug.
50
+ - Use the observation to narrow down: UI issue → look at widgets/views, logic issue → look at business logic/providers, data issue → look at models/repositories.
51
+
52
+ ### 2b. Read the relevant generated code
53
+
54
+ For each relevant file:
55
+ 1. Read the code and understand what it does.
56
+ 2. Compare the behavior to what the spec says it should do.
57
+ 3. Note any discrepancies — places where the code doesn't match the spec's intent.
58
+
59
+ ### 2c. Check conformance tests and unit tests (if relevant)
60
+
61
+ If the bug manifests as a test failure:
62
+ 1. Read the failing test — conformance tests in `plain_modules/<module_name>/tests/` (the module's whole suite, no per-functionality subfolders), unit tests inside `plain_modules/<module_name>/code/`.
63
+ 2. Understand what the test expects vs. what the implementation does.
64
+ 3. Determine whether the test expectation is correct (matches the spec) or incorrect (doesn't match the spec).
65
+
66
+ ## Phase 3 — Diagnose the Root Cause
67
+
68
+ Trace the issue from the generated code back to the specs. There are five possible root causes — determine which one applies **before** making changes:
69
+
70
+ | Root Cause | Symptom | Fix |
71
+ |------------|---------|-----|
72
+ | **Ambiguous spec** | The spec is correct in intent, but vague enough that the renderer interpreted it differently than intended. | Add explicit detail to the spec to eliminate the ambiguity. |
73
+ | **Missing spec** | The desired behavior is not covered by any spec. The renderer had no guidance and either did nothing or made an arbitrary choice. | Add a new functional spec using the `add-functional-spec` skill. |
74
+ | **Conflicting specs** | Two specs contradict each other, causing the renderer to produce inconsistent behavior. | Use the `resolve-spec-conflict` skill. |
75
+ | **Incorrect spec** | The spec explicitly describes the wrong behavior. The renderer implemented it faithfully, but the spec itself is wrong. | Rewrite the spec to describe the correct behavior. |
76
+ | **Missing implementation req** | The spec is correct, but the implementation req doesn't provide enough guidance for the renderer to produce the right code (e.g., missing library, missing architectural constraint, missing platform detail). | Add or update the implementation req using the `add-implementation-requirement` skill. |
77
+
78
+ ### How to diagnose
79
+
80
+ 1. **Read the spec that governs the buggy behavior.** Does it clearly and unambiguously describe the correct behavior?
81
+ - If the spec is clear and correct but the code is wrong → **ambiguous spec** (the renderer misinterpreted it) or **missing implementation req**.
82
+ - If the spec doesn't mention the behavior at all → **missing spec**.
83
+ - If the spec explicitly describes the wrong behavior → **incorrect spec**.
84
+ 2. **Check for conflicts.** Could another spec be overriding or contradicting this behavior?
85
+ - Read all functional specs that touch the same concepts.
86
+ - If two specs are in tension → **conflicting specs**.
87
+ 3. **Check implementation reqs.** Is the renderer missing guidance on how to implement correctly?
88
+ - Does the implementation req specify the right library, pattern, or constraint?
89
+ - If a platform-specific or framework-specific detail is missing → **missing implementation req**.
90
+
91
+ ## Phase 4 — Fix the Specs
92
+
93
+ Apply the fix based on the diagnosed root cause. Use the appropriate skill:
94
+
95
+ | Root Cause | Skill to Use |
96
+ |------------|-------------|
97
+ | Ambiguous spec | Edit the spec inline — add sub-bullets or reword for clarity |
98
+ | Missing spec | `add-functional-spec` |
99
+ | Conflicting specs | `resolve-spec-conflict` |
100
+ | Incorrect spec | Edit the spec inline — rewrite the incorrect part |
101
+ | Missing implementation req | `add-implementation-requirement` |
102
+
103
+ ### Fix guidelines
104
+
105
+ - **Minimal changes.** Only modify what is necessary to fix the observed bug. Avoid rewriting unrelated specs.
106
+ - **Preserve chronological order.** If adding a new spec, place it correctly relative to existing specs.
107
+ - **Stay language-agnostic.** Functional specs describe behavior, not implementation. Platform-specific guidance belongs in implementation reqs.
108
+ - **Respect the 200 LOC limit.** If a fix makes a spec too complex, use `break-down-func-spec` to split it.
109
+ - **Check for new conflicts.** After editing, verify the fix doesn't conflict with other specs by running `analyze-func-specs` once with the edited spec(s) plus every existing spec that touches the same concepts. The batched analyzer reports all conflicting pairs in a single call; resolve each with `resolve-spec-conflict`.
110
+
111
+ ## Phase 5 — Verify and Report
112
+
113
+ 1. **Re-read the modified `.plain` file(s)** in full to confirm correctness.
114
+ 2. **Summarize the findings** for the user:
115
+ - What was observed (the bug)
116
+ - What the generated code was doing (the symptom in code)
117
+ - Which spec(s) caused the issue (the root cause)
118
+ - What was changed in the specs (the fix)
119
+ - What to expect after re-rendering
120
+ 3. **If uncertain**, present the diagnosis and proposed fix to the user for confirmation before making changes. Some bugs have multiple possible causes — when in doubt, explain the options and let the user decide.
121
+
122
+ ## Debugging Strategies
123
+
124
+ ### Strategy 1: Observation-Driven (most common)
125
+
126
+ Start from the user's observation and work backward through the code to the spec.
127
+
128
+ ```
129
+ User sees bug → Read generated code → Find the responsible code path →
130
+ Identify which spec governs that code → Diagnose why the spec produced wrong code →
131
+ Fix the spec
132
+ ```
133
+
134
+ ### Strategy 2: Spec-Focused
135
+
136
+ The user suspects a specific spec. Compare the spec directly against the generated code.
137
+
138
+ ```
139
+ User points to spec → Read the spec → Find the generated code that implements it →
140
+ Compare spec intent vs. code behavior → Diagnose the gap → Fix the spec
141
+ ```
142
+
143
+ ### Strategy 3: Test-Failure-Driven
144
+
145
+ A test is failing. Use the test as the entry point.
146
+
147
+ ```
148
+ Read failing test → Understand what it expects → Read the implementation →
149
+ Determine if the test or the implementation is wrong → Trace back to the spec →
150
+ Fix the spec (or test reqs/acceptance tests if the test itself is wrong)
151
+ ```
152
+
153
+ ### Strategy 4: Differential
154
+
155
+ The bug appeared after a new spec was added. Compare before and after.
156
+
157
+ ```
158
+ Identify the newly added spec → Read the specs it might conflict with →
159
+ Check if the new spec introduced the bug → Use resolve-spec-conflict or
160
+ revise the new spec
161
+ ```
162
+
163
+ ## Common Pitfalls
164
+
165
+ ### Fixing the code instead of the spec
166
+ Never modify files in `plain_modules/<module>/code/` or `plain_modules/<module>/tests/`. Even if the fix is obvious in the code, the change must be made in the `.plain` file so it persists across re-renders.
167
+
168
+ ### Treating symptoms instead of root causes
169
+ If the user says "the button is in the wrong place," don't just add positioning detail. Investigate why the renderer placed it there — the root cause might be a missing layout spec, an ambiguous screen description, or a conflict with another spec.
170
+
171
+ ### Over-specifying the fix
172
+ Adding too much implementation detail to a functional spec (e.g., specific pixel values, widget names, CSS properties) makes it brittle. Prefer behavior-level fixes. Use implementation reqs for platform-specific guidance.
173
+
174
+ ### Ignoring ripple effects
175
+ A spec fix may affect other specs that reference the same concepts. Always check neighboring specs for conflicts after making a change.
176
+
177
+ ## Validation Checklist
178
+
179
+ - [ ] User's observation is clearly understood (expected vs. actual behavior)
180
+ - [ ] Generated code has been read to understand the current implementation
181
+ - [ ] Root cause is diagnosed (ambiguous / missing / conflicting / incorrect / missing impl req)
182
+ - [ ] Fix is applied in the `.plain` file(s) only — no generated code modified
183
+ - [ ] Fix is minimal and targeted to the observed bug
184
+ - [ ] Fix does not introduce new conflicts with existing specs
185
+ - [ ] Modified specs respect the 200 LOC limit
186
+ - [ ] Modified specs remain language-agnostic
187
+ - [ ] Chronological ordering is preserved
188
+ - [ ] Summary of findings and fix presented to the user
@@ -0,0 +1,238 @@
1
+ ---
2
+ name: implement-conformance-testing-script
3
+ description: >-
4
+ Implement a self-contained conformance-test runner script (Bash, run by the
5
+ harness on the person's machine; an optional PowerShell copy for running it by hand on
6
+ Windows) for an arbitrary programming language. The script stages the build,
7
+ installs its dependencies in isolation, runs the static checks of the conformance
8
+ tests - formatter, linter, type checker - and runs a module's whole conformance
9
+ suite against it. Use when the user wants to add a conformance-test runner for
10
+ a new language (Node.js, Go, Rust, Flutter, etc.) to a ***plain project, or
11
+ wants to regenerate / adapt one of the existing runners.
12
+ allowed-tools: [read, write, edit, bash, ls, grep, find]
13
+ ---
14
+
15
+ # Implement Conformance Testing Script
16
+
17
+ This skill produces a single executable script that runs the **conformance tests** for a generated build folder, following a consistent, language-agnostic pattern.
18
+
19
+ The reference implementations are:
20
+
21
+ - [assets/run_conformance_tests_java.sh](assets/run_conformance_tests_java.sh) — Java.
22
+ - [assets/run_conformance_tests_python.sh](assets/run_conformance_tests_python.sh) — Python.
23
+ - [assets/run_conformance_tests_<lang>.ps1](assets/run_conformance_tests_*.ps1) — Windows PowerShell equivalents, for running the scripts by hand on Windows.
24
+
25
+ Read both `.sh` references before writing anything — every script you produce must be a faithful translation of the same pattern into the target language's tooling.
26
+
27
+ ## How the harness uses the script
28
+
29
+ A module's conformance tests live in one folder, `plain_modules/<module>/tests` — the module's whole conformance suite: every functionality's tests, plus those carried up from the modules it requires. There are no per-functionality subfolders.
30
+
31
+ The harness (not the rendering agent) runs the script once per check, against the whole suite:
32
+
33
+ ```
34
+ bash run_conformance_tests_<lang>.sh <build_folder> <conformance_tests_folder>
35
+ ```
36
+
37
+ Both arguments are absolute paths: `<build_folder>` is the module's generated code (`plain_modules/<module>/code`), and `<conformance_tests_folder>` is the folder holding the whole suite. The harness runs the script on the person's machine - macOS, Linux or WSL, with its toolchains, in the person's own environment - and its exit code alone decides whether the conformance tests pass.
38
+
39
+ Every conformance script is self-contained: toolchain check, argument validation, stage the build into `<temp>/<lang>_<basename of $1>`, install dependencies there in isolation, check the tests in `$2` statically, run the suite in `$2` against it, clean up on exit. Nothing is prepared ahead of time by another script - unless the project already has a `prepare_environment*.sh` (codeplain's prepare script, or one `prepare-environment-script:` names): turri runs it on the same build before every run of the conformance script, so keep it, and let the conformance script rely on what it sets up rather than doing it again. Never write a prepare script yourself.
40
+
41
+ ## How conformance scripts differ from unit-test scripts
42
+
43
+ A conformance script is structurally very close to a unit-test script (see the sibling skill [`implement-unit-testing-script`](../implement-unit-testing-script/SKILL.md)) but with two important differences:
44
+
45
+ 1. **Two positional arguments instead of one.** A conformance script takes both the **build folder** (source under test) and a **separate conformance tests folder** (the tests to execute against that build). Both arrive as **absolute paths** from current renderers (older renderer versions passed relative ones) — the script must work with both.
46
+ 2. **Tests are loaded from outside the working folder.** The build is staged into the working folder `<temp>/<lang>_<basename>` (system temp directory + language id + basename of `$1` — see [Conventions](#conventions)) and the script `cd`s into it, but the test command is pointed at the conformance tests folder, resolved to an **absolute path** up front (`$CONFORMANCE_TESTS_FOLDER` below). Tests are never copied into the staging area.
47
+
48
+ Everything else — toolchain check, build staging, dependency isolation, exit codes — is the same.
49
+
50
+ ## Pick the Shell
51
+
52
+ The harness runs only Bash (`.sh`) scripts, on macOS, Linux and WSL alike. Always write `run_conformance_tests_<lang>.sh`, and make it work on all of them.
53
+
54
+ A PowerShell (`.ps1`) copy is optional and only for people who run the script by hand on native Windows; the harness never runs it. Write one only if the user asks for it. The same pattern applies to both — only the syntax changes.
55
+
56
+ ## The Pattern
57
+
58
+ 1. **Toolchain check.** Verify that the required language runtime / build tool (and the required version, if any) is installed. If not, print an error and exit with code `69`.
59
+ 2. **Argument validation.** Require **two** positional arguments: `<build_folder>` and `<conformance_tests_folder>`. If either is missing, print usage and exit with code `69`.
60
+ 3. **Resolve the conformance tests folder to an absolute path.** Current renderers pass `$2` as an absolute path; older ones passed it relative to the invocation directory. Resolve it once, up front, into a variable the test command in step 8 uses:
61
+ - Bash: `case "$2" in /*) CONFORMANCE_TESTS_FOLDER="$2" ;; *) CONFORMANCE_TESTS_FOLDER="$(pwd)/$2" ;; esac`
62
+ - PowerShell: `if (-not [System.IO.Path]::IsPathRooted($ConformanceTestsFolder)) { $ConformanceTestsFolder = Join-Path (Get-Location) $ConformanceTestsFolder }`
63
+
64
+ Never concatenate `$current_dir/$2` at the point of use — with an absolute `$2` that produces a doubled path (`/project//abs/path/...`), the classic symptom being `ImportError: Start directory is not importable` pointing at a path that contains the project root twice.
65
+ 4. **Working directory setup.** Define a working folder at `<temp>/<lang>_<basename>` (`/tmp/<lang>_$(basename "$1")` in Bash, `Join-Path ([System.IO.Path]::GetTempPath()) "<lang>_$(Split-Path $BuildFolder -Leaf)"` in PowerShell). Wipe it (`rm -rf` / `Remove-Item -Recurse -Force`) and recreate it. Register cleanup so the folder is removed when the script exits — `trap 'rm -rf "$WORKING_FOLDER"' EXIT` in Bash, `Remove-Item -Recurse -Force` in the `finally` block in PowerShell. This folder — and **only** this folder — is where every subsequent write must land.
66
+ 4b. **Refuse conformance tests in the build folder.** Conformance and acceptance tests live in the conformance tests folder (`$2`) and nowhere else. Before anything is staged, look for them in `$1`: any file carrying a conformance or acceptance label (`conformance tests of functionality`, `conformance tests of the spec`, `acceptance test <n> of functionality`), and any test file under a folder or name that says conformance or acceptance. Found any: print each path, say they belong in the conformance tests folder, and exit `1`. See [Tests in the build folder](#tests-in-the-build-folder).
67
+ 5. **Copy the build.** Recursively copy everything from `<build_folder>` (`$1`) into the working folder. **Do not** copy the conformance tests — they stay where they are. After this step both `$1` (build folder) and `$2` (conformance tests folder) are treated as **read-only** for the rest of the script.
68
+ 6. **Enter the working directory.** `cd` / `Set-Location` into `<temp>/<lang>_<basename>`. If that fails, exit with code `69`. All remaining steps run from inside the working folder; they must never write back to `$1` or `$2`.
69
+ 7. **Install dependencies into an isolated environment inside `<temp>/<lang>_<basename>`.** Set up a per-working-folder dependency location (a Python venv at `./.venv`, a local `./node_modules`, a project-scoped Maven repo at `./.m2`, etc.) and install/resolve all dependencies into it. **Never** install into the source build folder (`$1`), the conformance tests folder (`$2`), the user's global cache (`~/.m2`, system-wide `pip`, `~/.cargo`, `~/.npm`, ...), or anywhere outside `<temp>/<lang>_<basename>`. If the install command fails, propagate its exit code immediately and **do not** proceed to step 8. See [Dependency isolation](#dependency-isolation).
70
+ 7b. **Static checks of the conformance tests.** Once the build and the test libraries are installed - so the tests resolve against them as they do when they run - check **the conformance tests in `$CONFORMANCE_TESTS_FOLDER`, and only them**: the formatter in check mode, the linter, and the type checker where the language has one apart from its compiler. See [Static checks of the tests](#static-checks-of-the-tests). Run every check, even after one fails, print each one's whole output, remember whether any failed - and go on to step 8 whatever they said, so one run reports both.
71
+ 8. **Run the conformance tests.** Invoke the language's standard test command, **pointed at `$CONFORMANCE_TESTS_FOLDER`** (the absolute path resolved in step 3) **and at nothing else**, so it runs the whole suite in one go - and only it. The build's own tests (its unit tests, and anything else in it) are never collected: no discovery from the working folder, and no test configuration in the build (a `pytest.ini` / `pyproject.toml` `testpaths`, a Jest `roots`) allowed to widen the run beyond `$CONFORMANCE_TESTS_FOLDER`. The script's final exit code is whatever the test command returns — except for the "no tests discovered" case below.
72
+
73
+ Then exit: the test command's own non-zero code when the suite failed; else `80` when only the static checks of step 7b failed; else `0`.
74
+
75
+ The test command is **read-only** with respect to `$CONFORMANCE_TESTS_FOLDER`. It loads test files from there, but any artifacts the runner produces (caches, JUnit XML, coverage reports, compiled test classes, etc.) must land inside `<temp>/<lang>_<basename>`, not next to the test files. If your chosen runner defaults to writing output beside the tests, pass an explicit output-directory flag pointing inside the working folder (e.g. `pytest --basetemp=./.pytest_tmp`, `jest --cacheDirectory=./.jest_cache`, Maven `target/` under the working folder via `mvn -f "$CONFORMANCE_TESTS_FOLDER/pom.xml" -Dproject.build.directory="$(pwd)/target" test`).
76
+
77
+ ### Read-only inputs — hard rule
78
+
79
+ A conformance script has **two** read-only inputs: the source build folder (`$1`) and the conformance tests folder (`$2`). Neither one may be written to under any circumstances. The script must never:
80
+
81
+ - install dependencies into `$1` or `$2` (no `pip install` inside `$1`/`$2`, no `npm install` inside them, no `mvn install` writing into them, no Cargo build artifacts ending up under them),
82
+ - write a virtualenv / `node_modules` / `.m2` / `.gocache` / `.cargo` directory inside `$1` or `$2`,
83
+ - run the test command with its `cwd` set to `$1` or `$2` (every test command runs from inside `<temp>/<lang>_<basename>` after the `cd` in step 6),
84
+ - create logs, caches, build outputs, JUnit XML, coverage reports, compiled test classes, or temp files inside `$1` or `$2`.
85
+
86
+ Why each input is read-only:
87
+
88
+ - **`$1` (build folder)** is shared with the renderer (`plain_modules/<module>/code` by default) and downstream tooling. Writing into it corrupts the renderer's view of "what was generated" and breaks subsequent renders. The whole point of staging into the system temp directory is so the source folder stays a clean, reproducible artifact of the render.
89
+ - **`$2` (conformance tests folder)** is the user's authored test source — typically checked into version control. Writing into it pollutes the working tree, churns git status, and (with frameworks that auto-discover) can make subsequent runs pick up generated files as if they were tests.
90
+
91
+ If you find yourself about to issue any command whose `cwd` is `$1` or `$2`, or whose target path starts with `$1/` or `$2/`, **stop**. Either move the operation into `<temp>/<lang>_<basename>`, or you're doing something the script must not do.
92
+
93
+ ### Tests in the build folder
94
+
95
+ A conformance test written into the build folder is in the wrong place: nothing runs it as part of the conformance suite, and a runner that discovers tests from the working folder would run it as if it were one - a suite that seems to pass whatever `$2` holds. So the script catches it before it runs anything (step 4b), and says where it belongs. In Bash:
96
+
97
+ ```bash
98
+ MISPLACED=$(grep -rlE --exclude=".turri*" --exclude-dir=.venv --exclude-dir=node_modules --exclude-dir=target \
99
+ "conformance tests of (functionality [0-9]|the spec)|acceptance test [0-9]+ of functionality" "$1" 2>/dev/null; \
100
+ find "$1" -type f \( -ipath "*conformance*" -o -ipath "*acceptance*" \) -iname "*test*" \
101
+ -not -name ".turri*" -not -path "*/.venv/*" -not -path "*/node_modules/*" -not -path "*/target/*" 2>/dev/null)
102
+ if [ -n "$MISPLACED" ]; then
103
+ printf "Conformance tests found in the build folder %s - they belong in the conformance tests folder %s:\n%s\n" "$1" "$CONFORMANCE_TESTS_FOLDER" "$(echo "$MISPLACED" | sort -u)" >&2
104
+ exit 1
105
+ fi
106
+ ```
107
+
108
+ ### Static checks of the tests
109
+
110
+ The conformance tests are held to their language's formatter, linter and type checker, as the code is by the unit testing script. Three things make it work here:
111
+
112
+ - **Check them where they run.** The tests import the test libraries - and, for a library, the build itself - so a check of `$2` on its own cannot resolve them. Run the checks in step 7b, after the install, against the staged environment: the venv the build was installed into, the tests' own Maven, Go or Cargo project with the build in reach as the suite has it. What passes in the merged world is what counts; the tests are never checked alone.
113
+ - **Report the tests' findings only.** The code is checked by the unit testing script, and the conformance agent may not change it. Point each tool at `$CONFORMANCE_TESTS_FOLDER` and keep the code's findings out (`follow_imports = silent` for mypy, a tsconfig whose `include` is the tests alone).
114
+ - **Pin the profile and the flags in the script.** The tests' own configuration files - a `pyproject.toml`, `tsconfig.json`, `Cargo.toml`, `pom.xml` in `$2` - are written by the conformance agent, which could relax a check to pass it. Pass every setting that decides pass or fail on the command line, or in a configuration file the script writes into the working folder, and do not read one from `$2` or `$1`.
115
+
116
+ | Language | Formatter, in check mode | Linter | Type checker - a tests profile |
117
+ |---|---|---|---|
118
+ | Python | `ruff format --check --no-cache --isolated --output-format concise "$CONFORMANCE_TESTS_FOLDER"` | `ruff check --no-cache --isolated --output-format concise --no-fix "$CONFORMANCE_TESTS_FOLDER"` | `mypy --config-file <a file the script writes>` with `disallow_untyped_defs`, `follow_imports = silent` and `cache_dir` in the working folder - typed, not `--strict` |
119
+ | TypeScript | `prettier --check` on the tests' files | `eslint --max-warnings 0` on the tests | `tsc --noEmit -p <a tsconfig the script writes>`: `strict`, `include` the tests alone, the build's types in reach |
120
+ | JavaScript | `prettier --check` on the tests' files | `eslint --max-warnings 0` on the tests | none - unless the test reqs name one |
121
+ | Go | `gofmt -l "$CONFORMANCE_TESTS_FOLDER"` | `go vet ./...` in the tests' own module | the compiler |
122
+ | Rust | `cargo fmt --check --manifest-path "$CONFORMANCE_TESTS_FOLDER/Cargo.toml"` | `cargo clippy --all-targets --manifest-path "$CONFORMANCE_TESTS_FOLDER/Cargo.toml" -- -D warnings` | the compiler |
123
+ | Java | only one the test reqs name (`google-java-format --dry-run --set-exit-if-changed`) | the tests compiled with `-Xlint:all -Werror` (`-Dmaven.compiler.failOnWarning=true`) | the compiler |
124
+ | Dart / Flutter | `dart format --output=none --set-exit-if-changed "$CONFORMANCE_TESTS_FOLDER"` | `dart analyze --fatal-infos "$CONFORMANCE_TESTS_FOLDER"` (`flutter analyze` for Flutter) | the analyzer, in the same command |
125
+
126
+ The tools come from where the tests' dependencies come from - the build's dev dependencies installed in step 7, or what the script installs beside them for the tests (`uv pip install ruff mypy`, as it installs `pytest`). A checker the machine lacks, which nothing installs, is `69`. Every build artifact and cache the checks make goes in the working folder, never in `$2` - a Cargo or Maven project in `$2` is built with its target directory in the working folder.
127
+
128
+ turri reads exit `80` as the tests' own: the conformance agent is sent the findings, and no judge is asked whether the code or the tests are wrong. So `80` is only ever "the suite passed and only the checks of the tests failed".
129
+
130
+ ### "No tests discovered" detection
131
+
132
+ The Python reference script grep's the test runner output for `"Ran 0 tests in"` and exits `1` if no tests ran. Replicate the equivalent check for the target language wherever that language's test runner silently passes when given an empty test set:
133
+
134
+ - Python `unittest`: `"Ran 0 tests in"`
135
+ - Node.js `jest`: `"No tests found"`
136
+ - Go `go test`: `"no test files"` / `"no tests to run"`
137
+ - Rust `cargo test`: `"running 0 tests"`
138
+ - Java `mvn test`: usually fails loudly already; no extra check needed.
139
+
140
+ A silently-passing zero-test run is the most dangerous failure mode of a conformance runner — always guard against it.
141
+
142
+ ## Conventions
143
+
144
+ Shared across both shell flavors:
145
+
146
+ - **Exit codes:**
147
+ - `69` — unrecoverable invocation error: missing argument, missing toolchain, can't enter working folder, can't create venv. Matches the reference scripts' `UNRECOVERABLE_ERROR_EXIT_CODE`.
148
+ - `1` — "no tests discovered" guard tripped (see above).
149
+ - `80` — the suite passed and only the static checks of the tests failed (step 7b).
150
+ - Any other non-zero code — propagated from the underlying test command.
151
+ - **Working folder naming:** `<temp>/<lang>_<basename>` — the system temp directory (`/tmp` in Bash, `[System.IO.Path]::GetTempPath()` in PowerShell) plus a short identifier for the language (`java`, `python`, `node`, `go`, `rust`, ...) and the **basename** of the *first* argument (the build folder — `$(basename "$1")` / `Split-Path $BuildFolder -Leaf`), never the conformance tests folder and never the raw argument (it may be absolute; concatenating it produces broken doubled paths). All dependency installs, build outputs, caches, test runner artifacts, and the test invocation itself live inside this folder. Nothing the script does should touch `$1` after step 5, or `$2` at any point.
152
+ - **Cleanup ownership:** the script owns its working folder and removes it on exit, success and failure alike (`trap 'rm -rf "$WORKING_FOLDER"' EXIT` in Bash; `Remove-Item -Recurse -Force` in the PowerShell `finally` block, after `Pop-Location`).
153
+ - **Logging — be as verbose as possible.** The script is the only thing the operator sees between a `turri` render and a green/red conformance result; when it fails, the only forensic evidence anyone has is its stdout/stderr. Treat the script like a production runbook, not a quiet helper. Concretely:
154
+ - **Announce every step before doing it**, with the exact value of every variable involved — the resolved build folder, the resolved conformance-tests folder, the working folder, the language, the toolchain version detected, the isolation root being set up, and the test command about to run. "Running tests" alone is useless; "Running `python -m unittest discover -b -s /abs/path/to/tests` from working folder `/tmp/python_build/` with venv activated at `./.venv` (Python 3.11.6)" is triage-ready.
155
+ - **Echo every non-trivial command before executing it.** In Bash, use `set -x` for the body of the script (or `echo "+ <cmd>"` immediately before each call); in PowerShell, set `$VerbosePreference = 'Continue'` and use `Write-Verbose` / `Write-Host` to print each command line with its arguments.
156
+ - **Print clear section banners.** Each pattern step gets a banner like `===== [7/8] Install dependencies =====` so a long log can be navigated by eye.
157
+ - **Print resolved absolute paths**, not just the relative names. Operators reading the log on a different machine need to know where the venv / `.m2` / `node_modules` / `.gocache` / `.cargo` actually landed, and what `$2` resolved to.
158
+ - **Print the toolchain's own `--version` output** (and the path it resolved from) during step 1, even on success. This is the single most useful piece of forensic data when conformance passes on one machine but fails on another.
159
+ - **Surface the install output verbatim** — do not pipe it to `/dev/null`, do not redirect to a log file inside the working folder. The operator must see every dependency-resolver line in the script's own output stream. Drop the `VERBOSE`-gated wrapping from the Python reference — conformance output is where forensic data is most valuable.
160
+ - **On failure, print what was about to run before exiting** — the exact test command, the working directory, the resolved `$CONFORMANCE_TESTS_FOLDER`, and the relevant environment variables (`PYTHONPATH`, `NODE_PATH`, `GOMODCACHE`, `CARGO_HOME`, `MAVEN_OPTS`, `PATH`, plus `VIRTUAL_ENV` for Python).
161
+ - **Print a final summary line** that names the test command, the exit code, the resolved conformance-tests folder, and the working folder so the operator knows exactly what to re-run by hand if needed.
162
+ Verbosity is not noise here — a chatty script that documents itself in its own output is the difference between a 30-second triage and a 30-minute one. Never trade verbosity for terseness.
163
+ - **Resolve `$2` before any `cd`.** This is the single most common bug in hand-written conformance scripts: using the conformance-tests argument after changing directory. Resolve it to an absolute path in step 3 (absolute → use as-is; relative → prefix the invocation directory) and use only the resolved variable afterwards. The resolved value must also appear in the verbose log (per the logging rule above) so misresolutions of `$2` are visible at a glance.
164
+
165
+ ### Dependency isolation
166
+
167
+ The dependency environment must live **inside** `$WORKING_FOLDER` so the test run can't be polluted by — or pollute — the user's global caches. Pick the most idiomatic isolation mechanism for the language:
168
+
169
+ | Language | Isolation mechanism | Install command (run inside `$WORKING_FOLDER`) | Test command (point at `$CONFORMANCE_TESTS_FOLDER`) |
170
+ |---|---|---|---|
171
+ | Python | `venv` at `./.venv` | `python3 -m venv .venv && source .venv/bin/activate && pip install -r requirements.txt` | `python -m unittest discover -b -s "$CONFORMANCE_TESTS_FOLDER"` (or `pytest "$CONFORMANCE_TESTS_FOLDER"`) |
172
+ | Node.js | local `./node_modules` (default) | `npm ci` (preferred) or `npm install` | `npx jest --rootDir "$CONFORMANCE_TESTS_FOLDER"` |
173
+ | Java | project-scoped Maven repo at `./.m2` | `mvn -Dmaven.repo.local=./.m2 install -DskipTests` (build + install artifact so the test pom can resolve it) | `mvn -f "$CONFORMANCE_TESTS_FOLDER/pom.xml" -Dmaven.repo.local="$(pwd)/.m2" test` |
174
+ | Go | module cache at `./.gocache` | `GOMODCACHE="$PWD/.gocache" go mod download` (optional pre-warm) | `GOMODCACHE="$PWD/.gocache" go test "$CONFORMANCE_TESTS_FOLDER/..."` |
175
+ | Rust | cargo home at `./.cargo` | `CARGO_HOME="$PWD/.cargo" cargo fetch` (optional pre-warm) | `CARGO_HOME="$PWD/.cargo" cargo test --manifest-path "$CONFORMANCE_TESTS_FOLDER/Cargo.toml"` |
176
+
177
+ Notes:
178
+
179
+ - **Every path in the install command and test command is relative to `<temp>/<lang>_<basename>`.** That's why the script `cd`s into the working folder in step 6 — from that point on, `./.venv`, `./node_modules`, `./.m2`, etc. all resolve under `<temp>/<lang>_<basename>`, never under `$1` or `$2`.
180
+ - **Always pass the isolation flag/env var to both the install command and the test command.** They must agree on where deps live, otherwise the test command will silently fall back to the global cache **or** (worse) write into `$1` / `$2`.
181
+ - **Python is the only ecosystem where the venv is mandatory** to satisfy "into a virtual environment" literally. The others use language-native equivalents that achieve the same isolation.
182
+ - **Propagate the install exit code immediately.** In Bash: `<install cmd> || exit $?`. In PowerShell: check `$LASTEXITCODE` and `exit $LASTEXITCODE` if non-zero.
183
+ - **Time the dependency setup** with `date +%s.%N` (Bash) / `Get-Date` (PowerShell) and print `"Requirements setup completed in X.XX seconds"`.
184
+
185
+ ### Bash specifics
186
+
187
+ - **Shebang:** `#!/bin/bash`.
188
+ - **File naming:** `run_conformance_tests_<lang>.sh`, placed in `assets/` (skill reference) or `test_scripts/` (target project).
189
+ - **Arguments:** `$1` = build folder, `$2` = conformance tests folder.
190
+ - **Make it executable:** `chmod +x` the produced script.
191
+ - **`cd` failure check:** the reference scripts use the `cd ... 2>/dev/null` + `[ $? -ne 0 ]` pattern. Keep it.
192
+ - **Portable:** the harness runs the script on macOS and Linux alike. Stick to POSIX tools and flags both have (e.g. `cp -R`, `mktemp`, plain `grep` - not GNU-only or BSD-only flags, not a macOS-only `/usr/libexec/java_home`), and let the toolchain check report clearly when the runtime is missing.
193
+
194
+ ### PowerShell specifics (by-hand Windows copy only)
195
+
196
+ The harness never runs `.ps1` scripts. These notes apply only to an optional copy for people running the suite by hand on Windows.
197
+
198
+ - **No shebang.** Use a `param([Parameter(Mandatory=$true)][string]$BuildFolder, [Parameter(Mandatory=$true)][string]$ConformanceTestsFolder)` block at the top instead.
199
+ - **File naming:** `run_conformance_tests_<lang>.ps1`.
200
+ - **Exit codes:** use `exit 69` etc. (PowerShell honors them just like Bash).
201
+ - **Toolchain check:** prefer `Get-Command <tool> -ErrorAction SilentlyContinue` and, where a specific version is needed, parse the tool's `--version` output.
202
+ - **Filesystem:** use `Test-Path`, `Remove-Item -Recurse -Force`, `New-Item -ItemType Directory`, `Copy-Item -Recurse`, `Set-Location`. Quote paths to handle spaces.
203
+ - **Resolve `$ConformanceTestsFolder` to absolute** with `[System.IO.Path]::IsPathRooted` + `Join-Path (Get-Location) ...` **before** any `Set-Location` call.
204
+ - **No `chmod` step needed.** If execution policy is likely to block the script, mention `Set-ExecutionPolicy -Scope CurrentUser RemoteSigned` to the user — don't bake it into the script.
205
+
206
+ ## Workflow
207
+
208
+ 1. Confirm the target **language** and **dependency manifest** (`pom.xml`, `requirements.txt` / `pyproject.toml`, `package.json`, `go.mod`, `Cargo.toml`, ...). Ask if either is unclear.
209
+ 2. Read [assets/run_conformance_tests_java.sh](assets/run_conformance_tests_java.sh) and [assets/run_conformance_tests_python.sh](assets/run_conformance_tests_python.sh) to refresh the exact structure.
210
+ 3. Translate each step into the equivalent Bash commands for the target language. The toolchain check, dependency install, and test invocation are the language-specific parts; the rest is mechanical.
211
+ 4. Pick the right row from the [Dependency isolation](#dependency-isolation) table — use the same flag/env var in steps 7, 7b and 8 — and the checks from [Static checks of the tests](#static-checks-of-the-tests).
212
+ 5. Add the language-appropriate "no tests discovered" guard from [No tests discovered detection](#no-tests-discovered-detection), and the guard against conformance tests in the build folder from [Tests in the build folder](#tests-in-the-build-folder).
213
+ 6. Save the new script as `test_scripts/run_conformance_tests_<lang>.sh` and `chmod +x` it. Write a `.ps1` copy only if the user wants to run it by hand on Windows.
214
+ 7. **Make sure turri finds the script.** Do not link it from the specs - turri finds the conformance testing script in the project root (the folder that holds `plain_modules/`) and puts it, whole, into the prompts of the agents that write and review the conformance tests itself, whenever conformance tests are written for a build; a link to it from a spec is ignored. It looks, in order, at `config.turri.yaml` in the root (`conformance-tests-script: <path relative to the root>`) - with the chosen stack's `config.turri.<stack>.yaml` over it, then for the one `run_conformance_tests*.sh` in the root, then for the one in `test_scripts/`. Saving the script in `test_scripts/` (or the root) is enough when it is the only one there. If the project keeps it elsewhere, name it in `config.turri.yaml` as `conformance-tests-script:` - and when the project has only a `config.yaml`, copy it to `config.turri.yaml` first (and each `config.<name>.yaml` to `config.turri.<name>.yaml`) and edit the copy; `config.yaml` may be another tool's, and is never written. If the project has modules on different stacks - e.g. a Python backend and a React frontend side by side, sharing only an imported module - each part is on a stack of its own, and each stack names its own script in its own file beside `config.turri.yaml`: `conformance-tests-script:` in `config.turri.backend.yaml` for the stack `backend`, in `config.turri.frontend.yaml` for the stack `frontend`. A stack is chosen, never worked out: tell the user to choose it with `/stack <stack>` (`--stack <stack>` on the command line) before building that part. turri never guesses between two. The script is required: with conformance testing on, a build without one stops before it starts. The `***test reqs***` still describe the conformance framework and command in words; do not paraphrase the script into them.
215
+
216
+ ## Anti-Patterns
217
+
218
+ - **(Hard mistake) Don't install into, build into, or otherwise write to the source build folder (`$1`) or the conformance tests folder (`$2`).** Both arguments are read-only input. Every install, cache, build artifact, log, JUnit XML, coverage report, compiled test class, and temp file must land in `<temp>/<lang>_<basename>`. This includes never running `pip install`, `npm install`, `mvn install`, or `cargo build` with `$1` or `$2` as their `cwd` or target; never letting a venv / `node_modules` / `.m2` / `.gocache` / `.cargo` directory appear inside `$1` or `$2`; and never running the test command from inside either folder. The whole point of staging into the system temp directory is so the build folder remains a clean artifact of the render and the conformance tests folder remains a clean tree under the user's version control — writing to either one corrupts those guarantees.
219
+ - **(Hard mistake) Don't build any path by concatenating a raw argument.** `$1` and `$2` arrive as absolute paths from current renderers. Patterns like `WORKING_FOLDER=.tmp/$1`, `WORKING_FOLDER=<lang>_$1`, or `"$current_dir/$2"` silently produce doubled paths (`/project//abs/path/...`) — the classic symptom is `ImportError: Start directory is not importable` or "folder does not exist" pointing at a path that contains the project root twice. Always derive the working folder from `$(basename "$1")` / `Split-Path -Leaf`, and use the `$CONFORMANCE_TESTS_FOLDER` resolved in step 3.
220
+ - **Don't rely on anything being set up before the script runs.** The script is self-contained: it stages the build and installs dependencies itself, every time. Don't look for a pre-warmed working folder or environment left by an earlier run.
221
+ - **Don't copy the conformance tests folder into the working folder.** Only the build folder is staged. The test folder is read in place from `$CONFORMANCE_TESTS_FOLDER`.
222
+ - **Don't compute the test path after `cd`.** Resolve `$2` to an absolute path in step 3; otherwise a relative `$2` will be resolved against the working folder and silently miss the tests.
223
+ - **Don't expect per-functionality subfolders in `$2`.** `$2` holds the module's whole conformance suite; point the test command at it and let the runner discover every test in it.
224
+ - **Don't run tests from anywhere but the conformance tests folder, and don't let conformance tests in the build folder pass unnoticed.** The build's tests are the unit testing script's; a conformance test in the build folder is misplaced, and the script fails on it (step 4b) instead of running it or ignoring it.
225
+ - **Don't skip the "no tests discovered" check.** A conformance suite that finds zero tests and exits `0` is the worst possible failure mode — it looks like success.
226
+ - **Don't skip the toolchain check**, even when "everyone has it installed" — exit code `69` is what the calling system relies on to detect a missing runtime.
227
+ - **Don't reuse the source folder in place.** Always copy into `<temp>/<lang>_<basename>` first; the renderer relies on this isolation.
228
+ - **Don't skip cleanup.** Register the `trap` / `finally` removal of the working folder right after creating it, so it is removed on success and failure alike.
229
+ - **Don't change the exit-code contract.** Other parts of the system branch on `69`, `1` and `80` specifically — and these codes must be identical between the Bash script and any PowerShell copy.
230
+ - **Don't check the tests on their own, or the code with them.** The checks run after the install, against what the tests run with, and report the tests' findings alone.
231
+ - **Don't let the tests' own configuration decide the checks.** The flags and the profile are the script's; a config file in `$2` is the conformance agent's to write.
232
+ - **Don't skip the suite because a check failed, and don't exit `80` when the suite failed.** Both run every time; `80` means the suite passed.
233
+ - **Don't write a cross-shell hybrid** (e.g. a `.sh` that detects PowerShell, or vice versa). Ship one script per shell, named with the appropriate extension.
234
+ - **Don't ship only a `.ps1`.** The harness runs `.sh` scripts only; a project with just a PowerShell runner has no conformance testing script as far as turri is concerned.
235
+ - **Don't install dependencies into the user's global location** (`~/.m2`, system-wide `pip`, `~/.cargo`, etc.). Always isolate inside `$WORKING_FOLDER` so concurrent runs and other projects can't interfere.
236
+ - **Don't run the test command without first verifying the install succeeded.** A failed install followed by a "test" run produces misleading errors that look like test failures.
237
+ - **Don't link the script from the specs, and don't leave turri guessing.** turri finds the script in `config.turri.yaml`, the project root, or `test_scripts/`, shows it to the agents that write the conformance tests itself, and stops before the build starts without it; a link to it from a spec is ignored. Put it where it is found, and when there are two conformance testing scripts in one folder, name the one to use as `conformance-tests-script:` - in each stack's `config.turri.<stack>.yaml` when they are for parts on different stacks (see Workflow step 7).
238
+ - **Don't write a terse script.** Silent steps, `>/dev/null` redirects on the install output, missing `--version` prints, absent step banners, an un-logged resolved `$2`, and a missing final summary all make the script harder to debug than the tests it is running. Follow the *Logging — be as verbose as possible* rule under [Conventions](#conventions) literally: every step announces itself, every command is echoed, the resolved `$CONFORMANCE_TESTS_FOLDER` is printed, every failure prints what was about to run and where, and the final summary names the test command, exit code, and working folder.