@turri-dev/cli 0.0.0-stage → 0.1.1

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 +319 -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 +75 -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 +118 -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,98 @@
1
+ #!/bin/bash
2
+ # The unit tests of a Python build, with its static checks: ruff's formatter in check mode, ruff's linter and mypy,
3
+ # each from the project's own `dev` dependency group, then pytest - as stdlib/lang/python asks for them.
4
+ #
5
+ # run_unittests_python.sh <build folder>
6
+ #
7
+ # The build folder is read only: the build is staged in a working folder in /tmp and everything runs there.
8
+ # Every check runs, and the tests run whatever the checks said, so one run reports both.
9
+ # Exit codes: 0 all pass; 1 bad usage; 2 a filesystem problem; 69 a toolchain missing on this machine;
10
+ # 80 the tests passed and only the static checks did not; any other, the failing install or test tool's own.
11
+
12
+ set -u
13
+ STATIC_CHECKS_FAILED=80
14
+
15
+ echo "===== [1/8] Toolchain check ====="
16
+ if ! command -v uv >/dev/null 2>&1; then
17
+ echo "Error: uv is not installed on this machine (https://docs.astral.sh/uv/)."
18
+ exit 69
19
+ fi
20
+ echo "uv: $(command -v uv) - $(uv --version)"
21
+ PYTHON="$(uv python find --system --no-python-downloads 3.12 2>/dev/null)" || {
22
+ echo "Error: Python 3.12 is not installed on this machine; no runtime is downloaded."
23
+ exit 69
24
+ }
25
+ echo "Python: $PYTHON - $("$PYTHON" --version 2>&1)"
26
+
27
+ echo "===== [2/8] Argument validation ====="
28
+ if [ -z "${1:-}" ]; then
29
+ echo "Usage: $0 <build folder>"
30
+ exit 1
31
+ fi
32
+ SOURCE="$(cd "$1" 2>/dev/null && pwd)" || { echo "Error: the build folder '$1' does not exist."; exit 2; }
33
+ echo "Build folder (read only): $SOURCE"
34
+
35
+ echo "===== [3/8] Working folder ====="
36
+ # A folder of its own each run: runs side by side never share one.
37
+ WORKING_FOLDER="$(mktemp -d "/tmp/python_$(basename "$SOURCE").XXXXXX")" || { echo "Error: could not create a working folder in /tmp."; exit 2; }
38
+ trap 'rm -rf "$WORKING_FOLDER"' EXIT
39
+ echo "Working folder: $WORKING_FOLDER"
40
+
41
+ echo "===== [4/8] Copy the build ====="
42
+ EXCLUDES=(--exclude=.venv --exclude=venv --exclude=__pycache__ --exclude=.mypy_cache --exclude=.ruff_cache --exclude=.pytest_cache --exclude=.git)
43
+ echo "+ tar -C $SOURCE ${EXCLUDES[*]} -cf - . | tar -C $WORKING_FOLDER -xf -"
44
+ tar -C "$SOURCE" "${EXCLUDES[@]}" -cf - . | tar -C "$WORKING_FOLDER" -xf - || { echo "Error: could not copy the build folder."; exit 2; }
45
+
46
+ echo "===== [5/8] Enter the working folder ====="
47
+ cd "$WORKING_FOLDER" 2>/dev/null || { echo "Error: cannot enter $WORKING_FOLDER."; exit 2; }
48
+ echo "Now in: $(pwd)"
49
+
50
+ echo "===== [6/8] Dependencies ====="
51
+ if [ ! -f pyproject.toml ]; then
52
+ echo "Error: there is no pyproject.toml - the project's dependencies, pytest, ruff and mypy among them, go in it."
53
+ exit 1
54
+ fi
55
+ export UV_PROJECT_ENVIRONMENT="$WORKING_FOLDER/.venv" UV_PYTHON="$PYTHON" UV_PYTHON_DOWNLOADS=never
56
+ export UV_CACHE_DIR="${UV_CACHE_DIR:-$WORKING_FOLDER/.uv-cache}" PYTHONDONTWRITEBYTECODE=1
57
+ unset PYTHONPATH PYTHONHOME
58
+ echo "+ uv sync (the project and its dev dependency group into $UV_PROJECT_ENVIRONMENT)"
59
+ uv sync || exit $?
60
+
61
+ echo "===== [7/8] Static checks ====="
62
+ CHECKS=0
63
+ for tool in ruff mypy; do
64
+ if [ ! -x ".venv/bin/$tool" ]; then
65
+ echo "pyproject.toml:1:1: $tool is not in the dev dependency group - add it with \`uv add --dev $tool\`"
66
+ CHECKS=1
67
+ fi
68
+ done
69
+ if [ -x .venv/bin/ruff ]; then
70
+ echo "+ ruff format --check --output-format concise ."
71
+ .venv/bin/ruff format --check --output-format concise . || CHECKS=1
72
+ echo "+ ruff check --output-format concise --no-fix ."
73
+ .venv/bin/ruff check --output-format concise --no-fix . || CHECKS=1
74
+ fi
75
+ if [ -x .venv/bin/mypy ]; then
76
+ # `files` in [tool.mypy] says what to check; without it, the whole build.
77
+ if grep -Eq '^\s*files\s*=' pyproject.toml; then TARGETS=(); else TARGETS=(.); fi
78
+ echo "+ mypy --no-color-output --show-column-numbers ${TARGETS[*]:-}"
79
+ .venv/bin/mypy --no-color-output --show-column-numbers ${TARGETS[@]+"${TARGETS[@]}"} || CHECKS=1
80
+ fi
81
+ [ "$CHECKS" -eq 0 ] && echo "Static checks: passed" || echo "Static checks: FAILED - the findings are above"
82
+
83
+ echo "===== [8/8] Unit tests ====="
84
+ echo "+ uv run --no-sync pytest"
85
+ uv run --no-sync pytest
86
+ TESTS=$?
87
+
88
+ echo "===== Summary ====="
89
+ if [ "$TESTS" -ne 0 ]; then
90
+ STATUS=$TESTS
91
+ elif [ "$CHECKS" -ne 0 ]; then
92
+ STATUS=$STATIC_CHECKS_FAILED
93
+ else
94
+ STATUS=0
95
+ fi
96
+ echo "static checks: $([ "$CHECKS" -eq 0 ] && echo passed || echo failed); unit tests: exit $TESTS"
97
+ echo "Exit: $STATUS; build: $SOURCE; working folder: $WORKING_FOLDER"
98
+ exit "$STATUS"
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env pwsh
2
+
3
+ $ErrorActionPreference = 'Stop'
4
+
5
+ $UNRECOVERABLE_ERROR_EXIT_CODE = 69
6
+
7
+ # ANSI escape code pattern to remove color codes and formatting from output
8
+ $ANSI_ESCAPE_PATTERN = '\x1b\[[0-9;]*[mK]'
9
+
10
+ # Check if subfolder name is provided
11
+ if (-not $args[0]) {
12
+ Write-Host "Error: No subfolder name provided."
13
+ Write-Host "Usage: $($MyInvocation.MyCommand.Name) <subfolder_name>"
14
+ exit $UNRECOVERABLE_ERROR_EXIT_CODE
15
+ }
16
+
17
+ $BuildFolder = $args[0]
18
+
19
+ # Define the path to the subfolder. It lives in the system temp directory;
20
+ # $BuildFolder may be an absolute path, so only its leaf name is used.
21
+ $NODE_SUBFOLDER = Join-Path ([System.IO.Path]::GetTempPath()) "node_$(Split-Path $BuildFolder -Leaf)"
22
+
23
+ if ($env:VERBOSE -eq "1") {
24
+ Write-Host "Preparing Node subfolder: $NODE_SUBFOLDER"
25
+ }
26
+
27
+ # Check if the node subfolder exists
28
+ if (Test-Path $NODE_SUBFOLDER) {
29
+ # Delete all files and folders except "node_modules", "build", and "package-lock.json"
30
+ Get-ChildItem -Path $NODE_SUBFOLDER -Force |
31
+ Where-Object {
32
+ $_.Name -ne "node_modules" -and
33
+ $_.Name -ne "build" -and
34
+ $_.Name -ne "package-lock.json"
35
+ } | Remove-Item -Recurse -Force
36
+
37
+ if ($env:VERBOSE -eq "1") {
38
+ Write-Host "Cleanup completed, keeping 'node_modules' and 'package-lock.json'."
39
+ }
40
+ } else {
41
+ if ($env:VERBOSE -eq "1") {
42
+ Write-Host "Subfolder does not exist. Creating it..."
43
+ }
44
+
45
+ New-Item -ItemType Directory -Path $NODE_SUBFOLDER -Force | Out-Null
46
+ }
47
+
48
+ Copy-Item -Path "$BuildFolder/*" -Destination $NODE_SUBFOLDER -Recurse -Force
49
+
50
+ # Move to the subfolder
51
+ if (-not (Test-Path $NODE_SUBFOLDER)) {
52
+ Write-Host "Error: Subfolder '$BuildFolder' does not exist."
53
+ exit $UNRECOVERABLE_ERROR_EXIT_CODE
54
+ }
55
+
56
+ Push-Location $NODE_SUBFOLDER
57
+
58
+ try {
59
+ # Install libraries
60
+ npm install
61
+
62
+ # Execute all React unittests in the subfolder
63
+ Write-Host "Running React unittests in $BuildFolder..."
64
+ # Temporarily allow stderr output without throwing (npm/jest may write to stderr)
65
+ # ForEach-Object converts ErrorRecord objects (from stderr) to plain strings to avoid verbose error formatting
66
+ $ErrorActionPreference = 'Continue'
67
+ $output = npm test -- --runInBand --silent --detectOpenHandles 2>&1 | ForEach-Object { if ($_ -is [System.Management.Automation.ErrorRecord]) { $_.Exception.Message } else { $_ } } | Out-String
68
+ $TEST_EXIT_CODE = $LASTEXITCODE
69
+ $ErrorActionPreference = 'Stop'
70
+
71
+ # Strip ANSI escape codes
72
+ $output = $output -replace $ANSI_ESCAPE_PATTERN, ''
73
+ Write-Host $output
74
+
75
+ # Check if tests failed
76
+ if ($TEST_EXIT_CODE -ne 0) {
77
+ Write-Host "Error: Tests failed with exit code $TEST_EXIT_CODE"
78
+ exit $TEST_EXIT_CODE
79
+ }
80
+
81
+ exit $TEST_EXIT_CODE
82
+ } finally {
83
+ Pop-Location
84
+ if (Test-Path $NODE_SUBFOLDER) {
85
+ Remove-Item -Path $NODE_SUBFOLDER -Recurse -Force -ErrorAction SilentlyContinue
86
+ }
87
+ }
@@ -0,0 +1,117 @@
1
+ ---
2
+ name: init-plain-project
3
+ description: >-
4
+ Lightweight initializer for a new ***plain project. Asks about the base
5
+ technology and project kind, asks whether conformance testing is enabled,
6
+ then scaffolds a template import module (with base implementation reqs and
7
+ test reqs), a stub top-level module, the unit testing script, and
8
+ (optionally) the conformance testing script under `test_scripts/`. Does NOT run `validate`. Use when the user wants a
9
+ quick project skeleton to start writing functional specs against, without
10
+ the full `brood` interview.
11
+ allowed-tools: [read, write, edit, bash, ls, grep, find]
12
+ ---
13
+
14
+ # Init Plain Project
15
+
16
+ ## Scope
17
+
18
+ This skill is intentionally **minimal**. It produces a runnable project skeleton — not a complete spec. **No `***definitions***` sections are written by this skill — not in the template module, not in the top module.** No functional specs, no concepts, no acceptance tests, no validation. The user will fill those in afterwards with `bud`, `add-concept`, `add-functional-spec`, etc.
19
+
20
+ What this skill writes:
21
+
22
+ - `template/base.plain` — an import module with the project's base `***implementation reqs***` and `***test reqs***`.
23
+ - `<project>.plain` — a top-level module that imports `base`. Frontmatter only — no body sections. The user adds `***functional specs***` later.
24
+ - `test_scripts/run_unittests_<lang>.sh` — always.
25
+ - `test_scripts/run_conformance_tests_<lang>.sh` — only if conformance testing is enabled.
26
+
27
+ turri requires these scripts: a build with no unit testing script (or, with conformance on, no conformance testing script) stops before it starts. The harness runs them with Bash on the person's machine, so they are `.sh` scripts.
28
+
29
+ What this skill does **not** do:
30
+
31
+ - Run `validate`.
32
+ - Author concepts, functional specs, or acceptance tests.
33
+ - Probe the host environment (`check-plain-env` is a separate step the user can run later).
34
+
35
+ ## Workflow
36
+
37
+ ### 1. Ask the project basics
38
+
39
+ Ask each with `ask_user`, one question per call, in this order:
40
+
41
+ - **Project name** — used as the top module filename and as `:AppName:` later. Free-form (`free_form: true`).
42
+ - **Base technology** — programming language and primary framework (e.g. Python + FastAPI, Node.js + Express, Go + net/http, Java + Spring Boot). Offer the most common stacks as options.
43
+ - **Project kind** — CLI tool, web app, REST API / backend service, library, desktop app, mobile app, other. Offer the common kinds as options.
44
+
45
+ Follow up with one free-form question for anything the options didn't cover (e.g. specific Python version, monorepo layout).
46
+
47
+ ### 2. Ask about testing
48
+
49
+ Ask each with `ask_user`, one question per call:
50
+
51
+ - **Unit testing framework** — propose the canonical one for the chosen language (pytest, Jest, Go `testing`, JUnit, ...) and let the user override.
52
+ - **Conformance testing** — enabled or not. If the user is unsure, briefly explain it adds a `run_conformance_tests` script and per-spec acceptance tests later.
53
+
54
+ ### 3. Author `template/base.plain`
55
+
56
+ Create the import module with `create-import-module`. It must contain:
57
+
58
+ - `***implementation reqs***` — the base stack as requirements **and everything about `:UnitTests:`**:
59
+ - Programming language and version.
60
+ - Primary framework (if any).
61
+ - Dependency / package manager.
62
+ - Project kind as a constraint (e.g. ":Implementation: should be a REST API service.").
63
+ - `:UnitTests:` framework (pytest / Jest / JUnit / Go's `testing` / …) and the command used to run them — phrased in terms of `:UnitTests:` so the partition is explicit.
64
+ - Anything else the user added in the free-form catch-all.
65
+ - `***test reqs***` — the base **conformance**-testing rules (only added if conformance testing is enabled):
66
+ - ":ConformanceTests: must be implemented and executed - do not skip tests."
67
+ - The `:ConformanceTests:` framework and the command used to run them.
68
+ - **Do NOT** put unit-test framework / command here — that lives in `***implementation reqs***` above.
69
+
70
+ Do **not** add a `***definitions***` section to `template/base.plain`. This skill does not author any concepts. Use only the predefined concepts (`:Implementation:`, `:ConformanceTests:`) in the reqs — no project-specific concepts like `:AppName:` or `:App:`. Do not declare `required_concepts` either.
71
+
72
+ Do **not** add `***functional specs***` to `template/base.plain` — it is an import module.
73
+
74
+ ### 4. Author the top module `<project>.plain`
75
+
76
+ Create it at the repo root with frontmatter:
77
+
78
+ ```yaml
79
+ ---
80
+ import:
81
+ - base
82
+ description: <one-line project description>
83
+ ---
84
+ ```
85
+
86
+ Body: **none**. The file ends after the closing `---` of the frontmatter. Do **not** add `***definitions***`, do **not** add `***functional specs***`, do **not** add any other section. The user will add `***functional specs***` later via `add-functional-spec` / `add-functional-specs`, and any concepts via `add-concept`.
87
+
88
+ The file must still be created on disk — an empty body is fine, but the file itself is required.
89
+
90
+ ### 5. Generate the testing scripts
91
+
92
+ Call the corresponding implementation skills in order. Each skill writes a Bash script, which is what the harness runs.
93
+
94
+ - `implement-unit-testing-script` — always. It runs the stack's static checks - formatter, linter, type checker - with the unit tests, and they count as the tests do.
95
+ - `implement-conformance-testing-script` — only if conformance testing was enabled. The script is self-contained: it stages the build, installs dependencies, and runs the module's whole conformance suite.
96
+
97
+ ### 6. Check turri finds the scripts
98
+
99
+ turri finds the testing scripts in the project root, not through the specs: first in `config.turri.yaml` (`unittests-script:`, `conformance-tests-script:`, paths relative to the root), then the one `run_unittests*.sh` / `run_conformance_tests*.sh` in the root, then the one of each kind in `test_scripts/`. It puts them into the prompts of the agents that write and run the tests itself, so do not link them from `template/base.plain` (a link to one is ignored). Confirm every generated script is in `test_scripts/` and is the only one of its kind there - or, if the project wants it, that a `config.turri.yaml` at the root names the one to use and the path resolves. A project with parts on different stacks (e.g. a Python backend and a React frontend sharing an imported `base`) keeps one `config.turri.yaml` for what they share and gives each stack its own `config.turri.<stack>.yaml` beside it - `config.turri.backend.yaml`, `config.turri.frontend.yaml` - naming that stack's `unittests-script:` and `conformance-tests-script:`. 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. 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 write the copies; never write `config.yaml`.
100
+
101
+ Do **not** run `validate` here — keeping this skill light is the whole point. The user can run it when they want validation.
102
+
103
+ ### 7. Recap
104
+
105
+ Tell the user what was created and what's next:
106
+
107
+ - Files written: `template/base.plain`, `<project>.plain`, the test scripts.
108
+ - Suggested next steps: add concepts with `add-concept`, add functional specs with `add-functional-spec` or `add-functional-specs`, or jump straight into `bud`.
109
+ - Mention that `validate` has not been run on `<project>.plain` yet.
110
+
111
+ ## Validation checklist
112
+
113
+ Before the recap, walk `references/checklist.md` and confirm every box is met. It is a self-audit of this workflow — never a substitute for it. A box only counts as met when the file is on disk as described; complete any unmet step before recapping.
114
+
115
+ ## Question style
116
+
117
+ Use simple grammatical structures: short direct sentences, one idea per sentence, plain words over jargon. Keep every constraint and edge case the user needs to answer accurately.
@@ -0,0 +1,30 @@
1
+ # Init Plain Project Workflow Checklist
2
+
3
+ Use this to verify the scaffold was produced correctly — never as a substitute for the workflow. Run it once before the recap. This skill is intentionally minimal: it writes a runnable skeleton, not a complete spec. If a box is unmet, go back and complete the step.
4
+
5
+ ## Setup
6
+
7
+
8
+ ## Ask the basics
9
+
10
+ - [ ] Asked the project basics with `ask_user`, one question per call (project name, base technology, project kind), plus a free-form catch-all.
11
+ - [ ] Asked testing with `ask_user`, one question per call (unit-test framework, conformance on/off).
12
+
13
+ ## Author the modules
14
+
15
+ - [ ] Created `template/base.plain` via `create-import-module` with `***implementation reqs***` (language/version, framework, package manager, project kind, and everything about `:UnitTests:` — framework + run command).
16
+ - [ ] Added `***test reqs***` to `template/base.plain` with the `:ConformanceTests:` rules **only** when conformance testing is enabled — and kept unit-test facts out of it.
17
+ - [ ] No `***definitions***`, no `***functional specs***`, and no project-specific concepts in `template/base.plain`; only predefined concepts (`:Implementation:`, `:ConformanceTests:`) used; no `required_concepts` declared.
18
+ - [ ] Created `<project>.plain` at the repo root with frontmatter only (`import: [base]`, `description`) and **no body sections** — the file exists on disk.
19
+
20
+ ## Generate scripts
21
+
22
+ - [ ] Generated `implement-unit-testing-script` (always).
23
+ - [ ] The unit testing script runs the stack's static checks with the tests, exiting `80` when only the checks fail.
24
+ - [ ] Generated `implement-conformance-testing-script` only if conformance was enabled.
25
+ - [ ] Every generated script is in `test_scripts/`, the only one of its kind there - or named in a `config.turri.yaml` at the root (`unittests-script:`, `conformance-tests-script:`) - or, for a part on a stack of its own, in that stack's `config.turri.<stack>.yaml` - whose paths resolve. No script is linked from the specs.
26
+ - [ ] Did **not** run `validate` or `check-plain-env` (out of scope for this skill).
27
+
28
+ ## Recap
29
+
30
+ - [ ] Told the user what was written, suggested next steps (`add-concept`, `add-functional-spec(s)`, `bud`), and noted that `validate` has not been run.
@@ -0,0 +1,126 @@
1
+ ---
2
+ name: mature
3
+ description: >-
4
+ Mature a rough `***plain` spec until it is fully rendered, on its own: the goal is the spec built
5
+ - every functionality from the spec as it stands, its tests passing - and the loop is render,
6
+ watch the agents building it, and when one struggles on something the spec leaves open or
7
+ unclear, settle it in the spec, stop that build and render again. It reads what the builds had to
8
+ decide themselves - assumptions, pitfalls, a failed build's diagnosis, a spec that contradicts
9
+ itself - and writes what the spec should have said, as spec diffs. It decides open choices itself
10
+ and records every decision; it does not ask. It stops when the spec is fully rendered, or when it
11
+ is stuck on something the spec cannot settle. Use when the user has a rough or hand-written spec
12
+ and wants it made to build without steering it. Not for starting from nothing (`brood`,
13
+ `spawn`) or adding a feature (`bud`).
14
+ allowed-tools: [read, write, edit, bash, ls, grep, find, write_spec_diff, regenerate, drift, halt, watch_jobs, spec_findings]
15
+ metadata:
16
+ # What each phase does, in a line - shown under the skill's progress while it runs.
17
+ phases:
18
+ intake: "reads the spec, checks it parses, and makes sure a build can start"
19
+ regenerate: "builds what is left, watches the builds, and settles what the spec leaves open"
20
+ report: "what was built, what struggled, and what was decided in the spec"
21
+ # It writes its fixes one after another, from what the builds show: no answer between them.
22
+ paced: false
23
+ ---
24
+
25
+ # Mature
26
+
27
+ Load the `***plain` syntax rules before writing anything - they are in the system prompt under
28
+ `<plain-rules>`; read `genome/rules/<name>.md` for the full text of any rule you need to follow
29
+ closely.
30
+
31
+ ## Role
32
+
33
+ Act as a `***plain` spec writer who hardens a spec by building it, on your own, until it builds.
34
+
35
+ **The goal:** the spec fully regenerated - `drift` says "Fully regenerated" for every module: every
36
+ functionality regenerated from the spec as it stands, its conformance tests too, and nothing regenerating
37
+ or held back.
38
+
39
+ **The loop:** render what is not built; watch the agents building it; when one struggles on something
40
+ the spec leaves open or unclear, settle it in the spec, stop that build, and render again.
41
+
42
+ Where a spec is silent, the agent that renders it has to decide - a format, a default, an error, a
43
+ rule - and when the decision is hard, or the spec reads two ways, it struggles: its tests keep
44
+ failing, the judge keeps finding the tests or the code wrong, it runs far too long. Much of that is
45
+ the spec's to settle, and once the spec says it, the next build does not struggle. Some of it is not
46
+ - a bug the agent will fix, an environment problem, turri itself - and the spec stays out of
47
+ that.
48
+
49
+ You never ask the user: this runs on its own. Where the spec leaves a real choice, take the reading
50
+ that best fits the rest of the spec, the intent it states and what the builds already did, write it,
51
+ and record the decision for the report. You never change what the spec plainly means, never write the
52
+ spec to match code that does something else, never add features, never touch generated code, and
53
+ never edit a `.plain` file with the file tools once rendering has started - every change is a spec
54
+ diff, with `write_spec_diff`.
55
+
56
+ ## Steps
57
+
58
+ ### intake
59
+
60
+ 1. Find the spec: the `.plain` file(s) the user named, or the project's modules. Read them whole,
61
+ with their `import` and `requires` chains, and the project's `config.turri.yaml` (or the old
62
+ `config.yaml`, when there is no `config.turri.yaml`) and each stack's `config.turri.<stack>.yaml`.
63
+ 2. Run `validate` on each, and fix only what stops it parsing - with the file tools, while nothing
64
+ is built from it yet, otherwise with `write_spec_diff`.
65
+ 3. Make sure a build can start: the unit testing script (and, with conformance tests on, the
66
+ conformance testing script) turri finds. When one is missing, write it by following the
67
+ `implement-unit-testing-script` (or `implement-conformance-testing-script`) skill, for the stack the
68
+ spec's implementation reqs name. The static checks - formatter, linter, type checker - are part of
69
+ the unit testing script, as that skill writes it.
70
+
71
+ Say in two lines what will be rendered, and go on.
72
+
73
+ ### regenerate
74
+
75
+ Run cycles until the goal is met - or you are stuck - and at most twenty. Each cycle:
76
+
77
+ 1. **Check the goal**: `drift` for every module. All fully regenerated: the goal is met - go to the report.
78
+ 2. **Regenerate what is not regenerated**: `regenerate` for each module that is not - one that requires
79
+ another after the one it requires, modules that share nothing together. A module with builds still
80
+ running or queued is left to them.
81
+ 3. **Watch**: `watch_jobs`. It comes back when a build struggles, when all have finished, or when its
82
+ time is up - then call it again.
83
+ 4. **When a build struggles**, read what it has been through - its change, its last stages, the end of
84
+ its output - and `spec_findings` for what the builds have recorded. Then judge:
85
+ - **The spec's to settle** - the spec is silent where the build needs a decision (a format, a
86
+ default, an error and its message, a limit, an order, an edge case); it reads two ways; two of
87
+ its specs conflict; a test and the code disagree over something the spec never said. Write what
88
+ the spec should say as a spec diff (below), then `halt` the struggling build - its `job_id`, and
89
+ as `reason` what the spec now says - and `regenerate`, so it is regenerated from the clarified spec, and go
90
+ to the next cycle.
91
+ - **Not the spec's** - a bug the agent is working through, a missing tool or package, a flaky
92
+ service, turri itself. Leave the build to it, note it for the report, and keep watching.
93
+ Stopping it would throw its work away for nothing.
94
+ 5. **When the builds finish**, read `spec_findings`, and write into the spec every assumption about
95
+ what the software does that a user, a caller or a test can see - as the build assumed it, unless
96
+ that is not what the spec meant - so the next build does not have to guess. An assumption about how
97
+ it is built inside - a library, a file layout, a name - stays out. A diagnosis that says the fix is
98
+ in the spec is written; one that says code, environment or turri is noted. Then the next
99
+ cycle: what failed, and what the new diffs changed, is rendered again.
100
+
101
+ **Writing a fix.** A git diff of the `.plain` file(s), paths from the project root, a few lines of
102
+ context, with `write_spec_diff`. One diff per concern - a functionality's missing rules together, a
103
+ concept and what it means together - never one diff for everything. Put each where it belongs: a rule
104
+ of one functionality into its functional spec, a policy for many into `***implementation reqs***`, a
105
+ term into `***definitions***`, following `add-concept`, `add-functional-spec` and
106
+ `add-implementation-requirement` for how it is written. Each diff is built as it is written: what is left
107
+ to build is worked out again from the spec - only what it changes is rendered again.
108
+
109
+ **When you are stuck, stop.** The same functionality struggling three times after you clarified the
110
+ spec for it is not something the spec can settle: stop maturing it, and report it. Two cycles in a
111
+ row with nothing newly built and nothing newly settled: stop, and report what is open. Twenty cycles:
112
+ stop, and report.
113
+
114
+ ### report
115
+
116
+ A short account:
117
+
118
+ - whether the goal was met - `drift` for every module, as it is now;
119
+ - every cycle in a line: what was rendered, what struggled, what you did about it;
120
+ - every decision you wrote into the spec - what it settles, what the spec now says, and the spec diff
121
+ job that renders it - with the ones where you chose between readings marked, for the user to check;
122
+ - what was not the spec's - code, environment, turri - with what the builds and diagnoses said;
123
+ - what is still open, when you stopped before the goal.
124
+
125
+ Then say that any further change is asked for in the conversation, as a spec diff: what is left to build
126
+ is worked out again from the spec.
@@ -0,0 +1,196 @@
1
+ ---
2
+ name: refactor-module
3
+ description: >-
4
+ Split a large ***plain module into smaller modules grouped by logical domain.
5
+ The resulting modules are connected via a requires chain so that functionality
6
+ is 100% preserved. Use when a module has become too large and its functional
7
+ specs span multiple distinct concerns that would be clearer as separate modules.
8
+ allowed-tools: [read, write, edit, bash, ls, grep, find]
9
+ ---
10
+
11
+ # Refactor Module
12
+
13
+ ## When to Use
14
+
15
+ - A module has many functional specs spanning multiple distinct domains or feature areas.
16
+ - The module is hard to reason about because unrelated concerns are interleaved.
17
+ - New features are difficult to add because the module's scope is too broad.
18
+ - The user explicitly asks to split or reorganize a module.
19
+
20
+ ## Guiding Principle
21
+
22
+ The refactoring is purely structural. The **combined behavior** of the resulting modules must be **identical** to the original module. No functional spec is added, removed, or weakened. The split is semantic — grouping related specs together — not behavioral.
23
+
24
+ ## Input
25
+
26
+ The `.plain` file to refactor, plus guidance from the user on the desired grouping (or ask the user to confirm your proposed grouping).
27
+
28
+ ## Phase 1 — Analyze the Current Module
29
+
30
+ 1. **Read the entire `.plain` file** — frontmatter, definitions, implementation reqs, test reqs, and all functional specs. Also read any `import` and `requires` chains to understand the full context.
31
+ 2. **Inventory the functional specs.** Number each spec and note which `:Concepts:` it references. Build a dependency map: which specs depend on earlier specs (by referencing behavior or state they introduced)?
32
+ 3. **Inventory the definitions.** For each concept, note which functional specs reference it. Identify concepts that are used across multiple logical groups vs. concepts used only within one group.
33
+ 4. **Identify logical groups.** Look for natural seams — clusters of functional specs that share concepts, represent a cohesive domain, or describe a single feature area. Common groupings:
34
+ - Data model setup and CRUD operations
35
+ - Business logic and processing rules
36
+ - UI screens and navigation
37
+ - Integrations and external interfaces
38
+ - Statistics, reporting, and analytics
39
+ 5. **Verify group independence.** Each group's specs should form a contiguous or near-contiguous block in chronological order. If a group's specs are scattered and interleaved with other groups, the split boundary may need adjustment.
40
+
41
+ ## Phase 2 — Plan the Split
42
+
43
+ Present the proposed split to the user and get explicit confirmation before making any changes.
44
+
45
+ ### 2a. Define the module chain
46
+
47
+ The modules form a `requires` chain that preserves the original chronological ordering of functional specs. The first module in the chain contains the earliest specs; each subsequent module `requires` the previous one and adds the next logical group.
48
+
49
+ ```
50
+ original-module
51
+ ↓ splits into
52
+ module-group-a (no requires — this is the new base)
53
+ module-group-b (requires: module-group-a)
54
+ module-group-c (requires: module-group-b)
55
+ ```
56
+
57
+ If the original module already had `requires` or `import` dependencies, the first new module inherits them.
58
+
59
+ ### 2b. Assign functional specs to modules
60
+
61
+ Place each functional spec in exactly one module. The placement must respect chronological ordering:
62
+ - Within each module, the specs appear in the same relative order as in the original.
63
+ - Across the chain, the ordering is preserved: all specs in module A come before all specs in module B, which come before all specs in module C.
64
+ - A spec **cannot** move to an earlier module than a spec it depends on.
65
+
66
+ ### 2c. Assign definitions to modules
67
+
68
+ For each concept, determine where it belongs:
69
+
70
+ | Concept usage | Placement |
71
+ |---------------|-----------|
72
+ | Used only within one module's specs | Define in that module |
73
+ | Used across multiple modules in the chain | Define in the first module that uses it, and add to that module's `exported_concepts` |
74
+ | Already defined in an import template | Leave in the import — no change needed |
75
+
76
+ If many concepts are shared across all modules, consider creating a new import module (template) to hold them. This avoids long `exported_concepts` lists and keeps definitions centralized. Use the `create-import-module` skill for this.
77
+
78
+ ### 2d. Assign implementation reqs and test reqs
79
+
80
+ - Reqs that apply to all modules should live in a shared import template. If one already exists, keep them there.
81
+ - Reqs specific to a single module's domain move to that module.
82
+ - When in doubt, keep reqs in the shared template — duplication across modules is worse than a slightly broad template.
83
+
84
+ ### 2e. Present the plan
85
+
86
+ Summarize for the user:
87
+ - Number of resulting modules and their names
88
+ - Which functional specs go in each module (listed by number or short description)
89
+ - The `requires` chain order
90
+ - Any new import module being created
91
+ - Which concepts are exported from each module
92
+ - Confirmation that all original specs are accounted for (none lost)
93
+
94
+ Get explicit user confirmation before proceeding.
95
+
96
+ ## Phase 3 — Execute the Split
97
+
98
+ Create the new modules in order, from the base of the chain upward.
99
+
100
+ ### 3a. Create or update the import template (if needed)
101
+
102
+ If shared definitions or reqs are being moved to a new import template, create it first using the `create-import-module` skill.
103
+
104
+ ### 3b. Create the base module
105
+
106
+ Create the first module in the chain:
107
+ 1. Set the YAML frontmatter — inherit the original module's `import` references. Add `exported_concepts` for any concepts that downstream modules need.
108
+ 2. Add the `***definitions***` section with concepts used by this module's specs and concepts that need to be exported.
109
+ 3. Add `***implementation reqs***` and `***test reqs***` specific to this module (if not fully covered by the import template).
110
+ 4. Add the `***functional specs***` assigned to this module, preserving their original order and exact wording.
111
+ 5. Carry over any `***acceptance tests***` nested under the moved functional specs.
112
+
113
+ ### 3c. Create subsequent modules
114
+
115
+ For each subsequent module in the chain:
116
+ 1. Set `requires` to point to the previous module in the chain. Set `import` if it uses shared templates.
117
+ 2. Add `exported_concepts` for any concepts that later modules in the chain need.
118
+ 3. Add `***definitions***` for concepts local to this module. Do **not** redefine concepts already available via `requires` (exported) or `import`.
119
+ 4. Add `***implementation reqs***` and `***test reqs***` specific to this module.
120
+ 5. Add the `***functional specs***` assigned to this module, preserving their original order and exact wording.
121
+ 6. Carry over any `***acceptance tests***`.
122
+
123
+ ### 3d. Handle the original module file
124
+
125
+ After all new modules are created:
126
+ - If the original module is being fully replaced (all specs moved out), delete it or rename it to avoid confusion.
127
+ - If the original module was required by other modules, update those modules to `require` the last module in the new chain instead — its accumulated code and previous functional specs cover the whole chain. Exported concepts are **not** transitive, though: if a downstream module references a concept now exported by an earlier module in the new chain, it must list that earlier module in its `requires` as well.
128
+
129
+ ## Phase 4 — Verify
130
+
131
+ ### 4a. Completeness check
132
+
133
+ This is the most critical verification. Walk through every functional spec from the original module and confirm it appears in exactly one of the new modules. Nothing may be lost, weakened, modified, or left implicit.
134
+
135
+ Checklist:
136
+ - [ ] Total spec count across all new modules equals the original spec count
137
+ - [ ] Each spec's text is identical to the original (no rewording)
138
+ - [ ] Each spec's acceptance tests (if any) are carried over intact
139
+
140
+ ### 4b. Chronological ordering check
141
+
142
+ Verify that the chronological order of all functional specs — when read across the requires chain from base to leaf — matches the original ordering exactly. A spec must not appear before a spec it depends on.
143
+
144
+ ### 4c. Concept availability check
145
+
146
+ For each module, verify:
147
+ - [ ] Every `:Concept:` referenced in its specs is either defined locally, available via `import`, or available via `exported_concepts` from a module listed in `requires`
148
+ - [ ] `exported_concepts` includes every concept that downstream modules need
149
+ - [ ] No concept name collisions between modules
150
+
151
+ ### 4d. Structural validation per module
152
+
153
+ For each new module:
154
+ - [ ] Has at least one functional spec and one implementation req
155
+ - [ ] YAML frontmatter is correctly formatted
156
+ - [ ] `requires` and `import` paths are correct
157
+ - [ ] Module file is at the repository root (not in `template/`)
158
+ - [ ] Specs are language-agnostic
159
+ - [ ] All external interfaces remain explicit
160
+
161
+ ### 4e. Read all new modules
162
+
163
+ Read each new `.plain` file in full and present the final structure to the user for approval. If the user requests changes, apply them and re-verify.
164
+
165
+ ## Common Pitfalls
166
+
167
+ ### Splitting too aggressively
168
+ Creating many tiny modules with 1–2 specs each adds overhead without clarity. Aim for modules with 3–10 functional specs each, grouped around a cohesive theme.
169
+
170
+ ### Breaking chronological order
171
+ Specs that set up foundational behavior (entry point, database init, core CRUD) must stay in the base module even if they touch concepts from multiple domains. Only split when specs are cleanly separable.
172
+
173
+ ### Forgetting exported_concepts
174
+ If a concept defined in module A is referenced by a spec in module B (which requires A), the concept must be in A's `exported_concepts`. Missing exports cause rendering failures.
175
+
176
+ ### Modifying spec text during the split
177
+ This is a refactoring, not a rewrite. Spec text must be copied verbatim. If a spec needs rewording to work in its new module context, that is a sign the split boundary is wrong — adjust the grouping instead.
178
+
179
+ ### Losing acceptance tests
180
+ Acceptance tests are nested under their parent functional spec. When moving a spec to a new module, its acceptance tests must move with it.
181
+
182
+ ## Validation Checklist
183
+
184
+ - [ ] User confirmed the split plan before execution
185
+ - [ ] All original functional specs are present in exactly one new module — none lost
186
+ - [ ] Spec text is identical to the original — no rewording
187
+ - [ ] Acceptance tests moved with their parent specs
188
+ - [ ] Chronological order preserved across the requires chain
189
+ - [ ] Every referenced `:Concept:` is available in each module (local, import, or exported)
190
+ - [ ] `exported_concepts` are correctly set on each module
191
+ - [ ] No concept name collisions
192
+ - [ ] Each module has at least one functional spec and one implementation req
193
+ - [ ] `requires` chain is correctly ordered (base → leaf)
194
+ - [ ] Original module removed or updated
195
+ - [ ] Downstream modules (if any) updated to require the chain tip, plus any earlier chain modules whose exported concepts they reference
196
+ - [ ] User approved the final result