specdacular 0.8.1 → 0.9.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.
@@ -0,0 +1,376 @@
1
+ # Specdacular State Machine Reference
2
+
3
+ How the brain orchestrates tasks, how state transitions work, and what custom workflows need to do.
4
+
5
+ ---
6
+
7
+ ## How the Brain Works
8
+
9
+ The brain is a loop: read state → route → dispatch → update state → repeat.
10
+
11
+ ```
12
+ ┌─────────────────────────────────────────────────┐
13
+ │ BRAIN LOOP │
14
+ │ │
15
+ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
16
+ │ │ Read │───▶│ Route │───▶│ Dispatch │ │
17
+ │ │ State │ │ (pick │ │ Step │ │
18
+ │ │ │ │ next) │ │ │ │
19
+ │ └──────────┘ └──────────┘ └────┬─────┘ │
20
+ │ ▲ │ │
21
+ │ │ ┌──────────┐ │ │
22
+ │ └──────────│ Update │◀────────┘ │
23
+ │ │ State │ │
24
+ │ └──────────┘ │
25
+ └─────────────────────────────────────────────────┘
26
+ ```
27
+
28
+ **Each iteration:**
29
+ 1. Read `config.json`, `STATE.md`, `CONTEXT.md`
30
+ 2. Use the routing table (below) to pick the next step
31
+ 3. Run pre-hooks → step workflow → post-hooks
32
+ 4. Update state based on what the step did
33
+ 5. Loop back to step 1
34
+
35
+ ---
36
+
37
+ ## State: config.json
38
+
39
+ The brain reads two key fields from config.json to decide where you are:
40
+
41
+ ```json
42
+ {
43
+ "stage": "discussion | research | planning | execution | complete",
44
+ "phases": {
45
+ "current": 1,
46
+ "current_status": "pending | executing | executed | completed",
47
+ "total": 3,
48
+ "completed": 0,
49
+ "phase_start_commit": null
50
+ }
51
+ }
52
+ ```
53
+
54
+ | Field | What it means |
55
+ |-------|---------------|
56
+ | `stage` | Which part of the lifecycle you're in |
57
+ | `phases.current` | Which phase number is active (1-indexed) |
58
+ | `phases.current_status` | Where that phase is in its sub-lifecycle |
59
+ | `phases.total` | How many phases were planned |
60
+ | `phases.completed` | How many phases are fully done |
61
+
62
+ The brain also checks `CONTEXT.md` for gray area count (unchecked items in "Gray Areas Remaining").
63
+
64
+ ---
65
+
66
+ ## Routing Table
67
+
68
+ This is the complete decision table. The brain evaluates top-to-bottom and takes the first match:
69
+
70
+ ```
71
+ ┌─────────────────────────────────────────────────────────────────┐
72
+ │ ROUTING TABLE │
73
+ ├────────────────────────────┬──────────────┬────────────────────┤
74
+ │ State │ Next Step │ Pipeline │
75
+ ├────────────────────────────┼──────────────┼────────────────────┤
76
+ │ stage=discussion │ │ │
77
+ │ gray areas > 0 │ discuss │ main │
78
+ │ gray areas = 0 │ research │ main │
79
+ ├────────────────────────────┼──────────────┼────────────────────┤
80
+ │ stage=research │ │ │
81
+ │ no RESEARCH.md │ research │ main │
82
+ │ RESEARCH.md exists │ plan │ main │
83
+ ├────────────────────────────┼──────────────┼────────────────────┤
84
+ │ stage=planning │ │ │
85
+ │ no ROADMAP.md │ plan │ main │
86
+ │ ROADMAP.md exists │ plan │ phase-execution │
87
+ ├────────────────────────────┼──────────────┼────────────────────┤
88
+ │ stage=execution │ │ │
89
+ │ current_status=pending │ │ │
90
+ │ no PLAN.md │ plan │ phase-execution │
91
+ │ PLAN.md exists │ execute │ phase-execution │
92
+ │ current_status=executing │ execute │ phase-execution │
93
+ │ current_status=executed │ review │ phase-execution │
94
+ │ current_status=completed │ next phase │ phase-execution │
95
+ │ │ or COMPLETE │ │
96
+ └────────────────────────────┴──────────────┴────────────────────┘
97
+ ```
98
+
99
+ ---
100
+
101
+ ## Full Lifecycle Diagram
102
+
103
+ ```
104
+ ┌─────────┐
105
+ │ START │
106
+ └────┬────┘
107
+
108
+
109
+ ┌─────────────────────┐
110
+ │ DISCUSSION │
111
+ │ │ gray areas > 0
112
+ │ ┌───────────────┐ │◀─────────────────┐
113
+ │ │ discuss │──┼──────────────────┘
114
+ │ └───────────────┘ │
115
+ │ │ gray areas = 0
116
+ └──────────┬──────────┘
117
+
118
+
119
+ ┌─────────────────────┐
120
+ │ RESEARCH │
121
+ │ │
122
+ │ ┌───────────────┐ │
123
+ │ │ research │ │
124
+ │ └───────────────┘ │
125
+ └──────────┬──────────┘
126
+
127
+
128
+ ┌─────────────────────┐
129
+ │ PLANNING │
130
+ │ │
131
+ │ ┌───────────────┐ │
132
+ │ │ plan │ │
133
+ │ └───────────────┘ │
134
+ └──────────┬──────────┘
135
+
136
+
137
+ ┌──────────────────────────────────────────┐
138
+ │ EXECUTION (per phase) │
139
+ │ │
140
+ │ ┌──────┐ ┌─────────┐ ┌────────┐ ┌───────┐│
141
+ │ │ plan │─▶│ execute │─▶│ review │─▶│revise ││
142
+ │ └──────┘ └─────────┘ └────────┘ └───┬───┘│
143
+ │ ▲ │ │
144
+ │ └───────────────────────┘ │
145
+ │ (fix loop) │
146
+ │ │
147
+ │ Phase done? ──▶ Next phase ─┐ │
148
+ │ ▲ │ │
149
+ │ └──────────────────────┘ │
150
+ └──────────────────┬─────────────────────────────┘
151
+ │ all phases done
152
+
153
+ ┌────────────┐
154
+ │ COMPLETE │
155
+ └────────────┘
156
+ ```
157
+
158
+ ---
159
+
160
+ ## Hook Execution Order
161
+
162
+ Around every step, hooks execute in this order:
163
+
164
+ ```
165
+ ┌─────────────────────────────────┐
166
+ │ 1. Global pre-step hook │ pipeline.json → hooks.pre-step
167
+ ├─────────────────────────────────┤
168
+ │ 2. Step pre-hook │ step config or .specd/hooks/pre-{step}.md
169
+ ├─────────────────────────────────┤
170
+ │ 3. ▶▶▶ STEP WORKFLOW ◀◀◀ │ the actual step (discuss, execute, etc.)
171
+ ├─────────────────────────────────┤
172
+ │ 4. Step post-hook │ step config or .specd/hooks/post-{step}.md
173
+ ├─────────────────────────────────┤
174
+ │ 5. Global post-step hook │ pipeline.json → hooks.post-step
175
+ └─────────────────────────────────┘
176
+ ```
177
+
178
+ ---
179
+
180
+ ## Writing Custom Step Workflows
181
+
182
+ If you replace a step's workflow (e.g., `"workflow": ".specd/my-execute.md"`), your workflow **must update state** so the brain knows what happened. The brain reads config.json after your step returns.
183
+
184
+ ### What Each Step Must Do
185
+
186
+ **Custom `discuss` replacement:**
187
+ - Update `CONTEXT.md` — check off resolved gray areas
188
+ - The brain re-reads gray area count to decide whether to stay in discussion or advance
189
+
190
+ **Custom `research` replacement:**
191
+ - Create `RESEARCH.md` in the task directory
192
+ - The brain checks for this file to know research is done
193
+
194
+ **Custom `plan` replacement (task-level, main pipeline):**
195
+ - Create `ROADMAP.md` with phase goals (no PLAN.md files, no phase directories)
196
+ - Set in config.json:
197
+ ```json
198
+ {
199
+ "stage": "execution",
200
+ "phases": {
201
+ "current": 1,
202
+ "current_status": "pending",
203
+ "total": <number of phases>
204
+ }
205
+ }
206
+ ```
207
+
208
+ **Custom `plan` replacement (phase-level, phase-execution pipeline — `phase-plan.md`):**
209
+ - Create `phases/phase-NN/` directory and `PLAN.md` for the current phase
210
+ - Read phase goal from ROADMAP.md
211
+ - Do NOT change config.json (brain checks PLAN.md existence to route)
212
+
213
+ **Custom `execute` replacement:**
214
+ - Do whatever execution work is needed for the current phase
215
+ - Set in config.json:
216
+ ```json
217
+ { "phases": { "current_status": "executed" } }
218
+ ```
219
+ - The brain will then route to `review`
220
+
221
+ **Custom `review` replacement:**
222
+ - Review the executed phase
223
+ - Set in config.json based on outcome:
224
+ - **Approved:** `{ "phases": { "current_status": "completed" } }` — brain advances to next phase
225
+ - **Needs revision:** set up for revise step (keep `current_status` as `"executed"`)
226
+
227
+ **Custom `revise` replacement:**
228
+ - Create fix plan in a decimal phase directory (e.g., `phase-01.1/`)
229
+ - Set in config.json:
230
+ ```json
231
+ { "phases": { "current_status": "pending" } }
232
+ ```
233
+ - The brain loops back to execute for the fix phase
234
+
235
+ ### State Update Summary
236
+
237
+ | Your step | Must set | Brain then routes to |
238
+ |-----------|----------|---------------------|
239
+ | discuss | Update gray areas in CONTEXT.md | discuss (if gray areas remain) or research |
240
+ | research | Create RESEARCH.md | plan |
241
+ | plan (task-level) | Create ROADMAP.md, set stage=execution | plan (phase-level) |
242
+ | plan (phase-level) | Create phases/phase-NN/PLAN.md | execute |
243
+ | execute | Set current_status=executed | review |
244
+ | review (approved) | Set current_status=completed | next phase or complete |
245
+ | review (revisions) | Keep current_status=executed | revise |
246
+ | revise | Set current_status=pending | execute (fix phase) |
247
+
248
+ ---
249
+
250
+ ## Phase Sub-Lifecycle
251
+
252
+ Each phase goes through its own mini-lifecycle within execution:
253
+
254
+ ```
255
+ pending
256
+
257
+ ┌────┴─────┐
258
+ │ PLAN.md? │
259
+ └────┬─────┘
260
+
261
+ No ────┤──── Yes
262
+ │ │
263
+ ▼ │
264
+ ┌──────┐ │
265
+ │ plan │ │
266
+ └──┬───┘ │
267
+ │ │
268
+ └────┬───────┘
269
+
270
+
271
+ executing ◀──────┐
272
+ │ │
273
+ ▼ │
274
+ executed │
275
+ │ │
276
+ ▼ │
277
+ ┌────────┐ │
278
+ │ review │ │
279
+ └───┬────┘ │
280
+ │ │
281
+ ┌────┴─────┐ │
282
+ ▼ ▼ │
283
+ completed revise ────┘
284
+ │ (creates
285
+ │ fix phase,
286
+ ▼ resets to
287
+ next phase pending)
288
+ or DONE
289
+ ```
290
+
291
+ The plan step uses `phase-plan.md` — a dedicated workflow that reads the phase goal from ROADMAP.md and creates a detailed PLAN.md for that phase only. This allows later phases to adapt based on earlier phase outcomes.
292
+
293
+ **Decimal fix phases:** When revise creates `phase-01.1/`, the brain executes it before advancing to `phase-02/`. Multiple revisions create `phase-01.1`, `phase-01.2`, etc.
294
+
295
+ ---
296
+
297
+ ## Pipeline Configuration Reference
298
+
299
+ Full `pipeline.json` with all options:
300
+
301
+ ```json
302
+ {
303
+ "schema_version": "1.0",
304
+ "pipelines": {
305
+ "main": [
306
+ {
307
+ "name": "discuss",
308
+ "workflow": "discuss.md",
309
+ "hooks": { "pre": null, "post": null }
310
+ },
311
+ {
312
+ "name": "research",
313
+ "workflow": "research.md",
314
+ "hooks": { "pre": null, "post": null }
315
+ },
316
+ {
317
+ "name": "plan",
318
+ "workflow": "plan.md",
319
+ "hooks": { "pre": null, "post": null }
320
+ },
321
+ {
322
+ "name": "phase-execution",
323
+ "pipeline": "phase-execution"
324
+ }
325
+ ],
326
+ "phase-execution": [
327
+ {
328
+ "name": "plan",
329
+ "workflow": "phase-plan.md",
330
+ "hooks": { "pre": null, "post": null }
331
+ },
332
+ {
333
+ "name": "execute",
334
+ "workflow": "execute.md",
335
+ "pause": true,
336
+ "hooks": { "pre": null, "post": null }
337
+ },
338
+ {
339
+ "name": "review",
340
+ "workflow": "review.md",
341
+ "pause": true,
342
+ "hooks": { "pre": null, "post": null }
343
+ },
344
+ {
345
+ "name": "revise",
346
+ "workflow": "revise.md",
347
+ "pause": true,
348
+ "hooks": { "pre": null, "post": null }
349
+ }
350
+ ]
351
+ },
352
+ "hooks": {
353
+ "pre-step": null,
354
+ "post-step": null
355
+ }
356
+ }
357
+ ```
358
+
359
+ **Step fields:**
360
+
361
+ | Field | Required | Default | Description |
362
+ |-------|----------|---------|-------------|
363
+ | `name` | yes | — | Step identifier, used for routing and hook discovery |
364
+ | `workflow` | yes* | — | Markdown file to execute (* not needed if `pipeline` is set) |
365
+ | `pipeline` | — | — | Reference a sub-pipeline instead of a workflow |
366
+ | `pause` | no | `false` | Whether default mode pauses here (ignored in `--auto`, always prompts in `--interactive`) |
367
+ | `hooks.pre` | no | `null` | Pre-hook config or `null` for convention fallback |
368
+ | `hooks.post` | no | `null` | Post-hook config or `null` for convention fallback |
369
+
370
+ **Hook config fields:**
371
+
372
+ | Field | Required | Default | Description |
373
+ |-------|----------|---------|-------------|
374
+ | `workflow` | yes | — | Path to hook markdown file |
375
+ | `mode` | no | `"inline"` | `"inline"` (runs in brain context) or `"subagent"` (isolated) |
376
+ | `optional` | no | `false` | If `true`, failures are logged but don't stop the pipeline |
@@ -0,0 +1,76 @@
1
+ {
2
+ "schema_version": "1.0",
3
+ "pipelines": {
4
+ "main": [
5
+ {
6
+ "name": "discuss",
7
+ "workflow": "discuss.md",
8
+ "hooks": {
9
+ "pre": null,
10
+ "post": null
11
+ }
12
+ },
13
+ {
14
+ "name": "research",
15
+ "workflow": "research.md",
16
+ "hooks": {
17
+ "pre": null,
18
+ "post": null
19
+ }
20
+ },
21
+ {
22
+ "name": "plan",
23
+ "workflow": "plan.md",
24
+ "hooks": {
25
+ "pre": null,
26
+ "post": null
27
+ }
28
+ },
29
+ {
30
+ "name": "phase-execution",
31
+ "pipeline": "phase-execution"
32
+ }
33
+ ],
34
+ "phase-execution": [
35
+ {
36
+ "name": "plan",
37
+ "workflow": "phase-plan.md",
38
+ "hooks": {
39
+ "pre": null,
40
+ "post": null
41
+ }
42
+ },
43
+ {
44
+ "name": "execute",
45
+ "workflow": "execute.md",
46
+ "pause": true,
47
+ "hooks": {
48
+ "pre": null,
49
+ "post": null
50
+ }
51
+ },
52
+ {
53
+ "name": "review",
54
+ "workflow": "review.md",
55
+ "pause": true,
56
+ "hooks": {
57
+ "pre": null,
58
+ "post": null
59
+ }
60
+ },
61
+ {
62
+ "name": "revise",
63
+ "workflow": "revise.md",
64
+ "pause": true,
65
+ "hooks": {
66
+ "pre": null,
67
+ "post": null
68
+ }
69
+ }
70
+ ]
71
+ },
72
+ "hooks": {
73
+ "pre-step": null,
74
+ "post-step": null
75
+ }
76
+ }
@@ -0,0 +1,168 @@
1
+ <shared name="brain_routing">
2
+
3
+ ## Brain Routing
4
+
5
+ Determine the next pipeline step based on current state. The brain calls this after loading state to figure out where to dispatch.
6
+
7
+ **Before using this reference, you must have ready:**
8
+ - `$PIPELINE` — loaded pipeline config
9
+ - `$CONFIG` — task config.json contents
10
+ - `$STATE` — task STATE.md contents
11
+ - `$CONTEXT` — task CONTEXT.md contents
12
+ - `$TASK_DIR` — path to task directory
13
+
14
+ ### Read Current State
15
+
16
+ Extract from config.json:
17
+ - `stage` — discussion, research, planning, execution
18
+ - `phases.current` — current phase number (if in execution)
19
+ - `phases.current_status` — pending, executing, executed, completed (if in execution)
20
+ - `phases.total` — total phases (if planned)
21
+
22
+ Extract from CONTEXT.md:
23
+ - Count unchecked items in "Gray Areas Remaining" section → `$GRAY_AREAS_COUNT`
24
+
25
+ ### Route to Next Step
26
+
27
+ **State-to-step mapping:**
28
+
29
+ | State | Next Step | Pipeline |
30
+ |-------|-----------|----------|
31
+ | stage=discussion, gray areas > 0 | `discuss` | main |
32
+ | stage=discussion, gray areas = 0 | `research` (or `plan` if user skips) | main |
33
+ | stage=research, no RESEARCH.md | `research` | main |
34
+ | stage=planning, no phases dir | `plan` | main |
35
+ | stage=planning or execution, phases.current_status=pending, no PLAN.md | `plan` | phase-execution |
36
+ | stage=planning or execution, phases.current_status=pending, PLAN.md exists | `execute` | phase-execution |
37
+ | stage=execution, phases.current_status=executing | `execute` (resume) | phase-execution |
38
+ | stage=execution, phases.current_status=executed | `review` | phase-execution |
39
+ | stage=execution, phases.current_status=completed | check more phases | phase-execution |
40
+
41
+ ### Routing Logic
42
+
43
+ **1. Discussion stage with gray areas:**
44
+ ```
45
+ $NEXT_STEP = "discuss"
46
+ $NEXT_PIPELINE = "main"
47
+ ```
48
+ **2. Discussion stage, no gray areas:**
49
+ ```
50
+ $NEXT_STEP = "research"
51
+ $NEXT_PIPELINE = "main"
52
+ ```
53
+ Auto-proceed to research.
54
+
55
+ **3. Research stage:**
56
+ ```bash
57
+ [ -f "$TASK_DIR/RESEARCH.md" ] && echo "has_research"
58
+ ```
59
+ If no RESEARCH.md:
60
+ ```
61
+ $NEXT_STEP = "research"
62
+ $NEXT_PIPELINE = "main"
63
+ ```
64
+ If RESEARCH.md exists, advance to plan.
65
+
66
+ **4. Planning stage, no phases:**
67
+ ```bash
68
+ [ -d "$TASK_DIR/phases" ] && echo "has_phases"
69
+ ```
70
+ If no phases:
71
+ ```
72
+ $NEXT_STEP = "plan"
73
+ $NEXT_PIPELINE = "main"
74
+ ```
75
+ If phases exist, advance to execution.
76
+
77
+ **5. Execution — phases.current_status = "pending":**
78
+
79
+ Check if the current phase already has a PLAN.md (just-in-time planning):
80
+ ```bash
81
+ PHASE_DIR="$TASK_DIR/phases/phase-$(printf '%02d' $CURRENT)"
82
+ [ -f "$PHASE_DIR/PLAN.md" ] && echo "has_plan"
83
+ ```
84
+
85
+ If no PLAN.md — phase needs planning first:
86
+ ```
87
+ $NEXT_STEP = "plan"
88
+ $NEXT_PIPELINE = "phase-execution"
89
+ ```
90
+ plan.md detects stage=execution and creates a detailed PLAN.md for this phase only, reading the goal from ROADMAP.md.
91
+
92
+ If PLAN.md exists — phase is planned, ready to execute:
93
+ ```
94
+ $NEXT_STEP = "execute"
95
+ $NEXT_PIPELINE = "phase-execution"
96
+ ```
97
+
98
+ **6. Execution — phases.current_status = "executing":**
99
+ ```
100
+ $NEXT_STEP = "execute"
101
+ $NEXT_PIPELINE = "phase-execution"
102
+ $RESUME = true
103
+ ```
104
+ Interrupted execution — resume.
105
+
106
+ **7. Execution — phases.current_status = "executed":**
107
+ ```
108
+ $NEXT_STEP = "review"
109
+ $NEXT_PIPELINE = "phase-execution"
110
+ ```
111
+ Phase done, needs review.
112
+
113
+ **8. Execution — phases.current_status = "completed":**
114
+ Check for more phases:
115
+ ```bash
116
+ # Check if current phase < total phases
117
+ CURRENT=$(read phases.current from config.json)
118
+ TOTAL=$(read phases.total from config.json)
119
+ ```
120
+
121
+ Also check for decimal fix phases:
122
+ ```bash
123
+ ls -d $TASK_DIR/phases/phase-$(printf '%02d' $CURRENT).* 2>/dev/null
124
+ ```
125
+
126
+ If decimal fix phases exist and are incomplete → route to execute for fix phase.
127
+ If current < total → advance `phases.current`, set status to "pending", route to execute.
128
+ If current >= total → task complete.
129
+
130
+ ### Task Complete
131
+
132
+ When all phases are done:
133
+ ```
134
+ $NEXT_STEP = "complete"
135
+ $TASK_COMPLETE = true
136
+ ```
137
+
138
+ ### Find Step in Pipeline
139
+
140
+ To find a step by name in a pipeline array:
141
+
142
+ ```
143
+ For each step in $PIPELINE.pipelines.{pipeline_name}:
144
+ If step.name == $NEXT_STEP:
145
+ Return step (workflow path, hooks config)
146
+ ```
147
+
148
+ If step not found in pipeline → error:
149
+ ```
150
+ Step '{name}' not found in pipeline '{pipeline_name}'. Check your pipeline.json.
151
+ ```
152
+
153
+ ### Resolve Workflow Path
154
+
155
+ Step workflow values are filenames (e.g., `"discuss.md"`). Resolve to full path:
156
+
157
+ ```
158
+ ~/.claude/specdacular/workflows/{workflow}
159
+ ```
160
+
161
+ Or for local install:
162
+ ```
163
+ .claude/specdacular/workflows/{workflow}
164
+ ```
165
+
166
+ For user-overridden workflows (path contains `/`), use as-is (relative to project root).
167
+
168
+ </shared>
@@ -8,23 +8,26 @@ Commit implementation code changes, respecting the user's auto-commit setting.
8
8
  - `$FILES` — the files to `git add` (space-separated paths)
9
9
  - `$MESSAGE` — the commit message
10
10
 
11
- **Check auto-commit setting:**
11
+ **IMPORTANT — You MUST check the auto-commit setting BEFORE running any git commands. Do NOT skip this check.**
12
+
13
+ **Step 1: Read the setting (MANDATORY):**
12
14
 
13
15
  ```bash
14
16
  cat .specd/config.json 2>/dev/null || echo '{"auto_commit_code": true}'
15
17
  ```
16
18
 
17
- **If `auto_commit_code` is `false`:**
18
- Do NOT run git commands. Instead print:
19
+ Read the value of `auto_commit_code` from the output.
20
+
21
+ **Step 2: If `auto_commit_code` is `false` → STOP. Do NOT commit.**
22
+
23
+ Print this message and move on to the next workflow step:
19
24
 
20
25
  ```
21
26
  Auto-commit disabled for code — changes not committed.
22
27
  Modified files: $FILES
23
28
  ```
24
29
 
25
- Then skip ahead to the next step in your workflow.
26
-
27
- **If `auto_commit_code` is `true` or not set (default):**
30
+ **Step 3: If `auto_commit_code` is `true` or not set (default true) → commit:**
28
31
 
29
32
  ```bash
30
33
  git add $FILES
@@ -9,23 +9,26 @@ Commit `.specd/` documentation changes, respecting the user's auto-commit settin
9
9
  - `$MESSAGE` — the commit message
10
10
  - `$LABEL` — short label for the skip message (e.g., "discussion updates", "plan complete", "feature completion")
11
11
 
12
- **Check auto-commit setting:**
12
+ **IMPORTANT — You MUST check the auto-commit setting BEFORE running any git commands. Do NOT skip this check.**
13
+
14
+ **Step 1: Read the setting (MANDATORY):**
13
15
 
14
16
  ```bash
15
17
  cat .specd/config.json 2>/dev/null || echo '{"auto_commit_docs": true}'
16
18
  ```
17
19
 
18
- **If `auto_commit_docs` is `false`:**
19
- Do NOT run git commands. Instead print:
20
+ Read the value of `auto_commit_docs` from the output.
21
+
22
+ **Step 2: If `auto_commit_docs` is `false` → STOP. Do NOT commit.**
23
+
24
+ Print this message and move on to the next workflow step:
20
25
 
21
26
  ```
22
27
  Auto-commit disabled for docs — $LABEL not committed.
23
28
  Modified files: $FILES
24
29
  ```
25
30
 
26
- Then skip ahead to the next step in your workflow.
27
-
28
- **If `auto_commit_docs` is `true` or not set (default):**
31
+ **Step 3: If `auto_commit_docs` is `true` or not set (default true) → commit:**
29
32
 
30
33
  ```bash
31
34
  git add $FILES