prizmkit 1.0.35 → 1.0.58

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 (74) hide show
  1. package/bundled/VERSION.json +3 -3
  2. package/bundled/adapters/claude/agent-adapter.js +2 -1
  3. package/bundled/adapters/claude/command-adapter.js +4 -3
  4. package/bundled/agents/prizm-dev-team-dev.md +12 -12
  5. package/bundled/agents/prizm-dev-team-reviewer.md +10 -10
  6. package/bundled/dev-pipeline/README.md +15 -19
  7. package/bundled/dev-pipeline/assets/prizm-dev-team-integration.md +16 -23
  8. package/bundled/dev-pipeline/launch-bugfix-daemon.sh +8 -0
  9. package/bundled/dev-pipeline/launch-daemon.sh +2 -0
  10. package/bundled/dev-pipeline/lib/branch.sh +76 -0
  11. package/bundled/dev-pipeline/retry-bug.sh +5 -2
  12. package/bundled/dev-pipeline/retry-feature.sh +5 -2
  13. package/bundled/dev-pipeline/run-bugfix.sh +74 -0
  14. package/bundled/dev-pipeline/run.sh +76 -2
  15. package/bundled/dev-pipeline/scripts/check-session-status.py +3 -1
  16. package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +0 -8
  17. package/bundled/dev-pipeline/scripts/parse-stream-progress.py +1 -1
  18. package/bundled/dev-pipeline/scripts/update-bug-status.py +24 -1
  19. package/bundled/dev-pipeline/scripts/update-feature-status.py +3 -2
  20. package/bundled/dev-pipeline/templates/bootstrap-tier1.md +11 -25
  21. package/bundled/dev-pipeline/templates/bootstrap-tier2.md +12 -26
  22. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +54 -65
  23. package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +7 -7
  24. package/bundled/dev-pipeline/templates/session-status-schema.json +1 -1
  25. package/bundled/dev-pipeline/tests/conftest.py +19 -131
  26. package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +207 -0
  27. package/bundled/dev-pipeline/tests/test_utils.py +51 -110
  28. package/bundled/rules/prizm/prizm-commit-workflow.md +3 -3
  29. package/bundled/skills/_metadata.json +15 -16
  30. package/bundled/skills/app-planner/SKILL.md +8 -7
  31. package/bundled/skills/bug-fix-workflow/SKILL.md +174 -0
  32. package/bundled/skills/bug-planner/SKILL.md +20 -32
  33. package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +3 -5
  34. package/bundled/skills/dev-pipeline-launcher/SKILL.md +4 -6
  35. package/bundled/skills/feature-workflow/SKILL.md +25 -42
  36. package/bundled/skills/prizm-kit/SKILL.md +57 -21
  37. package/bundled/skills/prizm-kit/assets/{claude-md-template.md → project-memory-template.md} +2 -2
  38. package/bundled/skills/prizmkit-analyze/SKILL.md +41 -29
  39. package/bundled/skills/prizmkit-clarify/SKILL.md +40 -30
  40. package/bundled/skills/prizmkit-code-review/SKILL.md +48 -43
  41. package/bundled/skills/prizmkit-committer/SKILL.md +30 -68
  42. package/bundled/skills/prizmkit-implement/SKILL.md +48 -24
  43. package/bundled/skills/prizmkit-init/SKILL.md +57 -66
  44. package/bundled/skills/prizmkit-plan/SKILL.md +46 -20
  45. package/bundled/skills/prizmkit-prizm-docs/SKILL.md +60 -19
  46. package/bundled/skills/prizmkit-prizm-docs/assets/PRIZM-SPEC.md +23 -23
  47. package/bundled/skills/prizmkit-retrospective/SKILL.md +142 -65
  48. package/bundled/skills/prizmkit-retrospective/assets/retrospective-template.md +13 -0
  49. package/bundled/skills/prizmkit-specify/SKILL.md +63 -13
  50. package/bundled/skills/refactor-workflow/SKILL.md +105 -49
  51. package/bundled/team/prizm-dev-team.json +5 -19
  52. package/package.json +1 -1
  53. package/src/clean.js +0 -2
  54. package/src/manifest.js +8 -4
  55. package/src/scaffold.js +72 -6
  56. package/src/upgrade.js +32 -5
  57. package/bundled/agents/prizm-dev-team-coordinator.md +0 -141
  58. package/bundled/agents/prizm-dev-team-pm.md +0 -126
  59. package/bundled/dev-pipeline/tests/__init__.py +0 -0
  60. package/bundled/dev-pipeline/tests/test_check_session.py +0 -127
  61. package/bundled/dev-pipeline/tests/test_cleanup_logs.py +0 -119
  62. package/bundled/dev-pipeline/tests/test_detect_stuck.py +0 -207
  63. package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +0 -181
  64. package/bundled/dev-pipeline/tests/test_generate_prompt.py +0 -190
  65. package/bundled/dev-pipeline/tests/test_init_bugfix_pipeline.py +0 -153
  66. package/bundled/dev-pipeline/tests/test_init_pipeline.py +0 -241
  67. package/bundled/dev-pipeline/tests/test_update_bug_status.py +0 -142
  68. package/bundled/dev-pipeline/tests/test_update_feature_status.py +0 -268
  69. package/bundled/skills/prizm-kit/assets/codebuddy-md-template.md +0 -35
  70. package/bundled/skills/prizm-kit/assets/hooks/prizm-commit-hook.json +0 -15
  71. package/bundled/skills/prizmkit-summarize/SKILL.md +0 -51
  72. package/bundled/skills/prizmkit-summarize/assets/registry-template.md +0 -18
  73. package/bundled/templates/hooks/commit-intent-claude.json +0 -26
  74. /package/bundled/templates/hooks/{commit-intent-codebuddy.json → commit-intent.json} +0 -0
@@ -0,0 +1,207 @@
1
+ """Tests for generate-bootstrap-prompt.py core functions."""
2
+
3
+ import re
4
+
5
+ from generate_bootstrap_prompt import (
6
+ compute_feature_slug,
7
+ find_feature,
8
+ format_acceptance_criteria,
9
+ format_global_context,
10
+ get_completed_dependencies,
11
+ determine_pipeline_mode,
12
+ process_conditional_blocks,
13
+ process_mode_blocks,
14
+ )
15
+
16
+
17
+ # ---------------------------------------------------------------------------
18
+ # compute_feature_slug
19
+ # ---------------------------------------------------------------------------
20
+
21
+ class TestComputeFeatureSlug:
22
+ def test_basic(self):
23
+ assert compute_feature_slug("F-001", "Project Infrastructure Setup") == "001-project-infrastructure-setup"
24
+
25
+ def test_strips_special_chars(self):
26
+ assert compute_feature_slug("F-012", "Add (User) Auth!") == "012-add-user-auth"
27
+
28
+ def test_pads_numeric(self):
29
+ assert compute_feature_slug("F-1", "Init") == "001-init"
30
+
31
+ def test_collapses_hyphens(self):
32
+ assert compute_feature_slug("F-003", "foo - - bar") == "003-foo---bar" or \
33
+ compute_feature_slug("F-003", "foo bar") == "003-foo-bar"
34
+
35
+ def test_empty_title(self):
36
+ result = compute_feature_slug("F-099", "")
37
+ assert result == "099-"
38
+
39
+
40
+ # ---------------------------------------------------------------------------
41
+ # find_feature
42
+ # ---------------------------------------------------------------------------
43
+
44
+ class TestFindFeature:
45
+ def test_found(self):
46
+ features = [{"id": "F-001", "title": "A"}, {"id": "F-002", "title": "B"}]
47
+ assert find_feature(features, "F-002") == {"id": "F-002", "title": "B"}
48
+
49
+ def test_not_found(self):
50
+ assert find_feature([{"id": "F-001"}], "F-999") is None
51
+
52
+ def test_empty_list(self):
53
+ assert find_feature([], "F-001") is None
54
+
55
+ def test_non_dict_items(self):
56
+ assert find_feature(["garbage", 42, None, {"id": "F-001"}], "F-001") == {"id": "F-001"}
57
+
58
+
59
+ # ---------------------------------------------------------------------------
60
+ # format_acceptance_criteria
61
+ # ---------------------------------------------------------------------------
62
+
63
+ class TestFormatAcceptanceCriteria:
64
+ def test_none(self):
65
+ assert format_acceptance_criteria(None) == "- (none specified)"
66
+
67
+ def test_empty(self):
68
+ assert format_acceptance_criteria([]) == "- (none specified)"
69
+
70
+ def test_items(self):
71
+ result = format_acceptance_criteria(["Users can log in", "Password reset works"])
72
+ assert "- Users can log in" in result
73
+ assert "- Password reset works" in result
74
+
75
+
76
+ # ---------------------------------------------------------------------------
77
+ # format_global_context
78
+ # ---------------------------------------------------------------------------
79
+
80
+ class TestFormatGlobalContext:
81
+ def test_none(self):
82
+ assert format_global_context(None) == "- (none specified)"
83
+
84
+ def test_empty(self):
85
+ assert format_global_context({}) == "- (none specified)"
86
+
87
+ def test_dict(self):
88
+ result = format_global_context({"framework": "React", "lang": "TypeScript"})
89
+ assert "**framework**: React" in result
90
+ assert "**lang**: TypeScript" in result
91
+
92
+
93
+ # ---------------------------------------------------------------------------
94
+ # get_completed_dependencies
95
+ # ---------------------------------------------------------------------------
96
+
97
+ class TestGetCompletedDependencies:
98
+ def test_no_deps(self):
99
+ feature = {"id": "F-002", "dependencies": []}
100
+ assert "no dependencies" in get_completed_dependencies([], feature)
101
+
102
+ def test_with_completed_dep(self):
103
+ features = [
104
+ {"id": "F-001", "title": "Setup", "status": "completed"},
105
+ {"id": "F-002", "title": "Auth", "dependencies": ["F-001"]},
106
+ ]
107
+ result = get_completed_dependencies(features, features[1])
108
+ assert "F-001" in result
109
+ assert "completed" in result
110
+
111
+ def test_no_completed_dep(self):
112
+ features = [
113
+ {"id": "F-001", "title": "Setup", "status": "pending"},
114
+ {"id": "F-002", "title": "Auth", "dependencies": ["F-001"]},
115
+ ]
116
+ result = get_completed_dependencies(features, features[1])
117
+ assert "no completed dependencies" in result
118
+
119
+
120
+ # ---------------------------------------------------------------------------
121
+ # determine_pipeline_mode
122
+ # ---------------------------------------------------------------------------
123
+
124
+ class TestDeterminePipelineMode:
125
+ def test_low(self):
126
+ assert determine_pipeline_mode("low") == "lite"
127
+
128
+ def test_medium(self):
129
+ assert determine_pipeline_mode("medium") == "standard"
130
+
131
+ def test_high(self):
132
+ assert determine_pipeline_mode("high") == "full"
133
+
134
+ def test_critical(self):
135
+ assert determine_pipeline_mode("critical") == "full"
136
+
137
+ def test_unknown(self):
138
+ assert determine_pipeline_mode("banana") == "standard"
139
+
140
+
141
+ # ---------------------------------------------------------------------------
142
+ # process_conditional_blocks
143
+ # ---------------------------------------------------------------------------
144
+
145
+ class TestProcessConditionalBlocks:
146
+ def test_fresh_start_keeps_fresh_block(self):
147
+ tpl = "before\n{{IF_FRESH_START}}\nfresh content\n{{END_IF_FRESH_START}}\nafter"
148
+ result = process_conditional_blocks(tpl, "null")
149
+ assert "fresh content" in result
150
+ assert "IF_FRESH_START" not in result
151
+
152
+ def test_fresh_start_removes_resume_block(self):
153
+ tpl = "before\n{{IF_RESUME}}\nresume content\n{{END_IF_RESUME}}\nafter"
154
+ result = process_conditional_blocks(tpl, "null")
155
+ assert "resume content" not in result
156
+
157
+ def test_resume_keeps_resume_block(self):
158
+ tpl = "before\n{{IF_RESUME}}\nresume content\n{{END_IF_RESUME}}\nafter"
159
+ result = process_conditional_blocks(tpl, "3")
160
+ assert "resume content" in result
161
+ assert "IF_RESUME" not in result
162
+
163
+ def test_resume_removes_fresh_block(self):
164
+ tpl = "before\n{{IF_FRESH_START}}\nfresh content\n{{END_IF_FRESH_START}}\nafter"
165
+ result = process_conditional_blocks(tpl, "3")
166
+ assert "fresh content" not in result
167
+
168
+
169
+ # ---------------------------------------------------------------------------
170
+ # process_mode_blocks
171
+ # ---------------------------------------------------------------------------
172
+
173
+ class TestProcessModeBlocks:
174
+ def test_lite_mode_keeps_lite(self):
175
+ tpl = "{{IF_MODE_LITE}}lite content{{END_IF_MODE_LITE}}"
176
+ result = process_mode_blocks(tpl, "lite", init_done=True)
177
+ assert "lite content" in result
178
+ assert "IF_MODE" not in result
179
+
180
+ def test_lite_mode_removes_full(self):
181
+ tpl = "{{IF_MODE_FULL}}full content{{END_IF_MODE_FULL}}"
182
+ result = process_mode_blocks(tpl, "lite", init_done=True)
183
+ assert "full content" not in result
184
+
185
+ def test_init_done_keeps_init_done_block(self):
186
+ tpl = "{{IF_INIT_DONE}}\ninit done\n{{END_IF_INIT_DONE}}"
187
+ result = process_mode_blocks(tpl, "standard", init_done=True)
188
+ assert "init done" in result
189
+
190
+ def test_init_needed_when_not_done(self):
191
+ tpl = "{{IF_INIT_NEEDED}}\nneed init\n{{END_IF_INIT_NEEDED}}"
192
+ result = process_mode_blocks(tpl, "standard", init_done=False)
193
+ assert "need init" in result
194
+
195
+ def test_self_evolve_keeps_self_evolve_and_full(self):
196
+ tpl = (
197
+ "{{IF_MODE_SELF_EVOLVE}}se content{{END_IF_MODE_SELF_EVOLVE}}"
198
+ "{{IF_MODE_FULL}}full content{{END_IF_MODE_FULL}}"
199
+ )
200
+ result = process_mode_blocks(tpl, "self-evolve", init_done=True)
201
+ assert "se content" in result
202
+ assert "full content" in result
203
+
204
+ def test_self_evolve_removes_lite(self):
205
+ tpl = "{{IF_MODE_LITE}}lite content{{END_IF_MODE_LITE}}"
206
+ result = process_mode_blocks(tpl, "self-evolve", init_done=True)
207
+ assert "lite content" not in result
@@ -1,141 +1,82 @@
1
- """Tests for utils.py."""
1
+ """Tests for dev-pipeline/scripts/utils.py shared utilities."""
2
2
 
3
3
  import json
4
4
  import os
5
- import pytest
5
+ import tempfile
6
6
 
7
7
  from utils import load_json_file, write_json_file, pad_right, _build_progress_bar
8
8
 
9
9
 
10
- class TestLoadJsonFile:
11
- def test_valid_json(self, tmp_path):
12
- p = tmp_path / "valid.json"
13
- p.write_text('{"key": "value"}', encoding="utf-8")
14
- data, err = load_json_file(str(p))
15
- assert err is None
16
- assert data == {"key": "value"}
17
-
18
- def test_invalid_json(self, tmp_path):
19
- p = tmp_path / "invalid.json"
20
- p.write_text("{not valid json", encoding="utf-8")
21
- data, err = load_json_file(str(p))
22
- assert data is None
23
- assert "Invalid JSON" in err
24
-
25
- def test_missing_file(self, tmp_path):
26
- data, err = load_json_file(str(tmp_path / "missing.json"))
27
- assert data is None
28
- assert "File not found" in err
29
-
30
- def test_empty_file(self, tmp_path):
31
- p = tmp_path / "empty.json"
32
- p.write_text("", encoding="utf-8")
33
- data, err = load_json_file(str(p))
34
- assert data is None
35
- assert "Invalid JSON" in err
36
-
37
- def test_unicode_content(self, tmp_path):
38
- p = tmp_path / "unicode.json"
39
- p.write_text('{"name": "hello"}', encoding="utf-8")
40
- data, err = load_json_file(str(p))
41
- assert err is None
42
- assert data["name"] == "hello"
10
+ # ---------------------------------------------------------------------------
11
+ # load_json_file / write_json_file round-trip
12
+ # ---------------------------------------------------------------------------
43
13
 
44
- def test_nested_json(self, tmp_path):
45
- nested = {"a": {"b": [1, 2, 3]}}
46
- p = tmp_path / "nested.json"
47
- p.write_text(json.dumps(nested), encoding="utf-8")
48
- data, err = load_json_file(str(p))
14
+ class TestJsonIO:
15
+ def test_round_trip(self, tmp_path):
16
+ path = str(tmp_path / "data.json")
17
+ data = {"features": [{"id": "F-001"}]}
18
+ err = write_json_file(path, data)
49
19
  assert err is None
50
- assert data == nested
51
20
 
52
-
53
- class TestWriteJsonFile:
54
- def test_write_and_read_back(self, tmp_path):
55
- p = str(tmp_path / "output.json")
56
- data = {"hello": "world", "num": 42}
57
- err = write_json_file(p, data)
21
+ loaded, err = load_json_file(path)
58
22
  assert err is None
59
- read_data, read_err = load_json_file(p)
60
- assert read_err is None
61
- assert read_data == data
62
-
63
- def test_creates_parent_directories(self, tmp_path):
64
- p = str(tmp_path / "a" / "b" / "c" / "output.json")
65
- err = write_json_file(p, {"nested": True})
23
+ assert loaded == data
24
+
25
+ def test_load_missing_file(self):
26
+ loaded, err = load_json_file("/nonexistent/path.json")
27
+ assert loaded is None
28
+ assert "not found" in err.lower() or "File not found" in err
29
+
30
+ def test_load_invalid_json(self, tmp_path):
31
+ path = str(tmp_path / "bad.json")
32
+ with open(path, "w") as f:
33
+ f.write("{invalid json}")
34
+ loaded, err = load_json_file(path)
35
+ assert loaded is None
36
+ assert "invalid" in err.lower() or "Invalid" in err
37
+
38
+ def test_write_creates_parent_dirs(self, tmp_path):
39
+ path = str(tmp_path / "a" / "b" / "c" / "data.json")
40
+ err = write_json_file(path, {"ok": True})
66
41
  assert err is None
67
- assert os.path.isfile(p)
68
-
69
- def test_overwrites_existing(self, tmp_path):
70
- p = str(tmp_path / "overwrite.json")
71
- write_json_file(p, {"v": 1})
72
- write_json_file(p, {"v": 2})
73
- data, _ = load_json_file(p)
74
- assert data["v"] == 2
75
-
76
- def test_unicode_data(self, tmp_path):
77
- p = str(tmp_path / "unicode.json")
78
- err = write_json_file(p, {"name": "hello"})
79
- assert err is None
80
- data, _ = load_json_file(p)
81
- assert data["name"] == "hello"
42
+ assert os.path.isfile(path)
43
+
82
44
 
45
+ # ---------------------------------------------------------------------------
46
+ # pad_right
47
+ # ---------------------------------------------------------------------------
83
48
 
84
49
  class TestPadRight:
85
- def test_shorter_than_width(self):
50
+ def test_basic_padding(self):
86
51
  result = pad_right("abc", 10)
87
52
  assert len(result) == 10
88
53
  assert result == "abc "
89
54
 
90
- def test_exact_width(self):
91
- result = pad_right("abcde", 5)
92
- assert result == "abcde"
93
-
94
- def test_longer_than_width(self):
95
- result = pad_right("abcdefgh", 5)
96
- assert result == "abcdefgh"
55
+ def test_no_padding_needed(self):
56
+ result = pad_right("abcdef", 3)
57
+ assert result == "abcdef"
97
58
 
98
- def test_empty_string(self):
99
- result = pad_right("", 5)
100
- assert result == " "
59
+ def test_ansi_escape_ignored(self):
60
+ # ANSI color code should not count toward visible length
61
+ text = "\033[31mred\033[0m" # "red" with ANSI color (3 visible chars)
62
+ result = pad_right(text, 10)
63
+ # Visible length is 3, so 7 spaces of padding
64
+ assert result.endswith(" ")
101
65
 
102
- def test_ansi_codes_ignored(self):
103
- # ANSI escape should not count toward visible length
104
- text = "\033[92mHi\033[0m" # visible "Hi" = 2 chars
105
- result = pad_right(text, 5)
106
- # visible width is 2, so 3 spaces of padding
107
- assert result.endswith(" ")
108
-
109
- def test_zero_width(self):
110
- result = pad_right("abc", 0)
111
- assert result == "abc"
112
66
 
67
+ # ---------------------------------------------------------------------------
68
+ # _build_progress_bar
69
+ # ---------------------------------------------------------------------------
113
70
 
114
71
  class TestBuildProgressBar:
115
72
  def test_zero_percent(self):
116
- bar = _build_progress_bar(0)
73
+ bar = _build_progress_bar(0, width=10)
117
74
  assert "0%" in bar
118
- assert "\u2591" in bar # empty blocks
119
- assert "\u2588" not in bar # no filled blocks
120
-
121
- def test_fifty_percent(self):
122
- bar = _build_progress_bar(50, width=20)
123
- assert "50%" in bar
124
- assert bar.count("\u2588") == 10
125
- assert bar.count("\u2591") == 10
126
75
 
127
76
  def test_hundred_percent(self):
128
- bar = _build_progress_bar(100, width=20)
77
+ bar = _build_progress_bar(100, width=10)
129
78
  assert "100%" in bar
130
- assert bar.count("\u2588") == 20
131
- assert bar.count("\u2591") == 0
132
79
 
133
- def test_custom_width(self):
80
+ def test_fifty_percent(self):
134
81
  bar = _build_progress_bar(50, width=10)
135
- assert bar.count("\u2588") == 5
136
- assert bar.count("\u2591") == 5
137
-
138
- def test_partial_percent(self):
139
- bar = _build_progress_bar(33, width=10)
140
- assert bar.count("\u2588") == 3
141
- assert bar.count("\u2591") == 7
82
+ assert "50%" in bar
@@ -3,8 +3,8 @@ description: "PrizmKit commit workflow rules"
3
3
  ---
4
4
 
5
5
  Before any git commit in this project:
6
- 1. Update `.prizm-docs/` for affected modules
6
+ 1. Run `/prizmkit-retrospective` to sync `.prizm-docs/` (memory maintenance)
7
7
  2. Use Conventional Commits format: type(scope): description
8
8
  3. Bug fixes use `fix()` prefix, not `feat()`
9
- 4. Do NOT create REGISTRY.md entries for bug fixes
10
- 5. Use `/prizmkit-committer` command for the complete commit workflow
9
+ 4. Bug fixes run retrospective with structural sync only (Job 1)
10
+ 5. Use `/prizmkit-committer` command for the pure commit workflow
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.0.35",
2
+ "version": "1.0.58",
3
3
  "skills": {
4
4
  "prizm-kit": {
5
5
  "description": "Full-lifecycle dev toolkit. Covers spec-driven development, Prizm context docs, code quality, debugging, deployment, and knowledge management.",
@@ -23,7 +23,7 @@
23
23
  "hasScripts": false
24
24
  },
25
25
  "prizmkit-clarify": {
26
- "description": "Interactive requirement clarification. Resolves ambiguities in feature specs.",
26
+ "description": "Interactive requirement clarification. Resolves ambiguities in feature specs. Use when spec has unclear parts or you're unsure about requirements before planning.",
27
27
  "tier": "1",
28
28
  "category": "prizmkit-skill",
29
29
  "hasAssets": false,
@@ -37,7 +37,7 @@
37
37
  "hasScripts": false
38
38
  },
39
39
  "prizmkit-analyze": {
40
- "description": "Cross-document consistency analysis for spec.md and plan.md (including Tasks section).",
40
+ "description": "Cross-document consistency analysis for spec.md and plan.md. Check if spec and plan are aligned, validate documents before coding.",
41
41
  "tier": "1",
42
42
  "category": "prizmkit-skill",
43
43
  "hasAssets": false,
@@ -58,24 +58,17 @@
58
58
  "hasScripts": false
59
59
  },
60
60
  "prizmkit-committer": {
61
- "description": "Commit workflow with automatic Prizm doc updates and changelog management.",
61
+ "description": "Pure git commit workflow with safety checks. Does NOT modify .prizm-docs/.",
62
62
  "tier": "1",
63
63
  "category": "prizmkit-skill",
64
64
  "hasAssets": false,
65
65
  "hasScripts": false
66
66
  },
67
- "prizmkit-summarize": {
68
- "description": "Archive completed features to REGISTRY.md.",
69
- "tier": "1",
70
- "category": "prizmkit-skill",
71
- "hasAssets": true,
72
- "hasScripts": false
73
- },
74
67
  "prizmkit-retrospective": {
75
- "description": "Post-feature retrospective. Extracts lessons from completed features.",
68
+ "description": "Sole .prizm-docs/ maintainer. Update project documentation after code changes. Structural sync + knowledge injection (TRAPS/RULES/DECISIONS). Run after code review passes, before committing.",
76
69
  "tier": "1",
77
70
  "category": "prizmkit-skill",
78
- "hasAssets": false,
71
+ "hasAssets": true,
79
72
  "hasScripts": false
80
73
  },
81
74
  "prizmkit-prizm-docs": {
@@ -224,6 +217,13 @@
224
217
  "category": "Custom-skill",
225
218
  "hasAssets": false,
226
219
  "hasScripts": false
220
+ },
221
+ "bug-fix-workflow": {
222
+ "description": "Interactive single-bug fix in current session. Guides triage → reproduce → fix → review → commit without background pipeline.",
223
+ "tier": "companion",
224
+ "category": "Custom-skill",
225
+ "hasAssets": false,
226
+ "hasScripts": false
227
227
  }
228
228
  },
229
229
  "suites": {
@@ -244,14 +244,14 @@
244
244
  "prizmkit-implement",
245
245
  "prizmkit-code-review",
246
246
  "prizmkit-committer",
247
- "prizmkit-summarize",
248
247
  "prizmkit-retrospective",
249
248
  "feature-workflow",
250
249
  "refactor-workflow",
251
250
  "app-planner",
252
251
  "bug-planner",
253
252
  "dev-pipeline-launcher",
254
- "bugfix-pipeline-launcher"
253
+ "bugfix-pipeline-launcher",
254
+ "bug-fix-workflow"
255
255
  ]
256
256
  },
257
257
  "minimal": {
@@ -267,7 +267,6 @@
267
267
  "prizmkit-implement",
268
268
  "prizmkit-code-review",
269
269
  "prizmkit-committer",
270
- "prizmkit-summarize",
271
270
  "prizmkit-retrospective"
272
271
  ]
273
272
  }
@@ -92,7 +92,7 @@ Execute the selected scenario workflow in conversation mode with mandatory check
92
92
 
93
93
  ### Checkpoints (Mandatory Gates)
94
94
 
95
- Never skip checkpoints. If any checkpoint fails, follow error recovery flow (see §Error Recovery).
95
+ Checkpoints catch cascading errors early skipping one means the next phase builds on unvalidated assumptions, which compounds into much harder debugging later.
96
96
 
97
97
  | Checkpoint | Artifact/State | Criteria | Phase |
98
98
  |-----------|----------------|----------|-------|
@@ -311,16 +311,17 @@ Resume incremental planning? (Y/n)"
311
311
 
312
312
  ### Artifact Path Convention
313
313
 
314
- Recommended structure for feature planning artifacts:
314
+ The primary output `feature-list.json` is always written to the **project root** — this is where `dev-pipeline-launcher` and all pipeline scripts expect it.
315
315
 
316
316
  ```
317
- .prizmkit/planning/
318
- ├── feature-list.json # Primary output (always here)
319
- ├── feature-list.validated.json # Checkpoint backup after CP-AP-5
320
- └── <ISO-timestamp>.backup.json # Optional incremental backups
317
+ <project-root>/
318
+ ├── feature-list.json # Primary output (always here, at project root)
319
+ └── .prizmkit/planning/ # Optional organization for backups
320
+ ├── feature-list.validated.json # Checkpoint backup after CP-AP-5
321
+ └── <ISO-timestamp>.backup.json # Optional incremental backups
321
322
  ```
322
323
 
323
- Mention this path when summarizing (Phase 8 handoff) to help users organize future sessions.
324
+ The pipeline reads `feature-list.json` from the project root by default. If the user specifies a custom path, the launcher accepts it as an argument.
324
325
 
325
326
  Maintainer note: evaluation workflow moved to `assets/evaluation-guide.md`.
326
327