@openplaybooks/converge 0.2.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.
@@ -0,0 +1,168 @@
1
+ # Phases Reference
2
+
3
+ Step-by-step execution guide for converge-planning. Read during active planning when you need detailed instructions with commands.
4
+
5
+ ---
6
+
7
+ ## Process Overview
8
+
9
+ ```
10
+ 1. EXTRACT GOAL → clear one-sentence deliverable goal
11
+ 2. GATHER REQS → exhaustive list of must-haves, should-haves, constraints, non-goals
12
+ 3. DECOMPOSE → sub-goal tree (recursive, until leaves are workable)
13
+ 4. CONTRACT → write TASK.md + playbook.yml from the goal tree
14
+ 5. VALIDATE → contract review + requirement coverage gate
15
+ ```
16
+
17
+ These aren't separate phases producing separate files — they're the thinking steps you go through before writing contracts. The only files produced are the playbook structure.
18
+
19
+ ---
20
+
21
+ ## Step 1 — Extract Goal
22
+
23
+ Reduce the user's request to one sentence: what complete, usable thing must exist when this is done?
24
+
25
+ **Good:** "A deployed blog with post CRUD, comments, RSS feed, and responsive design."
26
+ **Bad:** "A blog." (too vague)
27
+ **Bad:** "Plan, design, implement, and test a blog." (process, not result)
28
+
29
+ If the user hasn't stated a clear goal, ask. If the goal is too broad ("Build me a SaaS platform"), narrow it with follow-up questions before proceeding.
30
+
31
+ ---
32
+
33
+ ## Step 2 — Gather Requirements
34
+
35
+ Extract every requirement from the user's prompt and from discovery questions. Capture them as specific, testable statements.
36
+
37
+ **Discovery questions (ask if not already answered):**
38
+
39
+ 1. **Vision** — what is this project, what problem does it solve?
40
+ 2. **Core features** — top 3–5, ranked by priority.
41
+ 3. **User flows** — the main journey through the product.
42
+ 4. **Data & APIs** — entities, external services, integrations.
43
+ 5. **Constraints** — deadlines, tech stack, compliance, budget.
44
+ 6. **Non-goals** — what are we explicitly NOT building? (Prevents scope creep.)
45
+
46
+ **Capture format:**
47
+
48
+ ```
49
+ R1: [must] Authors can create, edit, publish, and delete posts
50
+ R2: [must] Readers can submit comments on published posts
51
+ R3: [must] RSS feed of latest published posts at /feed.xml
52
+ R4: [should] Comments support threaded replies
53
+ R5: [must] Posts support markdown with syntax highlighting
54
+ R6: [constraint] Tech stack: Node.js + PostgreSQL + React
55
+ R7: [non-goal] No user registration beyond author account
56
+ ```
57
+
58
+ Tag each as `[must]`, `[should]`, `[constraint]`, or `[non-goal]`. Number them. This list is your requirement coverage checklist in later steps.
59
+
60
+ **Surfacing goals from requirements:** When the work is large, replayable, or reactive — and the user describes a measurable end state — surface these as candidate **playbook goals**. Goals are different from sub-goal deliverables:
61
+ - **Sub-goals** are things that must *exist* (a database, an API endpoint, a UI page)
62
+ - **Goals** are conditions that must be *true* (all tests pass, type checking is clean, coverage reaches 90%)
63
+
64
+ A requirement like "the codebase must have zero type errors" is a goal. It may require many sub-goal deliverables to achieve, but the goal itself is the completion condition. Goals become the `goals:` list in `playbook.yml` and drive a goal-driven epoch loop. See `references/patterns.md` § Goal-Driven Epoch Loop.
65
+
66
+ **Existing codebase?** Run these before gathering requirements:
67
+
68
+ ```bash
69
+ ls package.json pyproject.toml go.mod Cargo.toml 2>/dev/null # runtime
70
+ cat package.json 2>/dev/null | jq -r '.dependencies // {} | keys[]' | head -20 # framework
71
+ find . -maxdepth 2 -type d -not -path '*/node_modules/*' -not -path '*/.git/*' | sort # structure
72
+ git log --oneline -10 2>/dev/null && git status --short 2>/dev/null # state
73
+ ls -la .converge/ 2>/dev/null # existing converge
74
+ ```
75
+
76
+ Capture tech stack, conventions, and existing state. These inform constraints but don't produce a separate deliverable file.
77
+
78
+ ---
79
+
80
+ ## Step 3 — Decompose into Sub-Goals
81
+
82
+ Decompose the user's goal into deliverable sub-goals. Each sub-goal is a **complete, independently verifiable result**.
83
+
84
+ ### Decomposition rules
85
+
86
+ - **3–7 children per level.** Less than 3 → no real decomposition. More than 7 → group into an intermediate level.
87
+ - **Name by deliverable, not activity.** "Database schema" not "Design database." "Working API endpoints" not "Build API."
88
+ - **Each child produces a complete thing.** Not a stage of producing a thing.
89
+ - **Children form a complete cover.** Reading all children's deliverables together achieves the parent goal.
90
+
91
+ ### Recursive application
92
+
93
+ For each sub-goal, ask: *can one agent produce this complete deliverable in one session?*
94
+
95
+ - **Yes** → it's a leaf. Stop decomposing.
96
+ - **No** → decompose further. Split by sub-feature, by entity, by endpoint — not by workflow stage.
97
+ - **Same shape repeats N times** → use a runtime template plus `converge spawn` (see `references/static-dynamic.md`).
98
+
99
+ ### Requirement mapping
100
+
101
+ Before proceeding, run the requirement coverage check:
102
+
103
+ ```
104
+ R1 → Sub-goal A ✓
105
+ R2 → Sub-goal B ✓
106
+ R3 → Sub-goal C ✓
107
+ R4 → ??? ← GAP: add a sub-goal or expand existing scope
108
+ ```
109
+
110
+ Every `[must]` requirement must map to at least one sub-goal. Unmapped requirements are gaps. Sub-goals with no mapped requirements are scope creep.
111
+
112
+ ### Pattern recognition (after decomposition)
113
+
114
+ Once the goal tree exists, recognize its shape to sanity-check the design:
115
+
116
+ - Linear dependencies between sub-goals → ordered stages
117
+ - N identical sub-goals from a catalog → seed fan-out
118
+ - Iterative improvement until quality threshold → epoch loop
119
+ - N distinct domains with their own sub-trees → domain split
120
+
121
+ The shape confirms the decomposition; it doesn't drive it. If the shape looks wrong, the decomposition might be wrong.
122
+
123
+ ---
124
+
125
+ ## Step 4 — Write Contracts
126
+
127
+ Write contracts from the goal tree. Start at the root, one layer at a time.
128
+
129
+ ### For each leaf task
130
+
131
+ Write `TASK.md` with:
132
+ - **title + description:** What complete deliverable this produces
133
+ - **inputs:** Files it reads (upstream outputs, project data)
134
+ - **outputs:** Specific paths for its complete deliverable
135
+ - **checks:** Deterministic verification commands (exit 0 = pass)
136
+ - **depends_on:** Tasks that must complete first
137
+
138
+ ### For each container task
139
+
140
+ Write `TASK.md` + `PLAN.md`. The TASK.md body describes:
141
+ 1. **Decomposition** — what sub-goals exist and why
142
+ 2. **Convergence** — how to integrate children's deliverables, what cross-child validation to run, what the converged output is
143
+
144
+ ### Playbook-level
145
+
146
+ Write `playbook.yml` referencing top-level tasks with `depends_on` edges. Add playbook-level checks (e.g., `npx tsc --noEmit`, `npm test`).
147
+
148
+ Write the root `PLAN.md` capturing:
149
+ - **Goal:** The user's one-sentence goal
150
+ - **Decision:** Why this decomposition
151
+ - **Children:** Each top-level sub-goal with id, kind, objective, inputs, dependencies, outputs, checks
152
+ - **Requirements:** The full numbered list with sub-goal mappings
153
+ - **Open questions:** Things unknown at plan time
154
+
155
+ ---
156
+
157
+ ## Step 5 — Validate
158
+
159
+ Run contract review on every TASK.md. See SKILL.md §7 for the full checklist.
160
+
161
+ Key gates:
162
+ - Every output has a deterministic check
163
+ - Every input traces to an upstream output
164
+ - Every requirement maps to ≥1 task
165
+ - No middle work — every leaf produces a complete, usable deliverable
166
+ - No verb-named siblings
167
+
168
+ When validation passes, the plan is ready for `converge run`.
@@ -0,0 +1,313 @@
1
+ # Schema Reference
2
+
3
+ Format reference for converge planning artifacts. Read when you need to write or validate TASK.md frontmatter, playbook.yml, checks, container behavior, and spawn templates.
4
+
5
+ For the contract model that explains *why* these fields exist, see `../SKILL.md` or `model.md`.
6
+
7
+ ---
8
+
9
+ ## `playbook.yml`
10
+
11
+ Playbook manifest. Defines the top-level task list, dependencies, run config, and playbook-level checks.
12
+
13
+ **Location:** `.converge/playbooks/{name}/playbook.yml`
14
+
15
+ ```yaml
16
+ name: default
17
+ description: End-to-end app generation
18
+ run:
19
+ mode: autonomous
20
+ maxIterations: 50
21
+ maxTaskAttempts: 3
22
+ tasks:
23
+ - path: prepare
24
+ - path: design-system
25
+ - path: build-screens
26
+ checks:
27
+ - id: type-check
28
+ cmd: npx tsc --noEmit
29
+ ```
30
+
31
+ ---
32
+
33
+ ## `TASK.md`
34
+
35
+ The delegation contract. One per task directory. **Same schema at every nesting level** — top-level tasks and deeply nested children use identical TASK.md format.
36
+
37
+ **Location:** `.converge/playbooks/{name}/tasks/{path-to-task}/TASK.md`
38
+
39
+ ```yaml
40
+ ---
41
+ id: task-name
42
+ title: Human-Readable Title
43
+ description: What this task accomplishes in one sentence
44
+ depends_on:
45
+ - upstream-task-id
46
+ - prepare.catalog # Cross-branch dotted path
47
+ inputs:
48
+ - path/to/input.md
49
+ outputs:
50
+ - path/to/output.md
51
+ skills:
52
+ - skill-name
53
+ checks:
54
+ - id: check-id
55
+ cmd: shell-command-returns-0
56
+ description: What this validates
57
+ ---
58
+
59
+ # Task Title
60
+
61
+ [Concrete, step-by-step instructions for the executor]
62
+ ```
63
+
64
+ ### Three practical TASK.md roles
65
+
66
+ - **Leaf task** — produces outputs directly.
67
+ - **Static container** — owns child tasks under `tasks/` and converges their results.
68
+ - **Dynamic container** — marked `passthrough: true`; its body orchestrates work, emits `converge spawn ...`, and relies on a `converge` post-check contract to decide whether to continue.
69
+
70
+ ### Frontmatter fields
71
+
72
+ | Field | Required | Contract role | Type | Description |
73
+ |-------|----------|---------------|------|-------------|
74
+ | `id` | Yes | identity | string | Unique kebab-case slug (`prepare`, `build-screens`). No numeric prefix. |
75
+ | `title` | Yes | scope | string | Human-readable title |
76
+ | `description` | Recommended | scope | string | One-line purpose |
77
+ | `inputs` | If reads | **Context In** | string[] | Files this task reads (must be upstream outputs) |
78
+ | `outputs` | Yes | **Context Out** | string[] | Files this task produces |
79
+ | `checks` | Yes | acceptance | Check[] | Deterministic validation commands |
80
+ | `depends_on` | If needed | deps | string[] | Sibling/cross-branch task IDs that must complete first |
81
+ | `skills` | If using | resources | string[] | Converge skills to invoke |
82
+ | `references` | Optional | resources | string[] | Skill libraries to reference |
83
+ | `vars` | Optional | resources | object | Template variables passed to seed/children |
84
+ | `passthrough` | Dynamic/container tasks | execution | boolean | Run shell body directly; common for orchestration parents that emit `converge spawn ...` |
85
+ | `converge` | Looping/container tasks | convergence | string/object | Post-body verdict prompt that decides continue vs halt |
86
+ | `tags` | Optional | metadata | string[] | Categorization labels |
87
+ | `blocking` | Optional | scheduling | boolean | If true, blocks all downstream until done |
88
+ | `executor` | Optional | execution | object | Execution method override |
89
+ | `allowed-tools` | Optional | sandbox | string[] | Restrict available tools |
90
+
91
+ A leaky contract is one where any field above is missing, vague, or over-broad.
92
+
93
+ ### Recommended dynamic-container shape
94
+
95
+ Use this when a parent task needs to adapt at runtime:
96
+
97
+ ```yaml
98
+ ---
99
+ id: build
100
+ title: Build
101
+ passthrough: true
102
+ checks:
103
+ - id: finished
104
+ cmd: test -f output/done.flag
105
+ converge: |
106
+ Decide whether this task should continue or halt.
107
+ ---
108
+ ```
109
+
110
+ Then in the body:
111
+
112
+ - write evidence files
113
+ - emit `converge spawn <id> <template> --var ...` commands as needed
114
+ - use idempotency markers so repeat body runs do not duplicate-spawn
115
+ - call `converge tasks mark <id> --status done` when the stop condition is reached
116
+
117
+ ---
118
+
119
+ ## Dependency formats
120
+
121
+ ```yaml
122
+ # Sibling (same level)
123
+ depends_on:
124
+ - upstream-task
125
+
126
+ # Cross-branch (dotted path from playbook root)
127
+ depends_on:
128
+ - prepare.catalog
129
+
130
+ # Tag-based (any task with this tag)
131
+ depends_on:
132
+ - tag:setup
133
+
134
+ # Mixed
135
+ depends_on:
136
+ - setup
137
+ - prepare.catalog
138
+ - tag:foundation
139
+ ```
140
+
141
+ **Rules:**
142
+ - No cycles. If you find one, split the task.
143
+ - Minimize: depend only on what you actually consume.
144
+ - Dependencies are declared in `TASK.md` `depends_on` — each task owns its own edges.
145
+ - playbook.yml lists task paths only (no dependency wiring).
146
+
147
+ ---
148
+
149
+ ## Check schema
150
+
151
+ ```yaml
152
+ checks:
153
+ - id: string # Unique kebab-case identifier
154
+ cmd: string # Shell command (exit 0 = pass, non-zero = fail)
155
+ description: string # Human-readable description
156
+ ```
157
+
158
+ ### Common patterns
159
+
160
+ ```yaml
161
+ # File exists
162
+ - id: exists
163
+ cmd: test -f output.md
164
+ description: Output file exists
165
+ tags: [fast]
166
+
167
+ # Non-empty
168
+ - id: nonempty
169
+ cmd: test -s output.md
170
+ description: Output file is not empty
171
+ tags: [fast]
172
+
173
+ # Valid JSON
174
+ - id: valid-json
175
+ cmd: jq empty data.json
176
+ description: Valid JSON format
177
+ tags: [fast]
178
+
179
+ # JSON Schema validation
180
+ - id: valid-schema
181
+ cmd: jq -e '.items | type == "array" and length >= 3' data.json
182
+ description: Items array has at least 3 entries
183
+ tags: [fast]
184
+
185
+ # Valid YAML
186
+ - id: valid-yaml
187
+ cmd: python3 -c "import yaml; yaml.safe_load(open('config.yaml'))"
188
+ description: Valid YAML format
189
+ tags: [fast]
190
+
191
+ # Has required section
192
+ - id: has-overview
193
+ cmd: grep -q "## Overview" output.md
194
+ description: Has Overview section
195
+ tags: [fast]
196
+
197
+ # TypeScript compiles
198
+ - id: compiles
199
+ cmd: npx tsc --noEmit
200
+ description: TypeScript compiles
201
+ tags: [slow, build]
202
+
203
+ # Tests pass
204
+ - id: tests-pass
205
+ cmd: npm test -- --passWithNoTests
206
+ description: All tests passing
207
+ tags: [slow, build]
208
+
209
+ # File count
210
+ - id: screens-generated
211
+ cmd: test $(ls screens/*.html 2>/dev/null | wc -l) -ge 3
212
+ description: At least 3 screens generated
213
+ tags: [fast]
214
+
215
+ # Cross-reference: every catalog entry has a corresponding output
216
+ - id: all-catalog-entries-built
217
+ cmd: |
218
+ count=$(jq '.items | length' tokens-catalog.json)
219
+ built=$(ls tokens/*.json 2>/dev/null | wc -l)
220
+ test "$built" -eq "$count"
221
+ description: One output file per catalog entry
222
+ tags: [slow]
223
+
224
+ # Cross-task consistency: every screen in catalog has a source file
225
+ - id: screens-consistent
226
+ cmd: |
227
+ jq -r '.screens[].id' screens.json | while read id; do
228
+ test -f "lib/screens/$id.html" || exit 1
229
+ done
230
+ description: Every screen in catalog has a generated file
231
+ tags: [slow]
232
+
233
+ # No broken references
234
+ - id: no-broken-refs
235
+ cmd: |
236
+ ! grep -r "\[\[missing" output/ 2>/dev/null
237
+ description: No unresolved [[wikilinks]] in output
238
+ tags: [fast]
239
+ ```
240
+
241
+ **Rules:**
242
+ - Every output gets at least one check (existence + non-empty minimum).
243
+ - Code outputs add a compilation check. Data outputs add format validation.
244
+ - Container tasks add cross-child consistency checks (count match, every-catalog-entry).
245
+ - Playbook-level checks validate cross-task invariants.
246
+ - Tag checks by cost: `fast` for file/grep checks, `slow` for compilation/test suites.
247
+ - Never use exact string matching — too brittle.
248
+
249
+ ---
250
+
251
+ ## Dynamic work shapes
252
+
253
+ Current Converge uses one primary dynamic-work mechanism in source playbooks:
254
+
255
+ **Runtime spawn templates** in `templates/<name>/TASK.md`
256
+
257
+ Use them with `converge spawn <id> <template>` from a passthrough task body when the task needs to materialize children at runtime.
258
+
259
+ ---
260
+
261
+ ## Spawn-template pattern
262
+
263
+ Use runtime templates when the same child shape repeats:
264
+
265
+ ```bash
266
+ converge spawn sprint-3 sprint --var wave=3 --var sprint_id=sprint-3
267
+ ```
268
+
269
+ The template resolves to:
270
+
271
+ ```text
272
+ .converge/playbooks/<name>/templates/sprint/TASK.md
273
+ ```
274
+
275
+ Recommended usage:
276
+
277
+ - keep repeated child shapes in `templates/`
278
+ - pass runtime data with `--var`
279
+ - use idempotency markers in the parent body so repeated runs do not duplicate-spawn
280
+ - pair spawn with checks plus a `converge` verdict that decides whether to continue
281
+
282
+ ---
283
+
284
+ ## Directory naming
285
+
286
+ Static tasks live under `.converge/playbooks/{name}/tasks/`. Runtime-spawn templates live under `.converge/playbooks/{name}/templates/`.
287
+
288
+ ```
289
+ tasks/{id}/TASK.md → static task contract (executable or container)
290
+ tasks/{id}/PLAN.md → container blueprint
291
+ templates/{name}/TASK.md → runtime spawn template
292
+ ```
293
+
294
+ - IDs are plain kebab-case slugs (`prepare`, `build-screens`, `per-character`).
295
+ - **Static children** under a parent's `tasks/` subdirectory MUST use `\d{2,3}-` prefixes (e.g., `01-prepare`, `02-build-screens`). This is required by `discoverStaticChildren` which matches `^\d{2,3}-` to discover child TASK.md files. The numeric prefix controls execution order within the parent.
296
+ - **Top-level tasks** and **templates** use kebab-case without numeric prefixes — order comes from `depends_on` edges in `playbook.yml`.
297
+ - `tasks/` and `templates/` are siblings at the playbook root.
298
+ - Spawned children are materialized by the runtime, not written during init.
299
+
300
+ ```
301
+ playbooks/default/
302
+ ├── playbook.yml
303
+ ├── PLAN.md
304
+ ├── tasks/
305
+ │ └── build/
306
+ │ ├── TASK.md
307
+ │ └── PLAN.md
308
+ └── templates/
309
+ ├── sprint/
310
+ │ └── TASK.md
311
+ └── phase/
312
+ └── TASK.md
313
+ ```
@@ -0,0 +1,38 @@
1
+ # Static vs. Dynamic Subtask Reference
2
+
3
+ Decision guide for static vs. dynamic subtask decomposition. Read when planning a container and deciding whether to hand-write children or use runtime spawn templates.
4
+
5
+ ---
6
+
7
+ ## Static vs. Dynamic Subtasks
8
+
9
+ **The core decomposition choice: when you split a task into subtasks, each subtask is either static or dynamic.**
10
+
11
+ | Subtask type | How it's created | When it's knowable | Use when |
12
+ |---|---|---|---|
13
+ | **Static** | Hand-written `TASK.md` file | Compile time (*concrete*) | Fixed set, known at plan time, ≤ ~7 children |
14
+ | **Dynamic** | parent body spawns it from a template at runtime | After the parent runs (*expected* or *adaptive*) | Data-driven list, unknown at plan time, N > 7, or N may grow |
15
+
16
+ **Static subtasks** are the default. Write each child's `TASK.md` by hand. The DAG is fully concrete at compile time — every node exists on disk, every edge is declared.
17
+
18
+ **Dynamic subtasks** use runtime templates. The parent task body emits `converge spawn <id> <template>` for each child. Two sub-cases:
19
+
20
+ - **Expected** — an upstream "catalog" task produces a structured file (e.g., `tokens-catalog.json`) listing what entities exist. The parent reads it and spawns children from it. Children's IDs and count are predictable from the catalog.
21
+ - **Adaptive** — no catalog exists. The parent decides what to spawn at runtime. Children are unknowable until the parent runs.
22
+
23
+ **The catalog pattern** (prefer `expected` over `frontier`):
24
+
25
+ ```
26
+ upstream catalog task → downstream dynamic container
27
+ writes tokens-catalog.json → reads it, spawns per-token children
28
+ (concrete) → (children are expected)
29
+ ```
30
+
31
+ One extra task makes the rest of the DAG queryable. See `examples/game-assets-video` for the worked example.
32
+
33
+ **Decision heuristic:**
34
+ - ≤ 7 items, known at plan time → **static subtasks** (hand-write each `TASK.md`)
35
+ - > 7 items, or the list comes from data → **catalog task + dynamic container** (dynamic, expected)
36
+ - The list requires runtime reasoning to determine → **dynamic container** (adaptive)
37
+
38
+ **Mixed containers:** a container can have both static and dynamic children. A `03-build-screens` phase might have one static `001-design-system` task plus a body that spawns per-screen children. Both coexist in the same DAG.
@@ -0,0 +1,91 @@
1
+ # Checks Reference
2
+
3
+ Full check reference for converge-planning. Read when you need to design deterministic checks for tasks, wire reusable helpers through `scripts/`, or plan convergence loops that rely on post-check evidence.
4
+
5
+ ---
6
+
7
+ ## Checks are part of the contract
8
+
9
+ Write checks during planning, not after. For every task contract, add checks that validate:
10
+ - the output exists
11
+ - the output is well-formed
12
+ - the output satisfies the actual task contract
13
+
14
+ Examples:
15
+
16
+ ```yaml
17
+ checks:
18
+ - id: file-exists
19
+ cmd: test -f output.md
20
+ - id: schema-valid
21
+ cmd: jq empty data.json
22
+ - id: section-present
23
+ cmd: grep -q "## Required Section" output.md
24
+ ```
25
+
26
+ Use checks at every level:
27
+ - Leaf task: its own outputs exist and are valid.
28
+ - Container task: child outputs are complete and internally consistent.
29
+ - Playbook: cross-task invariants still hold.
30
+
31
+ ---
32
+
33
+ ## Reusable helpers live in `scripts/`
34
+
35
+ There is no `.test.md` registry and no `checks/` folder. If a check needs shared logic, put the helper under the playbook's `scripts/` tree and call it directly from `cmd`.
36
+
37
+ ```text
38
+ playbooks/default/
39
+ scripts/
40
+ file-exists.sh
41
+ backend-configured.js
42
+ ```
43
+
44
+ ```yaml
45
+ checks:
46
+ - id: idea-exists
47
+ cmd: bash scripts/file-exists.sh idea.md
48
+ - id: backend-configured
49
+ cmd: node scripts/backend-configured.js image-generate
50
+ ```
51
+
52
+ Rules:
53
+ - The command is the API. Keep it explicit.
54
+ - If a command references `scripts/...`, that file must actually exist.
55
+ - Do not rely on named test registries, `type: test`, or auto-discovered helper folders.
56
+
57
+ When to extract a helper into `scripts/`:
58
+ - the same command logic appears in multiple tasks
59
+ - the check needs real control flow or parsing
60
+ - the check needs a stable interface that several tasks can call
61
+
62
+ When not to extract:
63
+ - one-off shell checks
64
+ - tiny checks that stay readable inline
65
+
66
+ ---
67
+
68
+ ## Dynamic containers and post-check loops
69
+
70
+ For dynamic or adaptive parents, the checks should describe the real stop condition. The body does work and spawns children; the `converge` prompt decides whether another wave is needed after the checks run.
71
+
72
+ Typical shape:
73
+
74
+ ```yaml
75
+ id: improve
76
+ passthrough: true
77
+ checks:
78
+ - id: backlog-empty
79
+ cmd: test ! -s artifacts/backlog.txt
80
+ - id: report-valid
81
+ cmd: node scripts/verify-report.js artifacts/report.json
82
+ converge: |
83
+ Review the current evidence and decide whether to continue or halt.
84
+ ```
85
+
86
+ The important split:
87
+ - body: gather evidence, write state, `converge spawn ...`
88
+ - checks: verify the current state
89
+ - `converge`: decide continue vs halt based on the checked evidence
90
+
91
+ That is the current self-correcting loop model.