@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.
Files changed (39) hide show
  1. package/commands/link-dependencies.md +2 -2
  2. package/commands/workflow/start-discussion.md +5 -1
  3. package/commands/workflow/start-implementation.md +5 -1
  4. package/commands/workflow/start-planning.md +5 -1
  5. package/commands/workflow/start-research.md +5 -1
  6. package/commands/workflow/start-review.md +5 -1
  7. package/commands/workflow/start-specification.md +65 -11
  8. package/commands/workflow/status.md +5 -1
  9. package/commands/workflow/view-plan.md +1 -9
  10. package/package.json +1 -1
  11. package/scripts/discovery-for-specification.sh +62 -8
  12. package/scripts/migrate.sh +3 -1
  13. package/scripts/migrations/003-planning-frontmatter.sh +5 -3
  14. package/scripts/migrations/004-sources-object-format.sh +204 -0
  15. package/skills/technical-discussion/SKILL.md +7 -1
  16. package/skills/technical-implementation/SKILL.md +13 -2
  17. package/skills/technical-implementation/references/environment-setup.md +1 -1
  18. package/skills/technical-planning/SKILL.md +83 -20
  19. package/skills/technical-planning/references/{output-backlog-md.md → output-formats/output-backlog-md.md} +4 -4
  20. package/skills/technical-planning/references/{output-beads.md → output-formats/output-beads.md} +4 -4
  21. package/skills/technical-planning/references/{output-linear.md → output-formats/output-linear.md} +4 -4
  22. package/skills/technical-planning/references/{output-local-markdown.md → output-formats/output-local-markdown.md} +3 -3
  23. package/skills/technical-planning/references/output-formats.md +33 -6
  24. package/skills/technical-planning/references/phase-design.md +146 -0
  25. package/skills/technical-planning/references/planning-principles.md +44 -0
  26. package/skills/technical-planning/references/steps/author-tasks.md +63 -0
  27. package/skills/technical-planning/references/steps/define-phases.md +40 -0
  28. package/skills/technical-planning/references/steps/define-tasks.md +43 -0
  29. package/skills/technical-planning/references/steps/plan-review.md +96 -0
  30. package/skills/technical-planning/references/steps/resolve-dependencies.md +56 -0
  31. package/skills/technical-planning/references/steps/review-integrity.md +217 -0
  32. package/skills/technical-planning/references/steps/review-traceability.md +194 -0
  33. package/skills/technical-planning/references/task-design.md +158 -0
  34. package/skills/technical-research/SKILL.md +9 -1
  35. package/skills/technical-research/references/template.md +1 -0
  36. package/skills/technical-review/SKILL.md +9 -1
  37. package/skills/technical-specification/SKILL.md +10 -1
  38. package/skills/technical-specification/references/specification-guide.md +44 -0
  39. 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 before proceeding to Step 1.
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 before proceeding to Step 1.
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 before proceeding to Step 1.
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 before proceeding to Step 1.
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 before proceeding to Step 1.
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 before proceeding to Step 1.
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 are tightly coupled - they should become a single specification because their decisions are inseparable.
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 whether it has an individual spec
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} {if spec exists: "(spec: {spec_status})"}
443
+ ### 1. {Grouping Name} (spec: {effective_status})
402
444
  | Discussion | Status |
403
445
  |------------|--------|
404
- | {topic-a} | discussion only |
405
- | {topic-b} | spec: {spec_status} |
406
- | {topic-c} | discussion only |
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} | discussion only |
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
- Source: docs/workflow/discussion/{topic}.md
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
- Source: docs/workflow/discussion/{topic}.md
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 before proceeding to Step 1.
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leeovery/claude-technical-workflows",
3
- "version": "2.0.44",
3
+ "version": "2.0.46",
4
4
  "description": "Technical workflow skills & commands for Claude Code",
5
5
  "license": "MIT",
6
6
  "author": "Lee Overy <me@leeovery.com>",
@@ -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), excluding --- delimiters
39
- result=$(sed -n '/^---$/,/^---$/p' "$file" 2>/dev/null | \
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
- if [ -n "$sources" ]; then
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
- for src in $sources; do
116
- echo " - \"$src\""
117
- done
171
+ echo "$sources_output"
118
172
  fi
119
173
  done
120
174
  else
@@ -116,8 +116,10 @@ for script in "${MIGRATION_SCRIPTS[@]}"; do
116
116
  MIGRATIONS_RUN=$((MIGRATIONS_RUN + 1))
117
117
  done
118
118
 
119
- # Only output if files were actually updated
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
- format_value=$(sed -n '/^---$/,/^---$/p' "$file" 2>/dev/null | grep "^format:" | sed 's/^format:[[:space:]]*//' | xargs || echo "")
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=$(sed -n '/^---$/,/^---$/p' "$file" 2>/dev/null | grep "^epic:" | sed 's/^epic:[[:space:]]*//' | xargs || echo "")
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=$(sed -n '/^---$/,/^---$/p' "$file" 2>/dev/null | grep "^project:" | sed 's/^project:[[:space:]]*//' | xargs || echo "")
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:** Will ask user what topic they want to discuss.
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
- **If missing:** Will ask user for plan location. If no specification, plan becomes sole authority.
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.