@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.
- package/.pi/themes/turri-dark.json +80 -0
- package/.pi/themes/turri-light.json +82 -0
- package/LICENSE +21 -0
- package/README.md +272 -2
- package/assets/jellyfish/dark-00.png +0 -0
- package/assets/jellyfish/dark-01.png +0 -0
- package/assets/jellyfish/dark-02.png +0 -0
- package/assets/jellyfish/dark-03.png +0 -0
- package/assets/jellyfish/dark-04.png +0 -0
- package/assets/jellyfish/dark-05.png +0 -0
- package/assets/jellyfish/dark-06.png +0 -0
- package/assets/jellyfish/dark-07.png +0 -0
- package/assets/jellyfish/dark-08.png +0 -0
- package/assets/jellyfish/dark-09.png +0 -0
- package/assets/jellyfish/dark-10.png +0 -0
- package/assets/jellyfish/dark-11.png +0 -0
- package/assets/jellyfish/dark-12.png +0 -0
- package/assets/jellyfish/dark-13.png +0 -0
- package/assets/jellyfish/dark-14.png +0 -0
- package/assets/jellyfish/fallback.txt +252 -0
- package/assets/jellyfish/light-00.png +0 -0
- package/assets/jellyfish/light-01.png +0 -0
- package/assets/jellyfish/light-02.png +0 -0
- package/assets/jellyfish/light-03.png +0 -0
- package/assets/jellyfish/light-04.png +0 -0
- package/assets/jellyfish/light-05.png +0 -0
- package/assets/jellyfish/light-06.png +0 -0
- package/assets/jellyfish/light-07.png +0 -0
- package/assets/jellyfish/light-08.png +0 -0
- package/assets/jellyfish/light-09.png +0 -0
- package/assets/jellyfish/light-10.png +0 -0
- package/assets/jellyfish/light-11.png +0 -0
- package/assets/jellyfish/light-12.png +0 -0
- package/assets/jellyfish/light-13.png +0 -0
- package/assets/jellyfish/light-14.png +0 -0
- package/bin/turri.mjs +29 -0
- package/dist/ask.js +149 -0
- package/dist/brand.js +50 -0
- package/dist/btw.js +174 -0
- package/dist/chat-models.js +37 -0
- package/dist/chat-skills.js +18 -0
- package/dist/cli.js +178 -0
- package/dist/config-command.js +197 -0
- package/dist/config-edit.js +367 -0
- package/dist/config.js +489 -0
- package/dist/conform-cli.js +29 -0
- package/dist/cultivate-cli.js +110 -0
- package/dist/drift-cli.js +25 -0
- package/dist/environment.js +70 -0
- package/dist/extension.js +2372 -0
- package/dist/genome.js +301 -0
- package/dist/graph.js +246 -0
- package/dist/identity.js +35 -0
- package/dist/init-config.js +511 -0
- package/dist/judge.js +62 -0
- package/dist/lineage-cli.js +13 -0
- package/dist/loop-cli.js +132 -0
- package/dist/loop-tools.js +225 -0
- package/dist/mature-tools.js +193 -0
- package/dist/model-check.js +117 -0
- package/dist/module-report.js +9 -0
- package/dist/pi-launch.js +31 -0
- package/dist/pi.js +813 -0
- package/dist/plain/check.js +76 -0
- package/dist/plain/concepts.js +213 -0
- package/dist/plain/errors.js +43 -0
- package/dist/plain/files.js +57 -0
- package/dist/plain/highlight.js +195 -0
- package/dist/plain/index.js +15 -0
- package/dist/plain/liquid.js +129 -0
- package/dist/plain/markdown.js +208 -0
- package/dist/plain/parser.js +752 -0
- package/dist/plain/plain.tmLanguage.json +124 -0
- package/dist/plain/spec.js +291 -0
- package/dist/plain/stdlib.js +44 -0
- package/dist/question-dialog.js +125 -0
- package/dist/questioning.js +109 -0
- package/dist/quiet.js +125 -0
- package/dist/regenerate/activity.js +187 -0
- package/dist/regenerate/agent-env.js +190 -0
- package/dist/regenerate/agent-shell.js +114 -0
- package/dist/regenerate/arbiter.js +133 -0
- package/dist/regenerate/audit.js +203 -0
- package/dist/regenerate/cases.js +83 -0
- package/dist/regenerate/change-view.js +102 -0
- package/dist/regenerate/choose-conformance.js +117 -0
- package/dist/regenerate/chunk-plan.js +625 -0
- package/dist/regenerate/codebase.js +75 -0
- package/dist/regenerate/command-check.js +312 -0
- package/dist/regenerate/compaction.js +20 -0
- package/dist/regenerate/confine.js +310 -0
- package/dist/regenerate/conform.js +133 -0
- package/dist/regenerate/conformance-agents.js +955 -0
- package/dist/regenerate/conformance.js +936 -0
- package/dist/regenerate/conversation-writes.js +100 -0
- package/dist/regenerate/credentials.js +88 -0
- package/dist/regenerate/debug-log.js +228 -0
- package/dist/regenerate/debugger.js +90 -0
- package/dist/regenerate/delivery.js +19 -0
- package/dist/regenerate/diagnose-job.js +40 -0
- package/dist/regenerate/diagnose.js +81 -0
- package/dist/regenerate/diff-view.js +240 -0
- package/dist/regenerate/drift.js +194 -0
- package/dist/regenerate/engine.js +118 -0
- package/dist/regenerate/environment-error.js +220 -0
- package/dist/regenerate/job-log.js +102 -0
- package/dist/regenerate/job-panel.js +336 -0
- package/dist/regenerate/jobs-tree.js +300 -0
- package/dist/regenerate/jobs.js +427 -0
- package/dist/regenerate/lanes.js +32 -0
- package/dist/regenerate/lineage.js +384 -0
- package/dist/regenerate/loop.js +1435 -0
- package/dist/regenerate/masking.js +95 -0
- package/dist/regenerate/notes.js +397 -0
- package/dist/regenerate/os-sandbox.js +243 -0
- package/dist/regenerate/paths.js +165 -0
- package/dist/regenerate/plain-palette.js +83 -0
- package/dist/regenerate/prompt.js +704 -0
- package/dist/regenerate/records.js +294 -0
- package/dist/regenerate/regenerate.js +598 -0
- package/dist/regenerate/regression.js +181 -0
- package/dist/regenerate/release.js +262 -0
- package/dist/regenerate/requires.js +241 -0
- package/dist/regenerate/resources.js +164 -0
- package/dist/regenerate/self-check.js +111 -0
- package/dist/regenerate/services.js +155 -0
- package/dist/regenerate/shell.js +320 -0
- package/dist/regenerate/side-panel.js +278 -0
- package/dist/regenerate/spec-map-view.js +574 -0
- package/dist/regenerate/spec-map.js +561 -0
- package/dist/regenerate/spec-steps.js +527 -0
- package/dist/regenerate/state.js +10 -0
- package/dist/regenerate/steer.js +91 -0
- package/dist/regenerate/steering.js +119 -0
- package/dist/regenerate/stop-report.js +161 -0
- package/dist/regenerate/submit-work.js +71 -0
- package/dist/regenerate/test-kinds.js +124 -0
- package/dist/regenerate/test-scripts.js +695 -0
- package/dist/regenerate/testing.js +406 -0
- package/dist/regenerate/transcript-view.js +1 -0
- package/dist/regenerate/unit-gate.js +20 -0
- package/dist/regenerate/unit-review.js +347 -0
- package/dist/regenerate/web.js +256 -0
- package/dist/regenerate/workspace.js +99 -0
- package/dist/regenerate-cli.js +68 -0
- package/dist/release-agent.js +114 -0
- package/dist/release-cli.js +131 -0
- package/dist/release-tools.js +148 -0
- package/dist/review/live.js +165 -0
- package/dist/rules.js +47 -0
- package/dist/self-invocation.js +110 -0
- package/dist/setup.js +245 -0
- package/dist/skill-progress.js +78 -0
- package/dist/skill.js +149 -0
- package/dist/skills.js +74 -0
- package/dist/spec-diff-cli.js +37 -0
- package/dist/spec-tools.js +155 -0
- package/dist/stack.js +158 -0
- package/dist/stacks.js +97 -0
- package/dist/stdlib.js +100 -0
- package/dist/terminal-images.js +46 -0
- package/dist/tools.js +242 -0
- package/dist/validate-cli.js +52 -0
- package/docs/README.md +58 -0
- package/docs/authoring-plain.md +245 -0
- package/docs/config.md +353 -0
- package/docs/deploy.md +109 -0
- package/docs/development.md +88 -0
- package/docs/headless.md +148 -0
- package/docs/images/how-turri-works.svg +50 -0
- package/docs/images/turri-banner.png +0 -0
- package/docs/installation.md +119 -0
- package/docs/parser.md +108 -0
- package/docs/regenerating.md +1116 -0
- package/docs/sandbox.md +233 -0
- package/docs/skills-and-gates.md +254 -0
- package/docs/theming.md +76 -0
- package/docs/using.md +454 -0
- package/genome/rules/bullet-continuation.md +69 -0
- package/genome/rules/concise-specs-examples.md +431 -0
- package/genome/rules/concise-specs-integration-examples.md +270 -0
- package/genome/rules/concise-specs.md +80 -0
- package/genome/rules/definitions.md +107 -0
- package/genome/rules/examples/integration-embedded-testing/run_conformance_tests_java.sh +163 -0
- package/genome/rules/examples/integration-embedded-testing/run_unittests_java.sh +51 -0
- package/genome/rules/exported-concepts.md +39 -0
- package/genome/rules/func-specs.md +129 -0
- package/genome/rules/impl-reqs.md +68 -0
- package/genome/rules/import-modules.md +48 -0
- package/genome/rules/integration-embedded-testing.md +276 -0
- package/genome/rules/integration-embedded.md +171 -0
- package/genome/rules/integration-standalone.md +135 -0
- package/genome/rules/integrations.md +137 -0
- package/genome/rules/linked-resources.md +69 -0
- package/genome/rules/module-structure.md +105 -0
- package/genome/rules/project-model.md +88 -0
- package/genome/rules/required-concepts.md +44 -0
- package/genome/rules/requires-modules.md +80 -0
- package/genome/rules/stdlib.md +73 -0
- package/genome/rules/test-reqs.md +57 -0
- package/genome/skills/add-acceptance-test/SKILL.md +100 -0
- package/genome/skills/add-concept/SKILL.md +71 -0
- package/genome/skills/add-functional-spec/SKILL.md +84 -0
- package/genome/skills/add-functional-specs/SKILL.md +118 -0
- package/genome/skills/add-implementation-requirement/SKILL.md +86 -0
- package/genome/skills/add-resource/SKILL.md +105 -0
- package/genome/skills/add-template/SKILL.md +64 -0
- package/genome/skills/add-test-requirement/SKILL.md +73 -0
- package/genome/skills/analyze-2-func-specs/SKILL.md +101 -0
- package/genome/skills/analyze-func-specs/SKILL.md +123 -0
- package/genome/skills/analyze-if-func-spec-too-complex/SKILL.md +211 -0
- package/genome/skills/break-down-func-spec/SKILL.md +205 -0
- package/genome/skills/brood/SKILL.md +229 -0
- package/genome/skills/brood/references/intent.md +35 -0
- package/genome/skills/brood/references/product.md +101 -0
- package/genome/skills/brood/references/stack.md +61 -0
- package/genome/skills/brood/references/testing.md +56 -0
- package/genome/skills/bud/SKILL.md +148 -0
- package/genome/skills/bud/references/checklist.md +44 -0
- package/genome/skills/bud/references/intent.md +30 -0
- package/genome/skills/check-plain-env/SKILL.md +285 -0
- package/genome/skills/consolidate-concepts/SKILL.md +192 -0
- package/genome/skills/create-import-module/SKILL.md +104 -0
- package/genome/skills/create-requires-module/SKILL.md +109 -0
- package/genome/skills/debug-specs/SKILL.md +188 -0
- package/genome/skills/implement-conformance-testing-script/SKILL.md +238 -0
- package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_cypress.ps1 +337 -0
- package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_golang.ps1 +111 -0
- package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_java.sh +136 -0
- package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_python.ps1 +103 -0
- package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_python.sh +150 -0
- package/genome/skills/implement-unit-testing-script/SKILL.md +160 -0
- package/genome/skills/implement-unit-testing-script/assets/run_unittests_flutter.ps1 +87 -0
- package/genome/skills/implement-unit-testing-script/assets/run_unittests_golang.ps1 +73 -0
- package/genome/skills/implement-unit-testing-script/assets/run_unittests_java.sh +72 -0
- package/genome/skills/implement-unit-testing-script/assets/run_unittests_python.ps1 +81 -0
- package/genome/skills/implement-unit-testing-script/assets/run_unittests_python.sh +98 -0
- package/genome/skills/implement-unit-testing-script/assets/run_unittests_react.ps1 +87 -0
- package/genome/skills/init-plain-project/SKILL.md +117 -0
- package/genome/skills/init-plain-project/references/checklist.md +30 -0
- package/genome/skills/mature/SKILL.md +126 -0
- package/genome/skills/refactor-module/SKILL.md +196 -0
- package/genome/skills/resolve-section-ownership/SKILL.md +64 -0
- package/genome/skills/resolve-spec-conflict/SKILL.md +96 -0
- package/genome/skills/spawn/SKILL.md +163 -0
- package/package.json +68 -4
- package/stdlib/backend/common.plain +25 -0
- package/stdlib/backend/conformance/common.plain +12 -0
- package/stdlib/backend/conformance/go-gin.plain +9 -0
- package/stdlib/backend/conformance/go-nethttp.plain +9 -0
- package/stdlib/backend/conformance/java-springboot.plain +9 -0
- package/stdlib/backend/conformance/python-django.plain +9 -0
- package/stdlib/backend/conformance/python-fastapi.plain +9 -0
- package/stdlib/backend/conformance/python-flask.plain +9 -0
- package/stdlib/backend/conformance/rust-axum.plain +9 -0
- package/stdlib/backend/conformance/typescript-express.plain +9 -0
- package/stdlib/backend/conformance/typescript-fastify.plain +9 -0
- package/stdlib/backend/conformance/typescript-nestjs.plain +9 -0
- package/stdlib/backend/go-gin.plain +18 -0
- package/stdlib/backend/go-nethttp.plain +18 -0
- package/stdlib/backend/java-springboot.plain +19 -0
- package/stdlib/backend/python-django.plain +19 -0
- package/stdlib/backend/python-fastapi.plain +23 -0
- package/stdlib/backend/python-flask.plain +23 -0
- package/stdlib/backend/rust-axum.plain +17 -0
- package/stdlib/backend/typescript-express.plain +19 -0
- package/stdlib/backend/typescript-fastify.plain +19 -0
- package/stdlib/backend/typescript-nestjs.plain +19 -0
- package/stdlib/cli/common.plain +17 -0
- package/stdlib/cli/conformance/common.plain +11 -0
- package/stdlib/cli/conformance/go-cobra.plain +9 -0
- package/stdlib/cli/conformance/go-flag.plain +9 -0
- package/stdlib/cli/conformance/java-picocli.plain +9 -0
- package/stdlib/cli/conformance/python-argparse.plain +9 -0
- package/stdlib/cli/conformance/python-click.plain +9 -0
- package/stdlib/cli/conformance/python-typer.plain +9 -0
- package/stdlib/cli/conformance/rust-clap.plain +9 -0
- package/stdlib/cli/conformance/typescript-commander.plain +9 -0
- package/stdlib/cli/go-cobra.plain +14 -0
- package/stdlib/cli/go-flag.plain +14 -0
- package/stdlib/cli/java-picocli.plain +15 -0
- package/stdlib/cli/python-argparse.plain +18 -0
- package/stdlib/cli/python-click.plain +16 -0
- package/stdlib/cli/python-typer.plain +16 -0
- package/stdlib/cli/rust-clap.plain +14 -0
- package/stdlib/cli/typescript-commander.plain +17 -0
- package/stdlib/frontend/angular.plain +17 -0
- package/stdlib/frontend/common.plain +17 -0
- package/stdlib/frontend/conformance/angular.plain +5 -0
- package/stdlib/frontend/conformance/common.plain +11 -0
- package/stdlib/frontend/conformance/react-vite.plain +5 -0
- package/stdlib/frontend/conformance/sveltekit-spa.plain +5 -0
- package/stdlib/frontend/conformance/vue-vite.plain +5 -0
- package/stdlib/frontend/react-vite.plain +16 -0
- package/stdlib/frontend/sveltekit-spa.plain +16 -0
- package/stdlib/frontend/vue-vite.plain +16 -0
- package/stdlib/lang/go.plain +13 -0
- package/stdlib/lang/java.plain +12 -0
- package/stdlib/lang/python.plain +18 -0
- package/stdlib/lang/rust.plain +12 -0
- package/stdlib/lang/typescript.plain +13 -0
- package/stdlib/library/common.plain +15 -0
- package/stdlib/library/conformance/common.plain +9 -0
- package/stdlib/library/conformance/go.plain +9 -0
- package/stdlib/library/conformance/java-gradle.plain +9 -0
- package/stdlib/library/conformance/java-maven.plain +9 -0
- package/stdlib/library/conformance/python.plain +9 -0
- package/stdlib/library/conformance/rust.plain +9 -0
- package/stdlib/library/conformance/typescript.plain +9 -0
- package/stdlib/library/go.plain +12 -0
- package/stdlib/library/java-gradle.plain +13 -0
- package/stdlib/library/java-maven.plain +13 -0
- package/stdlib/library/python.plain +13 -0
- package/stdlib/library/rust.plain +12 -0
- package/stdlib/library/typescript.plain +15 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Rules for creating and using requires modules in .plain files
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Rules for requires modules
|
|
6
|
+
|
|
7
|
+
When creating or editing a `.plain` file that uses `requires`, or one that is referenced in another `.plain` file's `requires` directive, always follow these rules:
|
|
8
|
+
|
|
9
|
+
## What requires does
|
|
10
|
+
|
|
11
|
+
- `requires` attaches the current module to the project's **build chain**: the required module is built first, and its generated code is copied as the starting point for the current module
|
|
12
|
+
- The copied code is the required module's **accumulated** output — it already contains the code of all of that module's own ancestors
|
|
13
|
+
- The `***functional specs***` of the required module **and of all its ancestors** become visible as **previous functional specs** — this visibility **is transitive** down the whole chain
|
|
14
|
+
- Of a required module's definitions, only the concepts listed in its `exported_concepts` are visible; the module's other definitions stay internal. Each exported concept arrives with its full definition text
|
|
15
|
+
- Export visibility **is not transitive**: an ancestor's exports are visible only if that ancestor is itself listed in `requires`
|
|
16
|
+
|
|
17
|
+
## Chain topology
|
|
18
|
+
|
|
19
|
+
- All modules connected by `requires` form a single **tree** with a common root: code accumulates along each branch, and branches never reconverge
|
|
20
|
+
- **Diamond joins are prohibited.** A module must not require two modules from divergent branches — there is no way to merge two divergent codebases into one starting point
|
|
21
|
+
- When `requires` lists multiple modules, every entry must lie on **one root-to-tip ancestor path**: each listed module must be an ancestor of the deepest one
|
|
22
|
+
- The **deepest entry is the attachment point** — it alone determines the build order and the starting code. The other entries add nothing to ordering; they exist **only** to make those ancestors' `exported_concepts` visible
|
|
23
|
+
- Branching outward is fine: two modules may each require the same parent, creating independent branches (and therefore independent top modules)
|
|
24
|
+
|
|
25
|
+
## Tech stack must match (hard rule)
|
|
26
|
+
|
|
27
|
+
- Because the required module's generated code is copied as the starting point and the renderer continues building on top of it with a single toolchain, two modules can only be linked with `requires` when they target the **same language, framework, and runtime**
|
|
28
|
+
- A runtime / network dependency between systems is **not** a reason to use `requires`
|
|
29
|
+
- Example of the mistake: a React frontend that talks to a Python/FastAPI backend over HTTP must **not** `requires: [backend]` — the stacks differ
|
|
30
|
+
- Model that pair as two independent root modules (each with its own test scripts) and express the contract through a shared API schema in `resources/` or shared concepts in an `import`ed module — never through `requires`
|
|
31
|
+
|
|
32
|
+
## Building upon but not necessarily extension
|
|
33
|
+
|
|
34
|
+
- The current module does not need to functionally extend the required module — it may address a completely different concern
|
|
35
|
+
- Even so, the two are never independent artifacts: the current module's output physically contains the required module's code, because both are stages of one accumulating codebase
|
|
36
|
+
- Use `requires` to place a module at the right point in that lineage, whether or not it builds on the required module's functionality
|
|
37
|
+
|
|
38
|
+
## Conflict prevention
|
|
39
|
+
|
|
40
|
+
- The current module's functional specs must not conflict with the specs of **any module in its ancestor chain** — all of them are previous functional specs
|
|
41
|
+
- The renderer sees the whole chain's specs as prior requirements/context when rendering the current module
|
|
42
|
+
- Review the ancestor chain's functional specs before adding new ones
|
|
43
|
+
|
|
44
|
+
## Exports are the only visible definitions
|
|
45
|
+
|
|
46
|
+
- Only concepts listed in a required module's `exported_concepts` are available, and only for modules explicitly listed in `requires`
|
|
47
|
+
- Each exported concept is available with its full definition text
|
|
48
|
+
- Other concepts from required modules are internal and invisible
|
|
49
|
+
- To reference a concept exported by an ancestor deeper in the chain, list that ancestor in `requires` as well
|
|
50
|
+
- If you need shared definitions across branches or stacks, use `import` for that — not `requires`
|
|
51
|
+
|
|
52
|
+
## File locations
|
|
53
|
+
|
|
54
|
+
- Modules that use `requires` live at the **repository root** — they are functional modules with specs
|
|
55
|
+
- `requires` paths point to other root-level modules (e.g., `auth`, `messaging`)
|
|
56
|
+
- Never `require` an import module — import modules are for `import` only
|
|
57
|
+
|
|
58
|
+
## Format
|
|
59
|
+
|
|
60
|
+
```plain
|
|
61
|
+
---
|
|
62
|
+
requires:
|
|
63
|
+
- auth
|
|
64
|
+
import:
|
|
65
|
+
- airplain
|
|
66
|
+
description: Module built on top of auth, importing shared definitions
|
|
67
|
+
---
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
A module can list multiple required modules **only when they lie on one ancestor path**. Here `messaging` itself requires `auth`, so `auth` is an ancestor of `messaging`; the module attaches after `messaging` and lists `auth` only to see its exports:
|
|
71
|
+
|
|
72
|
+
```plain
|
|
73
|
+
---
|
|
74
|
+
requires:
|
|
75
|
+
- auth
|
|
76
|
+
- messaging
|
|
77
|
+
import:
|
|
78
|
+
- airplain
|
|
79
|
+
---
|
|
80
|
+
```
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: The ***plain standard library - import modules for a backend, a frontend, a command-line tool or a library, on a known stack
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Rules for the standard library
|
|
6
|
+
|
|
7
|
+
turri ships a standard library of import modules that settle everything about a generic piece
|
|
8
|
+
of software on one stack except what it does: its language and framework, its layout, its
|
|
9
|
+
configuration, how it handles errors, how it logs, how it stops, and how it is tested. A module that
|
|
10
|
+
imports one writes only what is its own - its concepts and its functional specs - and a requirement
|
|
11
|
+
only for what its stack does not settle.
|
|
12
|
+
|
|
13
|
+
```plain
|
|
14
|
+
---
|
|
15
|
+
import:
|
|
16
|
+
- stdlib/backend/python-flask
|
|
17
|
+
- stdlib/backend/conformance/python-flask
|
|
18
|
+
---
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## How it is built up
|
|
22
|
+
|
|
23
|
+
- Each stack imports its language's template - `stdlib/lang/python` - and its kind's `common` -
|
|
24
|
+
`stdlib/backend/common` - so importing the stack brings all three.
|
|
25
|
+
- Each stack's conformance tests are a template of their own, `stdlib/<kind>/conformance/<stack>`,
|
|
26
|
+
which imports `stdlib/<kind>/conformance/common`.
|
|
27
|
+
- The `common` of a kind settles what every stack of it shares. For a backend: settings from the
|
|
28
|
+
environment, checked at start; handler, service and repository layers; domain errors turned into
|
|
29
|
+
one error body `{"error": {"code", "message"}}` with fixed codes and statuses; JSON logs with a
|
|
30
|
+
request id; shutdown on a signal. For a command-line tool: `Error: <message>` on standard error,
|
|
31
|
+
exit codes 0, 1, 2 and 130, logs on standard error with `--verbose` and `--debug`. For a frontend:
|
|
32
|
+
one API layer with an `ApiError`, errors shown in place or at the root, one logger module. For a
|
|
33
|
+
library: one public entry point, one base error type, no output of its own.
|
|
34
|
+
|
|
35
|
+
## When to use it
|
|
36
|
+
|
|
37
|
+
- When the person wants a backend, a frontend, a command-line tool or a library, import the stack
|
|
38
|
+
that fits instead of writing its implementation reqs yourself.
|
|
39
|
+
- Pick the stack from what the person said, the project's other modules, and what the module talks
|
|
40
|
+
to. With nothing to go on: `stdlib/backend/python-fastapi`, `stdlib/frontend/react-vite`,
|
|
41
|
+
`stdlib/cli/python-typer`, `stdlib/library/python`.
|
|
42
|
+
- Import the conformance template only when the module has conformance tests - the person asked for
|
|
43
|
+
them, and the project's config does not turn them off (`conformance-tests: false`). Without it
|
|
44
|
+
the module has no test reqs, and no conformance tests are written or run for it. Turning them on
|
|
45
|
+
later is adding that one import.
|
|
46
|
+
- Read the templates a module imports before writing its specs - the folder is named below - and
|
|
47
|
+
write no requirement they already make (see `concise-specs.md`).
|
|
48
|
+
- Write a functional spec's errors in the templates' terms: a backend's failure by its status and
|
|
49
|
+
`error.code` - `not_found`, `conflict`, `validation_error`, `unauthenticated`, `forbidden`, or a
|
|
50
|
+
code of the module's own - and a command-line tool's by its exit code and message.
|
|
51
|
+
- Add a requirement on top for what the module needs beyond its stack - storage, an outside
|
|
52
|
+
service, a library it must use. When the module differs from its stack on something the stack
|
|
53
|
+
settles - another framework, another layout - write the stack yourself instead: an import cannot
|
|
54
|
+
be taken back in part. For a language with no stack of the kind wanted, import its
|
|
55
|
+
`stdlib/lang/<language>` and write the rest.
|
|
56
|
+
- `stdlib/` is a reserved name. An import that starts with it is always the standard library's
|
|
57
|
+
template, and a project module at such a path - `stdlib/backend/python-fastapi.plain` in the
|
|
58
|
+
spec's folder, its `template/` folder or `PLAIN_TEMPLATE_DIRS` - is an error. Never write a module
|
|
59
|
+
under a `stdlib/` folder of the project; a project's own shared template goes in `template/`
|
|
60
|
+
under a name of its own.
|
|
61
|
+
|
|
62
|
+
## What it does not do
|
|
63
|
+
|
|
64
|
+
- It defines no concepts: its requirements are on the predefined `:Implementation:`, `:UnitTests:`
|
|
65
|
+
and `:ConformanceTests:` only, so it never collides with the module's own definitions.
|
|
66
|
+
- It holds no storage: a module with a database says which, and how it is reached, on top.
|
|
67
|
+
- It holds no testing scripts. The module still needs its unit testing script, and its conformance
|
|
68
|
+
testing script when it has conformance tests - written with the `implement-unit-testing-script`
|
|
69
|
+
and `implement-conformance-testing-script` skills for the stack's language and test framework. Each
|
|
70
|
+
runs the static checks of what it tests - the formatter, linter and type checker its language template
|
|
71
|
+
names, on the code or on the conformance tests - and they count as the tests do.
|
|
72
|
+
- It names its stack's toolchain - Python 3.12, Node.js 24, Java 21, Go 1.25, Rust - which the agents use from the
|
|
73
|
+
machine turri runs on; they install none, so `turri doctor` says when the machine lacks it.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Rules for writing ***test reqs*** sections in .plain files
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Rules for writing `***test reqs***`
|
|
6
|
+
|
|
7
|
+
When writing or editing a `***test reqs***` section in a `.plain` file, always follow these rules:
|
|
8
|
+
|
|
9
|
+
## Conformance tests only
|
|
10
|
+
- Test reqs specify how **conformance tests** should be written and run
|
|
11
|
+
- Unit test guidance goes in `***implementation reqs***`, not here
|
|
12
|
+
- Acceptance tests are nested under individual functional specs, not here
|
|
13
|
+
- Behavioral requirements go in `***functional specs***`, not here
|
|
14
|
+
|
|
15
|
+
## `:ConformanceTests:` lives here (hard rule)
|
|
16
|
+
- **Everything** about `:ConformanceTests:` goes in `***test reqs***` — paths, approach, packages, framework, execution command, mocking / network policy, fixtures, pass criteria, environment prerequisites
|
|
17
|
+
- `:ConformanceTests:` live outside the generated codebase, in one folder, `plain_modules/<module>/tests/` - the module's whole conformance suite, so requirements that shape them belong in test reqs by definition
|
|
18
|
+
- The conformance-test generator reads **only** `***test reqs***` — anything about `:ConformanceTests:` placed elsewhere (e.g. `***implementation reqs***`) is silently ignored
|
|
19
|
+
- Author each `:ConformanceTests:` requirement via `add-test-requirement` and phrase it in terms of `:ConformanceTests:` so the partition stays visible at a glance
|
|
20
|
+
- Do not link the conformance testing script here (or anywhere in the specs; a link to it is ignored). turri finds it in the project root - `conformance-tests-script:` in `config.turri.yaml`, else the one `run_conformance_tests*.sh` in the root, else the one in `test_scripts/` - and shows it to the agents that write the conformance tests itself. Describe the framework and execution command here in words
|
|
21
|
+
|
|
22
|
+
## What belongs here
|
|
23
|
+
- Test framework: which framework to use (e.g., pytest, Unittest, xUnit)
|
|
24
|
+
- Execution method: the command to run the tests
|
|
25
|
+
- Testing constraints: what must or must not be done in tests (e.g., no skipping, mock requirements)
|
|
26
|
+
- Test data: how test fixtures or mock data should be structured
|
|
27
|
+
- Environment setup: any prerequisites for running conformance tests
|
|
28
|
+
|
|
29
|
+
## Test type reference
|
|
30
|
+
|
|
31
|
+
| Test type | Where to specify | Generated | Purpose |
|
|
32
|
+
|-----------|-----------------|-----------|---------|
|
|
33
|
+
| Unit tests | `***implementation reqs***` | Automatically | Test individual functionalities in isolation |
|
|
34
|
+
| Conformance tests | `***test reqs***` | Automatically | Verify each functionality's implementation against its functional spec |
|
|
35
|
+
| Acceptance tests | `***acceptance tests***` under a functional spec | Manually | Verify implementation of a functional spec through a specific end-to-end scenario |
|
|
36
|
+
|
|
37
|
+
## No duplication
|
|
38
|
+
- Do not duplicate guidance already present in the file or its imports
|
|
39
|
+
- Check imported modules before adding a new test req
|
|
40
|
+
|
|
41
|
+
## Concept references
|
|
42
|
+
- Reference predefined concepts like `:ConformanceTests:` where appropriate
|
|
43
|
+
- All other referenced `:Concepts:` must be defined in `***definitions***`
|
|
44
|
+
|
|
45
|
+
## Conciseness
|
|
46
|
+
- State each req in the fewest plain words that stay exact — see `concise-specs.md`
|
|
47
|
+
- Do not restate the default behavior of the test framework this section already names
|
|
48
|
+
|
|
49
|
+
## Format
|
|
50
|
+
|
|
51
|
+
```plain
|
|
52
|
+
***test reqs***
|
|
53
|
+
- :ConformanceTests: should be implemented using pytest framework.
|
|
54
|
+
- :ConformanceTests: will be run using "pytest" command.
|
|
55
|
+
- :ConformanceTests: must be implemented and executed - do not skip tests.
|
|
56
|
+
- :ConformanceTests: should mock all external HTTP calls.
|
|
57
|
+
```
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: add-acceptance-test
|
|
3
|
+
description: >-
|
|
4
|
+
Add acceptance tests under a functional spec in a ***plain spec file. Use
|
|
5
|
+
when the user wants to add verification criteria for a specific functional
|
|
6
|
+
spec, or after adding a functional spec that needs testable success criteria.
|
|
7
|
+
allowed-tools: [read, write, edit, bash, ls, grep, find]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Add Acceptance Test
|
|
11
|
+
|
|
12
|
+
## Workflow
|
|
13
|
+
|
|
14
|
+
1. **Identify the target `.plain` file and the functional spec** to attach the acceptance test to. If ambiguous, ask the user.
|
|
15
|
+
2. **Read the file** to understand the functional spec, existing acceptance tests (if any), and the `***test reqs***` section (acceptance tests are implemented according to test reqs).
|
|
16
|
+
3. **Draft the acceptance test(s)** following the rules below.
|
|
17
|
+
4. **Nest them** under the target functional spec using a `***acceptance tests***` subsection.
|
|
18
|
+
5. **Read the file again** to confirm correct placement, indentation, and syntax.
|
|
19
|
+
|
|
20
|
+
## When to Add Acceptance Tests
|
|
21
|
+
|
|
22
|
+
- The functional spec's correct behavior is **non-obvious** or easily misinterpreted.
|
|
23
|
+
- The spec involves **edge cases**, boundary conditions, or specific numeric outcomes.
|
|
24
|
+
- The user explicitly requests verification criteria.
|
|
25
|
+
- The spec was added via the `add-functional-spec` skill and warrants testable success criteria.
|
|
26
|
+
|
|
27
|
+
## Format
|
|
28
|
+
|
|
29
|
+
Acceptance tests are nested under the functional spec they verify, using a `***acceptance tests***` subsection:
|
|
30
|
+
|
|
31
|
+
```plain
|
|
32
|
+
***functional specs***
|
|
33
|
+
|
|
34
|
+
- :Task: items are processed in batches of 100.
|
|
35
|
+
|
|
36
|
+
***acceptance tests***
|
|
37
|
+
- Processing 250 :Task: items should result in 3 batches.
|
|
38
|
+
|
|
39
|
+
- Each batch should contain at most 100 items.
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Key formatting rules:
|
|
43
|
+
- The `***acceptance tests***` header is indented under the functional spec it belongs to.
|
|
44
|
+
- Each test bullet is indented under the `***acceptance tests***` header.
|
|
45
|
+
- Multiple acceptance tests can be listed under a single functional spec.
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
## Rules
|
|
49
|
+
|
|
50
|
+
### Conformance with the Functional Spec
|
|
51
|
+
|
|
52
|
+
An acceptance test is essentially an **example that illustrates** the functional spec — it clarifies intent by showing a concrete scenario. It may imply minor code changes, but those should not be substantial. The acceptance test **must be consistent with** the functional spec it is nested under. If the acceptance test asserts behavior that contradicts, narrows, or extends the functional spec in ways not implied by it, the system will reject it as a conflicting acceptance test. Before writing, re-read the parent functional spec and ensure every assertion in the acceptance test is a direct, logical consequence of what the spec states.
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
Functional spec:
|
|
56
|
+
- :Resource: items are returned sorted by creation date in descending order.
|
|
57
|
+
|
|
58
|
+
Good (consistent):
|
|
59
|
+
- The first :Resource: in the response should have the most recent creation date.
|
|
60
|
+
|
|
61
|
+
Bad (contradicts the spec — the spec says descending, not ascending):
|
|
62
|
+
- The first :Resource: in the response should have the oldest creation date.
|
|
63
|
+
|
|
64
|
+
Bad (extends beyond the spec — the spec says nothing about limiting results):
|
|
65
|
+
- The response should contain at most 50 :Resource: items.
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Scope
|
|
69
|
+
|
|
70
|
+
Each acceptance test verifies a specific, observable aspect of the functional spec it's nested under. Do not test behavior from other functional specs.
|
|
71
|
+
|
|
72
|
+
### Testability
|
|
73
|
+
|
|
74
|
+
Every acceptance test must describe a concrete, verifiable outcome — not a vague quality. The test should be implementable as an automated conformance test.
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
Good: - The response should contain exactly 3 items.
|
|
78
|
+
Bad: - The response should be correct.
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Language Agnosticism
|
|
82
|
+
|
|
83
|
+
Like functional specs, acceptance tests must be written in terms of behavior and outcomes — not language-specific constructs.
|
|
84
|
+
|
|
85
|
+
### Relationship to Test Reqs
|
|
86
|
+
|
|
87
|
+
Acceptance tests extend conformance tests and are implemented according to the `***test reqs***` specification. They do not replace test reqs — they add spec-specific verification on top of the general testing framework defined there.
|
|
88
|
+
|
|
89
|
+
## Validation Checklist
|
|
90
|
+
|
|
91
|
+
- [ ] Every assertion is a direct logical consequence of the parent functional spec
|
|
92
|
+
- [ ] No assertion contradicts, narrows, or extends beyond the parent spec
|
|
93
|
+
- [ ] Acceptance test illustrates the spec via example, not introducing substantial new behavior
|
|
94
|
+
- [ ] Nested under the correct functional spec
|
|
95
|
+
- [ ] Indentation is correct (`***acceptance tests***` indented under the spec)
|
|
96
|
+
- [ ] Each test describes a concrete, verifiable outcome
|
|
97
|
+
- [ ] Trimmed per `concise-specs.md`: plain words, no obvious steps, no restatement of the parent spec
|
|
98
|
+
- [ ] Tests are scoped to the parent functional spec only
|
|
99
|
+
- [ ] Written in language-agnostic terms
|
|
100
|
+
- [ ] No duplication with existing acceptance tests on the same spec
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: add-concept
|
|
3
|
+
description: >-
|
|
4
|
+
Add a concept to the ***definitions*** section of a ***plain spec file. Use
|
|
5
|
+
when the user wants to define a new concept, entity, or domain term in a
|
|
6
|
+
.plain file.
|
|
7
|
+
allowed-tools: [read, write, edit, bash, ls, grep, find]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Add Concept
|
|
11
|
+
|
|
12
|
+
## Workflow
|
|
13
|
+
|
|
14
|
+
1. **Identify the target `.plain` file.** If ambiguous, ask the user.
|
|
15
|
+
2. **Read the file** to understand existing definitions, imports, and concepts.
|
|
16
|
+
3. **Validate the concept name** against the syntax rules below.
|
|
17
|
+
4. **Check for uniqueness** — the concept name must not already exist in the file or its imports.
|
|
18
|
+
5. **Check referenced concepts** — any `:ConceptName:` used in the definition must already be defined above it (in this file or via `import`/`requires`). Concept references must not form cycles (e.g., A references B and B references A).
|
|
19
|
+
6. **Check for circular references** — if the new concept references `:B:`, then `:B:` must not reference the new concept (directly or indirectly). Example of a circular definition to avoid:
|
|
20
|
+
```plain
|
|
21
|
+
- :Order: is placed by :Customer: and contains :OrderItem: entries.
|
|
22
|
+
- :Customer: is a user who has placed at least one :Order:.
|
|
23
|
+
```
|
|
24
|
+
Fix by removing the back-reference:
|
|
25
|
+
```plain
|
|
26
|
+
- :Customer: is a user of the system.
|
|
27
|
+
- :Order: is placed by :Customer: and contains :OrderItem: entries.
|
|
28
|
+
```
|
|
29
|
+
7. **Insert the concept** into the `***definitions***` section, after any concepts it references.
|
|
30
|
+
8. **Read the file again** to confirm correct placement and syntax.
|
|
31
|
+
|
|
32
|
+
## Concept Syntax Rules
|
|
33
|
+
|
|
34
|
+
- Wrapped in colons: `:ConceptName:`
|
|
35
|
+
- CamelCase, starting with an uppercase letter
|
|
36
|
+
- Valid characters: letters, digits, `+`, `-`, `.`, `_`
|
|
37
|
+
- Must be globally unique across the spec and all its imports
|
|
38
|
+
- Exported concepts from `requires` modules are **not transitive** — to reference an ancestor's export, list that ancestor in `requires`; if a concept is shared across branches, define it in a common import module instead
|
|
39
|
+
|
|
40
|
+
## Definition Format
|
|
41
|
+
|
|
42
|
+
A concept definition is a bullet in `***definitions***` that starts with the concept name:
|
|
43
|
+
|
|
44
|
+
```plain
|
|
45
|
+
***definitions***
|
|
46
|
+
|
|
47
|
+
- :ConceptName: is a description of what it represents.
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Attributes and constraints are nested sub-bullets:
|
|
51
|
+
|
|
52
|
+
```plain
|
|
53
|
+
***definitions***
|
|
54
|
+
|
|
55
|
+
- :Task: describes an activity that needs to be done by :User:. :Task: has:
|
|
56
|
+
- Name - a short description (required)
|
|
57
|
+
- Notes - additional details (optional)
|
|
58
|
+
- Due Date - completion deadline (optional)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
## Validation Checklist
|
|
63
|
+
|
|
64
|
+
- [ ] Name uses `:CamelCase:` notation
|
|
65
|
+
- [ ] Name is globally unique (not defined elsewhere in the file or imports)
|
|
66
|
+
- [ ] Definition starts with the concept name
|
|
67
|
+
- [ ] All referenced concepts (`:OtherConcept:`) are already defined above
|
|
68
|
+
- [ ] No circular references between concepts
|
|
69
|
+
- [ ] Description is clear, concise, and language-agnostic
|
|
70
|
+
- [ ] Trimmed per `concise-specs.md`: one plain sentence, no restatement of the name, no rationale
|
|
71
|
+
- [ ] Placed inside a `***definitions***` section
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: add-functional-spec
|
|
3
|
+
description: >-
|
|
4
|
+
Add a single functional spec to the ***functional specs*** section of a
|
|
5
|
+
***plain spec file. Use whenever exactly one new functional spec is being
|
|
6
|
+
added — whether the user explicitly asks, or another skill/workflow
|
|
7
|
+
(e.g. `brood`, `bud`) needs to author a new functional spec.
|
|
8
|
+
Every new entry under ***functional specs*** must go through either this
|
|
9
|
+
skill or `add-functional-specs` (the bulk variant for adding multiple specs
|
|
10
|
+
in one pass); hand-authoring functional specs without invoking one of these
|
|
11
|
+
skills is forbidden.
|
|
12
|
+
allowed-tools: [read, write, edit, bash, ls, grep, find]
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Add Functional Spec
|
|
16
|
+
|
|
17
|
+
## Workflow
|
|
18
|
+
|
|
19
|
+
1. **Identify the target `.plain` file.** If ambiguous, ask the user.
|
|
20
|
+
2. **Read the entire file** to understand existing definitions, implementation reqs, and all current functional specs (including those in `requires` modules).
|
|
21
|
+
3. **Draft the functional spec** following the rules below, then run the review pass in `concise-specs.md` over the draft — trim it to the shortest wording that keeps every fact before any other check.
|
|
22
|
+
4. **Analyze complexity** — use the `analyze-if-func-spec-too-complex` skill to verify the drafted spec implies ≤ 200 LOC. If too complex, use the `break-down-func-spec` skill to split it, then repeat from step 3 for each resulting spec.
|
|
23
|
+
5. **Check for conflicts** with every existing functional spec — this is critical. Run `analyze-func-specs` **once** with the new spec plus all existing specs (in the file and in any `requires` chain) as a single batch. The batched analyzer returns every conflicting pair in one call — do **not** invoke a pair-by-pair analyzer. For each conflicting pair it reports, run `resolve-spec-conflict` on that pair; re-run `analyze-func-specs` over the touched set after each resolution until the verdict is `COMPATIBLE`.
|
|
24
|
+
6. **Append the spec** to the end of the `***functional specs***` section (specs are chronological; new ones go last).
|
|
25
|
+
7. **Read the file again** to confirm correct placement and syntax.
|
|
26
|
+
|
|
27
|
+
## Rules
|
|
28
|
+
|
|
29
|
+
### Complexity Limit
|
|
30
|
+
|
|
31
|
+
Each functional spec must imply a **maximum of 200 changed lines of code**. If the requirement is too large, use the `break-down-func-spec` skill to split it into multiple smaller, independent specs. Do not include LOC estimates in the spec text.
|
|
32
|
+
|
|
33
|
+
### Chronological Ordering
|
|
34
|
+
|
|
35
|
+
Specs are rendered incrementally, top to bottom. The renderer has **no knowledge of future specs** — only previously rendered specs are in context. This means:
|
|
36
|
+
- A new spec can reference behavior defined by earlier specs.
|
|
37
|
+
- A new spec **cannot** assume anything about specs that come after it.
|
|
38
|
+
- Place the new spec at the correct position if it must come before a future spec; otherwise append at the end.
|
|
39
|
+
|
|
40
|
+
### Language Agnosticism
|
|
41
|
+
|
|
42
|
+
Write in terms of behavior, concepts, and domain logic — not implementation constructs. Avoid language-specific types, generics syntax, framework annotations, or other constructs tied to a particular language or framework. General technical terms (null values, JSON types, HTTP status codes) are fine. Language-specific guidance belongs in `***implementation reqs***`.
|
|
43
|
+
|
|
44
|
+
### No Conflicts
|
|
45
|
+
|
|
46
|
+
The new spec must not contradict any existing functional spec. Conflicting specs are the most costly outcome. Before adding, review all existing specs and verify the new one is compatible. Use `analyze-func-specs` to check the new spec against every existing spec in **one batched call** — it lists every conflicting pair, so a pair-by-pair analyzer is not needed. If ambiguity exists, add explicit detail to eliminate any conflicting interpretation. For each conflicting pair the batched analyzer reports, use the `resolve-spec-conflict` skill to diagnose and fix it before proceeding.
|
|
47
|
+
|
|
48
|
+
### Disambiguation
|
|
49
|
+
|
|
50
|
+
Each functional spec must be unambiguous — the renderer should have only one reasonable interpretation. If a single line is not enough to fully disambiguate the behavior, use **nested sub-bullets** to add detail. Nested lines clarify the parent spec; they do not introduce separate functionality. Even with nested detail, the spec must still imply ≤ 200 LOC.
|
|
51
|
+
|
|
52
|
+
```plain
|
|
53
|
+
***functional specs***
|
|
54
|
+
|
|
55
|
+
- A :User: can send a :Message: to a :Conversation:.
|
|
56
|
+
- A :Message: must have non-empty content.
|
|
57
|
+
- The :Message: is appended to the end of the :Conversation:.
|
|
58
|
+
- All :Participant: members of the :Conversation: can see the new :Message:.
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
### Deterministic Interface
|
|
63
|
+
|
|
64
|
+
Specs must be detailed enough that a developer can use the built software without reading the generated code. All external interfaces must be explicit — REST endpoint paths and HTTP methods, CLI command names and arguments, file formats, message schemas, etc. Never leave interface details up to the renderer's discretion.
|
|
65
|
+
|
|
66
|
+
### Encapsulation
|
|
67
|
+
|
|
68
|
+
Functionality must be self-contained in the spec text. `requires` modules only import functional specs, so do not rely on implementation reqs to convey behavior — they won't be visible in downstream modules.
|
|
69
|
+
|
|
70
|
+
## Acceptance Tests
|
|
71
|
+
|
|
72
|
+
If the functional spec needs verification, use the `add-acceptance-test` skill to add acceptance tests after inserting the spec.
|
|
73
|
+
|
|
74
|
+
## Validation Checklist
|
|
75
|
+
|
|
76
|
+
- [ ] Spec implies ≤ 200 lines of code changes
|
|
77
|
+
- [ ] No conflict with any existing functional spec
|
|
78
|
+
- [ ] Written in language-agnostic terms (no language/framework specifics)
|
|
79
|
+
- [ ] All external interfaces are explicit (endpoint paths, methods, CLI args, formats, etc.)
|
|
80
|
+
- [ ] All referenced `:Concepts:` are defined in `***definitions***`
|
|
81
|
+
- [ ] Sentences are short, clear, and unambiguous
|
|
82
|
+
- [ ] Trimmed per `concise-specs.md`: nothing obvious, no rationale, no uncheckable adjectives or hedges, plain words throughout
|
|
83
|
+
- [ ] No redundancy with existing specs
|
|
84
|
+
- [ ] Placed in correct chronological position (usually at the end)
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: add-functional-specs
|
|
3
|
+
description: >-
|
|
4
|
+
Add multiple functional specs to the ***functional specs*** section of a
|
|
5
|
+
***plain spec file in a single batch. Use whenever more than one new
|
|
6
|
+
functional spec is being added — whether the user explicitly asks, or
|
|
7
|
+
another skill/workflow (e.g. `brood`, `bud`) needs to author
|
|
8
|
+
several specs in one pass. Bulk-writing or hand-authoring functional
|
|
9
|
+
specs without invoking this skill is forbidden; for adding a single spec,
|
|
10
|
+
use add-functional-spec instead.
|
|
11
|
+
allowed-tools: [read, write, edit, bash, ls, grep, find]
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Add Functional Specs
|
|
15
|
+
|
|
16
|
+
## When to Use
|
|
17
|
+
|
|
18
|
+
- The user asks for several functional specs to be added in one go (e.g. "add these three specs", "spec out this feature in a few bullets").
|
|
19
|
+
- A higher-level skill or workflow (`brood`, `bud`, `debug-specs`) needs to author a tight group of related specs.
|
|
20
|
+
- Anywhere you would otherwise be tempted to write more than one functional spec without running per-spec analysis.
|
|
21
|
+
|
|
22
|
+
If you only need to add a single spec, use the `add-functional-spec` skill instead. Either way, **never** edit the `***functional specs***` section by hand — every new entry must go through one of these two skills so the complexity and conflict checks actually run.
|
|
23
|
+
|
|
24
|
+
## Workflow
|
|
25
|
+
|
|
26
|
+
This skill is `add-functional-spec` applied **one spec at a time, in order**, with no shortcuts. The batch never escapes per-spec rigor.
|
|
27
|
+
|
|
28
|
+
1. **Identify the target `.plain` file.** If ambiguous, ask the user.
|
|
29
|
+
2. **Read the entire file** to understand existing definitions, implementation reqs, and all current functional specs (including those reachable via `import` / `requires`).
|
|
30
|
+
3. **Draft all the specs you intend to add**, in the chronological order they should appear. Keep the drafts in a working list — nothing is inserted yet. Run the review pass in `concise-specs.md` over every draft before continuing; trim each to the shortest wording that keeps every fact.
|
|
31
|
+
4. **For each drafted spec, in order:**
|
|
32
|
+
1. **Analyze complexity.** Run `analyze-if-func-spec-too-complex` on the spec. If the verdict is `TOO COMPLEX`, run `break-down-func-spec`, replace the entry in the working list with the resulting smaller specs (preserving order), and restart this step on the first of the replacements.
|
|
33
|
+
2. **Check for conflicts.** Run `analyze-func-specs` **once** with this single input set:
|
|
34
|
+
- the new spec, plus
|
|
35
|
+
- every existing functional spec in the file and its `requires` chain, plus
|
|
36
|
+
- every spec from this batch that has already been inserted.
|
|
37
|
+
|
|
38
|
+
The batched analyzer returns every conflicting pair in one call — do **not** loop over pairs invoking a per-pair analyzer. For each conflicting pair it reports, run `resolve-spec-conflict`. Apply the resolution — which may revise the new spec, an existing spec, or both — then re-run `analyze-func-specs` once over the touched set until the verdict is `COMPATIBLE`.
|
|
39
|
+
3. **Append the spec** to the `***functional specs***` section. Specs are chronological; the new entry goes at the end (unless an earlier existing spec must come *after* it — in that rare case, insert at the correct position).
|
|
40
|
+
5. **Read the file again** to confirm correct placement, ordering, and syntax for the full batch.
|
|
41
|
+
|
|
42
|
+
Order matters: each new spec is inserted only after its complexity and conflict checks pass, so subsequent specs in the batch are always checked against an already-validated file.
|
|
43
|
+
|
|
44
|
+
## Rules
|
|
45
|
+
|
|
46
|
+
All the rules from `add-functional-spec` apply per individual spec. They are restated here so this skill is self-contained.
|
|
47
|
+
|
|
48
|
+
### Complexity Limit (per spec)
|
|
49
|
+
|
|
50
|
+
Each functional spec must imply a **maximum of 200 changed lines of code**. If a spec is too large, use `break-down-func-spec` to split it into multiple smaller, independent specs. Do not include LOC estimates in the spec text.
|
|
51
|
+
|
|
52
|
+
### Chronological Ordering
|
|
53
|
+
|
|
54
|
+
Specs are rendered incrementally, top to bottom. The renderer has **no knowledge of future specs** — only previously rendered specs are in context.
|
|
55
|
+
- A new spec can reference behavior defined by earlier specs.
|
|
56
|
+
- A new spec **cannot** assume anything about specs that come after it.
|
|
57
|
+
- Order the batch so that each spec only depends on specs that precede it. If two new specs would otherwise reference each other, the dependent one comes second.
|
|
58
|
+
|
|
59
|
+
### Language Agnosticism
|
|
60
|
+
|
|
61
|
+
Write in terms of behavior, concepts, and domain logic — not implementation constructs. Avoid language-specific types, generics syntax, framework annotations, or other constructs tied to a particular language or framework. General technical terms (null values, JSON types, HTTP status codes) are fine. Language-specific guidance belongs in `***implementation reqs***`.
|
|
62
|
+
|
|
63
|
+
### No Conflicts (full coverage via one batched call per spec)
|
|
64
|
+
|
|
65
|
+
The new specs must not contradict each other **and** must not contradict any existing functional spec. Conflicting specs are the most costly outcome. The conflict check must cover:
|
|
66
|
+
- every (new × existing) pair, and
|
|
67
|
+
- every (new × new) pair within the batch.
|
|
68
|
+
|
|
69
|
+
That coverage is achieved by running `analyze-func-specs` **once per spec being inserted**, with the new spec plus every existing spec plus every already-inserted spec from this batch passed in as a single set. The batched analyzer lists every conflicting pair in one call — do not invoke a pair-by-pair analyzer. If ambiguity exists, add explicit detail to eliminate any conflicting interpretation. For each conflicting pair the batched analyzer reports, use the `resolve-spec-conflict` skill to diagnose and fix it before proceeding.
|
|
70
|
+
|
|
71
|
+
### Disambiguation (per spec)
|
|
72
|
+
|
|
73
|
+
Each functional spec must be unambiguous — the renderer should have only one reasonable interpretation. If a single line is not enough to fully disambiguate the behavior, use **nested sub-bullets** to add detail. Nested lines clarify the parent spec; they do not introduce separate functionality. Even with nested detail, the spec must still imply ≤ 200 LOC.
|
|
74
|
+
|
|
75
|
+
```plain
|
|
76
|
+
***functional specs***
|
|
77
|
+
|
|
78
|
+
- A :User: can send a :Message: to a :Conversation:.
|
|
79
|
+
- A :Message: must have non-empty content.
|
|
80
|
+
- The :Message: is appended to the end of the :Conversation:.
|
|
81
|
+
- All :Participant: members of the :Conversation: can see the new :Message:.
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
### Deterministic Interface
|
|
86
|
+
|
|
87
|
+
Specs must be detailed enough that a developer can use the built software without reading the generated code. All external interfaces must be explicit — REST endpoint paths and HTTP methods, CLI command names and arguments, file formats, message schemas, etc. Never leave interface details up to the renderer's discretion.
|
|
88
|
+
|
|
89
|
+
### Encapsulation
|
|
90
|
+
|
|
91
|
+
Functionality must be self-contained in the spec text. `requires` modules only import functional specs, so do not rely on implementation reqs to convey behavior — they won't be visible in downstream modules.
|
|
92
|
+
|
|
93
|
+
## Acceptance Tests
|
|
94
|
+
|
|
95
|
+
If any of the newly added functional specs need verification, use the `add-acceptance-test` skill to add acceptance tests after the batch has been inserted. Do this per spec, not as part of the bulk pass.
|
|
96
|
+
|
|
97
|
+
## Anti-Patterns
|
|
98
|
+
|
|
99
|
+
- **Don't skip per-spec checks because the batch "feels" small.** Even two specs require two complexity checks and a batched conflict check that includes both new specs.
|
|
100
|
+
- **Don't fall back to pair-by-pair conflict analysis.** Use `analyze-func-specs` with the full relevant set once per inserted spec — not `analyze-2-func-specs` across every pair.
|
|
101
|
+
- **Don't run all complexity checks first and all conflict checks last.** Interleave them per spec, as described in the Workflow — a failed complexity check earlier would otherwise waste later conflict checks.
|
|
102
|
+
- **Don't insert every spec first and then analyze.** A bad spec already in the file pollutes subsequent conflict analyses.
|
|
103
|
+
- **Don't fall back to hand-authoring** because there are "a lot" of specs to add. The right answer is more analyzer calls, not fewer.
|
|
104
|
+
- **Don't use this skill for a single spec.** Use `add-functional-spec` — it's the same checks without the bulk bookkeeping.
|
|
105
|
+
|
|
106
|
+
## Validation Checklist
|
|
107
|
+
|
|
108
|
+
- [ ] Every spec in the batch implies ≤ 200 lines of code changes (verified via `analyze-if-func-spec-too-complex`)
|
|
109
|
+
- [ ] No conflict between any new spec and any existing spec (verified via batched `analyze-func-specs` calls)
|
|
110
|
+
- [ ] No conflict between any two new specs in the batch (covered by the same batched `analyze-func-specs` calls)
|
|
111
|
+
- [ ] Every conflicting pair the batched analyzer reported was resolved via `resolve-spec-conflict` before the batch completed
|
|
112
|
+
- [ ] All specs written in language-agnostic terms (no language/framework specifics)
|
|
113
|
+
- [ ] All external interfaces explicit (endpoint paths, methods, CLI args, formats, etc.)
|
|
114
|
+
- [ ] All referenced `:Concepts:` are defined in `***definitions***`
|
|
115
|
+
- [ ] Sentences are short, clear, and unambiguous
|
|
116
|
+
- [ ] Every spec trimmed per `concise-specs.md`: nothing obvious, no rationale, no uncheckable adjectives or hedges, plain words throughout
|
|
117
|
+
- [ ] No redundancy with existing specs or within the batch
|
|
118
|
+
- [ ] Specs placed in correct chronological positions
|