Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ So a change here is almost always one of: (a) editing the installer CLI, or (b)
## Commands

```bash
npm test # full suite: node --test "test/**/*.test.mjs"
node --test --test-name-pattern="<regex>" "test/**/*.test.mjs" # run a single test by name
npm test # full suite: node --test test/*.test.mjs
node --test --test-name-pattern="<regex>" test/*.test.mjs # run a single test by name
node --test test/cli.test.mjs # run a single test file
```

Expand Down Expand Up @@ -69,12 +69,12 @@ A `.plain` file is a module: YAML frontmatter (`description`, `import:`, `requir
| `***test reqs***` | **everything about `:ConformanceTests:`** (framework, run command, mocking/network policy) |
| `***acceptance tests***` | nested under a functional spec (not top-level); full end-to-end workflows |

Other constraints the rules enforce (see `forge/rules/`): functional specs are mandatorily routed through `add-functional-spec(s)` (never hand-authored), checked for the 200-LOC limit (`analyze-if-func-spec-too-complex` → `break-down-func-spec`) and for conflicts (`analyze-func-specs` → `resolve-spec-conflict`); external artifacts (JSON Schema, OpenAPI, payloads) are **linked** as single local text files under `resources/`, never transcribed and never folders/URLs/binaries; generated code under `plain_modules/`/`conformance_tests/` is read-only — fixes go back into the spec and re-render.
Other constraints the rules enforce (see `forge/rules/`): functional specs are mandatorily routed through `add-functional-spec(s)` (never hand-authored), checked for the 200-LOC limit (`analyze-if-func-spec-too-complex` → `break-down-func-spec`) and for conflicts (`analyze-func-specs` → `resolve-spec-conflict`); external artifacts (JSON Schema, OpenAPI, payloads) are **linked** as single local text files under `resources/`, never transcribed and never folders/URLs/binaries; generated output under `plain_modules/<module>/code/` (implementation + unit tests) and `plain_modules/<module>/tests/` (conformance tests) is read-only — fixes go back into the spec and re-render.

### The skill lifecycle (orchestration)

`forge-plain` is the top-level orchestrator: a short Phase 0 intent interview followed by four gated phases — (1) definitions + functional specs, (2) implementation reqs / tech stack, (3) testing (unit→impl reqs, conformance→test reqs, generate `test_scripts/`, build `config.yaml`, probe host via `check-plain-env`), (4) validate via `plain-healthcheck` (`codeplain … --dry-run` gate) then hand off the render command. Phases 1–3 are **one-question-at-a-time, write-to-disk-immediately**. `add-feature` is the same authoring loop scoped to one feature on an existing project; `init-plain-project` is a no-interview scaffold; `run-codeplain` supervises a live `codeplain --headless` render. The installer ships `forge/rules/*.md` beside the skills; native rule consumers load them directly, while other agents reach them through `load-plain-reference`.

## Memory / persistent context

- Generated artifacts and project scratch (`plain_modules/`, `conformance_tests/`, `test_scripts/`, `*.yaml`, `codeplain.log`, env files) are gitignored.
- Generated artifacts and project scratch (`plain_modules/`, `test_scripts/`, `*.yaml`, `codeplain.log`, env files) are gitignored. The renderer writes everything it generates under `plain_modules/<module>/`: `code/` for implementation and unit tests, `tests/` for conformance tests (one folder per functional spec).
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,12 @@ A `.plain` file is a module: YAML frontmatter (`description`, `import:`, `requir
| `***test reqs***` | **everything about `:ConformanceTests:`** (framework, run command, mocking/network policy) |
| `***acceptance tests***` | nested under a functional spec (not top-level); full end-to-end workflows |

Other constraints the rules enforce (see `forge/rules/`): functional specs are mandatorily routed through `add-functional-spec(s)` (never hand-authored), checked for the 200-LOC limit (`analyze-if-func-spec-too-complex` → `break-down-func-spec`) and for conflicts (`analyze-func-specs` → `resolve-spec-conflict`); external artifacts (JSON Schema, OpenAPI, payloads) are **linked** as single local text files under `resources/`, never transcribed and never folders/URLs/binaries; generated code under `plain_modules/`/`conformance_tests/` is read-only — fixes go back into the spec and re-render.
Other constraints the rules enforce (see `forge/rules/`): functional specs are mandatorily routed through `add-functional-spec(s)` (never hand-authored), checked for the 200-LOC limit (`analyze-if-func-spec-too-complex` → `break-down-func-spec`) and for conflicts (`analyze-func-specs` → `resolve-spec-conflict`); external artifacts (JSON Schema, OpenAPI, payloads) are **linked** as single local text files under `resources/`, never transcribed and never folders/URLs/binaries; generated output under `plain_modules/<module>/code/` (implementation + unit tests) and `plain_modules/<module>/tests/` (conformance tests) is read-only — fixes go back into the spec and re-render.

### The skill lifecycle (orchestration)

`forge-plain` is the top-level orchestrator: a short Phase 0 intent interview followed by four gated phases — (1) definitions + functional specs, (2) implementation reqs / tech stack, (3) testing (unit→impl reqs, conformance→test reqs, generate `test_scripts/`, build `config.yaml`, probe host via `check-plain-env`), (4) validate via `plain-healthcheck` (`codeplain … --dry-run` gate) then hand off the render command. Phases 1–3 are **one-question-at-a-time, write-to-disk-immediately**. `add-feature` is the same authoring loop scoped to one feature on an existing project; `init-plain-project` is a no-interview scaffold; `run-codeplain` supervises a live `codeplain --headless` render. The installer ships `forge/rules/*.md` beside the skills; native rule consumers load them directly, while other agents reach them through `load-plain-reference`.

## Memory / persistent context

- Generated artifacts and project scratch (`plain_modules/`, `conformance_tests/`, `test_scripts/`, `*.yaml`, `codeplain.log`, env files) are gitignored.
- Generated artifacts and project scratch (`plain_modules/`, `test_scripts/`, `*.yaml`, `codeplain.log`, env files) are gitignored. The renderer writes everything it generates under `plain_modules/<module>/`: `code/` for implementation and unit tests, `tests/` for conformance tests (one folder per functional spec).
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ Hit a bug in the rendered app, a failing test, or behavior that doesn't match wh
2. plain-forge applies the fix in the `.plain` file(s) only and summarizes what changed.
3. Re-render to regenerate the code (see [Rendering specs](#rendering-specs)).

> **Important:** Never edit generated code under `plain_modules/` or `conformance_tests/` directly — your changes will be overwritten on the next render. Always fix the spec and re-render.
> **Important:** Never edit generated output under `plain_modules/` directly — neither the code in `plain_modules/<module>/code/` nor the conformance tests in `plain_modules/<module>/tests/`. Your changes will be overwritten on the next render. Always fix the spec and re-render.


## Repository Structure
Expand Down
2 changes: 1 addition & 1 deletion forge/rules/impl-reqs.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ When writing or editing an `***implementation reqs***` section in a `.plain` fil

## `:UnitTests:` lives here (hard rule)
- **Everything** about `:UnitTests:` goes in `***implementation reqs***` — paths, approach, packages, framework, conventions, fixtures, mocking policy, file layout, naming, lint / static-analysis gates
- `:UnitTests:` are part of the generated codebase (they sit inside `plain_modules/<module>/` alongside the implementation), so requirements that shape them are implementation reqs by definition
- `:UnitTests:` are part of the generated codebase (they sit inside `plain_modules/<module>/code/` alongside the implementation), so requirements that shape them are implementation reqs by definition
- The unit-test generator reads **only** `***implementation reqs***` — anything about `:UnitTests:` placed elsewhere (e.g. `***test reqs***`) is silently ignored
- Author each `:UnitTests:` requirement via `add-implementation-requirement` and phrase it in terms of `:UnitTests:` so the partition stays visible at a glance

Expand Down
6 changes: 3 additions & 3 deletions forge/rules/integration-embedded-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ mvn test -Dtest='<:UnitTests: package>.**.*Test' checkstyle:check

These reqs feed `run_conformance_tests_<lang>`. At minimum, declare:

1. **`:ConformanceTests:` source location** — where the conformance suite lives in the project (typically a sibling folder, e.g. `conformance_tests/<module>/`); the renderer passes the resolved path as `$2`
1. **`:ConformanceTests:` source location** — the generated suite lives under `plain_modules/<module>/tests/`, one folder per functional spec; the renderer passes the resolved path of the folder under test as `$2`
2. **`:ConformanceTests:` framework and execution command** — `mvn test --no-transfer-progress`, `pytest`, `npm test`, `go test ./...`, etc., with any flags / profiles the project requires
3. **Fully qualified `:ConformanceTests:` package** (or path / pattern) used to scope discovery, if the runner needs one
4. **`:ConformanceTests:` network and secrets policy** — by default the suite runs against the **live provider** (see [`integrations.md`](integrations.md) → *`:ConformanceTests:` always run against the live integration*). Declare the env-var names the script reads (e.g. `<PROVIDER>_API_KEY`), whether the script loads a `.env` file before running, and any specific endpoints that are mocked because they can't be exercised live safely (429, forced 5xx)
Expand All @@ -85,7 +85,7 @@ These reqs feed `run_conformance_tests_<lang>`. At minimum, declare:
Author the conformance facts as one or more entries, phrased in terms of `:ConformanceTests:`:

```plain
- :ConformanceTests: of :Implementation: live in `conformance_tests/foo/` and are implemented with JUnit 5 + Maven.
- :ConformanceTests: of :Implementation: live in `plain_modules/foo/tests/` and are implemented with JUnit 5 + Maven.
- The fully qualified package used for :ConformanceTests: discovery is `com.example.integrations.foo.conformance`.
- :ConformanceTests: are run via `mvn test --no-transfer-progress`; the host's Surefire plugin must be installed.
- :ConformanceTests: run against the live :ProviderName: sandbox — no mocking of provider calls.
Expand Down Expand Up @@ -139,7 +139,7 @@ All three scripts are invoked by the `codeplain` renderer with positional argume

## 1. `prepare_environment_<lang>` — copy into the host, then compile

Receives one positional argument: the renderer's build output folder (e.g. `plain_modules/<module>/`).
Receives one positional argument: the renderer's build output folder (e.g. `plain_modules/<module>/code/`).

Purpose: stage the generated code **into the host codebase at the module's package path**, then run the host's install / build so that downstream test projects (specifically the conformance suite) can depend on it from the local dependency cache.

Expand Down
5 changes: 4 additions & 1 deletion forge/rules/integration-embedded.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ The embedded integration's `.plain` specs (and the rest of the ***plain project
│ ├── resources/
│ ├── test_scripts/
│ ├── plain_modules/ # generated; gitignored
│ │ └── <module>/
│ │ ├── code/ # implementation + unit tests
│ │ └── tests/ # conformance tests, per functional spec
│ └── config.yaml
└── src/ # host source tree (Java, Python, etc.)
```
Expand Down Expand Up @@ -117,7 +120,7 @@ The renderer reads the directives from the spec and the shapes from the linked s

## Test-script wiring — copy into the host, run tests there

Embedded integrations are tested **inside the host codebase itself**. The prepare and unit-test scripts copy the renderer's output (`$1`, i.e. `plain_modules/<module>/`) into the host's source tree at the module's package path, then compile / test the host project in place. Only the conformance script uses a scratch folder in the system temp directory (`/tmp/<lang>_conformance/`), because the conformance suite is a separate project that consumes the host build as a dependency.
Embedded integrations are tested **inside the host codebase itself**. The prepare and unit-test scripts copy the renderer's output (`$1`, i.e. `plain_modules/<module>/code/`) into the host's source tree at the module's package path, then compile / test the host project in place. Only the conformance script uses a scratch folder in the system temp directory (`/tmp/<lang>_conformance/`), because the conformance suite is a separate project that consumes the host build as a dependency.

This matters because the integration's generated code references host symbols by their full import path (e.g. `from host_project.integrations.base import IntegrationContract`). Those imports only resolve cleanly when the test process is rooted in the host's package layout — anything else creates path edge cases that bite later in conformance failures.

Expand Down
2 changes: 1 addition & 1 deletion forge/rules/requires-modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ When creating or editing a `.plain` file that uses `requires`, always follow the

## What requires does
- `requires` establishes a **build ordering** — the required module is built before the current one
- The required module's generated code (`plain_modules/<required_module>`) is copied as the starting point
- The required module's generated code (`plain_modules/<required_module>/code`) is copied as the starting point
- The required module's `***functional specs***` become visible as **previous functional specs** — this property **is transitive**
- Only `exported_concepts` from the required module are available — not its full definitions — and this property **is not transitive**

Expand Down
2 changes: 1 addition & 1 deletion forge/rules/test-reqs.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ When writing or editing a `***test reqs***` section in a `.plain` file, always f

## `:ConformanceTests:` lives here (hard rule)
- **Everything** about `:ConformanceTests:` goes in `***test reqs***` — paths, approach, packages, framework, execution command, mocking / network policy, fixtures, pass criteria, environment prerequisites
- `:ConformanceTests:` live outside the generated codebase (typically in a separate project under `conformance_tests/<module>/`), so requirements that shape them belong in test reqs by definition
- `:ConformanceTests:` live outside the generated codebase, in their own tree under `plain_modules/<module>/tests/` (one folder per functional spec), so requirements that shape them belong in test reqs by definition
- The conformance-test generator reads **only** `***test reqs***` — anything about `:ConformanceTests:` placed elsewhere (e.g. `***implementation reqs***`) is silently ignored
- Author each `:ConformanceTests:` requirement via `add-test-requirement` and phrase it in terms of `:ConformanceTests:` so the partition stays visible at a glance
- Conformance testing run scripts should be linked here as a linked resource
Expand Down
2 changes: 1 addition & 1 deletion forge/skills/create-requires-module/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Always use the skill `load-plain-reference` to retrieve the ***plain syntax rule
`requires` establishes a build ordering between modules. The required module is built **before** the current one. This does not necessarily mean the current module extends or depends on the required module's code — it may be completely independent. The `requires` relationship simply ensures the build order is correct.

When this module is rendered:
- The required module's generated code (`plain_modules/<required_module>`) is copied as the starting point.
- The required module's generated code (`plain_modules/<required_module>/code`) is copied as the starting point.
- The required module's `***functional specs***` become visible as **previous functional specs**.
- Only `exported_concepts` from the required module are available (not its full definitions).

Expand Down
10 changes: 5 additions & 5 deletions forge/skills/debug-specs/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ Always use the skill `load-plain-reference` to retrieve the ***plain syntax rule

## Guiding Principle

Generated code in `plain_modules/` and `conformance_tests/` is **read-only** — it exists solely as evidence for diagnosis. All fixes are applied exclusively to the `.plain` spec files. The workflow is: observe → read generated code → trace to spec → fix the spec.
Generated code in `plain_modules/<module>/code/` and `plain_modules/<module>/tests/` is **read-only** — it exists solely as evidence for diagnosis. All fixes are applied exclusively to the `.plain` spec files. The workflow is: observe → read generated code → trace to spec → fix the spec.

## Input

1. **The module name** — identifies the `plain_modules/<module_name>/` directory and the corresponding `.plain` file(s).
1. **The module name** — identifies the `plain_modules/<module_name>/` directory (`code/` and `tests/`) and the corresponding `.plain` file(s).
2. **The user's observation** — what is wrong? This can be a bug description, a screenshot, a test failure, an error message, or a general "this doesn't work right."
3. **Optional: a specific functional spec** — if the user suspects a particular spec, start there. Otherwise, investigate broadly.

Expand All @@ -38,7 +38,7 @@ Generated code in `plain_modules/` and `conformance_tests/` is **read-only** —

## Phase 2 — Investigate the Generated Code

Read files in `plain_modules/<module_name>/` to understand what the renderer produced. **Do not modify any generated files.**
Read files in `plain_modules/<module_name>/code/` to understand what the renderer produced. **Do not modify any generated files.**

### 2a. Narrow the search

Expand All @@ -60,7 +60,7 @@ For each relevant file:
### 2c. Check conformance tests and unit tests (if relevant)

If the bug manifests as a test failure:
1. Read the failing test in `conformance_tests/<module_name>/` or `plain_modules/<module_name>/test/`.
1. Read the failing test — conformance tests in `plain_modules/<module_name>/tests/<functionality>/`, unit tests inside `plain_modules/<module_name>/code/`.
2. Understand what the test expects vs. what the implementation does.
3. Determine whether the test expectation is correct (matches the spec) or incorrect (doesn't match the spec).

Expand Down Expand Up @@ -164,7 +164,7 @@ revise the new spec
## Common Pitfalls

### Fixing the code instead of the spec
Never modify files in `plain_modules/` or `conformance_tests/`. Even if the fix is obvious in the code, the change must be made in the `.plain` file so it persists across re-renders.
Never modify files in `plain_modules/<module>/code/` or `plain_modules/<module>/tests/`. Even if the fix is obvious in the code, the change must be made in the `.plain` file so it persists across re-renders.

### Treating symptoms instead of root causes
If the user says "the button is in the wrong place," don't just add positioning detail. Investigate why the renderer placed it there — the root cause might be a missing layout spec, an ambiguous screen description, or a conflict with another spec.
Expand Down
2 changes: 1 addition & 1 deletion forge/skills/forge-plain/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,4 @@ Once the initial specs exist, the user will return with new features. Use the `a
- Applicable language rules and operational references: `load-plain-reference`.
- Spec-editing skills live in `.claude/skills/`.
- Templates go in `template/`, but import paths omit the `template/` prefix. Resources go in `resources/`.
- Generated code lands in `plain_modules/` (read-only, never edit). Test scripts live in `test_scripts/`.
- Generated code lands in `plain_modules/<module>/code/` and generated conformance tests in `plain_modules/<module>/tests/` (both read-only, never edit). Test scripts live in `test_scripts/`.
Loading
Loading