pi-loopflows 0.1.0 → 0.1.2
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/CHANGELOG.md +13 -0
- package/README.md +164 -45
- package/loopflows/build-review.loopflow.json +48 -0
- package/loopflows/plan-review.loopflow.json +48 -0
- package/package.json +6 -4
- package/scripts/validate.mjs +71 -0
- package/skills/loopflows/SKILL.md +12 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.2 - 2026-06-22
|
|
4
|
+
|
|
5
|
+
- Tighten README positioning around loopflows as LEGO-like subagent workflows.
|
|
6
|
+
- Remove the dedicated Launch Control README section while keeping it listed as a bundled workflow.
|
|
7
|
+
|
|
8
|
+
## 0.1.1 - 2026-06-22
|
|
9
|
+
|
|
10
|
+
- Polish product README and usage guidance for public release.
|
|
11
|
+
- Add bundled `build-review` loopflow for lightweight implementation feedback loops.
|
|
12
|
+
- Add bundled `plan-review` loopflow for plan quality gates before implementation.
|
|
13
|
+
- Expand loopflows skill instructions.
|
|
14
|
+
- Clarify adapter/backend direction for future compatible executors.
|
|
15
|
+
|
|
3
16
|
## 0.1.0 - 2026-06-22
|
|
4
17
|
|
|
5
18
|
- Initial release.
|
package/README.md
CHANGED
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
# pi-loopflows
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Build deterministic AI workflows out of Pi subagents.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Think of **loopflows** as LEGO for subagents. You take small specialist agents, connect them into a process, add gates where decisions matter, and let the workflow move forward, branch, loop back, or stop based on explicit results. Instead of one giant prompt, you get a reusable structure for how agents collaborate: steps, feedback loops, stop rules, and saved evidence.
|
|
6
6
|
|
|
7
|
-
## Why
|
|
7
|
+
## Why loopflows
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Linear chains are useful, but real work is not always linear. A reviewer can request changes. A validator can reject missing evidence. A planner can reveal that the task is blocked. A builder may need several focused passes before the result is safe to accept.
|
|
10
|
+
|
|
11
|
+
Loopflows make that control flow explicit:
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
step → step → gate
|
|
15
|
+
↓
|
|
16
|
+
approved → continue
|
|
17
|
+
changes_requested → loop back
|
|
18
|
+
blocked → stop
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The philosophy is simple: AI should work through a process, not just produce a confident answer. A loopflow defines who does the work, who checks it, what counts as success, how many attempts are allowed, where evidence is saved, and when the run must stop instead of guessing.
|
|
10
22
|
|
|
11
23
|
## Install
|
|
12
24
|
|
|
@@ -14,19 +26,19 @@ Normal chains are linear. Real work is not. A reviewer may request changes, a bu
|
|
|
14
26
|
pi install npm:pi-loopflows
|
|
15
27
|
```
|
|
16
28
|
|
|
17
|
-
|
|
29
|
+
`pi-loopflows` uses Pi subagent definitions as its first backend. Install `pi-subagents` if you have not already:
|
|
18
30
|
|
|
19
31
|
```bash
|
|
20
|
-
pi install
|
|
32
|
+
pi install npm:pi-subagents
|
|
21
33
|
```
|
|
22
34
|
|
|
23
|
-
|
|
35
|
+
Then reload Pi:
|
|
24
36
|
|
|
25
37
|
```text
|
|
26
38
|
/reload
|
|
27
39
|
```
|
|
28
40
|
|
|
29
|
-
## What
|
|
41
|
+
## What you get
|
|
30
42
|
|
|
31
43
|
### Tool
|
|
32
44
|
|
|
@@ -45,35 +57,55 @@ loopflow_run({
|
|
|
45
57
|
/loopflow launch-control -- Implement this approved backend plan
|
|
46
58
|
```
|
|
47
59
|
|
|
48
|
-
###
|
|
60
|
+
### Built-in loopflows
|
|
49
61
|
|
|
50
|
-
`launch-control
|
|
62
|
+
- `launch-control` — plan-as-contract implementation loop with builder/reviewer feedback and final audit.
|
|
63
|
+
- `build-review` — small generic build → review → fix loop for scoped implementation tasks.
|
|
64
|
+
- `plan-review` — planning loop that lets a reviewer reject vague or unsafe plans before implementation.
|
|
51
65
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
66
|
+
## Loopflows as a constructor
|
|
67
|
+
|
|
68
|
+
Think of loopflows as LEGO for agent processes. A loopflow can use any available Pi subagent role:
|
|
69
|
+
|
|
70
|
+
- `context-builder`
|
|
71
|
+
- `scout`
|
|
72
|
+
- `researcher`
|
|
73
|
+
- `planner`
|
|
74
|
+
- `worker`
|
|
75
|
+
- `reviewer`
|
|
76
|
+
- `oracle`
|
|
77
|
+
- your own custom agents
|
|
78
|
+
|
|
79
|
+
You decide:
|
|
80
|
+
|
|
81
|
+
- which agent runs first;
|
|
82
|
+
- what each agent receives;
|
|
83
|
+
- which output is saved;
|
|
84
|
+
- which step is a gate;
|
|
85
|
+
- what statuses mean pass, retry, or stop;
|
|
86
|
+
- how many loop iterations are allowed;
|
|
87
|
+
- where artifacts go;
|
|
88
|
+
- what final audit should prove.
|
|
89
|
+
|
|
90
|
+
Today, the backend runs Pi-compatible subagents. The engine is intentionally built behind an adapter boundary, so future versions can add other compatible backends — Codex CLI, OpenCode, ACP workers, remote agents, or custom executors — without changing the loopflow concept.
|
|
63
91
|
|
|
64
92
|
## Loopflow files
|
|
65
93
|
|
|
66
|
-
Loopflows are JSON files named
|
|
94
|
+
Loopflows are JSON files named:
|
|
95
|
+
|
|
96
|
+
```text
|
|
97
|
+
*.loopflow.json
|
|
98
|
+
```
|
|
67
99
|
|
|
68
100
|
Discovery locations:
|
|
69
101
|
|
|
70
|
-
- bundled package
|
|
71
|
-
- user: `~/.pi/agent/loopflows
|
|
72
|
-
- project: `.pi/loopflows
|
|
102
|
+
- bundled package loopflows;
|
|
103
|
+
- user loopflows: `~/.pi/agent/loopflows/`;
|
|
104
|
+
- project loopflows: `.pi/loopflows/`.
|
|
73
105
|
|
|
74
|
-
Project loopflows
|
|
106
|
+
Project loopflows are the easiest way to customize behavior for one repo.
|
|
75
107
|
|
|
76
|
-
## Minimal
|
|
108
|
+
## Minimal example
|
|
77
109
|
|
|
78
110
|
```json
|
|
79
111
|
{
|
|
@@ -114,14 +146,39 @@ Project loopflows can override or add workflows for a repo.
|
|
|
114
146
|
|
|
115
147
|
## Template variables
|
|
116
148
|
|
|
117
|
-
- `{task}` — original user task
|
|
118
|
-
- `{previous}` — previous step output
|
|
119
|
-
- `{outputs.stepId}` — output from a named step
|
|
120
|
-
- `{outputs.stepId.
|
|
121
|
-
- `{outputs.stepId.
|
|
122
|
-
- `{
|
|
123
|
-
- `{
|
|
124
|
-
- `{
|
|
149
|
+
- `{task}` — original user task.
|
|
150
|
+
- `{previous}` — previous step output.
|
|
151
|
+
- `{outputs.stepId}` — output from a named step.
|
|
152
|
+
- `{outputs.stepId.output}` — same as above, explicit form.
|
|
153
|
+
- `{outputs.stepId.status}` — parsed gate status.
|
|
154
|
+
- `{outputs.stepId.json}` — parsed gate JSON.
|
|
155
|
+
- `{loop.iteration}` — current loop iteration.
|
|
156
|
+
- `{artifactsDir}` — current run artifact directory.
|
|
157
|
+
- `{params.name}` — runtime params passed to `loopflow_run`.
|
|
158
|
+
|
|
159
|
+
## Gate contract
|
|
160
|
+
|
|
161
|
+
Gate steps should return JSON. A typical reviewer gate returns:
|
|
162
|
+
|
|
163
|
+
```json
|
|
164
|
+
{
|
|
165
|
+
"status": "approved",
|
|
166
|
+
"summary": "The implementation satisfies the plan.",
|
|
167
|
+
"findings": [],
|
|
168
|
+
"validation_gaps": [],
|
|
169
|
+
"requires_user_decision": false
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Common statuses:
|
|
174
|
+
|
|
175
|
+
- `approved` — move forward.
|
|
176
|
+
- `changes_requested` — loop back for another pass.
|
|
177
|
+
- `blocked` — stop; user or environment action is required.
|
|
178
|
+
- `complete` — final audit passed.
|
|
179
|
+
- `incomplete` — final audit failed.
|
|
180
|
+
|
|
181
|
+
Each loopflow decides which statuses pass, retry, or stop.
|
|
125
182
|
|
|
126
183
|
## Artifacts
|
|
127
184
|
|
|
@@ -131,7 +188,7 @@ Every run writes evidence to:
|
|
|
131
188
|
<cwd>/.pi/loopflows/runs/<timestamp>-<workflow>/
|
|
132
189
|
```
|
|
133
190
|
|
|
134
|
-
Typical
|
|
191
|
+
Typical artifacts:
|
|
135
192
|
|
|
136
193
|
```text
|
|
137
194
|
task.md
|
|
@@ -144,30 +201,92 @@ final-audit.json
|
|
|
144
201
|
summary.md
|
|
145
202
|
```
|
|
146
203
|
|
|
204
|
+
This makes loopflows inspectable. You can see what each agent claimed, what the gate decided, and why the run stopped or passed.
|
|
205
|
+
|
|
206
|
+
## Customization patterns
|
|
207
|
+
|
|
208
|
+
### Make Launch Control stricter
|
|
209
|
+
|
|
210
|
+
Copy the bundled file:
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
mkdir -p .pi/loopflows
|
|
214
|
+
cp ~/.pi/agent/npm/node_modules/pi-loopflows/loopflows/launch-control.loopflow.json \
|
|
215
|
+
.pi/loopflows/launch-control.loopflow.json
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Then edit the project copy. Common changes:
|
|
219
|
+
|
|
220
|
+
- increase `maxIterations`;
|
|
221
|
+
- change `reviewer` to a custom security reviewer;
|
|
222
|
+
- add stricter validation language;
|
|
223
|
+
- add a docs or migration audit step;
|
|
224
|
+
- change stop statuses;
|
|
225
|
+
- make the final audit require `complete` only.
|
|
226
|
+
|
|
227
|
+
### Create a lightweight workflow
|
|
228
|
+
|
|
229
|
+
Use `build-review` for small implementation tasks where full Launch Control is too formal.
|
|
230
|
+
|
|
231
|
+
```text
|
|
232
|
+
/loopflow build-review -- Add validation to the import endpoint
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Review a plan before coding
|
|
236
|
+
|
|
237
|
+
Use `plan-review` when you want a plan to be checked before a worker touches files.
|
|
238
|
+
|
|
239
|
+
```text
|
|
240
|
+
/loopflow plan-review -- Plan the database migration for workspace roles
|
|
241
|
+
```
|
|
242
|
+
|
|
147
243
|
## Backend design
|
|
148
244
|
|
|
149
|
-
The
|
|
245
|
+
The runtime uses an executor adapter boundary:
|
|
150
246
|
|
|
151
247
|
```ts
|
|
152
248
|
runAgent(agent, task, options) -> StepResult
|
|
153
249
|
```
|
|
154
250
|
|
|
155
|
-
Current backend:
|
|
251
|
+
Current backend:
|
|
156
252
|
|
|
157
|
-
|
|
253
|
+
- Pi subprocess agents compatible with `pi-subagents` agent definitions.
|
|
158
254
|
|
|
159
|
-
|
|
255
|
+
Future-compatible backend ideas:
|
|
160
256
|
|
|
161
|
-
-
|
|
162
|
-
-
|
|
257
|
+
- Codex CLI workers;
|
|
258
|
+
- OpenCode workers;
|
|
259
|
+
- ACP-compatible agents;
|
|
260
|
+
- remote worker pools;
|
|
261
|
+
- project-specific executors.
|
|
163
262
|
|
|
164
|
-
|
|
165
|
-
|
|
263
|
+
The point is that loopflows describe the process. The backend decides how each agent is actually executed.
|
|
264
|
+
|
|
265
|
+
## When to use loopflows vs chains
|
|
266
|
+
|
|
267
|
+
Use normal Pi subagent chains when the process is linear:
|
|
268
|
+
|
|
269
|
+
```text
|
|
270
|
+
scout → planner → worker
|
|
166
271
|
```
|
|
167
272
|
|
|
273
|
+
Use loopflows when a step can send work backward or stop the process:
|
|
274
|
+
|
|
275
|
+
```text
|
|
276
|
+
worker → reviewer → worker → reviewer
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
If you need a feedback loop, a quality gate, a max iteration limit, or saved evidence, use a loopflow.
|
|
280
|
+
|
|
168
281
|
## Status
|
|
169
282
|
|
|
170
|
-
|
|
283
|
+
`pi-loopflows` is early, but designed as a real product surface rather than a one-off script. The core model is intentionally small:
|
|
284
|
+
|
|
285
|
+
```text
|
|
286
|
+
steps + loops + gates + artifacts + adapters
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
That is enough to build useful workflows without turning the extension into a giant orchestration platform.
|
|
171
290
|
|
|
172
291
|
## License
|
|
173
292
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "build-review",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Generic scoped implementation loop: plan, build, independent review, repeat fixes until approved or blocked.",
|
|
5
|
+
"backend": "pi-subprocess",
|
|
6
|
+
"defaults": {
|
|
7
|
+
"agentScope": "both"
|
|
8
|
+
},
|
|
9
|
+
"steps": [
|
|
10
|
+
{
|
|
11
|
+
"id": "plan",
|
|
12
|
+
"agent": "planner",
|
|
13
|
+
"output": "plan.md",
|
|
14
|
+
"task": "Create a concise implementation plan for this task:\n\n{task}\n\nInclude acceptance criteria, likely files, validation commands, non-goals, and stop conditions. Do not edit files."
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"loop": {
|
|
18
|
+
"id": "build-review",
|
|
19
|
+
"maxIterations": 3,
|
|
20
|
+
"gateStep": "review",
|
|
21
|
+
"passStatuses": ["approved"],
|
|
22
|
+
"retryStatuses": ["changes_requested"],
|
|
23
|
+
"stopStatuses": ["blocked"],
|
|
24
|
+
"onExhausted": "stop",
|
|
25
|
+
"body": [
|
|
26
|
+
{
|
|
27
|
+
"id": "build",
|
|
28
|
+
"agent": "worker",
|
|
29
|
+
"output": "build-{loop.iteration}.md",
|
|
30
|
+
"task": "Implement or fix iteration {loop.iteration}.\n\nTask:\n{task}\n\nPlan:\n{outputs.plan}\n\nPrevious review, if any:\n{outputs.review.output}\n\nIf this is iteration 1, implement the planned change. If this is a later iteration, apply only required reviewer fixes. Use the real project stack. Do not add mocks, demos, fake validation, or hidden fallbacks unless explicitly requested. Run focused validation and report changed files, commands with exit codes, evidence, blockers, and remaining risks."
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"id": "review",
|
|
34
|
+
"agent": "reviewer",
|
|
35
|
+
"output": "review-{loop.iteration}.json",
|
|
36
|
+
"gate": {
|
|
37
|
+
"type": "json-status",
|
|
38
|
+
"passStatuses": ["approved"],
|
|
39
|
+
"retryStatuses": ["changes_requested"],
|
|
40
|
+
"stopStatuses": ["blocked"]
|
|
41
|
+
},
|
|
42
|
+
"task": "Review iteration {loop.iteration}. Do not edit project/source files.\n\nTask:\n{task}\n\nPlan:\n{outputs.plan}\n\nBuilder report:\n{outputs.build.output}\n\nReturn ONLY valid JSON:\n{\n \"status\": \"approved\" | \"changes_requested\" | \"blocked\",\n \"summary\": \"short verdict\",\n \"findings\": [{\"severity\": \"blocker|required|optional\", \"file\": \"path or null\", \"issue\": \"specific issue\", \"required_fix\": \"specific fix or null\"}],\n \"validation_gaps\": [\"gap\"],\n \"requires_user_decision\": false\n}\n\nApprove only if the implementation and evidence satisfy the plan. Request changes for required fixable issues. Block for missing credentials, missing decisions, unsafe scope, or stale plan."
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "plan-review",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Planning loop: gather context, draft a plan, review the plan, and revise until approved or blocked before implementation.",
|
|
5
|
+
"backend": "pi-subprocess",
|
|
6
|
+
"defaults": {
|
|
7
|
+
"agentScope": "both"
|
|
8
|
+
},
|
|
9
|
+
"steps": [
|
|
10
|
+
{
|
|
11
|
+
"id": "context",
|
|
12
|
+
"agent": "context-builder",
|
|
13
|
+
"output": "context.md",
|
|
14
|
+
"task": "Build planning context for this task:\n\n{task}\n\nInspect the repository enough to identify relevant files, constraints, validation commands, risks, and unknowns. Do not edit files."
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"loop": {
|
|
18
|
+
"id": "plan-review",
|
|
19
|
+
"maxIterations": 2,
|
|
20
|
+
"gateStep": "review",
|
|
21
|
+
"passStatuses": ["approved"],
|
|
22
|
+
"retryStatuses": ["changes_requested"],
|
|
23
|
+
"stopStatuses": ["blocked"],
|
|
24
|
+
"onExhausted": "stop",
|
|
25
|
+
"body": [
|
|
26
|
+
{
|
|
27
|
+
"id": "plan",
|
|
28
|
+
"agent": "planner",
|
|
29
|
+
"output": "plan-{loop.iteration}.md",
|
|
30
|
+
"task": "Draft or revise implementation plan iteration {loop.iteration}.\n\nTask:\n{task}\n\nContext:\n{outputs.context}\n\nPrevious review, if any:\n{outputs.review.output}\n\nReturn a practical implementation plan with scope, non-goals, acceptance criteria, likely files, validation commands, risks, and open questions. Do not edit files."
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"id": "review",
|
|
34
|
+
"agent": "reviewer",
|
|
35
|
+
"output": "plan-review-{loop.iteration}.json",
|
|
36
|
+
"gate": {
|
|
37
|
+
"type": "json-status",
|
|
38
|
+
"passStatuses": ["approved"],
|
|
39
|
+
"retryStatuses": ["changes_requested"],
|
|
40
|
+
"stopStatuses": ["blocked"]
|
|
41
|
+
},
|
|
42
|
+
"task": "Review this implementation plan before any code is written. Do not edit files.\n\nTask:\n{task}\n\nContext:\n{outputs.context}\n\nPlan:\n{outputs.plan}\n\nReturn ONLY valid JSON:\n{\n \"status\": \"approved\" | \"changes_requested\" | \"blocked\",\n \"summary\": \"short verdict\",\n \"findings\": [{\"severity\": \"blocker|required|optional\", \"issue\": \"specific issue\", \"required_fix\": \"specific plan change or null\"}],\n \"missing_acceptance_criteria\": [\"criterion\"],\n \"requires_user_decision\": false\n}\n\nApprove only if the plan is specific, scoped, testable, and safe to hand to a worker. Request changes for vague scope, missing validation, or unclear acceptance criteria. Block when user/product decisions or credentials are required."
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-loopflows",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Deterministic loop workflows for Pi subagents: steps, gates, feedback loops, and artifacts.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Nikita Nosov <20nik.nosov21@gmail.com>",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"extensions",
|
|
27
27
|
"loopflows",
|
|
28
28
|
"skills",
|
|
29
|
+
"scripts",
|
|
29
30
|
"README.md",
|
|
30
31
|
"LICENSE",
|
|
31
32
|
"CHANGELOG.md"
|
|
@@ -36,8 +37,7 @@
|
|
|
36
37
|
],
|
|
37
38
|
"skills": [
|
|
38
39
|
"./skills"
|
|
39
|
-
]
|
|
40
|
-
"image": "https://raw.githubusercontent.com/nik1t7n/pi-loopflows/main/assets/pi-loopflows.png"
|
|
40
|
+
]
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
43
|
"@earendil-works/pi-coding-agent": "*",
|
|
@@ -51,6 +51,8 @@
|
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|
|
53
53
|
"typecheck": "tsc --noEmit",
|
|
54
|
-
"pack:check": "npm pack --dry-run"
|
|
54
|
+
"pack:check": "npm pack --dry-run",
|
|
55
|
+
"validate": "node scripts/validate.mjs",
|
|
56
|
+
"prepublishOnly": "npm run validate && npm run typecheck && npm run pack:check"
|
|
55
57
|
}
|
|
56
58
|
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
const root = path.resolve(new URL('..', import.meta.url).pathname);
|
|
5
|
+
const loopflowsDir = path.join(root, 'loopflows');
|
|
6
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
|
|
7
|
+
|
|
8
|
+
const errors = [];
|
|
9
|
+
|
|
10
|
+
function assert(condition, message) {
|
|
11
|
+
if (!condition) errors.push(message);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
assert(pkg.name === 'pi-loopflows', 'package name must be pi-loopflows');
|
|
15
|
+
assert(pkg.keywords?.includes('pi-package'), 'package must include pi-package keyword');
|
|
16
|
+
assert(pkg.pi?.extensions?.includes('./extensions'), 'package pi manifest must expose extensions');
|
|
17
|
+
assert(pkg.pi?.skills?.includes('./skills'), 'package pi manifest must expose skills');
|
|
18
|
+
|
|
19
|
+
const files = fs.readdirSync(loopflowsDir).filter((file) => file.endsWith('.loopflow.json'));
|
|
20
|
+
assert(files.length >= 3, 'expected bundled launch-control, build-review, and plan-review loopflows');
|
|
21
|
+
|
|
22
|
+
for (const file of files) {
|
|
23
|
+
const full = path.join(loopflowsDir, file);
|
|
24
|
+
let wf;
|
|
25
|
+
try {
|
|
26
|
+
wf = JSON.parse(fs.readFileSync(full, 'utf8'));
|
|
27
|
+
} catch (error) {
|
|
28
|
+
errors.push(`${file}: invalid JSON: ${error.message}`);
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
assert(typeof wf.name === 'string' && wf.name.length > 0, `${file}: missing name`);
|
|
33
|
+
assert(typeof wf.description === 'string' && wf.description.length > 0, `${file}: missing description`);
|
|
34
|
+
assert(Array.isArray(wf.steps) && wf.steps.length > 0, `${file}: steps must be a non-empty array`);
|
|
35
|
+
|
|
36
|
+
const topLevelIds = new Set();
|
|
37
|
+
for (const [index, node] of wf.steps.entries()) {
|
|
38
|
+
if (node.loop) {
|
|
39
|
+
const loop = node.loop;
|
|
40
|
+
assert(typeof loop.id === 'string' && loop.id.length > 0, `${file}: loop ${index} missing id`);
|
|
41
|
+
assert(Number.isInteger(loop.maxIterations) && loop.maxIterations > 0, `${file}: loop ${loop.id} maxIterations must be positive integer`);
|
|
42
|
+
assert(Array.isArray(loop.body) && loop.body.length > 0, `${file}: loop ${loop.id} body must be non-empty`);
|
|
43
|
+
assert(typeof loop.gateStep === 'string' && loop.gateStep.length > 0, `${file}: loop ${loop.id} missing gateStep`);
|
|
44
|
+
const bodyIds = new Set(loop.body.map((step) => step.id));
|
|
45
|
+
assert(bodyIds.has(loop.gateStep), `${file}: loop ${loop.id} gateStep not present in body`);
|
|
46
|
+
for (const step of loop.body) validateStep(file, step, `loop ${loop.id}`);
|
|
47
|
+
} else {
|
|
48
|
+
validateStep(file, node, `step ${index}`);
|
|
49
|
+
if (node.id) {
|
|
50
|
+
assert(!topLevelIds.has(node.id), `${file}: duplicate top-level step id ${node.id}`);
|
|
51
|
+
topLevelIds.add(node.id);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function validateStep(file, step, label) {
|
|
58
|
+
assert(typeof step.id === 'string' && step.id.length > 0, `${file}: ${label} missing id`);
|
|
59
|
+
assert(typeof step.agent === 'string' && step.agent.length > 0, `${file}: ${label} missing agent`);
|
|
60
|
+
assert(typeof step.task === 'string' && step.task.length > 0, `${file}: ${label} missing task`);
|
|
61
|
+
if (step.gate) {
|
|
62
|
+
assert(step.task.includes('JSON') || step.task.includes('json'), `${file}: gate step ${step.id} should explicitly request JSON`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (errors.length) {
|
|
67
|
+
console.error(errors.map((e) => `- ${e}`).join('\n'));
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
console.log(`Validated ${files.length} loopflows for ${pkg.name}@${pkg.version}`);
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: loopflows
|
|
3
|
-
description: Use when the user wants deterministic multi-agent workflows, feedback loops between builder/reviewer agents, launch-control style implementation gates,
|
|
3
|
+
description: Use when the user wants deterministic multi-agent workflows, feedback loops between builder/reviewer agents, launch-control style implementation gates, repeatable Pi subagent processes, or custom workflow construction with max iterations, gates, stop conditions, and artifacts.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Loopflows
|
|
7
7
|
|
|
8
|
-
Use `loopflow_run`
|
|
8
|
+
Use `loopflow_run` when a task needs process control, not just a linear chain.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
A loopflow is a reusable workflow made from subagent steps, gates, and loops. Use it when work should be checked, sent back for fixes, capped by max iterations, or stopped when evidence is missing.
|
|
11
11
|
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
12
|
+
## Built-in loopflows
|
|
13
|
+
|
|
14
|
+
- `launch-control` — strict plan-as-contract flow: context → plan → build/review loop → final audit.
|
|
15
|
+
- `build-review` — lightweight implementation loop for scoped changes.
|
|
16
|
+
- `plan-review` — review and revise a plan before implementation starts.
|
|
17
17
|
|
|
18
18
|
## Commands
|
|
19
19
|
|
|
@@ -38,3 +38,7 @@ loopflow_run({ workflow: "launch-control", task: "...", maxIterations: 3 })
|
|
|
38
38
|
## Rule of thumb
|
|
39
39
|
|
|
40
40
|
Use `pi-subagents` chains for simple linear handoffs. Use `pi-loopflows` when a gate can send work backward for fixes or stop the run.
|
|
41
|
+
|
|
42
|
+
## Customization
|
|
43
|
+
|
|
44
|
+
Loopflows are `.loopflow.json` files. Copy bundled workflows into `.pi/loopflows/` to customize them for a project: change agents, prompts, max iterations, pass/retry/stop statuses, or final audit rules.
|