executant 1.6.0 → 1.8.0

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.
@@ -52,10 +52,27 @@ Complete structure with all available options:
52
52
  "forEach": "git diff --name-only HEAD~1",
53
53
  "prompt": "Review {{item}} for issues and suggest improvements."
54
54
  },
55
+ {
56
+ "name": "foreach_multi_step",
57
+ "forEach": ["pkg/api", "pkg/web"],
58
+ "steps": [
59
+ { "name": "lint {{item}}", "type": "script", "command": "cd {{item}} && npm run lint" },
60
+ { "name": "test {{item}}", "type": "script", "command": "cd {{item}} && npm test" },
61
+ { "name": "review {{item}}", "prompt": "Review the test results for {{item}} and summarize any issues." }
62
+ ]
63
+ },
55
64
  {
56
65
  "name": "repeated_audit",
57
66
  "repeat": 20,
58
67
  "prompt": "Review the codebase for issues. This is pass {{item}} of 20."
68
+ },
69
+ {
70
+ "name": "repeated_multi_step",
71
+ "repeat": 3,
72
+ "steps": [
73
+ { "name": "build pass {{item}}", "type": "script", "command": "npm run build" },
74
+ { "name": "test pass {{item}}", "type": "script", "command": "npm test" }
75
+ ]
59
76
  }
60
77
  ]
61
78
  }
@@ -94,6 +111,9 @@ or commands.
94
111
 
95
112
  **Pre-Output Self-Review — Vars (MANDATORY):**
96
113
  Before finalising your JSON, scan every `prompt` and `command` field you wrote — every sentence, every numbered instruction, every parenthetical.
114
+
115
+ **`{{item}}` is NOT a path — never extract it to `vars`.** It is a runtime placeholder that the runner substitutes per iteration. Only treat actual string literals as paths requiring `vars` extraction.
116
+
97
117
  For each field, identify ALL occurrences of paths, including:
98
118
  - Direct path references (e.g., `src/middleware/rate-limit.ts`)
99
119
  - Paths mentioned in narrative context (e.g., "match the style of tests in `src/tests/`")
@@ -158,11 +178,30 @@ Use the EXACT commands from the research document. Only skip a category if the r
158
178
 
159
179
  **REQUIRED: Always use `forEach` instead of enumerating items inline in a prompt.**
160
180
 
181
+ **Use nested `steps:` inside `forEach` or `repeat` when:**
182
+ - Each iteration requires **two or more** distinct actions (e.g., lint THEN test THEN review) — if there is only one action per item, use `command` or `prompt` directly on the forEach step instead
183
+ - Replace `command`/`prompt` on the forEach step with a `steps` array of child steps
184
+ - Child steps support all standard step fields (`type`, `command`, `prompt`, `llm_as_judge`, etc.)
185
+ - `{{item}}` substitution applies to all child step `name`, `command`, and `prompt` fields
186
+ - Mutually exclusive with `command`/`prompt` on the parent step
187
+
188
+ ```json
189
+ {
190
+ "name": "process each package",
191
+ "forEach": ["pkg/api", "pkg/web"],
192
+ "steps": [
193
+ { "name": "lint {{item}}", "type": "script", "command": "cd {{item}} && npm run lint" },
194
+ { "name": "test {{item}}", "type": "script", "command": "cd {{item}} && npm test" }
195
+ ]
196
+ }
197
+ ```
198
+
161
199
  **Use `repeat: N` when:**
162
200
  - The user asks to run the same prompt or command multiple times ("do this 20 times", "repeat 5 times", "run N iterations")
163
201
  - The step is identical each time — only the iteration number ({{item}}) differs
164
202
  - Prefer `repeat` over `forEach` when there is no meaningful list of items — just a count
165
203
  - NEVER expand "do X N times" into N separate steps — always use `repeat: N`
204
+ - Combine with nested `steps:` when each iteration needs multiple sub-steps
166
205
 
167
206
  ## Atomicity (MANDATORY)
168
207
 
@@ -231,6 +270,7 @@ Generate a JSON object that:
231
270
  10. Uses `output:` + `context:` to pass script step results to downstream prompt steps
232
271
  11. Declares ALL file paths in `vars` — no hardcoded paths in prompts or commands, including paths in narrative or example context
233
272
  12. Places `vars` before `steps` in the JSON output
273
+ 13. Uses nested `steps:` inside `forEach`/`repeat` when each iteration needs multiple sequential actions
234
274
 
235
275
  ## Critical Rules
236
276
 
@@ -35,6 +35,7 @@ Does the workflow contain at least one of: a lint step, a test step, or a build
35
35
 
36
36
  - Look for `type: "script"` steps whose `command` runs a linter, test runner, or build tool
37
37
  (e.g., `npm run lint`, `npm test`, `npm run build`, `pytest`, `tsc --noEmit`, `go test`, etc.)
38
+ - **This includes script steps nested inside a `forEach` or `repeat`'s `steps:` array** — a lint/test/build step inside a loop's child steps satisfies the verification requirement
38
39
  - A workflow with ZERO verification steps automatically FAILS regardless of other criteria
39
40
  - A visual check prompt step with `llm_as_judge: true` as the final step is acceptable if no
40
41
  lint/test/build commands exist in the project
@@ -45,6 +46,7 @@ Are steps focused on a single concern?
45
46
  - Does any step do more than one distinct thing (e.g., "implement AND test")?
46
47
  - Could any step be meaningfully split into two smaller steps?
47
48
  - Steps that combine unrelated operations are too large
49
+ - **Exception**: A `forEach`/`repeat` step with a nested `steps:` array is NOT an atomicity violation — each child step should itself be atomic, and the parent is a loop container, not a combined action
48
50
 
49
51
  ### 3. Goal Coverage
50
52
  Do the steps collectively accomplish the stated goal?
@@ -83,7 +85,7 @@ or
83
85
  ```
84
86
 
85
87
  Rules:
86
- - `pass` is `true` only if ALL four criteria above are met
88
+ - `pass` is `true` only if ALL five criteria above are met
87
89
  - `feedback` is an empty string when `pass` is `true`
88
90
  - `feedback` must be specific and actionable when `pass` is `false` — say EXACTLY what is wrong
89
91
  and what the decomposer must do to fix it
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "executant",
3
- "version": "1.6.0",
3
+ "version": "1.8.0",
4
4
  "description": "Harness for YAML-defined workflows that enables stepping through Claude sessions and bash commands",
5
5
  "repository": {
6
6
  "type": "git",
@@ -44,6 +44,7 @@
44
44
  "husky": "^9.1.7",
45
45
  "knip": "^5.88.1",
46
46
  "lint-staged": "^16.4.0",
47
+ "prettier": "^3.8.3",
47
48
  "semantic-release": "^24.2.9",
48
49
  "tsx": "^4.15.7",
49
50
  "typescript": "^5.4.5",
@@ -55,7 +56,10 @@
55
56
  ]
56
57
  },
57
58
  "lint-staged": {
58
- "*.{ts,tsx}": "eslint --fix"
59
+ "*.{ts,tsx}": [
60
+ "prettier --write",
61
+ "eslint --fix"
62
+ ]
59
63
  },
60
64
  "release": {
61
65
  "plugins": [