plain-forge 1.0.4 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,18 +4,39 @@
4
4
 
5
5
  # plain-forge
6
6
 
7
- A conversational spec-writing tool that runs in any AI coding agent (Claude Code, Codex, OpenCode, and more) and is built on the [***plain](https://plainlang.org) specification language. Describe what you want to build in plain English, and plain-forge guides you through a structured interview to produce complete `.plain` spec files which then generate production-ready code via the [Codeplain](https://codeplain.ai) renderer.
7
+ A toolkit for working with [***plain](https://plainlang.org) projects from inside your AI coding agent of choice — Claude Code, Codex, ForgeCode, OpenCode, and any other agent that reads from a standard skills directory. plain-forge ships skills, rules, and docs that turn a conversation into complete `.plain` spec files, then keeps maintaining them across the lifetime of the project. The specs are rendered into production-ready code by the [codeplain](https://codeplain.ai) renderer.
8
8
 
9
- ## How It Works
9
+ ## What plain-forge does
10
10
 
11
- The main entry point is `forge-plain`. It turns a conversation into ***plain specs through four phases:
11
+ plain-forge is organized around four kinds of work, each with its own entry-point skill (and a long tail of supporting skills behind it).
12
12
 
13
- 1. **What are we building?** — Walk through the product: description, users, scope, core entities, key features, user flows, business rules, and (if applicable) UI behavior. Produces the `***definitions***` and `***functional specs***` for each module.
14
- 2. **What technologies should it use?** — Pick the stack and architecture: language, frameworks, data storage, external services, project structure, and any other stack-wide constraints. Produces the `***implementation reqs***`.
15
- 3. **How should testing be done?** — Decide the testing strategy: framework, test types in scope, conformance/acceptance tests, environment-preparation scripts, layout, and execution. Produces the `***test reqs***`, any `***acceptance tests***`, the runnable scripts under `test_scripts/`, and the `config.yaml`(s) wiring them in. plain-forge then probes your machine to confirm everything those scripts need is actually installed.
16
- 4. **Validate and hand off** — plain-forge identifies the final module in the dependency chain and runs `codeplain <module>.plain --dry-run` itself to catch any static errors (syntax, undefined concepts, broken `import`/`requires` chains, complexity violations, conflicts). It fixes the `.plain` files until the dry-run passes, then hands you the exact `codeplain <module>.plain` command (plus any test scripts) so the real render starts from a clean spec.
13
+ ### 1. Bootstrap a new project
17
14
 
18
- Each phase is **incremental**, not a single long questionnaire. plain-forge walks one topic at a time, runs an **ask → author → review** loop on every topic — structured questions, immediate edits to the `.plain` files (and `test_scripts/` / `config.yaml` in Phase 3), then snippet-by-snippet confirmation — and only moves on once every flagged snippet is explicitly approved.
15
+ Pick whichever entry point matches how much upfront design you want:
16
+
17
+ - **`forge-plain`** — full end-to-end interview. One question at a time, immediate writes to disk, covers product → tech stack → testing → validation in four phases. Produces a complete `.plain` project with `config.yaml`, test scripts, and a successful `codeplain --dry-run` before handing off.
18
+ - **`init-plain-project`** — lightweight scaffold. Asks only about the base technology, project kind, and whether conformance testing is on; emits a template module, a stub top-level module, the testing scripts, and a `config.yaml`. No interview, no specs — pair it with `add-feature` to grow the project feature by feature.
19
+
20
+ ### 2. Grow an existing project
21
+
22
+ - **`add-feature`** — takes a feature request in plain English and runs the same one-question-at-a-time loop that `forge-plain` uses, scoped to a single feature against an existing `.plain` file.
23
+ - **Per-section authoring skills** — `add-functional-spec`, `add-functional-specs`, `add-implementation-requirement`, `add-test-requirement`, `add-concept`, `add-acceptance-test`, `add-resource`, `add-template`. Each enforces the relevant ***plain syntax rules (concept uniqueness, complexity limits, line-length, linked-resource constraints, …) so hand-authoring doesn't drift from the language.
24
+ - **Module-management skills** — `create-import-module`, `create-requires-module`, `refactor-module`, `consolidate-concepts` for restructuring as the project grows.
25
+
26
+ ### 3. Validate and maintain
27
+
28
+ - **`plain-healthcheck`** — the verification gate. Inventories every `.plain` module, validates every `config.yaml`, and dry-runs every top module with the right config. Returns `PASS` / `FAIL` with a numbered punch-list when something is broken.
29
+ - **`init-config-file`** — assembles the canonical `config.yaml` per part of a project from the decisions made during interviewing.
30
+ - **`check-plain-env`** — probes the host machine for everything the project needs (language toolchains, external services, system binaries, drivers, `codeplain` itself) and emits a `PASS` / `WARN` / `FAIL` report with OS-specific install commands.
31
+ - **`analyze-func-specs`** / **`analyze-if-func-spec-too-complex`** / **`break-down-func-spec`** / **`resolve-spec-conflict`** — the spec-quality toolchain that runs behind `add-feature` and `forge-plain` but can also be invoked directly when reviewing or refactoring.
32
+
33
+ ### 4. Debug and render
34
+
35
+ - **`debug-specs`** — when the rendered app misbehaves, this traces the generated code back to the spec that caused it and fixes the spec (never the generated code).
36
+ - **`run-codeplain`** — experimental supervised render. Launches `codeplain` for you, tails the log, watches generated code appear under `plain_modules/`, and detects pathologies (stuck conformance loops, complexity errors, missing concepts, render failures). On approval it stops the renderer, hands off to the right spec-edit skill, and resumes.
37
+ - **`implement-unit-testing-script`** / **`implement-conformance-testing-script`** / **`implement-prepare-environment-script`** — generate the per-language testing scripts that the renderer and you both invoke. New languages can be added by these skills without touching any other part of the project.
38
+
39
+ Each skill operates on the same one-question-at-a-time, write-immediately, refine-through-follow-ups loop. Specs land on disk after every answer; later answers fix earlier writes in place. There is no batched interview, no "I'll gather context first," and no hand-authored functional specs — every new spec goes through the authoring skills so the complexity and conflict checks actually run.
19
40
 
20
41
  ## Getting Started
21
42
 
@@ -38,12 +38,27 @@ Run host discovery **before** the first Phase 1 question. Treat the results as g
38
38
  - The renderer is allowed to redefine **only** symbols the host does not provide and the contract schema does not capture
39
39
  - Naming the symbol by FQN is not optional decoration — it tells the renderer where the type comes from, which prevents a duplicate definition under `plain_modules/`
40
40
 
41
- ## Add host files as linked resources, never restate them
41
+ ## Link host files at their original path — never copy them into `resources/`
42
42
 
43
- - Every host file the integration touches (base classes, configuration modules, registries, exception classes, lifecycle hooks) is added under `resources/host/` via the `add-resource` skill and referenced from the relevant spec using `***linked resource***` syntax
43
+ The integration's `.plain` module lives **inside the host codebase** (per the "adopt the host's `.plain` setup verbatim" step). That means host source files are already reachable as linked resources via their host-relative paths. The integration spec references them **in place**; it never duplicates them under `resources/host/`.
44
+
45
+ - Every host file the integration touches (base classes, configuration modules, registries, exception classes, lifecycle hooks) is referenced from the relevant spec using `***linked resource***` syntax with the **path as it exists in the host codebase** — e.g. `[base.py](host_project/integrations/base.py)` if the `.plain` module sits next to `host_project/`
46
+ - **Do NOT copy host files into `resources/host/`.** A copy creates a second source of truth that drifts the moment the host file is edited; the rendered code will then disagree with whatever the host actually ships
47
+ - **Do NOT add host files via the `add-resource` skill's default copy behavior** when that behavior would duplicate the file — point at the existing host path directly
44
48
  - **Never inline a host file's contents** into a spec
45
- - **Never describe a host symbol's shape from memory** — the renderer reads the linked file's bytes and that is the source of truth
46
- - This obeys the broader [`linked-resources.md`](linked-resources.md) rules a directory is not a valid link, a URL is not a valid link, a binary is not a valid link
49
+ - **Never describe a host symbol's shape from memory** — the renderer reads the linked file's bytes at its host path and that is the source of truth
50
+ - This still obeys the broader [`linked-resources.md`](linked-resources.md) rules: a directory is not a valid link, a URL is not a valid link, a binary is not a valid link. Only the *location* changes — host files live where the host put them, not under `resources/`
51
+
52
+ ### What still belongs under `resources/`
53
+
54
+ This rule applies to **host source code only**. Other artifacts still live under `resources/` exactly like in a non-embedded project:
55
+
56
+ - **Contract schemas authored by the integration** — `resources/contract/<entry-point>.schema.json`
57
+ - **Configuration schema** — `resources/config.schema.json`
58
+ - **Captured probe responses** (from the live-API cross-check) — `resources/fixtures/<endpoint>.<case>.json`
59
+ - **Static lookup tables** the integration owns — `resources/error-map.yaml`, `resources/retry-policy.yaml`, etc.
60
+
61
+ The rule of thumb: if the host wrote it and ships it, link it where the host put it. If the integration is authoring it for the first time, it goes under `resources/`.
47
62
 
48
63
  ## The contract spec declares inheritance, not duplication
49
64
 
@@ -125,7 +140,7 @@ Before declaring an embedded integration done, in addition to the shared checkli
125
140
  - [ ] `host-codebase` concept records host root path, host language + version, host dependency manager + manifest, target package path, host base class import path, target generated-class FQN, and the host conventions the contract follows
126
141
  - [ ] Contract spec carries renderer directives (target language, target file path, target class name, host base class to subclass, host-package pins) and **links** to the contract schema; no class body is inlined
127
142
  - [ ] Every host symbol referenced in any spec uses its fully qualified import path and is tagged "imported from the host codebase; do not redefine"
128
- - [ ] Every host file the integration touches has been added under `resources/host/` as a linked resource no host file contents are inlined in any spec
143
+ - [ ] Every host file the integration touches is linked at its **original host-relative path** — no host file has been copied into `resources/host/` or anywhere else, and no host file contents are inlined in any spec
129
144
  - [ ] `forge-plain` Phase 2's tech-stack decisions are transcribed verbatim from the host (no independent stack choices)
130
145
  - [ ] Host-package version pins are copied into `***implementation reqs***`
131
146
  - [ ] `prepare_environment` copies the host into `.tmp/<lang>_<arg>/`, overlays `plain_modules/<module>/` at the target package path, installs the merged tree's dependencies, and is the working folder conformance attaches to
@@ -140,7 +155,8 @@ Before declaring an embedded integration done, in addition to the shared checkli
140
155
 
141
156
  - **Choosing a different language, framework, or dependency manager than the host.** The host stack is inherited; cross-stack `requires` chains are forbidden by [`requires-modules.md`](requires-modules.md)
142
157
  - **Redefining a host class under `plain_modules/`.** Reference the host symbol by FQN; let the renderer import it
143
- - **Inlining a host base class body into the contract spec.** Add the host file as a linked resource under `resources/host/` and reference it
158
+ - **Inlining a host base class body into the contract spec.** Reference the host file as a linked resource **at its original host-relative path** — do not inline its contents and do not copy it into `resources/`
159
+ - **Copying host source files into `resources/host/` (or anywhere under `resources/`).** That creates a second source of truth that silently drifts from the host. Link the host file in place; the integration `.plain` module already lives inside the host codebase, so the path resolves naturally
144
160
  - **Hardcoding the host codebase path in any spec or script.** Read it from the env var declared in the configuration concept
145
161
  - **Asking the user to design the integration's tech stack.** Read it from the host's manifest files
146
162
  - **Authoring an integration spec that contradicts an existing integration in the same host** without first surfacing the conflict and getting explicit user confirmation
@@ -44,6 +44,30 @@ Key formatting rules:
44
44
  - Each test bullet is indented under the `***acceptance tests***` header.
45
45
  - Multiple acceptance tests can be listed under a single functional spec.
46
46
 
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
+
47
71
  ## Rules
48
72
 
49
73
  ### Conformance with the Functional Spec
@@ -56,6 +56,29 @@ Attributes and constraints are nested sub-bullets:
56
56
  - Due Date - completion deadline (optional)
57
57
  ```
58
58
 
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
+
59
82
  ## Validation Checklist
60
83
 
61
84
  - [ ] Name uses `:CamelCase:` notation
@@ -57,6 +57,29 @@ Each functional spec must be unambiguous — the renderer should have only one r
57
57
  - All :Participant: members of the :Conversation: can see the new :Message:.
58
58
  ```
59
59
 
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
+
60
83
  ### Deterministic Interface
61
84
 
62
85
  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.
@@ -80,6 +80,30 @@ Each functional spec must be unambiguous — the renderer should have only one r
80
80
  - All :Participant: members of the :Conversation: can see the new :Message:.
81
81
  ```
82
82
 
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
+
83
107
  ### Deterministic Interface
84
108
 
85
109
  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.
@@ -60,6 +60,30 @@ Implementation reqs are bullet points in the `***implementation reqs***` section
60
60
 
61
61
  Reference defined `:Concepts:` where they add clarity. Implementation reqs in non-leaf sections apply to all subsections.
62
62
 
63
+ ## Line syntax (hard rule)
64
+
65
+ **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.
66
+
67
+ - 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.
68
+ - Nested detail is also a `- ` item, indented under its parent. The indentation alone is not enough; the leading `- ` is required.
69
+
70
+ BAD — bare continuation lines (invalid ***plain syntax, will not render):
71
+
72
+ ```plain
73
+ - :Implementation: tech stack will be finalized in Phase 2.
74
+ - Until then, treat this section as a placeholder so the renderer accepts
75
+ the file. Phase 2 will replace this with language, framework, HTTP
76
+ client, packaging, and architecture decisions.
77
+ ```
78
+
79
+ GOOD — every line starts with `- `:
80
+
81
+ ```plain
82
+ - :Implementation: tech stack will be finalized in Phase 2.
83
+ - Until then, treat this section as a placeholder so the renderer accepts the file.
84
+ - Phase 2 will replace it with language, framework, HTTP client, packaging, and architecture decisions.
85
+ ```
86
+
63
87
  ## Encapsulation Warning
64
88
 
65
89
  `requires` modules only receive functional specs from their dependencies — not implementation reqs. If downstream modules need certain behavior to be visible, that behavior must be expressed in functional specs, not here.
@@ -59,6 +59,28 @@ Test reqs are bullet points in the `***test reqs***` section:
59
59
 
60
60
  Reference predefined concepts like `:ConformanceTests:` and any defined `:Concepts:` where they add clarity.
61
61
 
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
+
62
84
  ## Validation Checklist
63
85
 
64
86
  - [ ] Describes conformance testing concerns, not unit tests or behavior
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plain-forge",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "Conversational spec-writing tool for ***plain specification language",
5
5
  "type": "module",
6
6
  "engines": {