@leeovery/claude-technical-workflows 2.0.44 → 2.0.46
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/commands/link-dependencies.md +2 -2
- package/commands/workflow/start-discussion.md +5 -1
- package/commands/workflow/start-implementation.md +5 -1
- package/commands/workflow/start-planning.md +5 -1
- package/commands/workflow/start-research.md +5 -1
- package/commands/workflow/start-review.md +5 -1
- package/commands/workflow/start-specification.md +65 -11
- package/commands/workflow/status.md +5 -1
- package/commands/workflow/view-plan.md +1 -9
- package/package.json +1 -1
- package/scripts/discovery-for-specification.sh +62 -8
- package/scripts/migrate.sh +3 -1
- package/scripts/migrations/003-planning-frontmatter.sh +5 -3
- package/scripts/migrations/004-sources-object-format.sh +204 -0
- package/skills/technical-discussion/SKILL.md +7 -1
- package/skills/technical-implementation/SKILL.md +13 -2
- package/skills/technical-implementation/references/environment-setup.md +1 -1
- package/skills/technical-planning/SKILL.md +83 -20
- package/skills/technical-planning/references/{output-backlog-md.md → output-formats/output-backlog-md.md} +4 -4
- package/skills/technical-planning/references/{output-beads.md → output-formats/output-beads.md} +4 -4
- package/skills/technical-planning/references/{output-linear.md → output-formats/output-linear.md} +4 -4
- package/skills/technical-planning/references/{output-local-markdown.md → output-formats/output-local-markdown.md} +3 -3
- package/skills/technical-planning/references/output-formats.md +33 -6
- package/skills/technical-planning/references/phase-design.md +146 -0
- package/skills/technical-planning/references/planning-principles.md +44 -0
- package/skills/technical-planning/references/steps/author-tasks.md +63 -0
- package/skills/technical-planning/references/steps/define-phases.md +40 -0
- package/skills/technical-planning/references/steps/define-tasks.md +43 -0
- package/skills/technical-planning/references/steps/plan-review.md +96 -0
- package/skills/technical-planning/references/steps/resolve-dependencies.md +56 -0
- package/skills/technical-planning/references/steps/review-integrity.md +217 -0
- package/skills/technical-planning/references/steps/review-traceability.md +194 -0
- package/skills/technical-planning/references/task-design.md +158 -0
- package/skills/technical-research/SKILL.md +9 -1
- package/skills/technical-research/references/template.md +1 -0
- package/skills/technical-review/SKILL.md +9 -1
- package/skills/technical-specification/SKILL.md +10 -1
- package/skills/technical-specification/references/specification-guide.md +44 -0
- package/skills/technical-planning/references/formal-planning.md +0 -235
|
@@ -100,7 +100,7 @@ For each unresolved dependency:
|
|
|
100
100
|
|
|
101
101
|
2. **If plan exists**: Load the output format reference file
|
|
102
102
|
- Read `format:` from the dependency plan's frontmatter
|
|
103
|
-
- Load `skills/technical-planning/references/output-{format}.md`
|
|
103
|
+
- Load `skills/technical-planning/references/output-formats/output-{format}.md`
|
|
104
104
|
- Follow the "Querying Dependencies" section to search for matching tasks
|
|
105
105
|
|
|
106
106
|
3. **Handle ambiguous matches**:
|
|
@@ -115,7 +115,7 @@ For each resolved match:
|
|
|
115
115
|
- Change `- {topic}: {description}` to `- {topic}: {description} → {task-id}`
|
|
116
116
|
|
|
117
117
|
2. **Create dependency in output format**:
|
|
118
|
-
- Load `skills/technical-planning/references/output-{format}.md`
|
|
118
|
+
- Load `skills/technical-planning/references/output-formats/output-{format}.md`
|
|
119
119
|
- Follow the "Cross-Epic Dependencies" or equivalent section to create the blocking relationship
|
|
120
120
|
|
|
121
121
|
## Step 6: Bidirectional Check
|
|
@@ -40,7 +40,11 @@ Follow these steps EXACTLY as written. Do not skip steps or combine them. Presen
|
|
|
40
40
|
|
|
41
41
|
**This step is mandatory. You must complete it before proceeding.**
|
|
42
42
|
|
|
43
|
-
Invoke the `/migrate` command and assess its output
|
|
43
|
+
Invoke the `/migrate` command and assess its output.
|
|
44
|
+
|
|
45
|
+
**If files were updated**: STOP and wait for the user to review the changes (e.g., via `git diff`) and confirm before proceeding to Step 1. Do not continue automatically.
|
|
46
|
+
|
|
47
|
+
**If no updates needed**: Proceed to Step 1.
|
|
44
48
|
|
|
45
49
|
---
|
|
46
50
|
|
|
@@ -40,7 +40,11 @@ Follow these steps EXACTLY as written. Do not skip steps or combine them. Presen
|
|
|
40
40
|
|
|
41
41
|
**This step is mandatory. You must complete it before proceeding.**
|
|
42
42
|
|
|
43
|
-
Invoke the `/migrate` command and assess its output
|
|
43
|
+
Invoke the `/migrate` command and assess its output.
|
|
44
|
+
|
|
45
|
+
**If files were updated**: STOP and wait for the user to review the changes (e.g., via `git diff`) and confirm before proceeding to Step 1. Do not continue automatically.
|
|
46
|
+
|
|
47
|
+
**If no updates needed**: Proceed to Step 1.
|
|
44
48
|
|
|
45
49
|
---
|
|
46
50
|
|
|
@@ -40,7 +40,11 @@ Follow these steps EXACTLY as written. Do not skip steps or combine them. Presen
|
|
|
40
40
|
|
|
41
41
|
**This step is mandatory. You must complete it before proceeding.**
|
|
42
42
|
|
|
43
|
-
Invoke the `/migrate` command and assess its output
|
|
43
|
+
Invoke the `/migrate` command and assess its output.
|
|
44
|
+
|
|
45
|
+
**If files were updated**: STOP and wait for the user to review the changes (e.g., via `git diff`) and confirm before proceeding to Step 1. Do not continue automatically.
|
|
46
|
+
|
|
47
|
+
**If no updates needed**: Proceed to Step 1.
|
|
44
48
|
|
|
45
49
|
---
|
|
46
50
|
|
|
@@ -39,7 +39,11 @@ Follow these steps EXACTLY as written. Do not skip steps or combine them. Presen
|
|
|
39
39
|
|
|
40
40
|
**This step is mandatory. You must complete it before proceeding.**
|
|
41
41
|
|
|
42
|
-
Invoke the `/migrate` command and assess its output
|
|
42
|
+
Invoke the `/migrate` command and assess its output.
|
|
43
|
+
|
|
44
|
+
**If files were updated**: STOP and wait for the user to review the changes (e.g., via `git diff`) and confirm before proceeding to Step 1. Do not continue automatically.
|
|
45
|
+
|
|
46
|
+
**If no updates needed**: Proceed to Step 1.
|
|
43
47
|
|
|
44
48
|
---
|
|
45
49
|
|
|
@@ -40,7 +40,11 @@ Follow these steps EXACTLY as written. Do not skip steps or combine them. Presen
|
|
|
40
40
|
|
|
41
41
|
**This step is mandatory. You must complete it before proceeding.**
|
|
42
42
|
|
|
43
|
-
Invoke the `/migrate` command and assess its output
|
|
43
|
+
Invoke the `/migrate` command and assess its output.
|
|
44
|
+
|
|
45
|
+
**If files were updated**: STOP and wait for the user to review the changes (e.g., via `git diff`) and confirm before proceeding to Step 1. Do not continue automatically.
|
|
46
|
+
|
|
47
|
+
**If no updates needed**: Proceed to Step 1.
|
|
44
48
|
|
|
45
49
|
---
|
|
46
50
|
|
|
@@ -40,7 +40,11 @@ Follow these steps EXACTLY as written. Do not skip steps or combine them. Presen
|
|
|
40
40
|
|
|
41
41
|
**This step is mandatory. You must complete it before proceeding.**
|
|
42
42
|
|
|
43
|
-
Invoke the `/migrate` command and assess its output
|
|
43
|
+
Invoke the `/migrate` command and assess its output.
|
|
44
|
+
|
|
45
|
+
**If files were updated**: STOP and wait for the user to review the changes (e.g., via `git diff`) and confirm before proceeding to Step 1. Do not continue automatically.
|
|
46
|
+
|
|
47
|
+
**If no updates needed**: Proceed to Step 1.
|
|
44
48
|
|
|
45
49
|
---
|
|
46
50
|
|
|
@@ -324,7 +328,12 @@ Then analyze coupling between discussions:
|
|
|
324
328
|
- **Behavioral coupling**: Discussions where one's implementation requires another
|
|
325
329
|
- **Conceptual coupling**: Discussions that address different facets of the same problem
|
|
326
330
|
|
|
327
|
-
Group discussions that
|
|
331
|
+
Group discussions into specifications where each grouping represents a **coherent feature or capability that can be independently planned and built** — with clear stages delivering incremental, testable value. Coupling tells you what's related; the grouping decision also requires that the result is the right shape:
|
|
332
|
+
|
|
333
|
+
- **Tightly coupled discussions belong together** — their decisions are inseparable and would produce interleaved implementation work
|
|
334
|
+
- **Don't group too broadly** — if a grouping mixes unrelated concerns, the resulting specification will produce incoherent stages and tasks that jump between disconnected areas
|
|
335
|
+
- **Don't group too narrowly** — if a grouping is too thin, it may not warrant its own specification, planning, and implementation cycle
|
|
336
|
+
- **Flag cross-cutting discussions** — discussions about patterns or policies (not features) should become cross-cutting specifications rather than being grouped with feature discussions
|
|
328
337
|
|
|
329
338
|
#### Preserve Anchored Names
|
|
330
339
|
|
|
@@ -388,8 +397,41 @@ Present the groupings with FULL status information.
|
|
|
388
397
|
|
|
389
398
|
For each grouping, show:
|
|
390
399
|
- The grouping name
|
|
391
|
-
- Whether a specification already exists for this grouping
|
|
392
|
-
- Each discussion in the grouping and
|
|
400
|
+
- Whether a specification already exists for this grouping (and its effective status)
|
|
401
|
+
- Each discussion in the grouping and its incorporation status
|
|
402
|
+
|
|
403
|
+
### Determining Discussion Status Within a Grouping
|
|
404
|
+
|
|
405
|
+
For each grouping, first check if a grouped specification exists:
|
|
406
|
+
1. Convert the grouping name to kebab-case (lowercase, spaces to hyphens)
|
|
407
|
+
2. Check if `docs/workflow/specification/{kebab-name}.md` exists
|
|
408
|
+
3. If it exists, get its `sources` array from the discovery output
|
|
409
|
+
|
|
410
|
+
The sources array uses object format with explicit status tracking:
|
|
411
|
+
```yaml
|
|
412
|
+
sources:
|
|
413
|
+
- name: topic-a
|
|
414
|
+
status: incorporated
|
|
415
|
+
- name: topic-b
|
|
416
|
+
status: pending
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
**If a grouped spec exists for the grouping:**
|
|
420
|
+
|
|
421
|
+
For each discussion in the grouping:
|
|
422
|
+
1. Look up the discussion in the spec's `sources` array (by `name` field)
|
|
423
|
+
2. If found → use the source's `status` field (`incorporated` or `pending`)
|
|
424
|
+
3. If NOT found → status is `"pending"` (new source not yet added to spec)
|
|
425
|
+
|
|
426
|
+
Calculate the **effective spec status**:
|
|
427
|
+
- If ALL discussions in the grouping have `status: incorporated` → use the spec's actual status from file
|
|
428
|
+
- If ANY discussion has `status: pending` OR is not in sources → effective status is `"needs update"`
|
|
429
|
+
|
|
430
|
+
**If NO grouped spec exists:**
|
|
431
|
+
|
|
432
|
+
For each discussion in the grouping:
|
|
433
|
+
- If the discussion has an individual spec (`has_individual_spec: true`) → status is `"spec: {spec_status}"`
|
|
434
|
+
- If the discussion has no spec → status is `"ready"`
|
|
393
435
|
|
|
394
436
|
**Format:**
|
|
395
437
|
|
|
@@ -398,19 +440,20 @@ For each grouping, show:
|
|
|
398
440
|
|
|
399
441
|
Recommended Groupings:
|
|
400
442
|
|
|
401
|
-
### 1. {Grouping Name}
|
|
443
|
+
### 1. {Grouping Name} (spec: {effective_status})
|
|
402
444
|
| Discussion | Status |
|
|
403
445
|
|------------|--------|
|
|
404
|
-
| {topic-a} |
|
|
405
|
-
| {topic-b} |
|
|
406
|
-
| {topic-c} |
|
|
446
|
+
| {topic-a} | incorporated |
|
|
447
|
+
| {topic-b} | incorporated |
|
|
448
|
+
| {topic-c} | pending |
|
|
407
449
|
|
|
408
450
|
Coupling: {explanation}
|
|
409
451
|
|
|
410
452
|
### 2. {Another Grouping}
|
|
411
453
|
| Discussion | Status |
|
|
412
454
|
|------------|--------|
|
|
413
|
-
| {topic-d} |
|
|
455
|
+
| {topic-d} | ready |
|
|
456
|
+
| {topic-e} | spec: in-progress |
|
|
414
457
|
|
|
415
458
|
Coupling: {explanation}
|
|
416
459
|
|
|
@@ -429,6 +472,13 @@ How would you like to proceed?
|
|
|
429
472
|
(Enter 'refresh' to re-analyze)
|
|
430
473
|
```
|
|
431
474
|
|
|
475
|
+
**Status Legend:**
|
|
476
|
+
- `incorporated` - Discussion content has been woven into the grouped specification
|
|
477
|
+
- `pending` - Discussion is part of the group but not yet incorporated into the spec
|
|
478
|
+
- `ready` - Discussion has no spec yet (ready to be specified)
|
|
479
|
+
- `spec: {status}` - Discussion has its own individual specification
|
|
480
|
+
- `needs update` - Grouped spec exists but has pending sources to incorporate
|
|
481
|
+
|
|
432
482
|
**STOP.** Wait for user to choose.
|
|
433
483
|
|
|
434
484
|
→ Based on choice, proceed to **Step 8**.
|
|
@@ -636,7 +686,9 @@ Proceed? (y/n)
|
|
|
636
686
|
```
|
|
637
687
|
{Creating / Continuing} specification: {topic}
|
|
638
688
|
|
|
639
|
-
|
|
689
|
+
Sources:
|
|
690
|
+
- docs/workflow/discussion/{topic}.md
|
|
691
|
+
|
|
640
692
|
Output: docs/workflow/specification/{topic}.md
|
|
641
693
|
|
|
642
694
|
Proceed? (y/n)
|
|
@@ -680,7 +732,9 @@ Invoke the [technical-specification](../../skills/technical-specification/SKILL.
|
|
|
680
732
|
```
|
|
681
733
|
Specification session for: {topic}
|
|
682
734
|
|
|
683
|
-
|
|
735
|
+
Sources:
|
|
736
|
+
- docs/workflow/discussion/{topic}.md
|
|
737
|
+
|
|
684
738
|
Output: docs/workflow/specification/{topic}.md
|
|
685
739
|
|
|
686
740
|
Additional context: {summary of user's answers from Step 10}
|
|
@@ -8,7 +8,11 @@ Show the current state of the workflow for this project.
|
|
|
8
8
|
|
|
9
9
|
**This step is mandatory. You must complete it before proceeding.**
|
|
10
10
|
|
|
11
|
-
Invoke the `/migrate` command and assess its output
|
|
11
|
+
Invoke the `/migrate` command and assess its output.
|
|
12
|
+
|
|
13
|
+
**If files were updated**: STOP and wait for the user to review the changes (e.g., via `git diff`) and confirm before proceeding to Step 1. Do not continue automatically.
|
|
14
|
+
|
|
15
|
+
**If no updates needed**: Proceed to Step 1.
|
|
12
16
|
|
|
13
17
|
---
|
|
14
18
|
|
|
@@ -4,14 +4,6 @@ description: View a plan's tasks and progress, regardless of output format.
|
|
|
4
4
|
|
|
5
5
|
Display a readable summary of a plan's phases, tasks, and status.
|
|
6
6
|
|
|
7
|
-
## Step 0: Run Migrations
|
|
8
|
-
|
|
9
|
-
**This step is mandatory. You must complete it before proceeding.**
|
|
10
|
-
|
|
11
|
-
Invoke the `/migrate` command and assess its output before proceeding to Step 1.
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
7
|
## Step 1: Identify the Plan
|
|
16
8
|
|
|
17
9
|
If no topic is specified, list available plans:
|
|
@@ -31,7 +23,7 @@ Read the plan file from `docs/workflow/planning/{topic}.md` and check the `forma
|
|
|
31
23
|
Load the corresponding output format reference:
|
|
32
24
|
|
|
33
25
|
```
|
|
34
|
-
skills/technical-planning/references/output-{format}.md
|
|
26
|
+
skills/technical-planning/references/output-formats/output-{format}.md
|
|
35
27
|
```
|
|
36
28
|
|
|
37
29
|
This reference contains instructions for reading plans in that format.
|
package/package.json
CHANGED
|
@@ -35,9 +35,8 @@ extract_array_field() {
|
|
|
35
35
|
local file="$1"
|
|
36
36
|
local field="$2"
|
|
37
37
|
local result
|
|
38
|
-
# Look for field followed by array items (- item),
|
|
39
|
-
result=$(
|
|
40
|
-
grep -v "^---$" | \
|
|
38
|
+
# Look for field followed by array items (- item), within frontmatter only
|
|
39
|
+
result=$(awk 'BEGIN{c=0} /^---$/{c++; if(c==2) exit; next} c==1{print}' "$file" 2>/dev/null | \
|
|
41
40
|
sed -n "/^${field}:/,/^[a-z_]*:/p" | \
|
|
42
41
|
grep "^[[:space:]]*-" | \
|
|
43
42
|
sed 's/^[[:space:]]*-[[:space:]]*//' | \
|
|
@@ -46,6 +45,62 @@ extract_array_field() {
|
|
|
46
45
|
echo "$result"
|
|
47
46
|
}
|
|
48
47
|
|
|
48
|
+
# Helper: Extract sources with status from object format
|
|
49
|
+
# Outputs YAML-formatted source entries with name and status
|
|
50
|
+
# Usage: extract_sources_with_status <file>
|
|
51
|
+
#
|
|
52
|
+
# Note: This only handles the object format. Legacy simple array format
|
|
53
|
+
# is converted by migration 004 before discovery runs.
|
|
54
|
+
extract_sources_with_status() {
|
|
55
|
+
local file="$1"
|
|
56
|
+
local in_sources=false
|
|
57
|
+
local current_name=""
|
|
58
|
+
local current_status=""
|
|
59
|
+
|
|
60
|
+
# Read frontmatter and parse sources block
|
|
61
|
+
while IFS= read -r line; do
|
|
62
|
+
# Detect start of sources block
|
|
63
|
+
if [[ "$line" =~ ^sources: ]]; then
|
|
64
|
+
in_sources=true
|
|
65
|
+
continue
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
# Detect end of sources block (next top-level field)
|
|
69
|
+
if $in_sources && [[ "$line" =~ ^[a-z_]+: ]] && [[ ! "$line" =~ ^[[:space:]] ]]; then
|
|
70
|
+
# Output last source if pending
|
|
71
|
+
if [ -n "$current_name" ]; then
|
|
72
|
+
echo " - name: \"$current_name\""
|
|
73
|
+
echo " status: \"${current_status:-incorporated}\""
|
|
74
|
+
fi
|
|
75
|
+
break
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
if $in_sources; then
|
|
79
|
+
# Object format: " - name: value"
|
|
80
|
+
if [[ "$line" =~ ^[[:space:]]*-[[:space:]]*name:[[:space:]]*(.+)$ ]]; then
|
|
81
|
+
# Output previous source if exists
|
|
82
|
+
if [ -n "$current_name" ]; then
|
|
83
|
+
echo " - name: \"$current_name\""
|
|
84
|
+
echo " status: \"${current_status:-incorporated}\""
|
|
85
|
+
fi
|
|
86
|
+
current_name="${BASH_REMATCH[1]}"
|
|
87
|
+
current_name=$(echo "$current_name" | sed 's/^"//' | sed 's/"$//' | xargs)
|
|
88
|
+
current_status=""
|
|
89
|
+
# Status line: " status: value"
|
|
90
|
+
elif [[ "$line" =~ ^[[:space:]]*status:[[:space:]]*(.+)$ ]]; then
|
|
91
|
+
current_status="${BASH_REMATCH[1]}"
|
|
92
|
+
current_status=$(echo "$current_status" | sed 's/^"//' | sed 's/"$//' | xargs)
|
|
93
|
+
fi
|
|
94
|
+
fi
|
|
95
|
+
done < <(awk 'BEGIN{c=0} /^---$/{c++; if(c==2) exit; next} c==1{print}' "$file" 2>/dev/null)
|
|
96
|
+
|
|
97
|
+
# Output last source if pending (end of frontmatter)
|
|
98
|
+
if [ -n "$current_name" ]; then
|
|
99
|
+
echo " - name: \"$current_name\""
|
|
100
|
+
echo " status: \"${current_status:-incorporated}\""
|
|
101
|
+
fi
|
|
102
|
+
}
|
|
103
|
+
|
|
49
104
|
# Start YAML output
|
|
50
105
|
echo "# Specification Command State Discovery"
|
|
51
106
|
echo "# Generated: $(date -Iseconds)"
|
|
@@ -101,7 +156,6 @@ if [ -d "$SPEC_DIR" ] && [ -n "$(ls -A "$SPEC_DIR" 2>/dev/null)" ]; then
|
|
|
101
156
|
status=${status:-"active"}
|
|
102
157
|
|
|
103
158
|
superseded_by=$(extract_field "$file" "superseded_by")
|
|
104
|
-
sources=$(extract_array_field "$file" "sources")
|
|
105
159
|
|
|
106
160
|
echo " - name: \"$name\""
|
|
107
161
|
echo " status: \"$status\""
|
|
@@ -110,11 +164,11 @@ if [ -d "$SPEC_DIR" ] && [ -n "$(ls -A "$SPEC_DIR" 2>/dev/null)" ]; then
|
|
|
110
164
|
echo " superseded_by: \"$superseded_by\""
|
|
111
165
|
fi
|
|
112
166
|
|
|
113
|
-
|
|
167
|
+
# Extract sources with status (handles both old and new format)
|
|
168
|
+
sources_output=$(extract_sources_with_status "$file")
|
|
169
|
+
if [ -n "$sources_output" ]; then
|
|
114
170
|
echo " sources:"
|
|
115
|
-
|
|
116
|
-
echo " - \"$src\""
|
|
117
|
-
done
|
|
171
|
+
echo "$sources_output"
|
|
118
172
|
fi
|
|
119
173
|
done
|
|
120
174
|
else
|
package/scripts/migrate.sh
CHANGED
|
@@ -116,8 +116,10 @@ for script in "${MIGRATION_SCRIPTS[@]}"; do
|
|
|
116
116
|
MIGRATIONS_RUN=$((MIGRATIONS_RUN + 1))
|
|
117
117
|
done
|
|
118
118
|
|
|
119
|
-
#
|
|
119
|
+
# Report results
|
|
120
120
|
if [ "$FILES_UPDATED" -gt 0 ]; then
|
|
121
121
|
echo ""
|
|
122
122
|
echo "$FILES_UPDATED file(s) migrated. Review with \`git diff\`, then proceed."
|
|
123
|
+
else
|
|
124
|
+
echo "[SKIP] No changes needed"
|
|
123
125
|
fi
|
|
@@ -84,16 +84,18 @@ for file in "$PLAN_DIR"/*.md; do
|
|
|
84
84
|
topic_kebab=$(basename "$file" .md)
|
|
85
85
|
|
|
86
86
|
# Extract format from existing frontmatter (if present)
|
|
87
|
-
|
|
87
|
+
# Use awk to extract only the first frontmatter block (between first pair of --- delimiters)
|
|
88
|
+
# This avoids matching --- horizontal rules in body content
|
|
89
|
+
format_value=$(awk 'BEGIN{c=0} /^---$/{c++; if(c==2) exit; next} c==1{print}' "$file" 2>/dev/null | grep "^format:" | sed 's/^format:[[:space:]]*//' | xargs || echo "")
|
|
88
90
|
if [ -z "$format_value" ]; then
|
|
89
91
|
format_value="MISSING" # No default - missing format is an error
|
|
90
92
|
fi
|
|
91
93
|
|
|
92
94
|
# Extract plan_id from existing frontmatter - could be 'epic' (beads) or 'project' (linear/backlog)
|
|
93
95
|
# These are migrated to a unified 'plan_id' field
|
|
94
|
-
plan_id_value=$(
|
|
96
|
+
plan_id_value=$(awk 'BEGIN{c=0} /^---$/{c++; if(c==2) exit; next} c==1{print}' "$file" 2>/dev/null | grep "^epic:" | sed 's/^epic:[[:space:]]*//' | xargs || echo "")
|
|
95
97
|
if [ -z "$plan_id_value" ]; then
|
|
96
|
-
plan_id_value=$(
|
|
98
|
+
plan_id_value=$(awk 'BEGIN{c=0} /^---$/{c++; if(c==2) exit; next} c==1{print}' "$file" 2>/dev/null | grep "^project:" | sed 's/^project:[[:space:]]*//' | xargs || echo "")
|
|
97
99
|
fi
|
|
98
100
|
|
|
99
101
|
# Extract status from **Status**: Value
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# 004-sources-object-format.sh
|
|
4
|
+
#
|
|
5
|
+
# Migrates specification sources from simple array format to object format
|
|
6
|
+
# with status tracking. Also ensures all specs have a sources field.
|
|
7
|
+
#
|
|
8
|
+
# Previous format (from 002-specification-frontmatter.sh):
|
|
9
|
+
# sources:
|
|
10
|
+
# - topic-a
|
|
11
|
+
# - topic-b
|
|
12
|
+
#
|
|
13
|
+
# New format:
|
|
14
|
+
# sources:
|
|
15
|
+
# - name: topic-a
|
|
16
|
+
# status: incorporated
|
|
17
|
+
# - name: topic-b
|
|
18
|
+
# status: incorporated
|
|
19
|
+
#
|
|
20
|
+
# Status values:
|
|
21
|
+
# - pending: Source selected but content not yet extracted
|
|
22
|
+
# - incorporated: Source content has been fully woven into the specification
|
|
23
|
+
#
|
|
24
|
+
# For existing sources, we assume "incorporated" since they were part of
|
|
25
|
+
# the specification when it was created/worked on.
|
|
26
|
+
#
|
|
27
|
+
# For specs WITHOUT a sources field:
|
|
28
|
+
# - If a matching discussion exists (same filename), add it as incorporated
|
|
29
|
+
# - If no matching discussion, add empty sources: [] and report for user review
|
|
30
|
+
#
|
|
31
|
+
# This script is sourced by migrate.sh and has access to:
|
|
32
|
+
# - is_migrated "filepath" "migration_id"
|
|
33
|
+
# - record_migration "filepath" "migration_id"
|
|
34
|
+
# - report_update "filepath" "description"
|
|
35
|
+
# - report_skip "filepath"
|
|
36
|
+
#
|
|
37
|
+
|
|
38
|
+
MIGRATION_ID="004"
|
|
39
|
+
SPEC_DIR="docs/workflow/specification"
|
|
40
|
+
DISCUSSION_DIR="docs/workflow/discussion"
|
|
41
|
+
|
|
42
|
+
# Skip if no specification directory
|
|
43
|
+
if [ ! -d "$SPEC_DIR" ]; then
|
|
44
|
+
return 0
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
# Helper: Extract ONLY the frontmatter content (between first pair of --- delimiters)
|
|
48
|
+
# Documents may contain --- elsewhere (horizontal rules), so sed range matching
|
|
49
|
+
# can return content beyond frontmatter. Use awk for precise first-block extraction.
|
|
50
|
+
extract_frontmatter() {
|
|
51
|
+
local file="$1"
|
|
52
|
+
awk 'BEGIN{c=0} /^---$/{c++; if(c==2) exit; next} c==1{print}' "$file" 2>/dev/null
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# Helper: Check if sources are already in object format
|
|
56
|
+
# Returns 0 if already migrated (has "name:" entries), 1 if not
|
|
57
|
+
sources_already_object_format() {
|
|
58
|
+
local file="$1"
|
|
59
|
+
# Look for "- name:" pattern within the sources block (frontmatter only)
|
|
60
|
+
# This indicates the new object format
|
|
61
|
+
# Using subshell with || false to ensure proper exit code without pipefail issues
|
|
62
|
+
( extract_frontmatter "$file" | \
|
|
63
|
+
sed -n '/^sources:/,/^[a-z_]*:/p' | \
|
|
64
|
+
grep -q "^[[:space:]]*-[[:space:]]*name:" 2>/dev/null ) || return 1
|
|
65
|
+
return 0
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
# Helper: Extract sources array items (simple string format)
|
|
69
|
+
# Returns space-separated list of source names
|
|
70
|
+
extract_simple_sources() {
|
|
71
|
+
local file="$1"
|
|
72
|
+
# Extract sources from frontmatter only, then find the sources block
|
|
73
|
+
extract_frontmatter "$file" | \
|
|
74
|
+
sed -n '/^sources:/,/^[a-z_]*:/p' | \
|
|
75
|
+
grep -v "^sources:" | \
|
|
76
|
+
grep -v "^[a-z_]*:" | \
|
|
77
|
+
{ grep "^[[:space:]]*-[[:space:]]" || true; } | \
|
|
78
|
+
{ grep -v "name:" || true; } | \
|
|
79
|
+
sed 's/^[[:space:]]*-[[:space:]]*//' | \
|
|
80
|
+
sed 's/^"//' | \
|
|
81
|
+
sed 's/"$//' | \
|
|
82
|
+
tr '\n' ' ' | \
|
|
83
|
+
sed 's/[[:space:]]*$//' || true
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
# Process each specification file
|
|
87
|
+
for file in "$SPEC_DIR"/*.md; do
|
|
88
|
+
[ -f "$file" ] || continue
|
|
89
|
+
|
|
90
|
+
# Check if already migrated via tracking
|
|
91
|
+
if is_migrated "$file" "$MIGRATION_ID"; then
|
|
92
|
+
report_skip "$file"
|
|
93
|
+
continue
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
# Check if file has YAML frontmatter
|
|
97
|
+
if ! head -1 "$file" 2>/dev/null | grep -q "^---$"; then
|
|
98
|
+
record_migration "$file" "$MIGRATION_ID"
|
|
99
|
+
report_skip "$file"
|
|
100
|
+
continue
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
# Check if file has sources field at all
|
|
104
|
+
has_sources_field=false
|
|
105
|
+
if grep -q "^sources:" "$file" 2>/dev/null; then
|
|
106
|
+
has_sources_field=true
|
|
107
|
+
fi
|
|
108
|
+
|
|
109
|
+
# If sources field exists, check if already in object format
|
|
110
|
+
if $has_sources_field && sources_already_object_format "$file"; then
|
|
111
|
+
record_migration "$file" "$MIGRATION_ID"
|
|
112
|
+
report_skip "$file"
|
|
113
|
+
continue
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
#
|
|
117
|
+
# Build new sources block in object format
|
|
118
|
+
#
|
|
119
|
+
new_sources_block="sources:"
|
|
120
|
+
sources_added=false
|
|
121
|
+
|
|
122
|
+
if $has_sources_field; then
|
|
123
|
+
# Extract existing sources from simple array format
|
|
124
|
+
sources=$(extract_simple_sources "$file")
|
|
125
|
+
|
|
126
|
+
for src in $sources; do
|
|
127
|
+
# Clean the source name (trim whitespace, sed avoids xargs quote issues)
|
|
128
|
+
src=$(echo "$src" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
129
|
+
if [ -n "$src" ]; then
|
|
130
|
+
new_sources_block="${new_sources_block}
|
|
131
|
+
- name: $src
|
|
132
|
+
status: incorporated"
|
|
133
|
+
sources_added=true
|
|
134
|
+
fi
|
|
135
|
+
done
|
|
136
|
+
else
|
|
137
|
+
# No sources field - check for matching discussion by filename
|
|
138
|
+
spec_name=$(basename "$file" .md)
|
|
139
|
+
discussion_file="$DISCUSSION_DIR/${spec_name}.md"
|
|
140
|
+
|
|
141
|
+
if [ -f "$discussion_file" ]; then
|
|
142
|
+
# Matching discussion found - add it as incorporated
|
|
143
|
+
new_sources_block="${new_sources_block}
|
|
144
|
+
- name: $spec_name
|
|
145
|
+
status: incorporated"
|
|
146
|
+
sources_added=true
|
|
147
|
+
fi
|
|
148
|
+
fi
|
|
149
|
+
|
|
150
|
+
# If no sources were added, use empty array format
|
|
151
|
+
if ! $sources_added; then
|
|
152
|
+
new_sources_block="sources: []"
|
|
153
|
+
# Echo info for Claude to prompt user about unmatched specs
|
|
154
|
+
spec_name=$(basename "$file" .md)
|
|
155
|
+
echo "MIGRATION_INFO: Specification '$spec_name' has no matching discussion. Sources field set to empty - please review and add sources manually."
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
#
|
|
159
|
+
# Update sources block in file
|
|
160
|
+
#
|
|
161
|
+
|
|
162
|
+
# Extract frontmatter (only the first block between --- delimiters)
|
|
163
|
+
frontmatter=$(extract_frontmatter "$file")
|
|
164
|
+
|
|
165
|
+
if $has_sources_field; then
|
|
166
|
+
# Remove old sources block from frontmatter
|
|
167
|
+
# First, remove lines from "sources:" until the next top-level field or end of frontmatter
|
|
168
|
+
new_frontmatter=$(echo "$frontmatter" | awk '
|
|
169
|
+
/^sources:/ { skip=1; next }
|
|
170
|
+
/^[a-z_]+:/ && skip { skip=0 }
|
|
171
|
+
skip == 0 { print }
|
|
172
|
+
')
|
|
173
|
+
else
|
|
174
|
+
# No existing sources field - use frontmatter as-is
|
|
175
|
+
new_frontmatter="$frontmatter"
|
|
176
|
+
fi
|
|
177
|
+
|
|
178
|
+
# Add new sources block at the end
|
|
179
|
+
new_frontmatter="${new_frontmatter}
|
|
180
|
+
${new_sources_block}"
|
|
181
|
+
|
|
182
|
+
# Extract content after frontmatter (everything after the second ---)
|
|
183
|
+
# Uses awk to skip only the first two --- delimiters, preserving any --- in body content
|
|
184
|
+
content=$(awk '/^---$/ && c<2 {c++; next} c>=2 {print}' "$file")
|
|
185
|
+
|
|
186
|
+
# Write new file
|
|
187
|
+
{
|
|
188
|
+
echo "---"
|
|
189
|
+
echo "$new_frontmatter"
|
|
190
|
+
echo "---"
|
|
191
|
+
echo "$content"
|
|
192
|
+
} > "$file"
|
|
193
|
+
|
|
194
|
+
record_migration "$file" "$MIGRATION_ID"
|
|
195
|
+
|
|
196
|
+
# Report appropriate message based on what was done
|
|
197
|
+
if $has_sources_field; then
|
|
198
|
+
report_update "$file" "converted sources to object format"
|
|
199
|
+
elif $sources_added; then
|
|
200
|
+
report_update "$file" "added sources field with matching discussion"
|
|
201
|
+
else
|
|
202
|
+
report_update "$file" "added empty sources field (no matching discussion found)"
|
|
203
|
+
fi
|
|
204
|
+
done
|
|
@@ -21,7 +21,13 @@ Either way: Capture decisions, rationale, competing approaches, and edge cases.
|
|
|
21
21
|
- **Context** (optional) - Prior research, constraints, existing decisions
|
|
22
22
|
- **Questions to explore** (optional) - Specific architectural questions to address
|
|
23
23
|
|
|
24
|
-
**If missing
|
|
24
|
+
**Before proceeding**, confirm the required input is clear. If anything is missing or unclear, **STOP** and resolve with the user.
|
|
25
|
+
|
|
26
|
+
- **No topic provided?**
|
|
27
|
+
> "What topic would you like to discuss? This could be an architectural decision, a design problem, or edge cases to work through — anything that needs structured technical discussion."
|
|
28
|
+
|
|
29
|
+
- **Topic is broad or ambiguous?**
|
|
30
|
+
> "You mentioned {topic}. To keep the discussion focused, is there a specific aspect or decision you want to work through first?"
|
|
25
31
|
|
|
26
32
|
## What to Capture
|
|
27
33
|
|
|
@@ -25,7 +25,18 @@ Either way: Execute via strict TDD - tests first, implementation second.
|
|
|
25
25
|
- **Environment setup** (optional) - First-time setup instructions
|
|
26
26
|
- **Scope** (optional) - Specific phase/task to work on
|
|
27
27
|
|
|
28
|
-
**
|
|
28
|
+
**Before proceeding**, verify all required inputs are available and unambiguous. If anything is missing or unclear, **STOP** — do not proceed until resolved.
|
|
29
|
+
|
|
30
|
+
- **No plan provided?**
|
|
31
|
+
> "I need an implementation plan to execute. Could you point me to the plan file (e.g., `docs/workflow/planning/{topic}.md`)?"
|
|
32
|
+
|
|
33
|
+
- **Plan has no `format` field in frontmatter?**
|
|
34
|
+
> "The plan at {path} doesn't specify an output format in its frontmatter. Which format does this plan use?"
|
|
35
|
+
|
|
36
|
+
- **Plan status is not `concluded`?**
|
|
37
|
+
> "The plan at {path} has status '{status}' — it hasn't completed the review process. Should I proceed anyway, or should the plan be reviewed first?"
|
|
38
|
+
|
|
39
|
+
If no specification is available, the plan becomes the sole authority for design decisions.
|
|
29
40
|
|
|
30
41
|
## Hard Rules
|
|
31
42
|
|
|
@@ -60,7 +71,7 @@ Complete ALL setup steps before proceeding to implementation work.
|
|
|
60
71
|
|
|
61
72
|
2. **Read the plan** from the provided location (typically `docs/workflow/planning/{topic}.md`)
|
|
62
73
|
- Check the `format` field in frontmatter
|
|
63
|
-
- Load the output adapter: `skills/technical-planning/references/output-{format}.md`
|
|
74
|
+
- Load the output adapter: `skills/technical-planning/references/output-formats/output-{format}.md`
|
|
64
75
|
- If no format field, ask user which format the plan uses
|
|
65
76
|
- Follow the **Implementation** section for how to read tasks and update progress
|
|
66
77
|
|
|
@@ -55,7 +55,7 @@ If the environment setup document contains only "No special setup required" (or
|
|
|
55
55
|
Some plan formats require specific tools. Check the plan's `format` field and load the corresponding output adapter from the planning skill for setup instructions:
|
|
56
56
|
|
|
57
57
|
```
|
|
58
|
-
skills/technical-planning/references/output-{format}.md
|
|
58
|
+
skills/technical-planning/references/output-formats/output-{format}.md
|
|
59
59
|
```
|
|
60
60
|
|
|
61
61
|
Each output adapter contains prerequisites and installation instructions for that format.
|