plain-forge 1.0.22-next.e8a40fd → 1.0.22

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 (27) hide show
  1. package/README.md +17 -26
  2. package/bin/cli.mjs +7 -4
  3. package/bin/python-tools.mjs +139 -0
  4. package/forge/rules/integration-embedded-testing.md +1 -1
  5. package/forge/rules/linked-resources.md +5 -2
  6. package/forge/skills/add-feature/SKILL.md +2 -1
  7. package/forge/skills/add-feature/references/checklist.md +1 -1
  8. package/forge/skills/add-resource/SKILL.md +5 -3
  9. package/forge/skills/check-forge-version/SKILL.md +1 -1
  10. package/forge/skills/check-forge-version/scripts/check-forge-version.mjs +1 -1
  11. package/forge/skills/check-plain-env/SKILL.md +7 -8
  12. package/forge/skills/forge-plain/SKILL.md +3 -4
  13. package/forge/skills/forge-plain/references/checklist.md +2 -2
  14. package/forge/skills/forge-plain/references/phase-3-testing.md +1 -1
  15. package/forge/skills/forge-plain/references/phase-4-validate-handoff.md +13 -15
  16. package/forge/skills/implement-conformance-testing-script/SKILL.md +3 -3
  17. package/forge/skills/implement-prepare-environment-script/SKILL.md +3 -3
  18. package/forge/skills/implement-unit-testing-script/SKILL.md +3 -3
  19. package/forge/skills/init-config-file/SKILL.md +22 -134
  20. package/forge/skills/init-plain-project/SKILL.md +5 -5
  21. package/forge/skills/init-plain-project/references/checklist.md +2 -2
  22. package/forge/skills/load-plain-reference/SKILL.md +3 -4
  23. package/forge/skills/load-plain-reference/references/project-model.md +1 -1
  24. package/forge/skills/plain-healthcheck/SKILL.md +42 -33
  25. package/package.json +2 -2
  26. package/forge/skills/load-codeplain-reference/SKILL.md +0 -188
  27. package/forge/skills/run-codeplain/SKILL.md +0 -483
@@ -2,9 +2,9 @@
2
2
  name: plain-healthcheck
3
3
  description: >-
4
4
  Verification gate for a ***plain project. Verifies that every `config.yaml`
5
- exists, points at scripts that actually live in `test_scripts/`, and that
6
- `codeplain <top_module>.plain --dry-run` passes for every top module in
7
- the project. Run this whenever anything in the project is finalized —
5
+ exists and points at scripts that actually live in `test_scripts/`, parses
6
+ every top module with `plain-parser check`, and checks every module for what
7
+ the parser can't judge (section ownership, bullets, linked resources). Run this whenever anything in the project is finalized —
8
8
  including (but not limited to) the end of `forge-plain`, the end of
9
9
  `add-feature`, after `debug-specs`, after any single-skill edit that
10
10
  finalizes a concept, functional spec, requirement, template, or config —
@@ -13,13 +13,13 @@ description: >-
13
13
 
14
14
  # Plain Healthcheck
15
15
 
16
- Always use the skill `load-codeplain-reference` to retrieve the full `codeplain` CLI reference (every flag, path-resolution rules, `config.yaml` mapping, render banners, exit codes), and the skill `load-plain-reference` to retrieve the ***plain syntax rules — but only if you haven't done so yet. This skill runs `codeplain … --dry-run` and validates every `config.yaml`, so the CLI reference is required.
16
+ Always use the skill `load-plain-reference` to retrieve the ***plain syntax rules — but only if you haven't done so yet. Step 3b checks every module against those rules, and they are needed to fix what `plain-parser` reports in Step 3a.
17
17
 
18
18
  ## When to run
19
19
 
20
20
  Run this skill **whenever anything in the ***plain project is finalized** and the project is about to be left in a state the user (or another skill) might render from. That includes, but is not limited to:
21
21
 
22
- - **End of `forge-plain`** (Phase 4) — before presenting the render command.
22
+ - **End of `forge-plain`** (Phase 4) — before handing off the render target.
23
23
  - **End of `add-feature`** (Phase 3 final review) — before declaring the feature done.
24
24
  - **End of `debug-specs`** — after applying a fix, before telling the user to re-render.
25
25
  - **After finalizing any single edit** that changes the renderable surface — e.g. after `add-concept`, `add-functional-spec`, `add-functional-specs`, `add-implementation-requirement`, `add-test-requirement`, `add-acceptance-test`, `add-template`, `add-resource`, `resolve-spec-conflict`, `break-down-func-spec`, `consolidate-concepts`, `refactor-module`, `create-import-module`, `create-requires-module`, or any of the `implement-*-testing-script` skills.
@@ -28,7 +28,7 @@ Run this skill **whenever anything in the ***plain project is finalized** and th
28
28
 
29
29
  The healthcheck is **not** a forge-plain-only step. Treat it as the default closing move for any workflow that finalizes something in the project.
30
30
 
31
- Do **not** skip this skill because "the dry-run passed earlier" — `config.yaml`s, scripts, and specs can all drift between runs. The healthcheck is cheap; rendering against stale specs is expensive.
31
+ Do **not** skip this skill because "the healthcheck passed earlier" — `config.yaml`s, scripts, and specs can all drift between runs. The healthcheck is cheap; rendering against stale specs is expensive.
32
32
 
33
33
  ## Workflow
34
34
 
@@ -36,7 +36,7 @@ The skill is a **detect → fix → re-run** loop. It does not stop at the first
36
36
 
37
37
  ### Step 1 — Inventory the project
38
38
 
39
- 1. List every `.plain` file in the repo root (and any subdirectories that contain `.plain` files). Build the module graph from each file's YAML frontmatter (`requires`, `import`). Verify the `requires` graph forms a tree: every module's multiple `requires` entries must lie on one root-to-tip ancestor path.
39
+ 1. List every `.plain` file in the repo root (and any subdirectories that contain `.plain` files). Build the module graph from each file's YAML frontmatter (`requires`, `import`); Step 3a validates it.
40
40
  2. Identify **top modules** — every module that is not `requires`-ed by any other module. A single-stack project has one top module; a multi-part project (e.g. backend + frontend) has one top module per part.
41
41
  3. List every `config.yaml` in the repo (root and per-part directories such as `backend/`, `frontend/`).
42
42
  4. List every script under `test_scripts/`.
@@ -52,7 +52,7 @@ For each `config.yaml` in the inventory, check **all** of the following. Collect
52
52
  2. **At minimum `unittests-script` is present.** Every project gets a unit-test runner.
53
53
  3. **For every script field that is present** (`unittests-script`, `conformance-tests-script`, `prepare-environment-script`):
54
54
  - The path is a string ending in `.sh` (macOS/Linux) or `.ps1` (Windows). The extension must match the rest of the project — do not mix `.sh` and `.ps1` in a single config.
55
- - The referenced file actually exists on disk, resolved the way the renderer resolves it: absolute / `~` paths as-is, relative paths against the **config file's directory** (typically landing under `test_scripts/`). There is no other fallback — the renderer fails fast with a `FileNotFoundError` on a script path that doesn't resolve, so a path that only "works" from some other directory is a failure here.
55
+ - The referenced file actually exists on disk: absolute / `~` paths as-is, relative paths against the **config file's directory** (typically landing under `test_scripts/`). There is no other fallback, so a path that only "works" from some other directory is a failure here.
56
56
  - On Unix, the script has the executable bit set (`-x`). If not, that is a fixable failure.
57
57
  4. **No mixed stacks per config.** Every script referenced from a single `config.yaml` must target the same language/stack. For example, `backend/config.yaml` should not reference `run_unittests_js.sh`. If a config crosses stacks, that is a failure — the project should have been split into multiple configs per the applicable module rules loaded by `load-plain-reference`.
58
58
  5. **No dangling fields.** Any `*-script` field whose target file does not exist is a failure.
@@ -68,46 +68,54 @@ For each failure, record the offending config path, the offending field, and the
68
68
 
69
69
  Anything else (missing script, mixed stacks, missing `config.yaml`) must be surfaced to the user — do not silently regenerate scripts here. Re-invoking `implement-unit-testing-script`, `implement-conformance-testing-script`, or `implement-prepare-environment-script` from inside the healthcheck is allowed **only** if the user explicitly approves it after being shown the gap.
70
70
 
71
- ### Step 3 — Dry-run every top module
71
+ ### Step 3 — Validate every module
72
72
 
73
- For each `(top_module, config.yaml)` pair from Step 1, run a dry-run from the project root via the `terminal` tool:
73
+ Step 3 has two halves: a mechanical parse by `plain-parser`, then the checks that need judgement. Collect every failure from both — do **not** stop at the first.
74
74
 
75
- ```bash
76
- codeplain <top_module>.plain --dry-run
77
- ```
75
+ #### 3a. Parse every top module with `plain-parser`
78
76
 
79
- **Match the dry-run to how the user will actually render.** Pass the flags the user would pass for the real render so what you validate is what they will run:
77
+ [`plain-parser`](https://pypi.org/project/plain-parser/) is the ***plain parser. It parses a module together with its whole `import` / `requires` chain, so running it on every top module covers every module in the project.
80
78
 
81
- - **`--config-name <name>`** — required whenever the governing config file is not the default `config.yaml`, or when the project has multiple `config.yaml`s and the dry-run is being launched from somewhere that isn't the part's directory. `--config-name` takes a *file name*, not a path; if needed, `cd` into the part's directory before running so the right `config.yaml` is found.
82
- - **`--template-dir <path>`** — only when templates live outside `template/` **and** `template_dir` is not already set in the relevant config.
83
- - **`--full-plain`** — useful when an `import`/`requires` chain is suspect.
84
- - **`--verbose` / `-v`** — strongly recommended on a failed dry-run; the extra log output usually pinpoints the offending `.plain` file and spec.
79
+ 1. **Check it is installed.** Run `plain-parser --help`. If the command is not found, stop and report `FAIL` with the install command (`pipx install plain-parser` or `uv tool install plain-parser`; it needs Python 3.11 or newer). Do **not** fall back to checking these rules by reading the files — without the parser there is no syntax gate.
80
+ 2. **Run it from the top module's own directory**, once per top module:
85
81
 
86
- Treat the dry-run as a hard gate: the healthcheck **only passes** when every top module's dry-run exits successfully.
82
+ ```bash
83
+ cd <top-module-dir> && plain-parser check <top>.plain
84
+ ```
87
85
 
88
- #### When a dry-run fails
86
+ Add `--config-name <name>` when the governing config is not named `config.yaml`. `plain-parser` reads `template-dir` from the config next to the `.plain` file or in the working directory, and exits `2` when it finds one in both — running from the module's own directory avoids that in multi-part projects.
87
+ 3. **Read the result.** Exit `0` prints `<file>: OK`. Exit `1` prints `Error: …` on stderr — record that message verbatim as a failure against the top module. Exit `2` is a usage or config error (ambiguous or malformed config) — record it against the config.
89
88
 
90
- Iterate until it passes:
89
+ `plain-parser` checks, among other things: frontmatter, that every `import` / `requires` entry exists and the graph has no cycles, that `requires` modules have one fixed order, that imported modules have no functional specs, section headings (allowed, not duplicated, `***definitions***` first, `***acceptance tests***` nested under a functional spec), concepts (defined, exported and required correctly), that a module with functional specs has implementation reqs, and that every linked resource and template resolves to an existing, relative, non-`.plain` file. It does not always report every error in one run, so after fixing what it reported, run it again until it prints `OK`.
91
90
 
92
- 1. Read the error output. If the first run was not verbose, immediately re-run with `--verbose`. Identify the offending `.plain` file, the line (if reported), and the kind of issue: missing concept, syntax error, cyclic definition, complexity violation (`Functional spec too complex!`), conflicting reqs, missing template, broken `import`/`requires`, missing config field, etc.
93
- 2. Fix only the `.plain` files (or the relevant `config.yaml` / template) using the appropriate edit skill — `add-concept`, `add-functional-spec`, `add-functional-specs`, `add-implementation-requirement`, `resolve-spec-conflict`, `break-down-func-spec`, `consolidate-concepts`, or an inline edit. **Never** modify generated code under `plain_modules/<module>/code/` or `plain_modules/<module>/tests/`.
94
- 3. If you are uncertain about ***plain syntax for the failing construct, re-load `load-plain-reference` before fixing.
95
- 4. Re-run the same `codeplain <top_module>.plain --dry-run …` command with the same flags. Repeat until it exits successfully.
91
+ #### 3b. Check what the parser can't judge
96
92
 
97
- If the failure is something the healthcheck cannot reasonably fix on its own (e.g. the user has to choose between two contradictory specs and neither side was pre-approved, or a missing concept whose semantics aren't clear), **stop and surface it to the user** with the offending snippet and a concrete question. Do not invent behavior.
93
+ Check every `.plain` module against the rules loaded by `load-plain-reference`:
94
+
95
+ 1. **Section ownership.** No fact sits in a section that doesn't own it — `:UnitTests:` facts only in `***implementation reqs***`, `:ConformanceTests:` facts only in `***test reqs***`, technology only in `***implementation reqs***`.
96
+ 2. **Bullets.** Every line in every section is a valid `- ` list item or a correctly indented sub-bullet — no bare continuation lines.
97
+ 3. **Linked resources.** Every linked resource is a single **text** file (not a binary), and no URL or folder path appears in the surrounding spec text unless it is a runtime value the generated software itself uses.
98
+
99
+ Functional-spec complexity is checked when a spec is authored (`add-functional-spec(s)` → `analyze-if-func-spec-too-complex`). Re-run `analyze-if-func-spec-too-complex` here only for a spec that was hand-edited since it was authored.
98
100
 
99
- #### Environment failures
101
+ Treat 3a and 3b together as a hard gate: the healthcheck **only passes** when `plain-parser check` prints `OK` for every top module and every module passes every check in 3b.
100
102
 
101
- If `codeplain` is not on PATH, or `CODEPLAIN_API_KEY` is not set:
103
+ #### When a check fails
102
104
 
103
- - Do **not** pretend the dry-run passed.
104
- - Tell the user exactly what's missing and how to fix it (install the CLI, export the env var) and stop the healthcheck with a clearly-marked environment failure. This is the only kind of failure that may legitimately remain unresolved at the end of the skill.
105
+ Iterate until it passes:
106
+
107
+ 1. Identify the offending `.plain` file, the line, and the kind of issue: missing or duplicated concept, cyclic definition, broken `import`/`requires`, misplaced fact, bare continuation line, missing resource or template, etc.
108
+ 2. Fix only the `.plain` files (or the relevant `config.yaml` / template) using the appropriate edit skill — `add-concept`, `add-functional-spec`, `add-functional-specs`, `add-implementation-requirement`, `resolve-section-ownership`, `resolve-spec-conflict`, `break-down-func-spec`, `consolidate-concepts`, or an inline edit. **Never** modify generated code under `plain_modules/<module>/code/` or `plain_modules/<module>/tests/`.
109
+ 3. If you are uncertain about ***plain syntax for the failing construct, re-load `load-plain-reference` before fixing.
110
+ 4. Re-run the failed checks — for a `plain-parser` failure, re-run `plain-parser check`. Repeat until they pass.
111
+
112
+ If the failure is something the healthcheck cannot reasonably fix on its own (e.g. the user has to choose between two contradictory specs and neither side was pre-approved, or a missing concept whose semantics aren't clear), **stop and surface it to the user** with the offending snippet and a concrete question. Do not invent behavior.
105
113
 
106
114
  ### Step 4 — Report
107
115
 
108
116
  Emit one of:
109
117
 
110
- - **`PASS`** — followed by a short summary of what was checked: `N config.yaml(s) validated`, `M top module(s) dry-run`, `K scripts referenced`. The caller (`forge-plain`, `add-feature`, `debug-specs`) can then continue to its hand-off step.
118
+ - **`PASS`** — followed by a short summary of what was checked: `N config.yaml(s) validated`, `M module(s) checked (plain-parser OK for every top module)`, `K scripts referenced`. The caller (`forge-plain`, `add-feature`, `debug-specs`) can then continue to its hand-off step.
111
119
  - **`FAIL`** — followed by a numbered list of every unresolved problem. Each entry must include: the file (config / `.plain` / script) it applies to, the concrete issue, and what the user needs to decide if the healthcheck couldn't resolve it.
112
120
 
113
121
  The verdict goes on the first line so callers can pattern-match without parsing the whole report.
@@ -115,7 +123,7 @@ The verdict goes on the first line so callers can pattern-match without parsing
115
123
  ## What this skill does NOT do
116
124
 
117
125
  - It does **not** author new specs from scratch — use `forge-plain` / `add-feature` for that.
118
- - It does **not** run the real render — only `--dry-run`.
126
+ - It does **not** render anything.
119
127
  - It does **not** execute the testing scripts (`run_unittests`, `run_conformance_tests`, `prepare_environment`). It only verifies that the scripts are wired up correctly via `config.yaml`. The user runs the scripts themselves.
120
128
  - It does **not** silently regenerate config files or scripts. The most it does is `chmod +x` and (with user approval) re-invoke the relevant `implement-*-testing-script` skill.
121
129
 
@@ -128,5 +136,6 @@ The verdict goes on the first line so callers can pattern-match without parsing
128
136
  - [ ] No `config.yaml` mixes stacks (e.g. Python + JS scripts in the same file)
129
137
  - [ ] No `config.yaml` declares `prepare-environment-script` without also declaring `conformance-tests-script`
130
138
  - [ ] Every `test_scripts/*` file is referenced by some `config.yaml` (or surfaced as a warning)
131
- - [ ] `codeplain <top>.plain --dry-run` exits successfully for **every** top module, with the right `--config-name` for multi-part projects
139
+ - [ ] `plain-parser check` printed `OK` for every top module, run from that module's directory
140
+ - [ ] Every module passes every check in Step 3b (section ownership, bullets, linked resources)
132
141
  - [ ] Verdict (`PASS` / `FAIL`) is on the first line, with a numbered list of remaining problems if it failed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plain-forge",
3
- "version": "1.0.22-next.e8a40fd",
3
+ "version": "1.0.22",
4
4
  "description": "Conversational spec-writing tool for ***plain specification language",
5
5
  "type": "module",
6
6
  "engines": {
@@ -17,7 +17,6 @@
17
17
  "license": "MIT",
18
18
  "keywords": [
19
19
  "plain",
20
- "codeplain",
21
20
  "claude-code",
22
21
  "skills",
23
22
  "spec",
@@ -28,6 +27,7 @@
28
27
  },
29
28
  "files": [
30
29
  "bin/cli.mjs",
30
+ "bin/python-tools.mjs",
31
31
  "forge"
32
32
  ],
33
33
  "scripts": {
@@ -1,188 +0,0 @@
1
- ---
2
- name: load-codeplain-reference
3
- description: >-
4
- Loads the full `codeplain` CLI reference into context: the render command and
5
- its positional plain-file argument, every flag (render control, config,
6
- folders, test-script wiring, output copying, API, logging, headless mode),
7
- path-resolution rules, the CODEPLAIN_API_KEY environment variable, the
8
- config.yaml mapping, and the success/failure render banners. Use whenever
9
- running, configuring, resuming, or reasoning about a `codeplain` render or its
10
- config.yaml. Not for the ***plain language syntax itself (use
11
- load-plain-reference) or for supervising a live render (use run-codeplain).
12
- ---
13
-
14
- # CODEPLAIN_CLI_REFERENCE.md
15
-
16
- `codeplain` is the CLI that renders `***plain` specification files into production-ready code. It reads a `.plain` module (and everything it `import`s / `requires`), calls the codeplain API, and writes generated code under `plain_modules/<module>/code/` and conformance tests under `plain_modules/<module>/tests/`. The `.plain` specs are the source of truth; the generated code is a read-only artifact.
17
-
18
- This reference covers the CLI surface only. For the `***plain` language itself use `load-plain-reference`; to supervise a live render use `run-codeplain`; to assemble or validate `config.yaml` use `init-config-file` / `plain-healthcheck`.
19
-
20
- ## Usage
21
-
22
- ```text
23
- codeplain [options] filename
24
- ```
25
-
26
- ```text
27
- usage: codeplain [-h] [--verbose] [--base-folder BASE_FOLDER]
28
- [--build-folder BUILD_FOLDER]
29
- [--log-to-file | --no-log-to-file]
30
- [--log-file-name LOG_FILE_NAME] [--config-name CONFIG_NAME]
31
- [--render-range RENDER_RANGE | --render-from RENDER_FROM]
32
- [--force-render] [--unittests-script UNITTESTS_SCRIPT]
33
- [--conformance-tests-folder CONFORMANCE_TESTS_FOLDER]
34
- [--conformance-tests-script CONFORMANCE_TESTS_SCRIPT]
35
- [--prepare-environment-script PREPARE_ENVIRONMENT_SCRIPT]
36
- [--test-script-timeout TEST_SCRIPT_TIMEOUT] [--api [API]]
37
- [--api-key API_KEY] [--full-plain] [--dry-run]
38
- [--replay-with REPLAY_WITH] [--template-dir TEMPLATE_DIR]
39
- [--copy-build] [--build-dest BUILD_DEST]
40
- [--copy-conformance-tests]
41
- [--conformance-tests-dest CONFORMANCE_TESTS_DEST]
42
- [--render-machine-graph]
43
- [--logging-config-path LOGGING_CONFIG_PATH] [--headless]
44
- filename
45
- ```
46
-
47
- ## Positional argument
48
-
49
- - **`filename`** — path to the `.plain` file to render. The directory containing this file has the **highest precedence for template loading**, so custom templates placed there override the defaults (see `--template-dir`). Render the **top module** of the dependency chain — the module not `requires`-ed by any other; its `requires`/`import` graph is pulled in automatically.
50
-
51
- ## Path resolution (read this before setting any path flag)
52
-
53
- A path's meaning depends on **where it was written**:
54
-
55
- - Values given **on the command line** resolve against the **current working directory**.
56
- - Values read from **`config.yaml`** resolve against the **config file's directory**.
57
- - **Default** values resolve against the **directory containing the `.plain` file**.
58
- - **Absolute paths** (and paths starting with `~`) are used as-is.
59
-
60
- ## Options
61
-
62
- ### Render control
63
-
64
- - **`--dry-run`** — preview code generation without making any changes. This is the static-validation gate; `plain-healthcheck` runs `codeplain <top>.plain --dry-run` for every top module before a real render. **Per-invocation only — never store in `config.yaml`.**
65
- - **`--full-plain`** — full preview of the assembled `***plain` specification before code generation. Use to inspect the context of all `***plain` primitives that will be included to render the given module. **Per-invocation only — never in `config.yaml`.**
66
- - **`--render-range RENDER_RANGE`** — render a range of functionalities (e.g. `1`, or `2,3`). A comma separates the start and end IDs; the range is inclusive of both. A single ID renders only that one functionality. Mutually exclusive with `--render-from`. **Per-invocation only — never in `config.yaml`.**
67
- - **`--render-from RENDER_FROM`** — continue generation starting from this functionality ID (inclusive). The ID must match a functionality in the `.plain` file. This is how a run resumes after a spec fix — pass the **first functionality to re-render**. Mutually exclusive with `--render-range`. **Per-invocation only — never in `config.yaml`.**
68
- - **`--force-render`** — force a re-render of all required modules, invalidating cached module renders. Use only when a backward dependency genuinely changed; it costs more credits.
69
- - **`--replay-with REPLAY_WITH`** — replay a previous render. **Per-invocation only — never in `config.yaml`.**
70
-
71
- ### Configuration
72
-
73
- - **`--config-name CONFIG_NAME`** — name of the config file to look for. It is looked up in the `.plain` file's directory and in the current working directory. Defaults to `config.yaml`. Use it for multi-part projects (one config per part) or a non-default config file name.
74
-
75
- ### Folders
76
-
77
- - **`--base-folder BASE_FOLDER`** — base folder for the build files.
78
- - **`--build-folder BUILD_FOLDER`** — folder for build files (generated code lands under here, per module: `plain_modules/<module>/code/` and `plain_modules/<module>/tests/`).
79
- - **`--template-dir TEMPLATE_DIR`** — path to a custom template directory. Templates are searched in this order: 1) the directory containing the `.plain` file, 2) this custom template directory, 3) the built-in `standard_template_library` directory. In `config.yaml` the equivalent key is `template_dir` — set it whenever the project has import modules or templates.
80
-
81
- ### Test-script wiring
82
-
83
- - **`--unittests-script UNITTESTS_SCRIPT`** — shell script that runs unit tests on the generated code. Receives the build folder path as its first argument (default: `plain_modules`). `config.yaml` key: `unittests-script`.
84
- - **`--conformance-tests-folder CONFORMANCE_TESTS_FOLDER`** — folder for conformance test files.
85
- - **`--conformance-tests-script CONFORMANCE_TESTS_SCRIPT`** — path to the conformance-tests shell script. It must accept two arguments: 1) a folder containing generated source code (e.g. `plain_modules/module_name`), and 2) a subfolder of the conformance-tests folder containing the test files (e.g. `conformance_tests/subfoldername`). `config.yaml` key: `conformance-tests-script`.
86
- - **`--prepare-environment-script PREPARE_ENVIRONMENT_SCRIPT`** — path to a shell script that prepares the testing environment. It must accept the source-code folder path as its first argument. It runs once per render, only to warm the environment the conformance runner attaches to. `config.yaml` key: `prepare-environment-script`. If this is declared, `conformance-tests-script` must be declared too.
87
- - **`--test-script-timeout TEST_SCRIPT_TIMEOUT`** — timeout for test scripts, in seconds. Defaults to 120 seconds. Raise it if the project's test scripts are slow.
88
-
89
- ### Output copying
90
-
91
- - **`--copy-build`** — after a successful render, copy the rendered code in `--base-folder` to `--build-dest`.
92
- - **`--build-dest BUILD_DEST`** — target folder for `--copy-build` (used only when `--copy-build` is set).
93
- - **`--copy-conformance-tests`** — after a successful render, copy the conformance tests in `--conformance-tests-folder` to `--conformance-tests-dest`. Requires `--conformance-tests-script`.
94
- - **`--conformance-tests-dest CONFORMANCE_TESTS_DEST`** — target folder for `--copy-conformance-tests` (used only when it is set).
95
-
96
- ### API
97
-
98
- - **`--api [API]`** — alternative base URL for the API. Default: `https://api.codeplain.ai`.
99
- - **`--api-key API_KEY`** — API key used to access the API. If not provided, the `CODEPLAIN_API_KEY` environment variable is used. **Secret — never store it in `config.yaml`.**
100
-
101
- ### Logging & output mode
102
-
103
- - **`--verbose`, `-v`** — enable verbose output. Verbose logging captures each test script's stdout/stderr into the log file between the renderer's own wrapper lines, which is what makes a live render inspectable. Keep logging verbose.
104
- - **`--log-to-file` / `--no-log-to-file`** — enable or disable logging to a file. Defaults to `True`; pass `--no-log-to-file` to disable.
105
- - **`--log-file-name LOG_FILE_NAME`** — name of the log file. Defaults to `codeplain.log`. If a file already exists at the resolved path, it is **overwritten** by the current run's logs — the log is therefore per-run, and its default location is the `.plain` file's directory.
106
- - **`--logging-config-path LOGGING_CONFIG_PATH`** — path to a logging configuration file.
107
- - **`--headless`** — run without the TUI: no terminal output except a single render-started message; all logs are written to the log file. **Required for agent-supervised runs** — a terminal tool cannot drive the interactive TUI, so supervision reads `codeplain.log` instead.
108
- - **`--render-machine-graph`** — render the state-machine graph. Use only on explicit request.
109
- - **`-h`, `--help`** — show the help message and exit.
110
-
111
- ## Environment variables
112
-
113
- - **`CODEPLAIN_API_KEY`** — the API key used when `--api-key` is not passed on the command line. Export it before rendering (or pass `--api-key`). It is a secret and must never be written into `config.yaml`.
114
-
115
- ## `config.yaml` relationship
116
-
117
- `codeplain` reads persistent options from a `config.yaml` (or the file named by `--config-name`), looked up in the `.plain` file's directory and the current working directory. This avoids retyping stable options on every run.
118
-
119
- - **One `config.yaml` per part of the system that has its own test scripts.** A single-stack project has one at the root; a multi-part project (e.g. a Python backend and a React frontend) has one per part, each referencing only its own scripts.
120
- - **Established keys:** `unittests-script`, `conformance-tests-script`, `prepare-environment-script`, `template_dir`, `base-folder`, `build-folder`, plus copy/log settings. `init-config-file` is the canonical assembler and the source of truth for the full valid key set; treat it as authoritative.
121
- - **Constraint:** if `prepare-environment-script` is declared, `conformance-tests-script` must be declared too — a prepare script only exists in service of conformance.
122
- - **Never put in `config.yaml`:** secrets (`api-key`) and per-invocation flags (`dry-run`, `full-plain`, `render-range`, `render-from`, `replay-with`). Supply these on the command line only.
123
- - Remember the path-resolution rule above: a script path written in `config.yaml` resolves against the config file's directory, not the working directory.
124
-
125
- ## Render output
126
-
127
- Generated artifacts (gitignored, read-only — never edit):
128
-
129
- - `plain_modules/<module>/code/` — the generated project for each `.plain` spec (implementation + unit tests).
130
- - `plain_modules/<module>/tests/<functionality>/` — generated conformance tests, one subfolder per functionality.
131
- - `codeplain.log` — the per-run log (overwritten each run).
132
-
133
- When a run ends, `codeplain` writes a result banner (to the log, and to the terminal outside headless mode):
134
-
135
- - **Success:** `✓ rendering succeeded` (or `rendering complete`), followed by a metadata block: render id, input file, generated code folder, functionalities count, used credits, render time.
136
- - **Failure:** `✗ rendering failed`, followed by the same metadata block.
137
-
138
- ## Test-script exit-code contract
139
-
140
- The three wired scripts (`unittests-script`, `conformance-tests-script`, `prepare-environment-script`) share an exit-code contract that `codeplain`, `plain-healthcheck`, and `check-plain-env` all branch on:
141
-
142
- - **`69`** — unrecoverable error (missing toolchain, bad arguments, cannot enter the working folder, install failed).
143
- - **`1`** — the "no tests discovered" guard in the conformance runner (and bad usage in the unit-test runner).
144
- - **any other non-zero** — propagated verbatim from the underlying test command (a real test failure).
145
-
146
- Author or modify these scripts only through the matching `implement-{unit-testing,conformance-testing,prepare-environment}-script` skill — never by hand.
147
-
148
- ## Common invocation patterns
149
-
150
- ```bash
151
- # Static-validation gate before a real render (what plain-healthcheck runs)
152
- codeplain <module>.plain --dry-run
153
-
154
- # Full render of the top module
155
- codeplain <module>.plain
156
-
157
- # Multi-part project: render one part with its own config file
158
- codeplain backend/api.plain --config-name config.yaml
159
-
160
- # Agent-supervised render: background + headless, watch codeplain.log
161
- nohup codeplain <module>.plain --headless > /dev/null 2>&1 &
162
-
163
- # Resume after a spec fix: re-render from functionality N (inclusive)
164
- codeplain <module>.plain --render-from <N>
165
-
166
- # Re-render exactly one functionality
167
- codeplain <module>.plain --render-range <N>
168
-
169
- # Force a full re-render (backward dependency changed) — costs more credits
170
- codeplain <module>.plain --force-render
171
- ```
172
-
173
- ## Common errors and signals
174
-
175
- - **`codeplain: command not found`** — the CLI is not installed or not on `PATH`. Confirm with `command -v codeplain`.
176
- - **`401` / `403` / `unauthorized`** — `CODEPLAIN_API_KEY` is unset or invalid; export it or pass `--api-key`. This is an API/auth problem, not a spec problem.
177
- - **`429` / `rate limit` / `quota`** — API throttling or credit limit; not a spec problem.
178
- - **`Functional spec too complex!`** — a single functional spec implies more than 200 lines of code; break it down (`break-down-func-spec`).
179
- - **`missing concept` / `unknown definition` / `cyclic` / `not defined` / `cannot resolve`** — a spec-graph error (a concept used before it is defined, a cycle, or a broken `import`/`requires` chain). A `--dry-run` catches these before spending credits.
180
- - **`Traceback (most recent call last):`** — the renderer itself crashed (a bug), not a spec error; capture the stack for a bug report.
181
-
182
- ## See also
183
-
184
- - `load-plain-reference` — the `***plain` language syntax and authoring rules.
185
- - `run-codeplain` — supervising a live render (monitor loop, pathologies, resume).
186
- - `plain-healthcheck` — the pre-render dry-run gate across every top module.
187
- - `init-config-file` — canonical `config.yaml` assembly and the full valid key set.
188
- - `implement-{unit-testing,conformance-testing,prepare-environment}-script` — authoring the wired test scripts.