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.
Files changed (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +247 -0
  3. package/bin/cli.mjs +143 -0
  4. package/forge/docs/.gitkeep +0 -0
  5. package/forge/rules/definitions.md +57 -0
  6. package/forge/rules/exported-concepts.md +39 -0
  7. package/forge/rules/func-specs.md +72 -0
  8. package/forge/rules/impl-reqs.md +50 -0
  9. package/forge/rules/import-modules.md +51 -0
  10. package/forge/rules/required-concepts.md +45 -0
  11. package/forge/rules/requires-modules.md +59 -0
  12. package/forge/rules/test-reqs.md +47 -0
  13. package/forge/skills/add-acceptance-test/SKILL.md +98 -0
  14. package/forge/skills/add-concept/SKILL.md +67 -0
  15. package/forge/skills/add-feature/SKILL.md +136 -0
  16. package/forge/skills/add-functional-spec/SKILL.md +81 -0
  17. package/forge/skills/add-functional-specs/SKILL.md +115 -0
  18. package/forge/skills/add-implementation-requirement/SKILL.md +73 -0
  19. package/forge/skills/add-resource/SKILL.md +108 -0
  20. package/forge/skills/add-template/SKILL.md +65 -0
  21. package/forge/skills/add-test-requirement/SKILL.md +68 -0
  22. package/forge/skills/analyze-2-func-specs/SKILL.md +102 -0
  23. package/forge/skills/analyze-func-specs/SKILL.md +124 -0
  24. package/forge/skills/analyze-if-func-spec-too-complex/SKILL.md +152 -0
  25. package/forge/skills/break-down-func-spec/SKILL.md +156 -0
  26. package/forge/skills/check-plain-env/SKILL.md +288 -0
  27. package/forge/skills/consolidate-concepts/SKILL.md +193 -0
  28. package/forge/skills/create-import-module/SKILL.md +98 -0
  29. package/forge/skills/create-requires-module/SKILL.md +104 -0
  30. package/forge/skills/debug-specs/SKILL.md +189 -0
  31. package/forge/skills/forge-integration/SKILL.md +443 -0
  32. package/forge/skills/forge-plain/SKILL.md +333 -0
  33. package/forge/skills/implement-conformance-testing-script/SKILL.md +247 -0
  34. package/forge/skills/implement-conformance-testing-script/assets/run_conformance_tests_cypress.ps1 +324 -0
  35. package/forge/skills/implement-conformance-testing-script/assets/run_conformance_tests_golang.ps1 +100 -0
  36. package/forge/skills/implement-conformance-testing-script/assets/run_conformance_tests_java.sh +102 -0
  37. package/forge/skills/implement-conformance-testing-script/assets/run_conformance_tests_python.ps1 +92 -0
  38. package/forge/skills/implement-conformance-testing-script/assets/run_conformance_tests_python.sh +100 -0
  39. package/forge/skills/implement-prepare-environment-script/SKILL.md +242 -0
  40. package/forge/skills/implement-prepare-environment-script/assets/prepare_environment_java.sh +42 -0
  41. package/forge/skills/implement-prepare-environment-script/assets/prepare_environment_python.sh +81 -0
  42. package/forge/skills/implement-unit-testing-script/SKILL.md +133 -0
  43. package/forge/skills/implement-unit-testing-script/assets/run_unittests_flutter.ps1 +82 -0
  44. package/forge/skills/implement-unit-testing-script/assets/run_unittests_golang.ps1 +68 -0
  45. package/forge/skills/implement-unit-testing-script/assets/run_unittests_java.sh +45 -0
  46. package/forge/skills/implement-unit-testing-script/assets/run_unittests_python.ps1 +76 -0
  47. package/forge/skills/implement-unit-testing-script/assets/run_unittests_python.sh +90 -0
  48. package/forge/skills/implement-unit-testing-script/assets/run_unittests_react.ps1 +83 -0
  49. package/forge/skills/init-config-file/SKILL.md +261 -0
  50. package/forge/skills/init-plain-project/SKILL.md +124 -0
  51. package/forge/skills/load-plain-reference/SKILL.md +646 -0
  52. package/forge/skills/plain-healthcheck/SKILL.md +132 -0
  53. package/forge/skills/refactor-module/SKILL.md +197 -0
  54. package/forge/skills/resolve-spec-conflict/SKILL.md +88 -0
  55. package/forge/skills/run-codeplain/SKILL.md +540 -0
  56. 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)