plain-forge 1.0.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.
- package/LICENSE +21 -0
- package/README.md +247 -0
- package/bin/cli.mjs +143 -0
- package/forge/docs/.gitkeep +0 -0
- package/forge/rules/definitions.md +57 -0
- package/forge/rules/exported-concepts.md +39 -0
- package/forge/rules/func-specs.md +72 -0
- package/forge/rules/impl-reqs.md +50 -0
- package/forge/rules/import-modules.md +51 -0
- package/forge/rules/required-concepts.md +45 -0
- package/forge/rules/requires-modules.md +59 -0
- package/forge/rules/test-reqs.md +47 -0
- package/forge/skills/add-acceptance-test/SKILL.md +98 -0
- package/forge/skills/add-concept/SKILL.md +67 -0
- package/forge/skills/add-feature/SKILL.md +136 -0
- package/forge/skills/add-functional-spec/SKILL.md +81 -0
- package/forge/skills/add-functional-specs/SKILL.md +115 -0
- package/forge/skills/add-implementation-requirement/SKILL.md +73 -0
- package/forge/skills/add-resource/SKILL.md +108 -0
- package/forge/skills/add-template/SKILL.md +65 -0
- package/forge/skills/add-test-requirement/SKILL.md +68 -0
- package/forge/skills/analyze-2-func-specs/SKILL.md +102 -0
- package/forge/skills/analyze-func-specs/SKILL.md +124 -0
- package/forge/skills/analyze-if-func-spec-too-complex/SKILL.md +152 -0
- package/forge/skills/break-down-func-spec/SKILL.md +156 -0
- package/forge/skills/check-plain-env/SKILL.md +288 -0
- package/forge/skills/consolidate-concepts/SKILL.md +193 -0
- package/forge/skills/create-import-module/SKILL.md +98 -0
- package/forge/skills/create-requires-module/SKILL.md +104 -0
- package/forge/skills/debug-specs/SKILL.md +189 -0
- package/forge/skills/forge-integration/SKILL.md +443 -0
- package/forge/skills/forge-plain/SKILL.md +333 -0
- package/forge/skills/implement-conformance-testing-script/SKILL.md +247 -0
- package/forge/skills/implement-conformance-testing-script/assets/run_conformance_tests_cypress.ps1 +324 -0
- package/forge/skills/implement-conformance-testing-script/assets/run_conformance_tests_golang.ps1 +100 -0
- package/forge/skills/implement-conformance-testing-script/assets/run_conformance_tests_java.sh +102 -0
- package/forge/skills/implement-conformance-testing-script/assets/run_conformance_tests_python.ps1 +92 -0
- package/forge/skills/implement-conformance-testing-script/assets/run_conformance_tests_python.sh +100 -0
- package/forge/skills/implement-prepare-environment-script/SKILL.md +242 -0
- package/forge/skills/implement-prepare-environment-script/assets/prepare_environment_java.sh +42 -0
- package/forge/skills/implement-prepare-environment-script/assets/prepare_environment_python.sh +81 -0
- package/forge/skills/implement-unit-testing-script/SKILL.md +133 -0
- package/forge/skills/implement-unit-testing-script/assets/run_unittests_flutter.ps1 +82 -0
- package/forge/skills/implement-unit-testing-script/assets/run_unittests_golang.ps1 +68 -0
- package/forge/skills/implement-unit-testing-script/assets/run_unittests_java.sh +45 -0
- package/forge/skills/implement-unit-testing-script/assets/run_unittests_python.ps1 +76 -0
- package/forge/skills/implement-unit-testing-script/assets/run_unittests_python.sh +90 -0
- package/forge/skills/implement-unit-testing-script/assets/run_unittests_react.ps1 +83 -0
- package/forge/skills/init-config-file/SKILL.md +261 -0
- package/forge/skills/init-plain-project/SKILL.md +124 -0
- package/forge/skills/load-plain-reference/SKILL.md +646 -0
- package/forge/skills/plain-healthcheck/SKILL.md +132 -0
- package/forge/skills/refactor-module/SKILL.md +197 -0
- package/forge/skills/resolve-spec-conflict/SKILL.md +88 -0
- package/forge/skills/run-codeplain/SKILL.md +540 -0
- package/package.json +42 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Rules for creating and using import modules in .plain files
|
|
3
|
+
globs: "**/*.plain"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Rules for import modules
|
|
7
|
+
|
|
8
|
+
When creating or editing a `.plain` file that uses `import` or is intended to be imported by other modules, always follow these rules:
|
|
9
|
+
|
|
10
|
+
## What an import module is
|
|
11
|
+
- An import module contains **only** `***definitions***`, `***implementation reqs***`, and/or `***test reqs***`
|
|
12
|
+
- It must **not** contain `***functional specs***`
|
|
13
|
+
- It must **not** use `requires` in its frontmatter
|
|
14
|
+
- It must live in the **`template/`** directory
|
|
15
|
+
- It may optionally `import` other modules or templates for layered reuse
|
|
16
|
+
|
|
17
|
+
## What import does
|
|
18
|
+
- `import` pulls in `***definitions***`, `***implementation reqs***`, and `***test reqs***` from the target module
|
|
19
|
+
- It does **not** pull in `***functional specs***`
|
|
20
|
+
- The default import directory is `template/` — the `template/` prefix is not needed in import paths
|
|
21
|
+
- Import paths omit the `.plain` extension
|
|
22
|
+
|
|
23
|
+
## Concept visibility
|
|
24
|
+
- All concepts defined in the imported module become available in the importing module
|
|
25
|
+
- Check for concept name collisions between imports and local definitions before adding
|
|
26
|
+
|
|
27
|
+
## Format
|
|
28
|
+
|
|
29
|
+
```plain
|
|
30
|
+
---
|
|
31
|
+
import:
|
|
32
|
+
- airplain
|
|
33
|
+
description: Module that imports shared definitions and reqs
|
|
34
|
+
---
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
A module can import multiple modules:
|
|
38
|
+
|
|
39
|
+
```plain
|
|
40
|
+
---
|
|
41
|
+
import:
|
|
42
|
+
- airplain
|
|
43
|
+
- shared_utils
|
|
44
|
+
---
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Combining import with requires
|
|
48
|
+
- A module can use both `import` and `requires` together
|
|
49
|
+
- `import` brings in shared definitions and reqs
|
|
50
|
+
- `requires` brings in the build dependency chain and functional specs
|
|
51
|
+
- An import module itself must **not** use `requires`
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Rules for using required_concepts in .plain files
|
|
3
|
+
globs: "**/*.plain"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Rules for `required_concepts`
|
|
7
|
+
|
|
8
|
+
When adding or editing `required_concepts` in a `.plain` file's frontmatter, always follow these rules:
|
|
9
|
+
|
|
10
|
+
## What required_concepts does
|
|
11
|
+
- `required_concepts` declares concepts that any module importing this file **must** define
|
|
12
|
+
- It creates a contract: the import module references these concepts but does not define them — the importing module is responsible for providing definitions
|
|
13
|
+
- This is used exclusively on import modules and templates
|
|
14
|
+
|
|
15
|
+
## When to use it
|
|
16
|
+
- Use `required_concepts` when an import module or template (in `template/`) references concepts that vary per project or per importing module
|
|
17
|
+
- The import module can reference these concepts in its definitions, implementation reqs, or test reqs — but their actual definitions come from whoever imports the file
|
|
18
|
+
|
|
19
|
+
## Importing module must satisfy the contract
|
|
20
|
+
- Every concept listed in `required_concepts` must be defined in the importing module's own `***definitions***` section
|
|
21
|
+
- If the importing module does not define a required concept, the spec is invalid
|
|
22
|
+
- Check `required_concepts` of all imported modules before finalizing a module
|
|
23
|
+
|
|
24
|
+
## Do not define required concepts locally
|
|
25
|
+
- The import module that declares `required_concepts` must **not** define those concepts itself
|
|
26
|
+
- The whole point is that the importing module provides the definition
|
|
27
|
+
|
|
28
|
+
## Format
|
|
29
|
+
|
|
30
|
+
```plain
|
|
31
|
+
---
|
|
32
|
+
required_concepts: [":AppName:", ":AppConfig:"]
|
|
33
|
+
description: Template that requires AppName and AppConfig to be defined by the importer
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
***definitions***
|
|
37
|
+
- :MainFile: is the entry point for :AppName:.
|
|
38
|
+
|
|
39
|
+
***implementation reqs***
|
|
40
|
+
- :MainFile: should load :AppConfig: on startup.
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
In this example, `:AppName:` and `:AppConfig:` are referenced but not defined — the module that imports this template must define them.
|
|
44
|
+
|
|
45
|
+
List concepts as a YAML array with each concept in `:ConceptName:` notation.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Rules for creating and using requires modules in .plain files
|
|
3
|
+
globs: "**/*.plain"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Rules for requires modules
|
|
7
|
+
|
|
8
|
+
When creating or editing a `.plain` file that uses `requires`, always follow these rules:
|
|
9
|
+
|
|
10
|
+
## What requires does
|
|
11
|
+
- `requires` establishes a **build ordering** — the required module is built before the current one
|
|
12
|
+
- The required module's generated code (`plain_modules/<required_module>`) is copied as the starting point
|
|
13
|
+
- The required module's `***functional specs***` become visible as **previous functional specs**
|
|
14
|
+
- Only `exported_concepts` from the required module are available — not its full definitions
|
|
15
|
+
|
|
16
|
+
## Build order, not necessarily dependency
|
|
17
|
+
- The current module does not need to extend or depend on the required module's code
|
|
18
|
+
- The two modules may be completely independent
|
|
19
|
+
- `requires` ensures the build order is correct for the project as a whole
|
|
20
|
+
|
|
21
|
+
## Conflict prevention
|
|
22
|
+
- The current module's functional specs must not conflict with the required module's specs
|
|
23
|
+
- The required module's specs are treated as previous requirements — the renderer sees them as context
|
|
24
|
+
- Review the required module's functional specs before adding new ones
|
|
25
|
+
|
|
26
|
+
## No access to full definitions
|
|
27
|
+
- Only concepts listed in the required module's `exported_concepts` are available
|
|
28
|
+
- Other concepts from the required module are internal and invisible
|
|
29
|
+
- If you need shared definitions, use `import` for that — not `requires`
|
|
30
|
+
|
|
31
|
+
## File locations
|
|
32
|
+
- Modules that use `requires` live at the **repository root** — they are functional modules with specs
|
|
33
|
+
- `requires` paths point to other root-level modules (e.g., `auth`, `messaging`)
|
|
34
|
+
- The default import directory is `template/` — the `template/` prefix is not needed in import paths (e.g., `airplain`)
|
|
35
|
+
- Never `require` a template — templates are for `import` only
|
|
36
|
+
|
|
37
|
+
## Format
|
|
38
|
+
|
|
39
|
+
```plain
|
|
40
|
+
---
|
|
41
|
+
requires:
|
|
42
|
+
- auth
|
|
43
|
+
import:
|
|
44
|
+
- airplain
|
|
45
|
+
description: Module built after auth, importing shared definitions
|
|
46
|
+
---
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
A module can require multiple modules:
|
|
50
|
+
|
|
51
|
+
```plain
|
|
52
|
+
---
|
|
53
|
+
requires:
|
|
54
|
+
- auth
|
|
55
|
+
- messaging
|
|
56
|
+
import:
|
|
57
|
+
- airplain
|
|
58
|
+
---
|
|
59
|
+
```
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Rules for writing ***test reqs*** sections in .plain files
|
|
3
|
+
globs: "**/*.plain"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Rules for writing `***test reqs***`
|
|
7
|
+
|
|
8
|
+
When writing or editing a `***test reqs***` section in a `.plain` file, always follow these rules:
|
|
9
|
+
|
|
10
|
+
## Conformance tests only
|
|
11
|
+
- Test reqs specify how **conformance tests** should be written and run
|
|
12
|
+
- Unit test guidance goes in `***implementation reqs***`, not here
|
|
13
|
+
- Acceptance tests are nested under individual functional specs, not here
|
|
14
|
+
- Behavioral requirements go in `***functional specs***`, not here
|
|
15
|
+
|
|
16
|
+
## What belongs here
|
|
17
|
+
- Test framework: which framework to use (e.g., pytest, Unittest, xUnit)
|
|
18
|
+
- Execution method: the command to run the tests
|
|
19
|
+
- Testing constraints: what must or must not be done in tests (e.g., no skipping, mock requirements)
|
|
20
|
+
- Test data: how test fixtures or mock data should be structured
|
|
21
|
+
- Environment setup: any prerequisites for running conformance tests
|
|
22
|
+
|
|
23
|
+
## Test type reference
|
|
24
|
+
|
|
25
|
+
| Test type | Where to specify | Purpose |
|
|
26
|
+
|-----------|-----------------|---------|
|
|
27
|
+
| Unit tests | `***implementation reqs***` | Test individual functionalities in isolation |
|
|
28
|
+
| Conformance tests | `***test reqs***` | Verify implementation conforms to the full spec |
|
|
29
|
+
| Acceptance tests | `***acceptance tests***` under a functional spec | Verify a specific functional spec |
|
|
30
|
+
|
|
31
|
+
## No duplication
|
|
32
|
+
- Do not duplicate guidance already present in the file or its imports
|
|
33
|
+
- Check imported templates before adding a new test req
|
|
34
|
+
|
|
35
|
+
## Concept references
|
|
36
|
+
- Reference predefined concepts like `:ConformanceTests:` where appropriate
|
|
37
|
+
- All other referenced `:Concepts:` must be defined in `***definitions***`
|
|
38
|
+
|
|
39
|
+
## Format
|
|
40
|
+
|
|
41
|
+
```plain
|
|
42
|
+
***test reqs***
|
|
43
|
+
- :ConformanceTests: should be implemented using pytest framework.
|
|
44
|
+
- :ConformanceTests: will be run using "pytest" command.
|
|
45
|
+
- :ConformanceTests: must be implemented and executed - do not skip tests.
|
|
46
|
+
- :ConformanceTests: should mock all external HTTP calls.
|
|
47
|
+
```
|
|
@@ -0,0 +1,98 @@
|
|
|
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
|
+
---
|
|
8
|
+
|
|
9
|
+
# Add Acceptance Test
|
|
10
|
+
|
|
11
|
+
Always use the skill `load-plain-reference` to retrieve the ***plain syntax rules — but only if you haven't done so yet.
|
|
12
|
+
|
|
13
|
+
## Workflow
|
|
14
|
+
|
|
15
|
+
1. **Identify the target `.plain` file and the functional spec** to attach the acceptance test to. If ambiguous, ask the user.
|
|
16
|
+
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).
|
|
17
|
+
3. **Draft the acceptance test(s)** following the rules below.
|
|
18
|
+
4. **Nest them** under the target functional spec using a `***acceptance tests***` subsection.
|
|
19
|
+
5. **Read the file again** to confirm correct placement, indentation, and syntax.
|
|
20
|
+
|
|
21
|
+
## When to Add Acceptance Tests
|
|
22
|
+
|
|
23
|
+
- The functional spec's correct behavior is **non-obvious** or easily misinterpreted.
|
|
24
|
+
- The spec involves **edge cases**, boundary conditions, or specific numeric outcomes.
|
|
25
|
+
- The user explicitly requests verification criteria.
|
|
26
|
+
- The spec was added via the `add-functional-spec` skill and warrants testable success criteria.
|
|
27
|
+
|
|
28
|
+
## Format
|
|
29
|
+
|
|
30
|
+
Acceptance tests are nested under the functional spec they verify, using a `***acceptance tests***` subsection:
|
|
31
|
+
|
|
32
|
+
```plain
|
|
33
|
+
***functional specs***
|
|
34
|
+
|
|
35
|
+
- The system should process :Task: items in batches of 100.
|
|
36
|
+
|
|
37
|
+
***acceptance tests***
|
|
38
|
+
- Processing 250 :Task: items should result in 3 batches.
|
|
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
|
+
## Rules
|
|
48
|
+
|
|
49
|
+
### Conformance with the Functional Spec
|
|
50
|
+
|
|
51
|
+
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.
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
Functional spec:
|
|
55
|
+
- The system should return :Resource: items sorted by creation date in descending order.
|
|
56
|
+
|
|
57
|
+
Good (consistent):
|
|
58
|
+
- The first :Resource: in the response should have the most recent creation date.
|
|
59
|
+
|
|
60
|
+
Bad (contradicts the spec — the spec says descending, not ascending):
|
|
61
|
+
- The first :Resource: in the response should have the oldest creation date.
|
|
62
|
+
|
|
63
|
+
Bad (extends beyond the spec — the spec says nothing about limiting results):
|
|
64
|
+
- The response should contain at most 50 :Resource: items.
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Scope
|
|
68
|
+
|
|
69
|
+
Each acceptance test verifies a specific, observable aspect of the functional spec it's nested under. Do not test behavior from other functional specs.
|
|
70
|
+
|
|
71
|
+
### Testability
|
|
72
|
+
|
|
73
|
+
Every acceptance test must describe a concrete, verifiable outcome — not a vague quality. The test should be implementable as an automated conformance test.
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
Good: - The response should contain exactly 3 items.
|
|
77
|
+
Bad: - The response should be correct.
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Language Agnosticism
|
|
81
|
+
|
|
82
|
+
Like functional specs, acceptance tests must be written in terms of behavior and outcomes — not language-specific constructs.
|
|
83
|
+
|
|
84
|
+
### Relationship to Test Reqs
|
|
85
|
+
|
|
86
|
+
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.
|
|
87
|
+
|
|
88
|
+
## Validation Checklist
|
|
89
|
+
|
|
90
|
+
- [ ] Every assertion is a direct logical consequence of the parent functional spec
|
|
91
|
+
- [ ] No assertion contradicts, narrows, or extends beyond the parent spec
|
|
92
|
+
- [ ] Acceptance test illustrates the spec via example, not introducing substantial new behavior
|
|
93
|
+
- [ ] Nested under the correct functional spec
|
|
94
|
+
- [ ] Indentation is correct (`***acceptance tests***` indented under the spec)
|
|
95
|
+
- [ ] Each test describes a concrete, verifiable outcome
|
|
96
|
+
- [ ] Tests are scoped to the parent functional spec only
|
|
97
|
+
- [ ] Written in language-agnostic terms
|
|
98
|
+
- [ ] No duplication with existing acceptance tests on the same spec
|
|
@@ -0,0 +1,67 @@
|
|
|
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
|
+
---
|
|
8
|
+
|
|
9
|
+
# Add Concept
|
|
10
|
+
|
|
11
|
+
Always use the skill `load-plain-reference` to retrieve the ***plain syntax rules — but only if you haven't done so yet.
|
|
12
|
+
|
|
13
|
+
## Workflow
|
|
14
|
+
|
|
15
|
+
1. **Identify the target `.plain` file.** If ambiguous, ask the user.
|
|
16
|
+
2. **Read the file** to understand existing definitions, imports, and concepts.
|
|
17
|
+
3. **Validate the concept name** against the syntax rules below.
|
|
18
|
+
4. **Check for uniqueness** — the concept name must not already exist in the file or its imports.
|
|
19
|
+
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).
|
|
20
|
+
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:
|
|
21
|
+
```plain
|
|
22
|
+
- :Order: is placed by :Customer: and contains :OrderItem: entries.
|
|
23
|
+
- :Customer: is a user who has placed at least one :Order:.
|
|
24
|
+
```
|
|
25
|
+
Fix by removing the back-reference:
|
|
26
|
+
```plain
|
|
27
|
+
- :Customer: is a user of the system.
|
|
28
|
+
- :Order: is placed by :Customer: and contains :OrderItem: entries.
|
|
29
|
+
```
|
|
30
|
+
7. **Insert the concept** into the `***definitions***` section, after any concepts it references.
|
|
31
|
+
8. **Read the file again** to confirm correct placement and syntax.
|
|
32
|
+
|
|
33
|
+
## Concept Syntax Rules
|
|
34
|
+
|
|
35
|
+
- Wrapped in colons: `:ConceptName:`
|
|
36
|
+
- CamelCase, starting with an uppercase letter
|
|
37
|
+
- Valid characters: letters, digits, `+`, `-`, `.`, `_`
|
|
38
|
+
- Must be globally unique across the spec and all its imports
|
|
39
|
+
- Exported concepts from `requires` modules are **not transitive** — if a concept needs to be shared across multiple `requires` modules, define it in a common import module instead
|
|
40
|
+
|
|
41
|
+
## Definition Format
|
|
42
|
+
|
|
43
|
+
A concept definition is a bullet in `***definitions***` that starts with the concept name:
|
|
44
|
+
|
|
45
|
+
```plain
|
|
46
|
+
***definitions***
|
|
47
|
+
- :ConceptName: is a description of what it represents.
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Attributes and constraints are nested sub-bullets:
|
|
51
|
+
|
|
52
|
+
```plain
|
|
53
|
+
- :Task: describes an activity that needs to be done by :User:. :Task: has:
|
|
54
|
+
- Name - a short description (required)
|
|
55
|
+
- Notes - additional details (optional)
|
|
56
|
+
- Due Date - completion deadline (optional)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Validation Checklist
|
|
60
|
+
|
|
61
|
+
- [ ] Name uses `:CamelCase:` notation
|
|
62
|
+
- [ ] Name is globally unique (not defined elsewhere in the file or imports)
|
|
63
|
+
- [ ] Definition starts with the concept name
|
|
64
|
+
- [ ] All referenced concepts (`:OtherConcept:`) are already defined above
|
|
65
|
+
- [ ] No circular references between concepts
|
|
66
|
+
- [ ] Description is clear, concise, and language-agnostic
|
|
67
|
+
- [ ] Placed inside a `***definitions***` section
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: add-feature
|
|
3
|
+
description: >-
|
|
4
|
+
End-to-end feature addition: takes a feature request in plain English and
|
|
5
|
+
incrementally writes ***plain specs (concepts, implementation reqs, functional
|
|
6
|
+
specs, acceptance tests) one functionality at a time, asking, authoring, and reviewing
|
|
7
|
+
per functionality. Use when the user wants to add a new feature to an existing project.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Add Feature
|
|
11
|
+
|
|
12
|
+
Always use the skill `load-plain-reference` to retrieve the ***plain syntax rules — but only if you haven't done so yet.
|
|
13
|
+
|
|
14
|
+
This skill is the continuous-loop counterpart of the full QA workflow in `forge-plain`. Where that workflow bootstraps an entire project from scratch, `add-feature` adds a single feature to an **existing** set of `.plain` specs.
|
|
15
|
+
|
|
16
|
+
## Core principle: one question → one answer → write specs
|
|
17
|
+
|
|
18
|
+
This skill runs as a tight, granular loop. **Each iteration is a single question to the user, followed by an immediate write to a `.plain` file.** No multi-question batches, no upfront interview, no "I'll gather a few things and then author." The cycle is:
|
|
19
|
+
|
|
20
|
+
1. Ask **one** focused question.
|
|
21
|
+
2. User answers.
|
|
22
|
+
3. **Immediately** write the resulting spec snippet to disk — even if you suspect it's incomplete or partly wrong.
|
|
23
|
+
4. Ask the next question, which often refines, extends, or corrects what you just wrote.
|
|
24
|
+
|
|
25
|
+
Writing eagerly is the point. A spec that's mostly right and gets corrected two questions later is better than a spec that waits for "enough" context before being written. The user can read what's on disk after every step and see exactly where things stand. Wrong-on-first-attempt specs are expected and welcome — you'll fix them in place on the next iteration. The questions themselves should be **shaped to produce immediately writable content**: a single attribute, a single behavior, a single edge case, a single constraint — not open-ended design questions that can't be turned into a snippet.
|
|
26
|
+
|
|
27
|
+
**One question at a time — but dig as deep as the topic needs.** "One question per iteration" is a rule about the AskUserQuestion call, not about the topic. If the user's answer is vague, ambiguous, or leaves real choices open, your **next** question should drill into that same topic — same loop, just another iteration. Keep drilling until the topic is concrete enough to produce a writable snippet. Only then move on to the next topic. Stopping too early and writing on top of a vague answer is worse than asking one more focused follow-up on the same thing.
|
|
28
|
+
|
|
29
|
+
## Input
|
|
30
|
+
|
|
31
|
+
A feature request from the user — anything from a one-liner ("add dark mode") to a detailed description. The request may be vague; the functionality loop in Phase 2 will sharpen it as you go.
|
|
32
|
+
|
|
33
|
+
## Phase 1 — Scope
|
|
34
|
+
|
|
35
|
+
Keep this phase short. The goal is to know enough to ask the **very first** writable question — not to design the entire feature on paper.
|
|
36
|
+
|
|
37
|
+
1. **Read the request.** Identify what is being asked for at a high level and which existing `.plain` file(s) the feature most likely belongs to.
|
|
38
|
+
2. **Read the target `.plain` file(s).** Follow their `import` and `requires` chains so you understand the existing definitions, implementation reqs, functional specs, test reqs, and acceptance tests. You need this context to recognize impact when it surfaces in Phase 2.
|
|
39
|
+
3. **Pick the target module** with one question — only if it's actually ambiguous which file to modify. Otherwise skip this and start authoring immediately.
|
|
40
|
+
|
|
41
|
+
End Phase 1 the moment you can name the file you'll write into and a single concrete starter question. Do **not** ask framing questions, scope questions, or multi-part design questions here.
|
|
42
|
+
|
|
43
|
+
## Phase 2 — One-question loop
|
|
44
|
+
|
|
45
|
+
This phase is a single, repeating cycle. Each iteration is **exactly one question** to the user followed by **an immediate write** to a `.plain` file. The loop ends when the user says the feature is fully covered.
|
|
46
|
+
|
|
47
|
+
### 2a. Ask one question
|
|
48
|
+
|
|
49
|
+
Use **AskUserQuestion** with **one** question per call. The question must be **writable**: phrase it so that any plausible answer maps directly to a concrete spec snippet you can insert. Bad shape: "How should the feature behave?" Good shape: "When the user submits an empty title, should the request be rejected with HTTP 400, accepted with a default title, or something else?"
|
|
50
|
+
|
|
51
|
+
Each question targets exactly one of:
|
|
52
|
+
|
|
53
|
+
- **Behavior** — a single trigger and its outcome.
|
|
54
|
+
- **A concept** — does this introduce a new concept, or extend an existing one? Which single attribute?
|
|
55
|
+
- **A single edge case** — one invalid input, empty state, boundary value.
|
|
56
|
+
- **A single constraint** — one business rule, permission, ordering, or size limit.
|
|
57
|
+
- **Implementation guidance** — only when the functionality requires technology / library / pattern not already in the file or its imports.
|
|
58
|
+
- **Verification** — only when the *Conformance gate* below is satisfied: one concrete outcome that proves this functionality works.
|
|
59
|
+
|
|
60
|
+
Always offer concrete options when the answer space is predictable, plus a free-form catch-all. Never bundle a second question into the prompt; never ask a question whose answer doesn't translate into a writable snippet on its own.
|
|
61
|
+
|
|
62
|
+
### 2b. Write immediately
|
|
63
|
+
|
|
64
|
+
The moment the user answers, write the resulting snippet to disk. Do **not** wait for additional context. Do **not** batch with the next question's output. Eager writes are the point — they may be wrong on the first try and that's expected. The next question will let the user correct them.
|
|
65
|
+
|
|
66
|
+
- **New concept** → use `add-concept` to add to `***definitions***`. Define before any reference.
|
|
67
|
+
- **New functional spec** → use `add-functional-spec`. That skill runs `analyze-if-func-spec-too-complex` and `analyze-func-specs` for you; let it. **Never hand-author functional specs.** If the skill reports the spec is too complex, ask the user a follow-up question to split it (the next iteration of the loop) — don't break it down on your own.
|
|
68
|
+
- **New implementation req** → use `add-implementation-requirement`. Only when the answer introduces technology / library / data format / architectural pattern not already present.
|
|
69
|
+
- **New acceptance test** → use `add-acceptance-test` under the relevant functional spec. Only when the *Conformance gate* is satisfied and the answer describes a concrete verification.
|
|
70
|
+
- **New test req** → use `add-test-requirement`. Only when conformance testing is configured and this answer changes how conformance tests are run.
|
|
71
|
+
|
|
72
|
+
If the user's answer **contradicts or refines** something you wrote in a previous iteration, fix the existing snippet in place right now — edit the spec, the concept, or the requirement directly. This is the explicit "correct on the next pass" behavior. Surface the change in the next question if it's non-trivial.
|
|
73
|
+
|
|
74
|
+
### 2c. Handle conflicts just-in-time
|
|
75
|
+
|
|
76
|
+
If `add-functional-spec` (via the analyzers it calls) reports a conflict with an existing spec, or if the snippet you just wrote would **break** (contradict, invalidate) or **augment** (change the meaning of, add behavior to) an existing concept / functional spec / implementation req / test req / acceptance test, your **next question** to the user must be about that conflict.
|
|
77
|
+
|
|
78
|
+
Show the exact existing snippet in the question and offer:
|
|
79
|
+
|
|
80
|
+
- **(a) keep** the existing spec — back out or narrow what you just wrote,
|
|
81
|
+
- **(b) augment** the existing spec — embed the proposed new wording in the question,
|
|
82
|
+
- **(c) replace** the existing spec.
|
|
83
|
+
|
|
84
|
+
Apply the user's choice the instant they answer. If they augmented a concept, walk every spec that references it and update each in place; limit changes to the approved scope. Never silently rewrite prior intent.
|
|
85
|
+
|
|
86
|
+
### 2d. Decide what's next
|
|
87
|
+
|
|
88
|
+
Ask the user whether the feature is fully covered. If yes, go to Phase 3. If no, return to 2a with the next single question — which often refines what you just wrote, or starts the next behavior, concept, edge case, or constraint.
|
|
89
|
+
|
|
90
|
+
### Conformance gate
|
|
91
|
+
|
|
92
|
+
Steps 2a–2d above only generate `***test reqs***` and `***acceptance tests***` when the project has a `config.yaml` with a valid `conformance-tests-script` entry pointing at an existing conformance-test script in `test_scripts/`. Check the relevant `config.yaml` (the one that covers this module — there may be more than one in multi-part projects) and confirm the referenced script file exists. If conformance testing is not configured, skip those authoring paths entirely; functional specs, concepts, and implementation reqs still get authored normally.
|
|
93
|
+
|
|
94
|
+
## Phase 3 — Final review
|
|
95
|
+
|
|
96
|
+
Most checks have already happened in the one-question loop. Phase 3 is a slim consistency pass, and its **final automated step is always `plain-healthcheck`**.
|
|
97
|
+
|
|
98
|
+
1. Read the modified `.plain` file(s) in full.
|
|
99
|
+
2. Verify:
|
|
100
|
+
- All new concepts are defined before use and have no circular references.
|
|
101
|
+
- Chronological ordering is correct end-to-end (no new spec depends on something that comes after it).
|
|
102
|
+
- Functional specs are language-agnostic.
|
|
103
|
+
- All external interfaces are explicit (endpoint paths, methods, CLI args, formats, etc.).
|
|
104
|
+
- Acceptance tests (if any) are consistent with their parent specs.
|
|
105
|
+
3. Present the final diff for the modified file(s) to the user for approval.
|
|
106
|
+
4. If the user requests changes, drop **straight back into the one-question loop** to fix them — one question, one write, one fix at a time. Do not restart the whole loop from scratch.
|
|
107
|
+
5. **Final automated step — run `plain-healthcheck`.** This is the last thing the skill does before handing control back to the user. After the user approves the final diff, invoke the `plain-healthcheck` skill. It validates every `config.yaml` and dry-runs every top module, so a feature is never considered finished while the project would fail to render. If `plain-healthcheck` returns `FAIL`, work through the numbered list it produced (fix only `.plain` files / `config.yaml` / scripts — never generated code) by dropping back into the one-question loop, and then re-run `plain-healthcheck`. Repeat until it returns `PASS`. The skill is not done until `plain-healthcheck` has returned `PASS` — only then tell the user the feature is ready and remind them to re-render with `codeplain <module>.plain`.
|
|
108
|
+
|
|
109
|
+
## When the User Comes Back with Another Feature
|
|
110
|
+
|
|
111
|
+
After completing one feature, the user may immediately describe the next. Start again from Phase 1. This creates a continuous loop: **scope → functionality loop → final review → scope → ...**
|
|
112
|
+
|
|
113
|
+
## Validation Checklist
|
|
114
|
+
|
|
115
|
+
- [ ] Target `.plain` file(s) and their `import`/`requires` chain were read before authoring
|
|
116
|
+
- [ ] Every iteration asked exactly one question and wrote to disk immediately after the answer
|
|
117
|
+
- [ ] Every functional spec was authored via `add-functional-spec` (never hand-written)
|
|
118
|
+
- [ ] New concepts defined before they are referenced
|
|
119
|
+
- [ ] No circular concept references
|
|
120
|
+
- [ ] Every conflict / break / augment surfaced by the analyzers was put to the user as the next question and resolved before continuing
|
|
121
|
+
- [ ] Functional specs are language-agnostic
|
|
122
|
+
- [ ] All external interfaces are explicit (endpoint paths, methods, CLI args, formats, etc.)
|
|
123
|
+
- [ ] Acceptance tests are consistent with their parent functional specs
|
|
124
|
+
- [ ] User approved the final diff
|
|
125
|
+
- [ ] `plain-healthcheck` returned `PASS` after the final diff was approved
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
## Question style
|
|
129
|
+
|
|
130
|
+
The questions you put to the user must use simple grammatical structures:
|
|
131
|
+
|
|
132
|
+
- Prefer short, direct sentences over compound or nested clauses.
|
|
133
|
+
- Use plain words over jargon when both convey the same meaning.
|
|
134
|
+
- One idea per sentence. If a sentence needs a comma-separated list of clauses, split it.
|
|
135
|
+
|
|
136
|
+
Simpler grammar must not come at the cost of detail. Keep every constraint, edge case, option, and piece of context the user needs to answer accurately. If simplifying a sentence would drop a detail, split it into more sentences instead.
|
|
@@ -0,0 +1,81 @@
|
|
|
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. forge-plain, add-feature) 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
|
+
---
|
|
13
|
+
|
|
14
|
+
# Add Functional Spec
|
|
15
|
+
|
|
16
|
+
Always use the skill `load-plain-reference` to retrieve the ***plain syntax rules — but only if you haven't done so yet.
|
|
17
|
+
|
|
18
|
+
## Workflow
|
|
19
|
+
|
|
20
|
+
1. **Identify the target `.plain` file.** If ambiguous, ask the user.
|
|
21
|
+
2. **Read the entire file** to understand existing definitions, implementation reqs, and all current functional specs (including those in `requires` modules).
|
|
22
|
+
3. **Draft the functional spec** following the rules below.
|
|
23
|
+
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.
|
|
24
|
+
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`.
|
|
25
|
+
6. **Append the spec** to the end of the `***functional specs***` section (specs are chronological; new ones go last).
|
|
26
|
+
7. **Read the file again** to confirm correct placement and syntax.
|
|
27
|
+
|
|
28
|
+
## Rules
|
|
29
|
+
|
|
30
|
+
### Complexity Limit
|
|
31
|
+
|
|
32
|
+
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.
|
|
33
|
+
|
|
34
|
+
### Chronological Ordering
|
|
35
|
+
|
|
36
|
+
Specs are rendered incrementally, top to bottom. The renderer has **no knowledge of future specs** — only previously rendered specs are in context. This means:
|
|
37
|
+
- A new spec can reference behavior defined by earlier specs.
|
|
38
|
+
- A new spec **cannot** assume anything about specs that come after it.
|
|
39
|
+
- Place the new spec at the correct position if it must come before a future spec; otherwise append at the end.
|
|
40
|
+
|
|
41
|
+
### Language Agnosticism
|
|
42
|
+
|
|
43
|
+
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***`.
|
|
44
|
+
|
|
45
|
+
### No Conflicts
|
|
46
|
+
|
|
47
|
+
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.
|
|
48
|
+
|
|
49
|
+
### Disambiguation
|
|
50
|
+
|
|
51
|
+
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.
|
|
52
|
+
|
|
53
|
+
```plain
|
|
54
|
+
- :User: should be able to send a :Message: to a :Conversation:.
|
|
55
|
+
- A :Message: must have non-empty content.
|
|
56
|
+
- The :Message: is appended to the end of the :Conversation:.
|
|
57
|
+
- All :Participant: members of the :Conversation: can see the new :Message:.
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Deterministic Interface
|
|
61
|
+
|
|
62
|
+
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.
|
|
63
|
+
|
|
64
|
+
### Encapsulation
|
|
65
|
+
|
|
66
|
+
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.
|
|
67
|
+
|
|
68
|
+
## Acceptance Tests
|
|
69
|
+
|
|
70
|
+
If the functional spec needs verification, use the `add-acceptance-test` skill to add acceptance tests after inserting the spec.
|
|
71
|
+
|
|
72
|
+
## Validation Checklist
|
|
73
|
+
|
|
74
|
+
- [ ] Spec implies ≤ 200 lines of code changes
|
|
75
|
+
- [ ] No conflict with any existing functional spec
|
|
76
|
+
- [ ] Written in language-agnostic terms (no language/framework specifics)
|
|
77
|
+
- [ ] All external interfaces are explicit (endpoint paths, methods, CLI args, formats, etc.)
|
|
78
|
+
- [ ] All referenced `:Concepts:` are defined in `***definitions***`
|
|
79
|
+
- [ ] Sentences are short, clear, and unambiguous
|
|
80
|
+
- [ ] No redundancy with existing specs
|
|
81
|
+
- [ ] Placed in correct chronological position (usually at the end)
|