plain-forge 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +247 -0
- package/bin/cli.mjs +143 -0
- package/forge/docs/.gitkeep +0 -0
- package/forge/rules/definitions.md +57 -0
- package/forge/rules/exported-concepts.md +39 -0
- package/forge/rules/func-specs.md +72 -0
- package/forge/rules/impl-reqs.md +50 -0
- package/forge/rules/import-modules.md +51 -0
- package/forge/rules/required-concepts.md +45 -0
- package/forge/rules/requires-modules.md +59 -0
- package/forge/rules/test-reqs.md +47 -0
- package/forge/skills/add-acceptance-test/SKILL.md +98 -0
- package/forge/skills/add-concept/SKILL.md +67 -0
- package/forge/skills/add-feature/SKILL.md +136 -0
- package/forge/skills/add-functional-spec/SKILL.md +81 -0
- package/forge/skills/add-functional-specs/SKILL.md +115 -0
- package/forge/skills/add-implementation-requirement/SKILL.md +73 -0
- package/forge/skills/add-resource/SKILL.md +108 -0
- package/forge/skills/add-template/SKILL.md +65 -0
- package/forge/skills/add-test-requirement/SKILL.md +68 -0
- package/forge/skills/analyze-2-func-specs/SKILL.md +102 -0
- package/forge/skills/analyze-func-specs/SKILL.md +124 -0
- package/forge/skills/analyze-if-func-spec-too-complex/SKILL.md +152 -0
- package/forge/skills/break-down-func-spec/SKILL.md +156 -0
- package/forge/skills/check-plain-env/SKILL.md +288 -0
- package/forge/skills/consolidate-concepts/SKILL.md +193 -0
- package/forge/skills/create-import-module/SKILL.md +98 -0
- package/forge/skills/create-requires-module/SKILL.md +104 -0
- package/forge/skills/debug-specs/SKILL.md +189 -0
- package/forge/skills/forge-integration/SKILL.md +443 -0
- package/forge/skills/forge-plain/SKILL.md +333 -0
- package/forge/skills/implement-conformance-testing-script/SKILL.md +247 -0
- package/forge/skills/implement-conformance-testing-script/assets/run_conformance_tests_cypress.ps1 +324 -0
- package/forge/skills/implement-conformance-testing-script/assets/run_conformance_tests_golang.ps1 +100 -0
- package/forge/skills/implement-conformance-testing-script/assets/run_conformance_tests_java.sh +102 -0
- package/forge/skills/implement-conformance-testing-script/assets/run_conformance_tests_python.ps1 +92 -0
- package/forge/skills/implement-conformance-testing-script/assets/run_conformance_tests_python.sh +100 -0
- package/forge/skills/implement-prepare-environment-script/SKILL.md +242 -0
- package/forge/skills/implement-prepare-environment-script/assets/prepare_environment_java.sh +42 -0
- package/forge/skills/implement-prepare-environment-script/assets/prepare_environment_python.sh +81 -0
- package/forge/skills/implement-unit-testing-script/SKILL.md +133 -0
- package/forge/skills/implement-unit-testing-script/assets/run_unittests_flutter.ps1 +82 -0
- package/forge/skills/implement-unit-testing-script/assets/run_unittests_golang.ps1 +68 -0
- package/forge/skills/implement-unit-testing-script/assets/run_unittests_java.sh +45 -0
- package/forge/skills/implement-unit-testing-script/assets/run_unittests_python.ps1 +76 -0
- package/forge/skills/implement-unit-testing-script/assets/run_unittests_python.sh +90 -0
- package/forge/skills/implement-unit-testing-script/assets/run_unittests_react.ps1 +83 -0
- package/forge/skills/init-config-file/SKILL.md +261 -0
- package/forge/skills/init-plain-project/SKILL.md +124 -0
- package/forge/skills/load-plain-reference/SKILL.md +646 -0
- package/forge/skills/plain-healthcheck/SKILL.md +132 -0
- package/forge/skills/refactor-module/SKILL.md +197 -0
- package/forge/skills/resolve-spec-conflict/SKILL.md +88 -0
- package/forge/skills/run-codeplain/SKILL.md +540 -0
- package/package.json +42 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: analyze-if-func-spec-too-complex
|
|
3
|
+
description: >-
|
|
4
|
+
Analyze a functional spec to determine if it is too complex for the renderer.
|
|
5
|
+
A spec is too complex if it would produce more than 200 lines of code changes.
|
|
6
|
+
Use after drafting a new functional spec (during `add-functional-spec`, or
|
|
7
|
+
per spec during `add-functional-specs`) to verify it fits within the
|
|
8
|
+
complexity limit before inserting it.
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Analyze If Functional Spec Is Too Complex
|
|
12
|
+
|
|
13
|
+
Always use the skill `load-plain-reference` to retrieve the ***plain syntax rules — but only if you haven't done so yet.
|
|
14
|
+
|
|
15
|
+
## Why This Matters
|
|
16
|
+
|
|
17
|
+
The renderer enforces a hard complexity limit: each functional spec must imply a **maximum of 200 changed lines of code**. If a spec exceeds this, the renderer rejects it with "Functional spec too complex!" and the spec must be broken down. Catching this before insertion saves a failed render cycle.
|
|
18
|
+
|
|
19
|
+
## Input
|
|
20
|
+
|
|
21
|
+
A drafted functional spec (not yet inserted into the file), plus the full context of the `.plain` file it will be added to — definitions, implementation reqs, and existing functional specs.
|
|
22
|
+
|
|
23
|
+
## Workflow
|
|
24
|
+
|
|
25
|
+
1. **Read the full `.plain` file** (and any `requires`/`import` modules) to understand the current codebase context — what already exists and what the new spec builds on.
|
|
26
|
+
2. **Read the drafted functional spec** carefully.
|
|
27
|
+
3. **Run the complexity analysis** using the checklist below.
|
|
28
|
+
4. **Output the verdict and nothing else** — either `ACCEPTABLE` or `TOO COMPLEX`. No reasoning, no LOC estimate, no breakdown.
|
|
29
|
+
|
|
30
|
+
## Complexity Analysis Checklist
|
|
31
|
+
|
|
32
|
+
Work through each indicator. A single "yes" does not automatically mean the spec is too complex, but multiple "yes" answers are a strong signal.
|
|
33
|
+
|
|
34
|
+
### 1. Number of Distinct Behaviors
|
|
35
|
+
|
|
36
|
+
Does the spec describe more than one independently testable behavior?
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
Too complex:
|
|
40
|
+
- :User: should be able to create, edit, delete, and archive :Task: items,
|
|
41
|
+
with validation on all fields and confirmation dialogs for destructive actions.
|
|
42
|
+
|
|
43
|
+
Acceptable (one behavior each):
|
|
44
|
+
- :User: should be able to create :Task:. Only valid :Task: items can be added.
|
|
45
|
+
- :User: should be able to edit :Task:.
|
|
46
|
+
- :User: should be able to delete :Task:.
|
|
47
|
+
- :User: should be able to archive :Task:.
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 2. Number of Concepts Introduced or Modified
|
|
51
|
+
|
|
52
|
+
Does the spec require introducing new data structures, UI components, API endpoints, or other constructs that don't already exist? Count them.
|
|
53
|
+
|
|
54
|
+
- 0–1 new constructs → likely fine
|
|
55
|
+
- 2–3 new constructs → borderline, examine closely
|
|
56
|
+
- 4+ new constructs → almost certainly too complex
|
|
57
|
+
|
|
58
|
+
### 3. Branching Logic and Conditions
|
|
59
|
+
|
|
60
|
+
Does the spec describe multiple conditional paths, modes, or special cases?
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
Too complex:
|
|
64
|
+
- The system should process :Order: differently based on :OrderType:.
|
|
65
|
+
Standard orders are validated and stored. Express orders skip validation
|
|
66
|
+
and are queued for immediate dispatch. Bulk orders are split into
|
|
67
|
+
sub-orders of 100 items each, validated individually, and processed
|
|
68
|
+
in parallel with progress tracking.
|
|
69
|
+
|
|
70
|
+
Acceptable (separate the modes):
|
|
71
|
+
- The system should process standard :Order: by validating and storing it.
|
|
72
|
+
- The system should process express :Order: by queuing it for immediate dispatch
|
|
73
|
+
without validation.
|
|
74
|
+
- The system should process bulk :Order: by splitting it into sub-orders of 100
|
|
75
|
+
items each and processing them individually.
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 4. Cross-Cutting Concerns
|
|
79
|
+
|
|
80
|
+
Does the spec bundle core functionality with cross-cutting concerns like error handling, logging, retry logic, pagination, or caching?
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
Too complex:
|
|
84
|
+
- The system should fetch :Resource: items from the external API with
|
|
85
|
+
pagination support, retry on transient errors with exponential backoff,
|
|
86
|
+
cache results for 5 minutes, and log all API calls.
|
|
87
|
+
|
|
88
|
+
Acceptable (separate concerns):
|
|
89
|
+
- The system should fetch :Resource: items from the external API.
|
|
90
|
+
- The system should paginate when fetching :Resource: items from the external API.
|
|
91
|
+
- The system should retry fetching :Resource: on transient errors using
|
|
92
|
+
exponential backoff.
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 5. UI Complexity
|
|
96
|
+
|
|
97
|
+
Does the spec describe a complete screen or page with multiple interactive elements, layouts, and state transitions?
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
Too complex:
|
|
101
|
+
- Display a dashboard showing :User: profile, recent :Task: items in a
|
|
102
|
+
sortable table, a notification bell with unread count, and a sidebar
|
|
103
|
+
with navigation links that highlights the active page.
|
|
104
|
+
|
|
105
|
+
Acceptable (build incrementally):
|
|
106
|
+
- Display a dashboard page for :User:.
|
|
107
|
+
- Show recent :Task: items in a sortable table on the dashboard.
|
|
108
|
+
- Show a notification indicator with the unread count on the dashboard.
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 6. Data Transformation Complexity
|
|
112
|
+
|
|
113
|
+
Does the spec involve complex data mapping, aggregation, or transformation across multiple entities?
|
|
114
|
+
|
|
115
|
+
- Simple field mapping or filtering → likely fine
|
|
116
|
+
- Multi-step transformations, joins across entities, or aggregations → likely too complex
|
|
117
|
+
|
|
118
|
+
### 7. Rough LOC Estimation
|
|
119
|
+
|
|
120
|
+
Mentally estimate the implementation. Consider:
|
|
121
|
+
- New files that need to be created
|
|
122
|
+
- New functions/methods
|
|
123
|
+
- Data model changes (schema, migrations, types)
|
|
124
|
+
- UI components (if applicable)
|
|
125
|
+
- Test setup and assertions (unit tests are auto-generated alongside)
|
|
126
|
+
- Error handling paths
|
|
127
|
+
- Import statements and boilerplate
|
|
128
|
+
|
|
129
|
+
If the estimate exceeds ~150 LOC, the spec is at high risk of being too complex (leave headroom for the renderer to add necessary boilerplate).
|
|
130
|
+
|
|
131
|
+
## Output Format
|
|
132
|
+
|
|
133
|
+
The skill emits exactly one of these two strings, with no surrounding text, explanation, estimate, or breakdown:
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
ACCEPTABLE
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
or
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
TOO COMPLEX
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
The internal analysis (checklist, LOC estimation, reasoning) informs the verdict but must not appear in the output. The caller decides what to do with the result.
|
|
146
|
+
|
|
147
|
+
## Integration with add-functional-spec / add-functional-specs
|
|
148
|
+
|
|
149
|
+
This skill is called during step 3 of the `add-functional-spec` workflow (or per spec during `add-functional-specs`), after drafting a spec but **before** inserting it into the file. The caller acts on the one-word verdict:
|
|
150
|
+
|
|
151
|
+
- **ACCEPTABLE** — proceed to insert the spec.
|
|
152
|
+
- **TOO COMPLEX** — invoke `break-down-func-spec` to produce smaller specs, then insert each one individually (running conflict checks on each).
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: break-down-func-spec
|
|
3
|
+
description: >-
|
|
4
|
+
Break down a functional spec that is too complex into smaller specs that
|
|
5
|
+
each imply ≤ 200 lines of code. Use when analyze-if-func-spec-too-complex
|
|
6
|
+
flags a spec as TOO COMPLEX, or when a spec is suspected of being too large.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Break Down Functional Spec
|
|
10
|
+
|
|
11
|
+
Always use the skill `load-plain-reference` to retrieve the ***plain syntax rules — but only if you haven't done so yet.
|
|
12
|
+
|
|
13
|
+
## When to Use
|
|
14
|
+
|
|
15
|
+
- `analyze-if-func-spec-too-complex` flagged a spec as TOO COMPLEX.
|
|
16
|
+
- A spec is suspected of exceeding the 200 LOC limit and needs to be split preemptively.
|
|
17
|
+
- A spec bundles multiple behaviors, constructs, or concerns that should be separated.
|
|
18
|
+
|
|
19
|
+
## Input
|
|
20
|
+
|
|
21
|
+
The functional spec to break down, plus the full `.plain` file it belongs to.
|
|
22
|
+
|
|
23
|
+
## Workflow
|
|
24
|
+
|
|
25
|
+
1. **Read the full `.plain` file** — definitions, implementation reqs, and all functional specs (including `requires` modules) to understand context.
|
|
26
|
+
2. **Identify the spec to break down** — the one flagged as too complex or pointed to by the user.
|
|
27
|
+
3. **Analyze why it is too complex** — use the indicators from `analyze-if-func-spec-too-complex`:
|
|
28
|
+
- Multiple distinct behaviors bundled together?
|
|
29
|
+
- Too many new constructs introduced at once?
|
|
30
|
+
- Complex branching logic or conditional paths?
|
|
31
|
+
- Cross-cutting concerns mixed with core functionality?
|
|
32
|
+
- A full UI screen described in one spec?
|
|
33
|
+
- Complex data transformations across multiple entities?
|
|
34
|
+
4. **Identify the split boundaries** — find the natural seams where the spec can be divided. Each resulting spec must be:
|
|
35
|
+
- Independently meaningful (makes sense on its own with previous specs as context)
|
|
36
|
+
- Self-contained (does not require a later spec to be useful)
|
|
37
|
+
- Within the 200 LOC limit
|
|
38
|
+
5. **Draft the replacement specs** — write the smaller specs in chronological order. The first replacement spec typically sets up the foundation, and subsequent ones layer behavior on top.
|
|
39
|
+
6. **Verify functional completeness** — this is critical. The replacement specs taken together must cover **100% of the functionality** described in the original spec. Walk through every behavior, condition, and detail in the original and confirm it appears in exactly one of the replacement specs. Nothing may be lost, weakened, or left implicit. If any functionality from the original is missing, add it to the appropriate replacement spec or create an additional one.
|
|
40
|
+
7. **Verify each replacement spec** — run `analyze-if-func-spec-too-complex` on each to confirm it fits within the limit.
|
|
41
|
+
8. **Check for conflicts** — run `analyze-func-specs` **once** with the full set of replacement specs plus every existing spec in the file and its `requires` chain. The batched analyzer reports every conflicting pair (replacement × existing and replacement × replacement) in one call — do not loop over pairs. Resolve each reported pair with `resolve-spec-conflict`, then re-run `analyze-func-specs` over the touched set until the verdict is `COMPATIBLE`.
|
|
42
|
+
9. **Replace in the file** — remove the original spec and insert the replacement specs in its position, preserving chronological order.
|
|
43
|
+
10. **Read the file again** to confirm correct placement and syntax.
|
|
44
|
+
|
|
45
|
+
## Splitting Strategies
|
|
46
|
+
|
|
47
|
+
### Strategy 1: Separate Distinct Behaviors
|
|
48
|
+
|
|
49
|
+
If the spec bundles multiple independently testable actions, split each into its own spec.
|
|
50
|
+
|
|
51
|
+
**Before:**
|
|
52
|
+
```plain
|
|
53
|
+
- :User: should be able to create, edit, and delete :Recipe: items, with
|
|
54
|
+
validation on all fields.
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**After:**
|
|
58
|
+
```plain
|
|
59
|
+
- :User: should be able to create a :Recipe:. Only valid :Recipe: items can be created.
|
|
60
|
+
- :User: should be able to edit an existing :Recipe:. Validation rules apply to the edited fields.
|
|
61
|
+
- :User: should be able to delete a :Recipe:.
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Strategy 2: Separate Setup from Behavior
|
|
65
|
+
|
|
66
|
+
If the spec introduces a new construct and immediately defines complex behavior on it, split into setup + behavior.
|
|
67
|
+
|
|
68
|
+
**Before:**
|
|
69
|
+
```plain
|
|
70
|
+
- The system should provide a :MealPlan: screen that displays a weekly grid of
|
|
71
|
+
:Slot: items, allows drag-and-drop reordering, and shows nutritional totals
|
|
72
|
+
per day.
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**After:**
|
|
76
|
+
```plain
|
|
77
|
+
- The system should provide a :MealPlan: screen that displays a weekly grid of :Slot: items.
|
|
78
|
+
- :User: should be able to reorder :Slot: items within a day on the :MealPlan: screen using drag-and-drop.
|
|
79
|
+
- The :MealPlan: screen should display nutritional totals for each day.
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Strategy 3: Separate Core Logic from Cross-Cutting Concerns
|
|
83
|
+
|
|
84
|
+
If the spec mixes primary functionality with error handling, retries, caching, pagination, or logging, pull cross-cutting concerns into their own specs.
|
|
85
|
+
|
|
86
|
+
**Before:**
|
|
87
|
+
```plain
|
|
88
|
+
- The system should fetch :Ingredient: data from the external API with
|
|
89
|
+
pagination, retry on transient errors, and cache results for 10 minutes.
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**After:**
|
|
93
|
+
```plain
|
|
94
|
+
- The system should fetch :Ingredient: data from the external API.
|
|
95
|
+
- The system should paginate when fetching :Ingredient: data from the external API.
|
|
96
|
+
- The system should retry fetching :Ingredient: data on transient errors.
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Strategy 4: Separate Conditional Paths
|
|
100
|
+
|
|
101
|
+
If the spec describes different modes or branches, give each its own spec.
|
|
102
|
+
|
|
103
|
+
**Before:**
|
|
104
|
+
```plain
|
|
105
|
+
- The system should process :MealPlan: generation differently based on :DietType:.
|
|
106
|
+
Standard plans use round-robin assignment. Restrictive plans filter out
|
|
107
|
+
excluded ingredients first, then apply round-robin. Custom plans allow manual
|
|
108
|
+
slot-by-slot selection.
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**After:**
|
|
112
|
+
```plain
|
|
113
|
+
- The system should generate a standard :MealPlan: using round-robin :Recipe: assignment.
|
|
114
|
+
- The system should generate a restrictive :MealPlan: by filtering out excluded
|
|
115
|
+
:Ingredient: items before applying round-robin assignment.
|
|
116
|
+
- The system should allow :User: to manually assign :Recipe: items to individual
|
|
117
|
+
:Slot: items for a custom :MealPlan:.
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Strategy 5: Build UI Incrementally
|
|
121
|
+
|
|
122
|
+
If the spec describes a full screen, split into layout + individual interactive elements.
|
|
123
|
+
|
|
124
|
+
**Before:**
|
|
125
|
+
```plain
|
|
126
|
+
- Display the :Dashboard: screen showing a summary card with stats, a scrollable
|
|
127
|
+
list of recent :MealPlan: items, a floating action button to create a new plan,
|
|
128
|
+
and a bottom navigation bar.
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**After:**
|
|
132
|
+
```plain
|
|
133
|
+
- Display the :Dashboard: screen with a summary card showing :MealFrameStats:.
|
|
134
|
+
- The :Dashboard: screen should show a scrollable list of recent :MealPlan: items.
|
|
135
|
+
- The :Dashboard: screen should include a button to create a new :MealPlan:.
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Preserving Chronological Order
|
|
139
|
+
|
|
140
|
+
The replacement specs take the position of the original spec. Earlier specs remain unchanged. The first replacement spec should make sense given only the specs above it. Each subsequent replacement spec can reference behavior from the ones before it.
|
|
141
|
+
|
|
142
|
+
If the original spec had acceptance tests, redistribute them to the most appropriate replacement spec — or drop tests that no longer apply to a single smaller spec and rewrite them.
|
|
143
|
+
|
|
144
|
+
## Validation Checklist
|
|
145
|
+
|
|
146
|
+
- [ ] Original spec has been removed from the file
|
|
147
|
+
- [ ] Replacement specs together cover 100% of the original spec's functionality — nothing lost
|
|
148
|
+
- [ ] Each replacement spec implies ≤ 200 LOC (verified via `analyze-if-func-spec-too-complex`)
|
|
149
|
+
- [ ] No conflicts between replacement specs and existing specs (verified via one batched `analyze-func-specs` call)
|
|
150
|
+
- [ ] No conflicts between the replacement specs themselves (covered by the same batched call)
|
|
151
|
+
- [ ] Replacement specs are in correct chronological order
|
|
152
|
+
- [ ] Each replacement spec is independently meaningful
|
|
153
|
+
- [ ] All `:Concepts:` referenced in replacement specs are defined
|
|
154
|
+
- [ ] Replacement specs are language-agnostic
|
|
155
|
+
- [ ] All external interfaces remain explicit
|
|
156
|
+
- [ ] Acceptance tests (if any) have been redistributed or rewritten
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: check-plain-env
|
|
3
|
+
description: >-
|
|
4
|
+
Read a ***plain project — its `.plain` files, `test_scripts/`, `config.yaml`(s),
|
|
5
|
+
and `resources/` — and determine every command-line tool, runtime, package
|
|
6
|
+
manager, and external service the project needs on the host machine. Probe
|
|
7
|
+
the host for each one, then emit a `PASS` / `FAIL` report listing what's
|
|
8
|
+
installed (with versions), what's missing, and concrete OS-specific install
|
|
9
|
+
commands for the gaps. Run this any time someone is about to render, test,
|
|
10
|
+
or onboard onto a ***plain project for the first time.
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Check Plain Env
|
|
14
|
+
|
|
15
|
+
Always use the skill `load-plain-reference` to retrieve the ***plain syntax rules — but only if you haven't done so yet.
|
|
16
|
+
|
|
17
|
+
This skill answers one question: **does the host machine have everything the ***plain project needs to render and test?** It reads the project, derives the requirement list, probes the machine, and returns a report. It never installs anything itself — that decision belongs to the user.
|
|
18
|
+
|
|
19
|
+
## When to run
|
|
20
|
+
|
|
21
|
+
- **First time you open a ***plain project on a new machine** — before the first `codeplain <module>.plain` or `./test_scripts/run_unittests*.sh` invocation. This is the most common case.
|
|
22
|
+
- **At the start of `forge-plain` Phase 3 environment verification** — `forge-plain` historically did this inline; delegate to this skill instead so the same check runs the same way everywhere.
|
|
23
|
+
- **After `add-feature`** — when the new feature brought in a new dependency (a new framework, a new service, a new package manager) the project didn't need before.
|
|
24
|
+
- **Before a real render** — alongside `plain-healthcheck`. `plain-healthcheck` answers "are the specs renderable?"; this skill answers "can this machine render them?". Both should pass.
|
|
25
|
+
- **Onboarding** — when a teammate (or CI runner, or fresh dev container) is about to start using the project.
|
|
26
|
+
- **Debugging a confusing failure** — when a test script exits with "command not found", "module not found", "could not connect", or similar before any test runs.
|
|
27
|
+
- **On demand** — whenever the user asks "what do I need to install for this project?".
|
|
28
|
+
|
|
29
|
+
This skill is **read-only and observational**. It does not edit `.plain` files, scripts, or configs, and it never invokes install commands on the user's behalf.
|
|
30
|
+
|
|
31
|
+
## What this skill does NOT do
|
|
32
|
+
|
|
33
|
+
- It does **not** install anything. It only suggests install commands and lets the user run them.
|
|
34
|
+
- It does **not** generate scripts, modify `config.yaml`, or change project files. Use `implement-*-testing-script`, `init-config-file`, etc. for that.
|
|
35
|
+
- It does **not** start services (databases, brokers, Docker daemons). It only checks whether the right binaries and (optionally) running endpoints are reachable.
|
|
36
|
+
- It does **not** validate the specs themselves (syntax, dry-run, complexity). Use `plain-healthcheck` for that — the two skills are complementary.
|
|
37
|
+
- It does **not** print secrets. Check whether an env var is *set* (e.g. `printenv FOO >/dev/null && echo set || echo missing`), never echo its value.
|
|
38
|
+
|
|
39
|
+
## Workflow
|
|
40
|
+
|
|
41
|
+
The skill is a **derive → probe → report** pass. It does not stop at the first missing tool; it surfaces every gap so the user gets a single complete shopping list.
|
|
42
|
+
|
|
43
|
+
### Step 1 — Inventory the project
|
|
44
|
+
|
|
45
|
+
1. **Detect the host OS** first. Run `uname -s 2>/dev/null || echo "$OS"`. Use the result to (a) pick the right script extensions to inspect (`.sh` vs `.ps1`) and (b) pick the right install commands later (Homebrew, apt, dnf, pacman, choco, scoop, winget).
|
|
46
|
+
2. **List every `.plain` file** in the repo root and in any subdirectory that contains them. Note which are top modules (not `requires`-ed by anything) and which are import modules (under `template/`).
|
|
47
|
+
3. **List every `config.yaml`** in the repo and read each one. Note the `*-script` keys it sets and the values they point at.
|
|
48
|
+
4. **List every script under `test_scripts/`** (both `.sh` and `.ps1` — projects can ship both).
|
|
49
|
+
5. **List every file under `resources/`** if the directory exists. Schemas and protocol files there often imply running services (e.g. a Postgres `.sql` schema implies a Postgres server).
|
|
50
|
+
6. Print a one-line inventory summary, e.g. `Detected: 2 top modules (backend/api.plain, frontend/web.plain), 2 config.yaml(s), 4 test_scripts, 3 resources. Host: Darwin.`
|
|
51
|
+
|
|
52
|
+
### Step 2 — Derive the requirement list (at runtime, from what the project actually says)
|
|
53
|
+
|
|
54
|
+
The requirement list is **not pre-baked into this skill**. There is no catalog of "things to always check". The list is derived for each project from the project itself, by reading the specs and scripts in front of you and classifying every signal into one of the categories below.
|
|
55
|
+
|
|
56
|
+
#### What to check vs. what *not* to check
|
|
57
|
+
|
|
58
|
+
The single most important rule:
|
|
59
|
+
|
|
60
|
+
> **Check only the layers a package manager cannot install.** Anything `pip install -r requirements.txt`, `npm ci`, `mvn install`, `cargo fetch`, `go mod download`, `bundle install`, `composer install`, etc. would resolve is **out of scope** for this skill. It will be installed by the project's own scripts the moment they run. Checking it here is wasted work and creates false-negative reports the moment the manifest changes.
|
|
61
|
+
|
|
62
|
+
Concretely:
|
|
63
|
+
|
|
64
|
+
- ❌ **Do NOT check individual language packages** — not `torch`, not `requests`, not `numpy`, not `FastAPI`, not `express`, not `react`, not a specific JAR in `pom.xml`, not a specific gem in `Gemfile`, not a specific crate in `Cargo.toml`. The language's package manager handles all of it. The same rule applies in every language — Python, Node.js, Java, Go, Rust, Ruby, PHP, .NET, Dart, etc.
|
|
65
|
+
- ✅ **Do check the layers below the package manager**, which fall into four categories. Build the requirement list at runtime by walking through each category and adding only what the project actually needs.
|
|
66
|
+
|
|
67
|
+
#### Category 1 — Language toolchains and their package managers
|
|
68
|
+
|
|
69
|
+
For each language the project uses, the *toolchain* must be on the host — the package manager cannot install itself. Decide which toolchains apply by reading the specs and scripts:
|
|
70
|
+
|
|
71
|
+
- **Signals in `.plain` files**: phrases like `should be in Python`, `should be in Java`, `should be in Go` in `***implementation reqs***`. Find the language; ignore the framework (the framework is a package, not a toolchain).
|
|
72
|
+
- **Signals in `test_scripts/`** (more reliable, because scripts are the executable contract): which interpreter / build tool is invoked at the top level. `python3` / `pip` → Python toolchain. `node` / `npm` / `pnpm` / `yarn` → Node.js toolchain. `mvn` / `gradle` → JDK + Maven/Gradle. `go` → Go toolchain. `cargo` → Rust toolchain. `dotnet` → .NET SDK. `ruby` / `bundle` → Ruby + Bundler. `php` / `composer` → PHP + Composer. `dart` / `flutter` → Dart/Flutter SDK.
|
|
73
|
+
|
|
74
|
+
For each detected toolchain, probe both the interpreter/compiler **and** its package manager:
|
|
75
|
+
|
|
76
|
+
- Python → `python3 --version` + `pip --version`.
|
|
77
|
+
- Node.js → `node --version` + `npm --version` (or `pnpm`/`yarn` if the scripts use them).
|
|
78
|
+
- Java → `java -version` + `javac -version` + `mvn -version` (or `gradle --version`).
|
|
79
|
+
- Go → `go version`.
|
|
80
|
+
- Rust → `cargo --version` + `rustc --version`.
|
|
81
|
+
- .NET → `dotnet --version`.
|
|
82
|
+
- Ruby → `ruby --version` + `bundle --version`.
|
|
83
|
+
- PHP → `php --version` + `composer --version`.
|
|
84
|
+
- Flutter / Dart → `flutter --version` + `dart --version`.
|
|
85
|
+
|
|
86
|
+
**That's where the language-package check stops.** Once `python3` and `pip` are on the host, `pip install -r requirements.txt` will handle `torch`, `numpy`, `requests`, etc. when the test script runs. Don't probe for them here.
|
|
87
|
+
|
|
88
|
+
#### Category 2 — External services
|
|
89
|
+
|
|
90
|
+
Services that run as separate processes / daemons and cannot be installed by a language package manager. Identify them at runtime by reading the specs and config:
|
|
91
|
+
|
|
92
|
+
- **Signals**: a `.plain` file names a service the implementation talks to (database, cache, queue, broker, orchestrator). A `resources/*.sql` schema implies a database. A `docker-compose.yml` (if present) lists services explicitly.
|
|
93
|
+
- For each service found, probe **both** that its CLI is available **and** — when possible — that the service is reachable. "Binary present but service not running" should report as `WARN`, not `FAIL`; the user may want to start it on demand.
|
|
94
|
+
|
|
95
|
+
No catalog — if the spec says "uses PostgreSQL" you check Postgres, if it says "uses Redis" you check Redis, if it says "uses some-niche-service" you look up its CLI on the fly and probe that. Don't pretend the list is closed.
|
|
96
|
+
|
|
97
|
+
#### Category 3 — System binaries that language packages wrap
|
|
98
|
+
|
|
99
|
+
Some language packages are thin wrappers around a system binary that **`pip install` / `npm install` cannot install for you**. The package manager installs the wrapper; the wrapped binary still has to be on the host separately. This is the most commonly missed category.
|
|
100
|
+
|
|
101
|
+
Decide at runtime by reading the workflow described in the specs. If the workflow can't physically run without an external tool, that tool needs to be checked even though the language wrapper around it is in `requirements.txt`. Examples of the *pattern* (not an exhaustive list — derive yours from the actual project):
|
|
102
|
+
|
|
103
|
+
- The spec describes OCR → a wrapper like `pytesseract` is in `requirements.txt`, but the host still needs the `tesseract` binary and the language data files.
|
|
104
|
+
- The spec describes video/audio processing → `ffmpeg-python` is in the manifest, but the `ffmpeg` binary itself must be on the host.
|
|
105
|
+
- The spec describes PDF extraction → a Python wrapper is in the manifest, but the `pdftotext` / `pdftoppm` binaries from poppler-utils are still required.
|
|
106
|
+
- The spec describes headless-browser e2e testing → the npm package is in `package.json`, but the actual browser binaries (Chromium, Firefox, WebKit) must be downloaded onto the host separately.
|
|
107
|
+
- The spec describes shelling out to any external CLI from generated code → that CLI must be on the host.
|
|
108
|
+
|
|
109
|
+
**Heuristic for spotting Category 3:** if removing the package from `requirements.txt` would still leave a binary on the host that the project depends on, the binary belongs in Category 3. If the package *is* the only thing the project needs, it's package-manager territory and out of scope.
|
|
110
|
+
|
|
111
|
+
Whenever the test scripts themselves invoke a non-language binary (`ffmpeg`, `psql`, `docker`, `tesseract`, ...), that binary is automatically Category 3 — the script is the executable contract. **Always reconcile the spec-derived list against the scripts** before probing.
|
|
112
|
+
|
|
113
|
+
#### Category 4 — Hardware, drivers, accelerators
|
|
114
|
+
|
|
115
|
+
Things the OS — not any package manager — must provide. The only category where the chain runs deeper than "is this binary on PATH?".
|
|
116
|
+
|
|
117
|
+
- **Signals**: a spec mentions GPU acceleration, local model training/fine-tuning, real-time inference, CUDA, MPS / Apple Silicon, hardware-accelerated video encoding, etc.
|
|
118
|
+
- The check is **layered**, and each layer fails independently. Probe each one and surface each result separately, in order, so the user sees exactly where the chain breaks:
|
|
119
|
+
1. **Driver present?** (e.g. `nvidia-smi` succeeds.)
|
|
120
|
+
2. **Device visible?** (e.g. `nvidia-smi -L` lists ≥ 1 GPU.)
|
|
121
|
+
3. **Accelerator SDK installed?** (e.g. `nvcc --version` for the CUDA toolkit.)
|
|
122
|
+
4. **Acceleration libraries discoverable?** (e.g. cuDNN via `ldconfig -p \| grep libcudnn` on Linux.)
|
|
123
|
+
5. **The runtime can actually see the accelerator?** (e.g. a one-line Python probe through whatever framework the spec named: `python -c "import torch; print(torch.cuda.is_available(), torch.version.cuda)"`.) This particular layer **does** require the language package, so run it after the test scripts have had a chance to install dependencies — or surface it as "can be verified after `pip install`" if dependencies aren't installed yet.
|
|
124
|
+
6. **Version compatibility.** If the runtime reports a different CUDA major version than the toolkit, surface a `WARN`. Driver / toolkit / runtime version mismatches are the most common silent GPU bug.
|
|
125
|
+
|
|
126
|
+
The same shape applies to other accelerators: Apple Silicon / MPS (`uname -m`, `sw_vers`, framework probe), AMD ROCm (`rocminfo`), Intel oneAPI, etc. Look up the relevant probe at runtime from the spec's terminology.
|
|
127
|
+
|
|
128
|
+
Worked example — the GPU case:
|
|
129
|
+
|
|
130
|
+
> A `.plain` file declares: `:Implementation: should fine-tune :BaseModel: on the user's local hardware using PyTorch. Training should use available GPUs when present.`
|
|
131
|
+
>
|
|
132
|
+
> What the package manager handles (out of scope for this skill): `torch` itself. `pip install -r requirements.txt` will fetch the right wheel.
|
|
133
|
+
>
|
|
134
|
+
> What this skill must probe (in scope):
|
|
135
|
+
>
|
|
136
|
+
> 1. The **Python toolchain** (Category 1): `python3 --version`, `pip --version`.
|
|
137
|
+
> 2. The **NVIDIA driver** (Category 4, layer 1): `nvidia-smi`.
|
|
138
|
+
> 3. **At least one GPU visible** (Category 4, layer 2): `nvidia-smi -L` lists ≥ 1 device.
|
|
139
|
+
> 4. **CUDA toolkit** (Category 4, layer 3): `nvcc --version`.
|
|
140
|
+
> 5. **cuDNN discoverable** (Category 4, layer 4): `ldconfig -p \| grep libcudnn` on Linux; skip on macOS.
|
|
141
|
+
> 6. **PyTorch actually sees the GPU** (Category 4, layer 5): `python -c "import torch; print(torch.cuda.is_available(), torch.version.cuda)"` — noting this requires `torch` to be installed (i.e. requires the test scripts to have run their install step at least once).
|
|
142
|
+
> 7. **Version match** (Category 4, layer 6): cross-check `torch.version.cuda` against `nvcc --version`. Mismatch → `WARN`.
|
|
143
|
+
>
|
|
144
|
+
> The skill never asks "is `torch` installed?". That belongs to `pip`.
|
|
145
|
+
|
|
146
|
+
#### Category 5 — Always required
|
|
147
|
+
|
|
148
|
+
Add these to every requirement list regardless of project:
|
|
149
|
+
|
|
150
|
+
- `codeplain` CLI on `PATH` — `codeplain --version`.
|
|
151
|
+
- `CODEPLAIN_API_KEY` env var **set** — `printenv CODEPLAIN_API_KEY >/dev/null && echo set || echo missing` (never echo the value).
|
|
152
|
+
- A shell matching the testing scripts' extension (Bash for `.sh`, PowerShell for `.ps1`).
|
|
153
|
+
- `git` (the renderer uses it; almost every plain project tracks itself in git).
|
|
154
|
+
|
|
155
|
+
### Step 3 — Probe the host
|
|
156
|
+
|
|
157
|
+
For every requirement the project produced in Step 2, run a check using the `terminal` tool. Capture stdout/stderr and exit code. Classify each result:
|
|
158
|
+
|
|
159
|
+
- **PASS** — present and (where a version was specified) at or above the required version.
|
|
160
|
+
- **WARN** — present but at a version that doesn't match what the project explicitly asks for (e.g. spec says Java 17, host has Java 21), or service binary present but the service itself isn't running, or a Category 4 sub-layer is mismatched against another (e.g. CUDA toolkit version doesn't match what the framework expects).
|
|
161
|
+
- **FAIL** — missing, unreachable, or below the minimum version.
|
|
162
|
+
|
|
163
|
+
Probe in the same category order Step 2 produced them, so the report reads top-down:
|
|
164
|
+
|
|
165
|
+
1. **Category 1 — Language toolchains.** Run the toolchain + package-manager probes listed in Step 2's Category 1 for the languages this project actually uses. Do not probe individual language packages.
|
|
166
|
+
2. **Category 5 — Codeplain and `git`.** Always required, independent of the project. `codeplain --version`, `printenv CODEPLAIN_API_KEY >/dev/null`, `git --version`. Verify the shell flavor matches the scripts' extension; a `.sh`-only project on native Windows is a `FAIL` (suggest WSL).
|
|
167
|
+
3. **Category 2 — External services.** For each service identified at runtime, probe the CLI's presence first, then — if the CLI exists — check whether the service itself is reachable. Service binary present but daemon down → `WARN`, not `FAIL`.
|
|
168
|
+
4. **Category 3 — System binaries that language packages wrap.** For each one identified in Step 2, check the system binary is on `PATH` (`which <bin>` / `<bin> --version`). The wrapper package itself isn't probed.
|
|
169
|
+
5. **Category 4 — Hardware, drivers, accelerators.** Walk the layered probe from Step 2 in order (driver → device visibility → SDK → acceleration libs → framework-sees-it → version match), reporting each layer's result separately. Never collapse a multi-layer failure into a single "GPU not available" message — each layer has a different fix.
|
|
170
|
+
6. **Credentials and config holes.** For every env var, dotfile, or cloud CLI login state the project implies, probe its presence without printing its value: `printenv VAR >/dev/null && echo set || echo missing`, `[ -f <path> ] && echo present || echo missing`, `aws sts get-caller-identity` / `gcloud auth list` / `az account show` for cloud SDKs.
|
|
171
|
+
|
|
172
|
+
### Step 4 — Report
|
|
173
|
+
|
|
174
|
+
Emit a single report with **the verdict on the first line** so callers can pattern-match without parsing the body:
|
|
175
|
+
|
|
176
|
+
- **`PASS`** — every required item is present at an acceptable version. Follow with a one-paragraph summary listing what was checked.
|
|
177
|
+
- **`WARN`** — everything required is present but at least one item triggered a soft warning (version mismatch, service not currently running). Follow with the numbered list of warnings.
|
|
178
|
+
- **`FAIL`** — at least one required item is missing or below minimum version. Follow with a numbered list of every gap.
|
|
179
|
+
|
|
180
|
+
For every **FAIL** and **WARN** item, the report must include four columns:
|
|
181
|
+
|
|
182
|
+
| Column | Content |
|
|
183
|
+
|---|---|
|
|
184
|
+
| **What** | The missing tool/service/credential. |
|
|
185
|
+
| **Why** | Which spec, script, or library introduced this requirement (e.g. "`backend/api.plain` says `using FastAPI`", "`test_scripts/run_unittests_python.sh` calls `pytest`"). |
|
|
186
|
+
| **Status** | "missing", "outdated (found X, need Y)", "binary present but service not running", or "env var not set". |
|
|
187
|
+
| **How to install** | OS-specific command(s). See [Install suggestions](#install-suggestions) below. |
|
|
188
|
+
|
|
189
|
+
Group the report into the same six probe groups used in Step 3 (toolchains, codeplain/git, services, system binaries, hardware, credentials), so the user can fix one whole layer at a time.
|
|
190
|
+
|
|
191
|
+
End the report with a one-liner reminder: `Re-run check-plain-env after installing missing items to confirm.`
|
|
192
|
+
|
|
193
|
+
## Install suggestions
|
|
194
|
+
|
|
195
|
+
When emitting an install command, **match the host OS** detected in Step 1. Prefer the OS's first-party package manager. Don't suggest `curl | sh` style installs unless there is no alternative.
|
|
196
|
+
|
|
197
|
+
The tables below are a **starter set** of well-known install commands for the things projects most often need. They are **not** a list of "things to check" — that list is derived per project in Step 2. When the requirement list contains something not in these tables (e.g. a niche service, a specialty CLI), look up the canonical install command for the detected OS at the time of report generation rather than skipping the row or inventing a command.
|
|
198
|
+
|
|
199
|
+
### macOS (Darwin)
|
|
200
|
+
|
|
201
|
+
| Requirement | Suggested install |
|
|
202
|
+
|---|---|
|
|
203
|
+
| Python 3 | `brew install python@3.12` |
|
|
204
|
+
| Node.js | `brew install node` (or `brew install nvm` for multi-version) |
|
|
205
|
+
| Go | `brew install go` |
|
|
206
|
+
| Rust | `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \| sh` (no Homebrew equivalent that stays current) |
|
|
207
|
+
| Java | `brew install openjdk@21` then follow the post-install `sudo ln -sfn ...` step |
|
|
208
|
+
| Maven | `brew install maven` |
|
|
209
|
+
| Gradle | `brew install gradle` |
|
|
210
|
+
| PostgreSQL | `brew install postgresql@16` then `brew services start postgresql@16` |
|
|
211
|
+
| MySQL | `brew install mysql` then `brew services start mysql` |
|
|
212
|
+
| Redis | `brew install redis` then `brew services start redis` |
|
|
213
|
+
| Docker | Install Docker Desktop from https://docker.com/products/docker-desktop |
|
|
214
|
+
| `pg_config` (psycopg) | comes with `brew install postgresql@16` |
|
|
215
|
+
| Xcode CLT | `xcode-select --install` |
|
|
216
|
+
| `codeplain` | follow the install instructions at https://codeplain.ai |
|
|
217
|
+
|
|
218
|
+
### Linux (Debian/Ubuntu)
|
|
219
|
+
|
|
220
|
+
| Requirement | Suggested install |
|
|
221
|
+
|---|---|
|
|
222
|
+
| Python 3 | `sudo apt update && sudo apt install -y python3 python3-pip python3-venv` |
|
|
223
|
+
| Node.js | `curl -fsSL https://deb.nodesource.com/setup_20.x \| sudo -E bash - && sudo apt install -y nodejs` |
|
|
224
|
+
| Go | `sudo apt install -y golang-go` (or download from https://go.dev/dl/ for the latest) |
|
|
225
|
+
| Rust | `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \| sh` |
|
|
226
|
+
| Java | `sudo apt install -y openjdk-21-jdk` |
|
|
227
|
+
| Maven | `sudo apt install -y maven` |
|
|
228
|
+
| PostgreSQL | `sudo apt install -y postgresql postgresql-contrib && sudo systemctl start postgresql` |
|
|
229
|
+
| Redis | `sudo apt install -y redis-server && sudo systemctl start redis-server` |
|
|
230
|
+
| Docker | follow https://docs.docker.com/engine/install/ubuntu/ |
|
|
231
|
+
| `pg_config` (psycopg) | `sudo apt install -y libpq-dev` |
|
|
232
|
+
| C/C++ build tools | `sudo apt install -y build-essential` |
|
|
233
|
+
|
|
234
|
+
### Linux (Fedora/RHEL)
|
|
235
|
+
|
|
236
|
+
Equivalent commands with `sudo dnf install -y ...` instead of `apt`. Surface them when the host is detected as Fedora/RHEL (e.g. presence of `/etc/redhat-release` or `dnf --version` succeeding).
|
|
237
|
+
|
|
238
|
+
### Windows (native PowerShell)
|
|
239
|
+
|
|
240
|
+
| Requirement | Suggested install |
|
|
241
|
+
|---|---|
|
|
242
|
+
| Python 3 | `winget install Python.Python.3.12` or `choco install python` |
|
|
243
|
+
| Node.js | `winget install OpenJS.NodeJS.LTS` or `choco install nodejs-lts` |
|
|
244
|
+
| Go | `winget install GoLang.Go` |
|
|
245
|
+
| Rust | `winget install Rustlang.Rustup` |
|
|
246
|
+
| Java | `winget install Microsoft.OpenJDK.21` |
|
|
247
|
+
| PostgreSQL | `winget install PostgreSQL.PostgreSQL` |
|
|
248
|
+
| Docker | `winget install Docker.DockerDesktop` |
|
|
249
|
+
| MSVC build tools | `winget install Microsoft.VisualStudio.2022.BuildTools` |
|
|
250
|
+
|
|
251
|
+
If the project's `test_scripts/` are `.sh` only and the host is native Windows, suggest **WSL** (`wsl --install`) rather than trying to make Bash scripts run under PowerShell.
|
|
252
|
+
|
|
253
|
+
### When you can't pick
|
|
254
|
+
|
|
255
|
+
When the host OS detection in Step 1 was inconclusive (e.g. an unrecognized Linux distro), include the macOS and Debian/Ubuntu commands and tell the user to adapt for their package manager. Never invent install commands for a distro you can't identify.
|
|
256
|
+
|
|
257
|
+
## Anti-patterns
|
|
258
|
+
|
|
259
|
+
- **(Hard mistake) Don't probe individual language packages.** Anything `pip install -r requirements.txt`, `npm ci`, `mvn install`, `cargo fetch`, `go mod download`, `bundle install`, `composer install`, etc. would resolve is out of scope. `torch`, `requests`, `numpy`, `FastAPI`, `express`, `react`, JARs, gems, crates — all package-manager territory. Check the toolchain (`python3`, `pip`, `node`, `npm`, `mvn`, `cargo`, ...) and stop there. Probing the package itself creates false negatives the moment `requirements.txt` changes and duplicates work the test scripts will do anyway.
|
|
260
|
+
- **Don't stop after the directly named technologies.** A spec that says "fine-tune on local hardware using PyTorch" never says "CUDA", but the workflow can't run without CUDA. Always work through Category 3 (system binaries that language packages wrap) and Category 4 (hardware/drivers) — not only the directly named runtimes. These categories are where the workflow's hidden requirements live.
|
|
261
|
+
- **Don't merge a chain of failures into one generic message.** "GPU not available" is not a useful report. The chain is `driver → device visibility → toolkit → acceleration libs → framework-sees-it → version match`; each layer has a different fix. Surface each layer separately.
|
|
262
|
+
- **Don't work only from `.plain` files.** Always cross-reference with `test_scripts/` — the scripts are the executable contract. If a script invokes a non-language binary the specs never mention, that binary is automatically a Category 3 requirement.
|
|
263
|
+
- **Don't pre-bake a catalog.** Derive the requirement list at runtime from the project in front of you. A hard-coded "things to always check" table becomes wrong the moment any project deviates from the assumed shape — and every project does.
|
|
264
|
+
- **Don't probe testing framework binaries as if they were independent.** `pytest`, `jest`, `vitest`, `phpunit`, `junit-console`, etc. are installed by the package manager via `requirements.txt` / `package.json` / `pom.xml`. The toolchain check (Category 1) is enough — the framework binary itself is out of scope.
|
|
265
|
+
- **Don't probe in silence.** Use the `terminal` tool and capture the actual command output (version strings, exit codes). Telling the user "looks like Python is installed" without running `python3 --version` is guessing.
|
|
266
|
+
- **Don't print secret values.** Check whether `CODEPLAIN_API_KEY`, `DATABASE_URL`, etc. are set, not what they contain. Use `printenv VAR >/dev/null` not `printenv VAR`.
|
|
267
|
+
- **Don't install anything on the user's behalf.** Even when the install command is obvious. The user needs to opt in.
|
|
268
|
+
- **Don't stop at the first FAIL.** Run the full sweep so the report is complete in one pass.
|
|
269
|
+
- **Don't suggest `curl | sh` installs when a package manager works.** Reserve the upstream installer fallback for cases where no package-manager option exists (e.g. `rustup`, sometimes Go).
|
|
270
|
+
- **Don't ignore version mismatches.** If a spec says Java 17 and the host has Java 21, surface that as a `WARN` so the user can decide — don't silently let it pass.
|
|
271
|
+
- **Don't duplicate this check inline elsewhere.** Other skills (`forge-plain`, `add-feature`, `plain-healthcheck`) that need an env check should **delegate to `check-plain-env`** rather than re-implementing the probe themselves. This skill is the single source of truth.
|
|
272
|
+
|
|
273
|
+
## Validation Checklist
|
|
274
|
+
|
|
275
|
+
- [ ] Host OS detected (`uname -s` / `$OS`) before any other action.
|
|
276
|
+
- [ ] Requirement list derived **at runtime from this project's** `.plain` files, `test_scripts/`, `config.yaml`(s), and `resources/` — no pre-baked catalog used.
|
|
277
|
+
- [ ] **No individual language packages probed.** Only the toolchain + package manager for each detected language.
|
|
278
|
+
- [ ] Every script under `test_scripts/` opened and read; every non-language binary it invokes added to the Category 3 list.
|
|
279
|
+
- [ ] Every external service named in the specs is in the Category 2 list, with both a binary probe and (when feasible) a reachability probe.
|
|
280
|
+
- [ ] Every hardware / accelerator signal ("GPU", "fine-tune", "local inference", "CUDA", "MPS", etc.) triggered the layered Category 4 probe.
|
|
281
|
+
- [ ] Every requirement probed via the `terminal` tool with an actual version / availability command (no "looks installed" guesses).
|
|
282
|
+
- [ ] GPU / accelerator chains probed layer-by-layer (driver → device visibility → toolkit → acceleration libs → framework-sees-it → version match), with each layer reported separately.
|
|
283
|
+
- [ ] Each result classified as PASS / WARN / FAIL.
|
|
284
|
+
- [ ] Report has the verdict on the first line.
|
|
285
|
+
- [ ] Every FAIL and WARN row has all four columns: What / Why / Status / How to install.
|
|
286
|
+
- [ ] Install suggestions match the detected host OS (no Debian commands on macOS, no `brew` on Linux, etc.).
|
|
287
|
+
- [ ] No secret values were printed at any point.
|
|
288
|
+
- [ ] Nothing was installed; no project files were modified.
|