plain-forge 1.0.18 → 1.0.20

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 (50) hide show
  1. package/README.md +17 -10
  2. package/bin/cli.mjs +53 -24
  3. package/forge/rules/bullet-continuation.md +59 -0
  4. package/forge/rules/definitions.md +15 -0
  5. package/forge/rules/func-specs.md +52 -7
  6. package/forge/rules/impl-reqs.md +1 -1
  7. package/forge/rules/integration-embedded-testing.md +7 -4
  8. package/forge/rules/integration-embedded.md +4 -1
  9. package/forge/rules/linked-resources.md +7 -6
  10. package/forge/rules/requires-modules.md +1 -1
  11. package/forge/rules/test-reqs.md +1 -1
  12. package/forge/skills/add-acceptance-test/SKILL.md +3 -25
  13. package/forge/skills/add-concept/SKILL.md +3 -22
  14. package/forge/skills/add-feature/SKILL.md +71 -67
  15. package/forge/skills/add-feature/references/checklist.md +38 -0
  16. package/forge/skills/add-feature/references/phase-0-intent.md +29 -0
  17. package/forge/skills/add-functional-spec/SKILL.md +3 -23
  18. package/forge/skills/add-functional-specs/SKILL.md +3 -24
  19. package/forge/skills/add-implementation-requirement/SKILL.md +4 -23
  20. package/forge/skills/add-resource/SKILL.md +7 -8
  21. package/forge/skills/add-test-requirement/SKILL.md +4 -21
  22. package/forge/skills/analyze-2-func-specs/SKILL.md +10 -10
  23. package/forge/skills/analyze-func-specs/SKILL.md +10 -10
  24. package/forge/skills/analyze-if-func-spec-too-complex/SKILL.md +93 -31
  25. package/forge/skills/break-down-func-spec/SKILL.md +78 -29
  26. package/forge/skills/create-import-module/SKILL.md +7 -0
  27. package/forge/skills/create-requires-module/SKILL.md +3 -2
  28. package/forge/skills/debug-specs/SKILL.md +5 -5
  29. package/forge/skills/forge-plain/SKILL.md +80 -299
  30. package/forge/skills/forge-plain/references/checklist.md +66 -0
  31. package/forge/skills/forge-plain/references/phase-0-intent.md +29 -0
  32. package/forge/skills/forge-plain/references/phase-1-product.md +40 -0
  33. package/forge/skills/forge-plain/references/phase-2-tech.md +24 -0
  34. package/forge/skills/forge-plain/references/phase-3-testing.md +66 -0
  35. package/forge/skills/forge-plain/references/phase-4-validate-handoff.md +49 -0
  36. package/forge/skills/implement-conformance-testing-script/SKILL.md +2 -2
  37. package/forge/skills/implement-prepare-environment-script/SKILL.md +2 -2
  38. package/forge/skills/implement-unit-testing-script/SKILL.md +1 -1
  39. package/forge/skills/init-config-file/SKILL.md +4 -3
  40. package/forge/skills/init-plain-project/SKILL.md +4 -0
  41. package/forge/skills/init-plain-project/references/checklist.md +31 -0
  42. package/forge/skills/load-codeplain-reference/SKILL.md +188 -0
  43. package/forge/skills/load-plain-reference/SKILL.md +48 -678
  44. package/forge/skills/load-plain-reference/references/project-model.md +48 -0
  45. package/forge/skills/load-plain-reference/references/rendering-and-testing.md +57 -0
  46. package/forge/skills/plain-healthcheck/SKILL.md +3 -3
  47. package/forge/skills/resolve-spec-conflict/SKILL.md +13 -5
  48. package/forge/skills/run-codeplain/SKILL.md +15 -15
  49. package/package.json +2 -2
  50. package/forge/rules/line-length.md +0 -45
@@ -32,10 +32,11 @@ Acceptance tests are nested under the functional spec they verify, using a `***a
32
32
  ```plain
33
33
  ***functional specs***
34
34
 
35
- - The system should process :Task: items in batches of 100.
35
+ - :Task: items are processed in batches of 100.
36
36
 
37
37
  ***acceptance tests***
38
38
  - Processing 250 :Task: items should result in 3 batches.
39
+
39
40
  - Each batch should contain at most 100 items.
40
41
  ```
41
42
 
@@ -44,29 +45,6 @@ Key formatting rules:
44
45
  - Each test bullet is indented under the `***acceptance tests***` header.
45
46
  - Multiple acceptance tests can be listed under a single functional spec.
46
47
 
47
- ### Line syntax (hard rule)
48
-
49
- **Every line inside `***acceptance tests***` must be its own list item starting with `- `.** ***plain has no concept of bare continuation lines — indented prose without a leading `- ` is **invalid syntax** and the renderer will reject it.
50
-
51
- - Hard limit: 120 characters per line. If a sentence is too long, **split it at a natural clause boundary into nested `- ` bullets** — never wrap onto an unprefixed line.
52
- - Nested clarifications are also `- ` items, indented under the parent. The indentation alone is not enough; the leading `- ` is required.
53
-
54
- BAD — bare continuation lines (invalid ***plain syntax, will not render):
55
-
56
- ```plain
57
- ***acceptance tests***
58
- - Processing 250 :Task: items should result in 3 batches with the
59
- last batch containing the remaining 50 items.
60
- ```
61
-
62
- GOOD — every line starts with `- `:
63
-
64
- ```plain
65
- ***acceptance tests***
66
- - Processing 250 :Task: items should result in 3 batches.
67
- - The first two batches each contain 100 items.
68
- - The last batch contains the remaining 50 items.
69
- ```
70
48
 
71
49
  ## Rules
72
50
 
@@ -76,7 +54,7 @@ An acceptance test is essentially an **example that illustrates** the functional
76
54
 
77
55
  ```
78
56
  Functional spec:
79
- - The system should return :Resource: items sorted by creation date in descending order.
57
+ - :Resource: items are returned sorted by creation date in descending order.
80
58
 
81
59
  Good (consistent):
82
60
  - The first :Resource: in the response should have the most recent creation date.
@@ -44,40 +44,21 @@ A concept definition is a bullet in `***definitions***` that starts with the con
44
44
 
45
45
  ```plain
46
46
  ***definitions***
47
+
47
48
  - :ConceptName: is a description of what it represents.
48
49
  ```
49
50
 
50
51
  Attributes and constraints are nested sub-bullets:
51
52
 
52
53
  ```plain
54
+ ***definitions***
55
+
53
56
  - :Task: describes an activity that needs to be done by :User:. :Task: has:
54
57
  - Name - a short description (required)
55
58
  - Notes - additional details (optional)
56
59
  - Due Date - completion deadline (optional)
57
60
  ```
58
61
 
59
- ## Line syntax (hard rule)
60
-
61
- **Every line inside `***definitions***` must be its own list item starting with `- `.** ***plain has no concept of bare continuation lines — indented prose without a leading `- ` is **invalid syntax** and the renderer will reject it.
62
-
63
- - Hard limit: 120 characters per line. If a sentence is too long, **split it at a natural clause boundary into nested `- ` bullets** — never wrap onto an unprefixed line.
64
- - Nested attributes are also `- ` items, indented under the parent. The indentation alone is not enough; the leading `- ` is required.
65
-
66
- BAD — bare continuation lines (invalid ***plain syntax, will not render):
67
-
68
- ```plain
69
- - :Task: describes an activity that needs to be done by :User:.
70
- - Name is a short description that the user provides when creating
71
- the task and is shown in the task list.
72
- ```
73
-
74
- GOOD — every line starts with `- `:
75
-
76
- ```plain
77
- - :Task: describes an activity that needs to be done by :User:.
78
- - Name is a short description provided when creating the task.
79
- - The name is shown in the task list.
80
- ```
81
62
 
82
63
  ## Validation Checklist
83
64
 
@@ -1,136 +1,140 @@
1
1
  ---
2
2
  name: add-feature
3
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.
4
+ End-to-end feature addition on an existing ***plain project: runs a short feature-intent
5
+ interview, then takes the confirmed request and, one question at a time, incrementally writes
6
+ ***plain specs (concepts, implementation reqs, functional specs, test reqs,
7
+ acceptance tests) to disk — asking, authoring, and reviewing per
8
+ functionality — then closes with a plain-healthcheck gate. Use when the user
9
+ wants to add a feature to an existing project. Not for bootstrapping a new
10
+ project from scratch (use forge-plain) or for editing generated code (the
11
+ .plain specs are the source of truth).
8
12
  ---
9
13
 
10
14
  # Add Feature
11
15
 
12
16
  Always use the skill `load-plain-reference` to retrieve the ***plain syntax rules — but only if you haven't done so yet.
13
17
 
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.
18
+ `add-feature` is the continuous-loop counterpart of `forge-plain`. Where `forge-plain` bootstraps an entire project from scratch, `add-feature` adds a single feature to an **existing** set of `.plain` specs. It begins with a short intent phase, then runs the authoring loop scoped to one feature.
15
19
 
16
- ## Core principle: one question → one answer → write specs
20
+ ## Core loop: one question → one answer → write to disk
17
21
 
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:
22
+ This loop starts after Phase 0. Each iteration is a single question followed by an immediate write:
19
23
 
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
+ 1. **Ask** one focused question via `AskUserQuestion` — never bundle two. Shape it so any plausible answer maps directly to one writable snippet: a single behavior, concept, attribute, edge case, or constraint — not an open-ended design question. 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?" Offer concrete options plus a free-form catch-all whenever the answer space is predictable.
25
+ 2. **Author immediately** — the moment the user answers, write the snippet to disk (see *2b* for which skill to route to). Do not wait for "enough" context; eager writes are the point. A snippet that is wrong on the first try is expected — the next question corrects it, and the user can read exactly where things stand after every step.
26
+ 3. **Refine on the next question**, which often extends or corrects what was just written.
24
27
 
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.
28
+ **One question per call, but drill as deep as the topic needs.** "One question" governs the `AskUserQuestion` call, not the topic. If an answer is vague or leaves real choices open, the *next* question drills into the same topic — another iteration of the loop — until it is concrete enough to write. Stopping early and writing on top of a vague answer is worse than one more focused follow-up.
26
29
 
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.
30
+ **Fix contradictions in place.** If a later answer refines or contradicts a snippet already on disk, edit that snippet right now. Never leave stale intent on disk; surface a non-trivial change in the next question.
28
31
 
29
32
  ## Input
30
33
 
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.
34
+ A feature request from the user — anything from a one-liner ("add dark mode") to a detailed
35
+ description. Phase 0 turns it into a confirmed feature-intent brief; Phase 2 sharpens the behavior
36
+ as it is authored.
37
+
38
+ ## Phase 0 — Feature intent
39
+
40
+ Read `references/phase-0-intent.md`. Ask its five core questions one at a time, write nothing to
41
+ disk, summarize the answers as a feature-intent brief, and get explicit confirmation. Ask no more
42
+ than one focused clarification when an answer is too vague to summarize.
43
+
44
+ Carry the confirmed brief into every later phase. Before advancing, check the Phase 0 block in
45
+ `references/checklist.md` inline.
32
46
 
33
47
  ## Phase 1 — Scope
34
48
 
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.
49
+ Keep this short. The goal is to know enough to ask the **very first** writable question — not to design the whole feature on paper.
36
50
 
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.
51
+ 1. **Read the confirmed feature-intent brief.** Identify which existing `.plain` file(s) the feature most likely belongs to.
52
+ 2. **Read the target `.plain` file(s)**, following their `import` and `requires` chains, so the existing definitions, implementation reqs, functional specs, test reqs, and acceptance tests are in context. This is what lets Phase 2 recognize impact when it surfaces.
53
+ 3. **Pick the target module with one question — only if it is genuinely ambiguous** which file to modify. Otherwise skip it and start authoring immediately.
40
54
 
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.
55
+ End Phase 1 the moment the target file and a single concrete starter question are clear. Do **not** ask framing, scope, or multi-part design questions here.
42
56
 
43
57
  ## Phase 2 — One-question loop
44
58
 
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.
59
+ A single repeating cycle: exactly one question, then an immediate write. The loop ends when the user says the feature is fully covered.
46
60
 
47
61
  ### 2a. Ask one question
48
62
 
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:
63
+ Ask one writable question per `AskUserQuestion` call, targeting exactly one of:
52
64
 
53
65
  - **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.
66
+ - **A concept** — a new concept, or one single attribute of an existing one.
67
+ - **A single edge case** — one invalid input, empty state, or boundary value.
56
68
  - **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.
69
+ - **Implementation guidance** — only when the functionality needs technology / a library / a pattern not already in the file or its imports.
58
70
  - **Verification** — only when the *Conformance gate* below is satisfied: one concrete outcome that proves this functionality works.
59
71
 
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.
72
+ 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
73
 
62
74
  ### 2b. Write immediately
63
75
 
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.
76
+ Route each answer to the right edit skill — never hand-author a `***plain` section:
65
77
 
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.
78
+ - **New concept** → `add-concept` (into `***definitions***`; define before any reference).
79
+ - **New functional spec** → `add-functional-spec`. It runs `analyze-if-func-spec-too-complex` and `analyze-func-specs` for you — let it. **Never hand-author functional specs.** If it reports the spec is too complex, ask the user a follow-up question to split it (the next loop iteration) — do not break it down alone.
80
+ - **New implementation req** → `add-implementation-requirement`. Only when the answer introduces technology / a library / a data format / an architectural pattern not already present.
81
+ - **New acceptance test** → `add-acceptance-test`, under the relevant functional spec. Only when the *Conformance gate* is satisfied and the answer describes a concrete verification.
82
+ - **New test req** → `add-test-requirement`. Only when conformance testing is configured and the answer changes how conformance tests are run.
71
83
 
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.
84
+ If the answer contradicts or refines an earlier snippet, fix that snippet in place now (per *Fix contradictions in place* above).
73
85
 
74
86
  ### 2c. Handle conflicts just-in-time
75
87
 
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.
88
+ If `add-functional-spec` (via its analyzers) reports a conflict, or the snippet just written would **break** (contradict, invalidate) or **augment** (change the meaning of, add behavior to) an existing concept / functional spec / implementation req / test req / acceptance test, the **next question** must be about that conflict. Show the exact existing snippet in the question and offer:
77
89
 
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,
90
+ - **(a) keep** the existing spec — back out or narrow what was just written,
81
91
  - **(b) augment** the existing spec — embed the proposed new wording in the question,
82
92
  - **(c) replace** the existing spec.
83
93
 
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.
94
+ Apply the choice the instant the user answers. If they augmented a concept, walk every spec that references it and update each in place, limited to the approved scope. Never silently rewrite prior intent.
85
95
 
86
96
  ### 2d. Decide what's next
87
97
 
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.
98
+ Ask the user whether the feature is fully covered. Yes → Phase 3. No → return to 2a with the next single question.
89
99
 
90
100
  ### Conformance gate
91
101
 
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.
102
+ Author `***test reqs***` and `***acceptance tests***` **only** when the project has a `config.yaml` with a valid `conformance-tests-script` entry pointing at an existing script in `test_scripts/`. Check the `config.yaml` that covers this module (multi-part projects may have several) and confirm the referenced script exists. If conformance testing is not configured, skip those two authoring paths entirely — concepts, functional specs, and implementation reqs are still authored normally.
93
103
 
94
104
  ## Phase 3 — Final review
95
105
 
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`**.
106
+ Most checks already happened in the loop; this is a slim consistency pass whose final automated step is always `plain-healthcheck`.
97
107
 
98
108
  1. Read the modified `.plain` file(s) in full.
99
109
  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).
110
+ - Every new concept is defined before use, with no circular references.
111
+ - Chronological ordering is correct end-to-end — no spec depends on something that comes after it.
102
112
  - Functional specs are language-agnostic.
103
- - All external interfaces are explicit (endpoint paths, methods, CLI args, formats, etc.).
113
+ - Every external interface is explicit (endpoint paths, methods, CLI args, formats).
104
114
  - 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`.
115
+ 3. Present the final diff for the modified file(s) and get the user's approval.
116
+ 4. If the user requests changes, drop **straight back into the one-question loop** — one question, one write, one fix at a time. Do not restart the loop from scratch.
117
+ 5. **Run `plain-healthcheck`** — the last thing this skill does. It validates every `config.yaml` and dry-runs every top module, so a feature is never finished while the project would fail to render. If it returns `FAIL`, work through its numbered list (fixing only `.plain` files / `config.yaml` / scripts — never generated code) by dropping back into the loop, then re-run. Repeat until `PASS`. Only then tell the user the feature is ready and remind them to re-render with `codeplain <module>.plain`.
108
118
 
109
- ## When the User Comes Back with Another Feature
119
+ ## Next feature
110
120
 
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 → ...**
121
+ After one feature is done, the user may describe the next. Start again from Phase 0 — a continuous
122
+ loop: **intent → scope → one-question loop → final review → intent → …**
112
123
 
113
- ## Validation Checklist
124
+ ## Error handling
114
125
 
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
+ - **A user answer contradicts prior specs** → edit the affected snippet in place immediately; surface a non-trivial change in the next question.
127
+ - **`add-functional-spec` reports "too complex"** → ask the user a follow-up question to split the spec (next loop iteration); never split it alone.
128
+ - **A conflict / break / augment surfaces** → make it the next question (2c) and resolve it before continuing.
129
+ - **`plain-healthcheck` returns `FAIL`** → do not declare the feature done; fix the listed `.plain` / `config.yaml` / script items via the loop and re-run until `PASS`.
126
130
 
131
+ ## Validation checklist
127
132
 
128
- ## Question style
133
+ Run the loop block in `references/checklist.md` on each iteration, and walk the whole list during Phase 3 before declaring the feature done. It is a self-audit of this workflow — never a substitute for it. A box only counts as met when the spec is on disk and explicitly approved; complete any unmet step before finishing.
129
134
 
130
- The questions you put to the user must use simple grammatical structures:
135
+ ## Question style
131
136
 
132
137
  - Prefer short, direct sentences over compound or nested clauses.
133
138
  - 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.
139
+ - One idea per sentence; split a comma-chained list of clauses into separate sentences.
140
+ - Never drop detail to simplify — keep every constraint, edge case, and option the user needs, splitting into more sentences instead.
@@ -0,0 +1,38 @@
1
+ # Add Feature Workflow Checklist
2
+
3
+ Use this to verify the workflow was followed — never as a substitute for it. Run the loop block on each iteration, and run the whole list once more during Phase 3 before declaring the feature done. A box only counts as met when the spec is on disk and explicitly approved, not merely discussed. If a box is unmet, go back and complete the step.
4
+
5
+ ## Phase 0 — Feature intent
6
+
7
+ - [ ] Invoked `load-plain-reference` first (unless already loaded this session).
8
+ - [ ] Read `references/phase-0-intent.md` and asked its five core questions one at a time.
9
+ - [ ] Asked no more than one focused clarification for an answer too vague to summarize.
10
+ - [ ] Wrote no project or specification files during Phase 0.
11
+ - [ ] Kept concepts, spec wording, implementation technology, and tests for later phases.
12
+ - [ ] Summarized motivation, affected user, desired outcome, observable success criterion, and
13
+ boundary with explicit exclusions; got explicit confirmation.
14
+
15
+ ## Phase 1 — Scope
16
+
17
+ - [ ] Carried the confirmed feature-intent brief into scope and identified the likely target
18
+ `.plain` file(s) without restarting intent discovery.
19
+ - [ ] Read the target `.plain` file(s) and followed their `import`/`requires` chain before authoring.
20
+ - [ ] Picked the target module with a question only when genuinely ambiguous — otherwise started authoring immediately (no framing/scope/multi-part design questions here).
21
+
22
+ ## Every loop iteration (Phase 2)
23
+
24
+ - [ ] Asked exactly one focused question via `AskUserQuestion` — not two bundled together — targeting one writable snippet (behavior, one concept/attribute, one edge case, one constraint, implementation guidance, or verification).
25
+ - [ ] Wrote the snippet to disk immediately after the answer via the dedicated edit skill — never hand-authored a `***plain` section.
26
+ - [ ] Every functional spec was authored via `add-functional-spec` (never hand-written); if it reported "too complex", split it via a follow-up question rather than alone.
27
+ - [ ] New concepts defined before they are referenced, with no circular references.
28
+ - [ ] Any answer that contradicted an earlier snippet was fixed in place before the next question — no stale intent left on disk.
29
+ - [ ] Every conflict / break / augment surfaced by the analyzers was put to the user as the *next* question (keep / augment / replace) and resolved before continuing.
30
+ - [ ] `***test reqs***` / `***acceptance tests***` authored only when the Conformance gate holds (a `config.yaml` with a valid `conformance-tests-script` pointing at an existing script).
31
+ - [ ] Asked the user whether the feature is fully covered before leaving the loop.
32
+
33
+ ## Phase 3 — Final review
34
+
35
+ - [ ] Read the modified `.plain` file(s) in full.
36
+ - [ ] Verified: concepts defined before use, no cycles, chronological ordering correct end-to-end, functional specs language-agnostic, every external interface explicit (endpoints, methods, CLI args, formats), acceptance tests consistent with their parent specs.
37
+ - [ ] Presented the final diff and got the user's approval (change requests dropped back into the one-question loop, not a restart).
38
+ - [ ] Ran `plain-healthcheck`; worked its numbered list to `PASS` (fixing only `.plain`/`config.yaml`/scripts — never generated code) before declaring the feature ready and reminding the user to re-render with `codeplain <module>.plain`.
@@ -0,0 +1,29 @@
1
+ # Phase 0 — What is the feature intent?
2
+
3
+ Extract the intent of this feature before choosing files or authoring specifications. Ask exactly
4
+ five core questions, one at a time, and do not write to disk.
5
+
6
+ ## Questions
7
+
8
+ 1. **Motivation** — What problem or limitation should this feature address?
9
+ 2. **Affected user** — Who should benefit from or interact with this feature?
10
+ 3. **Desired outcome** — What should that user be able to accomplish after the feature exists?
11
+ 4. **Success criterion** — What observable result would prove the feature is useful and working?
12
+ 5. **Boundary** — What should this feature deliberately leave unchanged or out of scope?
13
+
14
+ Ask one focused follow-up only when an answer is too vague to summarize. Do not choose concepts,
15
+ spec wording, implementation technology, or tests yet.
16
+
17
+ ## Feature-intent brief
18
+
19
+ Summarize the answers in five short bullets:
20
+
21
+ - Motivation
22
+ - Affected user
23
+ - Desired outcome
24
+ - Observable success criterion
25
+ - Boundary and explicit exclusions
26
+
27
+ Ask the user to confirm or correct the brief. Phase 0 finishes only after explicit confirmation.
28
+ Carry the brief into Phase 1 so scope discovery maps the intent onto existing modules instead of
29
+ restarting the feature discussion.
@@ -51,34 +51,14 @@ The new spec must not contradict any existing functional spec. Conflicting specs
51
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
52
 
53
53
  ```plain
54
- - :User: should be able to send a :Message: to a :Conversation:.
54
+ ***functional specs***
55
+
56
+ - A :User: can send a :Message: to a :Conversation:.
55
57
  - A :Message: must have non-empty content.
56
58
  - The :Message: is appended to the end of the :Conversation:.
57
59
  - All :Participant: members of the :Conversation: can see the new :Message:.
58
60
  ```
59
61
 
60
- ### Line syntax (hard rule)
61
-
62
- **Every line inside `***functional specs***` must be its own list item starting with `- `.** ***plain has no concept of bare continuation lines — indented prose without a leading `- ` is **invalid syntax** and the renderer will reject it.
63
-
64
- - Hard limit: 120 characters per line. If a sentence is too long, **split it at a natural clause boundary into nested `- ` bullets** — never wrap onto an unprefixed line.
65
- - Nested clarifications are also `- ` items, indented under the parent. The indentation alone is not enough; the leading `- ` is required.
66
-
67
- BAD — bare continuation lines (invalid ***plain syntax, will not render):
68
-
69
- ```plain
70
- - :GatewayWebhook: should hand off :StripeRequest: to :StripeIntegration:.handle(),
71
- which returns a list of :EventEnvelope: dicts conforming to the gateway's
72
- contract.
73
- ```
74
-
75
- GOOD — every line starts with `- `:
76
-
77
- ```plain
78
- - :GatewayWebhook: should hand off :StripeRequest: to :StripeIntegration:.handle().
79
- - The method returns a list of :EventEnvelope: dicts.
80
- - The dicts must conform to the gateway's :EventEnvelope: contract.
81
- ```
82
62
 
83
63
  ### Deterministic Interface
84
64
 
@@ -74,35 +74,14 @@ That coverage is achieved by running `analyze-func-specs` **once per spec being
74
74
  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.
75
75
 
76
76
  ```plain
77
- - :User: should be able to send a :Message: to a :Conversation:.
77
+ ***functional specs***
78
+
79
+ - A :User: can send a :Message: to a :Conversation:.
78
80
  - A :Message: must have non-empty content.
79
81
  - The :Message: is appended to the end of the :Conversation:.
80
82
  - All :Participant: members of the :Conversation: can see the new :Message:.
81
83
  ```
82
84
 
83
- ### Line syntax (hard rule, per spec)
84
-
85
- **Every line inside `***functional specs***` must be its own list item starting with `- `.** ***plain has no concept of bare continuation lines — indented prose without a leading `- ` is **invalid syntax** and the renderer will reject the whole file.
86
-
87
- - Hard limit: 120 characters per line. If a sentence is too long, **split it at a natural clause boundary into nested `- ` bullets** — never wrap onto an unprefixed line.
88
- - Nested clarifications are also `- ` items, indented under the parent. The indentation alone is not enough; the leading `- ` is required.
89
- - This rule applies to **every** spec in the batch — one bad continuation line invalidates the entire insert.
90
-
91
- BAD — bare continuation lines (invalid ***plain syntax, will not render):
92
-
93
- ```plain
94
- - :GatewayWebhook: should hand off :StripeRequest: to :StripeIntegration:.handle(),
95
- which returns a list of :EventEnvelope: dicts conforming to the gateway's
96
- contract.
97
- ```
98
-
99
- GOOD — every line starts with `- `:
100
-
101
- ```plain
102
- - :GatewayWebhook: should hand off :StripeRequest: to :StripeIntegration:.handle().
103
- - The method returns a list of :EventEnvelope: dicts.
104
- - The dicts must conform to the gateway's :EventEnvelope: contract.
105
- ```
106
85
 
107
86
  ### Deterministic Interface
108
87
 
@@ -61,36 +61,17 @@ Implementation reqs are bullet points in the `***implementation reqs***` section
61
61
 
62
62
  ```plain
63
63
  ***implementation reqs***
64
- - :Implementation: should be in Python 3.12.
65
- - :Implementation: should use pip for dependency management.
66
- - When writing CSV files, :Implementation: should use streaming writes to avoid holding large datasets in memory.
67
- ```
68
-
69
- Reference defined `:Concepts:` where they add clarity. Implementation reqs in non-leaf sections apply to all subsections.
70
-
71
- ## Line syntax (hard rule)
72
64
 
73
- **Every line inside a section must be its own list item starting with `- `.** ***plain has no concept of bare continuation lines — indented prose without a leading `- ` is **invalid syntax** and the renderer will reject it.
65
+ - :Implementation: should be in Python 3.12.
74
66
 
75
- - Hard limit: 120 characters per line. If a sentence is too long, **split it at a natural clause boundary into nested `- ` bullets** — never wrap onto an unprefixed line.
76
- - Nested detail is also a `- ` item, indented under its parent. The indentation alone is not enough; the leading `- ` is required.
67
+ - :Implementation: should use pip for dependency management.
77
68
 
78
- BAD — bare continuation lines (invalid ***plain syntax, will not render):
69
+ - When writing CSV files, :Implementation: should use streaming writes to avoid holding large datasets in memory.
79
70
 
80
- ```plain
81
- - :Implementation: tech stack will be finalized in Phase 2.
82
- - Until then, treat this section as a placeholder so the renderer accepts
83
- the file. Phase 2 will replace this with language, framework, HTTP
84
- client, packaging, and architecture decisions.
85
71
  ```
86
72
 
87
- GOOD — every line starts with `- `:
73
+ Reference defined `:Concepts:` where they add clarity. Implementation reqs in non-leaf sections apply to all subsections.
88
74
 
89
- ```plain
90
- - :Implementation: tech stack will be finalized in Phase 2.
91
- - Until then, treat this section as a placeholder so the renderer accepts the file.
92
- - Phase 2 will replace it with language, framework, HTTP client, packaging, and architecture decisions.
93
- ```
94
75
 
95
76
  ## Encapsulation Warning
96
77
 
@@ -15,7 +15,7 @@ Linked resources are external files referenced from within a `.plain` spec using
15
15
 
16
16
  ## Workflow
17
17
 
18
- 1. **Identify or create the resource file.** It should be in the `resources/` directory or in the same folder (or a subfolder) as the `.plain` file.
18
+ 1. **Identify or create the resource file.** Keep it inside the project — the `resources/` directory is the conventional home; it does not have to sit next to the `.plain` file.
19
19
  2. **Add the markdown link** at the appropriate place in the spec.
20
20
  3. **Verify the file path** is relative to the `.plain` file location.
21
21
  4. **Read the file back** to confirm correct link syntax and path.
@@ -35,16 +35,15 @@ Use standard markdown link syntax inside any spec section:
35
35
 
36
36
  ***functional specs***
37
37
 
38
- - The system should expose an API conforming to the [API specification](resources/api_spec.yaml).
38
+ - An API conforming to the [API specification](resources/api_spec.yaml) is exposed.
39
39
  ```
40
40
 
41
41
  ## Path Rules
42
42
 
43
- - Paths are resolved **relative to the `.plain` file location**.
44
- - Only files in the same folder or subfolders are supported.
45
- - No absolute paths.
43
+ - Paths are resolved **relative to the directory where `codeplain` is run** (the current working directory).
44
+ - Relative paths may traverse into parent directories — `[resource](../../resources/resource.md)` is valid — as long as they resolve to a real text file on disk.
46
45
  - **No external URLs** — only local file references.
47
- - **No folder paths** — only local file references.
46
+ - **No folder paths** — the target must be a file, not a directory.
48
47
  - Only text-based files are supported.
49
48
 
50
49
  ### A linked resource MUST be a single, text-based file that exists on disk
@@ -70,7 +69,7 @@ The **only** exceptions are URLs and paths that are *values the produced softwar
70
69
 
71
70
  ### What a linked resource CAN be
72
71
 
73
- - A single file in the same folder as the `.plain` file, or in any subfolder of it (`resources/` is the conventional home).
72
+ - A single file inside the project, reachable by a path relative to where `codeplain` is run — parent-directory traversal (`../`) is allowed (`resources/` is the conventional home).
74
73
  - A **text-based** file the renderer can read end-to-end: JSON, YAML, XML, HTML, Markdown, plain text, CSV, TSV, source code in any language (`.py`, `.js`, `.ts`, `.go`, `.java`, `.rb`, `.rs`, `.kt`, `.swift`, `.c`, `.cpp`, `.cs`, …), shell scripts, SQL, JSON Schema, OpenAPI, AsyncAPI, Protobuf `.proto`, GraphQL SDL, `.jolt`, `.env.example`, `.toml`, `.ini`, `.proto`, `Dockerfile`, etc.
75
74
 
76
75
  ## Common Resource Types
@@ -102,6 +101,6 @@ The **only** exceptions are URLs and paths that are *values the produced softwar
102
101
  - [ ] **Target is a text-based file** (no binary extensions: `.png`, `.jpg`, `.jpeg`, `.gif`, `.bmp`, `.tiff`, `.webp`, `.ico`, `.pdf`, `.docx`, `.xlsx`, `.pptx`, `.zip`, `.tar`, `.gz`, `.mp3`, `.mp4`, `.wav`, `.exe`, `.so`, `.dylib`, `.class`, `.wasm`, …)
103
102
  - [ ] **No URLs or folder paths anywhere in the surrounding `.plain` content** (not as link targets, not in body prose), with the sole exception of URLs / paths that are runtime values the generated software itself uses
104
103
  - [ ] Path is relative to the `.plain` file, not absolute
105
- - [ ] File is in the same folder or a subfolder (no `../` references)
104
+ - [ ] Path resolves to a real text file on disk from where `codeplain` is run (`../` traversal is allowed)
106
105
  - [ ] Markdown link syntax is correct: `[display text](relative/path)`
107
106
  - [ ] Resource content is relevant and adds value beyond what the spec text says
@@ -51,35 +51,18 @@ Test reqs are bullet points in the `***test reqs***` section:
51
51
 
52
52
  ```plain
53
53
  ***test reqs***
54
+
54
55
  - :ConformanceTests: should be implemented using pytest framework.
56
+
55
57
  - :ConformanceTests: will be run using "pytest" command.
58
+
56
59
  - :ConformanceTests: must be implemented and executed - do not skip tests.
60
+
57
61
  - :ConformanceTests: should mock all external HTTP calls.
58
62
  ```
59
63
 
60
64
  Reference predefined concepts like `:ConformanceTests:` and any defined `:Concepts:` where they add clarity.
61
65
 
62
- ## Line syntax (hard rule)
63
-
64
- **Every line inside `***test reqs***` must be its own list item starting with `- `.** ***plain has no concept of bare continuation lines — indented prose without a leading `- ` is **invalid syntax** and the renderer will reject it.
65
-
66
- - Hard limit: 120 characters per line. If a sentence is too long, **split it at a natural clause boundary into nested `- ` bullets** — never wrap onto an unprefixed line.
67
- - Nested clarifications are also `- ` items, indented under the parent. The indentation alone is not enough; the leading `- ` is required.
68
-
69
- BAD — bare continuation lines (invalid ***plain syntax, will not render):
70
-
71
- ```plain
72
- - :ConformanceTests: must mock all external HTTP calls so that the
73
- test suite remains hermetic and does not depend on network access.
74
- ```
75
-
76
- GOOD — every line starts with `- `:
77
-
78
- ```plain
79
- - :ConformanceTests: must mock all external HTTP calls.
80
- - The test suite must remain hermetic.
81
- - Tests must not depend on network access.
82
- ```
83
66
 
84
67
  ## Validation Checklist
85
68