prizmkit 1.1.118 → 1.1.120

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 (70) hide show
  1. package/bin/create-prizmkit.js +1 -5
  2. package/bundled/VERSION.json +3 -3
  3. package/bundled/dev-pipeline/README.md +41 -38
  4. package/bundled/dev-pipeline/assets/skill-subagent-integration.md +76 -0
  5. package/bundled/dev-pipeline/prizmkit_runtime/config.py +2 -8
  6. package/bundled/dev-pipeline/prizmkit_runtime/gitops.py +2 -4
  7. package/bundled/dev-pipeline/prizmkit_runtime/interoperability.py +1 -1
  8. package/bundled/dev-pipeline/prizmkit_runtime/platform_detection.py +3 -3
  9. package/bundled/dev-pipeline/prizmkit_runtime/runner_bookkeeping.py +21 -11
  10. package/bundled/dev-pipeline/prizmkit_runtime/runners.py +45 -3
  11. package/bundled/dev-pipeline/prizmkit_runtime/sessions.py +28 -6
  12. package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +60 -102
  13. package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +1 -19
  14. package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +1 -19
  15. package/bundled/dev-pipeline/scripts/{init-dev-team.py → init-change-artifact.py} +6 -16
  16. package/bundled/dev-pipeline/scripts/parse-stream-progress.py +364 -76
  17. package/bundled/dev-pipeline/scripts/utils.py +1 -1
  18. package/bundled/dev-pipeline/templates/bootstrap-prompt.md +2 -2
  19. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +7 -9
  20. package/bundled/dev-pipeline/templates/sections/bugfix-phase-review.md +2 -2
  21. package/bundled/dev-pipeline/templates/sections/context-budget-rules.md +1 -1
  22. package/bundled/dev-pipeline/templates/sections/critical-paths-agent.md +0 -1
  23. package/bundled/dev-pipeline/templates/sections/critical-paths-full.md +0 -2
  24. package/bundled/dev-pipeline/templates/sections/phase-commit-full.md +8 -1
  25. package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +6 -7
  26. package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +6 -7
  27. package/bundled/dev-pipeline/templates/sections/phase-implement-lite.md +4 -2
  28. package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +2 -2
  29. package/bundled/dev-pipeline/templates/sections/phase-review-full.md +4 -2
  30. package/bundled/dev-pipeline/templates/sections/phase-specify-plan-full.md +20 -0
  31. package/bundled/dev-pipeline/templates/sections/refactor-phase-review.md +2 -2
  32. package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +204 -141
  33. package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +16 -10
  34. package/bundled/dev-pipeline/tests/test_generate_refactor_prompt.py +2 -13
  35. package/bundled/dev-pipeline/tests/test_python_runner_parity.py +13 -14
  36. package/bundled/dev-pipeline/tests/test_unified_cli.py +227 -7
  37. package/bundled/skills/_metadata.json +1 -1
  38. package/bundled/skills/app-planner/SKILL.md +2 -2
  39. package/bundled/skills/app-planner/references/architecture-decisions.md +1 -3
  40. package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +4 -2
  41. package/bundled/skills/bugfix-pipeline-launcher/references/configuration.md +40 -1
  42. package/bundled/skills/feature-pipeline-launcher/SKILL.md +4 -2
  43. package/bundled/skills/feature-pipeline-launcher/references/configuration.md +40 -1
  44. package/bundled/skills/prizmkit-code-review/SKILL.md +16 -14
  45. package/bundled/skills/prizmkit-code-review/references/reviewer-agent-prompt.md +9 -9
  46. package/bundled/skills/prizmkit-implement/SKILL.md +21 -1
  47. package/bundled/skills/prizmkit-implement/references/implementation-subagent-procedure.md +67 -0
  48. package/bundled/skills/refactor-pipeline-launcher/SKILL.md +4 -2
  49. package/bundled/skills/refactor-pipeline-launcher/references/configuration.md +40 -1
  50. package/package.json +1 -1
  51. package/src/clean.js +12 -8
  52. package/src/config.js +24 -42
  53. package/src/index.js +1 -10
  54. package/src/manifest.js +3 -9
  55. package/src/metadata.js +0 -26
  56. package/src/prompts.js +0 -13
  57. package/src/scaffold.js +76 -201
  58. package/src/upgrade.js +16 -33
  59. package/bundled/adapters/claude/agent-adapter.js +0 -96
  60. package/bundled/adapters/claude/team-adapter.js +0 -183
  61. package/bundled/adapters/codebuddy/agent-adapter.js +0 -42
  62. package/bundled/adapters/codebuddy/team-adapter.js +0 -46
  63. package/bundled/adapters/codex/agent-adapter.js +0 -38
  64. package/bundled/adapters/codex/team-adapter.js +0 -37
  65. package/bundled/agents/prizm-dev-team-dev.md +0 -123
  66. package/bundled/agents/prizm-dev-team-reviewer.md +0 -113
  67. package/bundled/dev-pipeline/assets/prizm-dev-team-integration.md +0 -65
  68. package/bundled/dev-pipeline/templates/bootstrap-tier1.md +0 -436
  69. package/bundled/dev-pipeline/templates/bootstrap-tier2.md +0 -510
  70. package/bundled/team/prizm-dev-team.json +0 -27
@@ -17,6 +17,7 @@ from generate_bootstrap_prompt import (
17
17
  format_global_context,
18
18
  get_completed_dependencies,
19
19
  determine_pipeline_mode,
20
+ determine_legacy_template_mode,
20
21
  process_conditional_blocks,
21
22
  process_mode_blocks,
22
23
  assemble_sections,
@@ -235,7 +236,7 @@ class TestExplicitProjectRoot:
235
236
  )
236
237
  assert not replacements["{{SESSION_STATUS_PATH}}"].startswith(str(execution_root.resolve()))
237
238
  assert replacements["{{PROJECT_BRIEF}}"] == "worktree brief"
238
- assert replacements["{{DEV_SUBAGENT_PATH}}"].startswith(str(execution_root.resolve()))
239
+ assert "{{" + "DEV_" + "SUBAGENT_PATH" + "}}" not in replacements
239
240
  assert replacements["{{SESSION_LOG_PATH}}"].endswith(
240
241
  ".prizmkit/state/features/F-001/sessions/session-1/logs/session.log"
241
242
  )
@@ -254,9 +255,6 @@ class TestExplicitProjectRoot:
254
255
  feature_list.parent.mkdir(parents=True)
255
256
  state_dir.mkdir(parents=True)
256
257
  execution_root.mkdir(parents=True)
257
- (execution_root / ".claude" / "agents").mkdir(parents=True)
258
- (execution_root / ".claude" / "agents" / "prizm-dev-team-dev.md").write_text("dev", encoding="utf-8")
259
- (execution_root / ".claude" / "agents" / "prizm-dev-team-reviewer.md").write_text("reviewer", encoding="utf-8")
260
258
  feature_list.write_text(
261
259
  json.dumps({"features": [{"id": "F-001", "title": "Worktree Prompt", "estimated_complexity": "medium", "status": "pending"}]}),
262
260
  encoding="utf-8",
@@ -285,7 +283,7 @@ class TestExplicitProjectRoot:
285
283
  "--output",
286
284
  str(output_path),
287
285
  "--template",
288
- str(pipeline_root / "templates" / "bootstrap-tier1.md"),
286
+ str(pipeline_root / "templates" / "bootstrap-tier3.md"),
289
287
  ],
290
288
  )
291
289
 
@@ -332,20 +330,16 @@ class TestGetCompletedDependencies:
332
330
  # ---------------------------------------------------------------------------
333
331
 
334
332
  class TestDeterminePipelineMode:
335
- def test_low(self):
336
- assert determine_pipeline_mode("low") == "lite"
333
+ def test_all_complexities_use_unified_full_guidance(self):
334
+ for complexity in ("low", "medium", "high", "critical", "banana", None):
335
+ assert determine_pipeline_mode(complexity) == "full"
337
336
 
338
- def test_medium(self):
339
- assert determine_pipeline_mode("medium") == "lite"
340
-
341
- def test_high(self):
342
- assert determine_pipeline_mode("high") == "standard"
343
-
344
- def test_critical(self):
345
- assert determine_pipeline_mode("critical") == "full"
346
-
347
- def test_unknown(self):
348
- assert determine_pipeline_mode("banana") == "lite"
337
+ def test_legacy_template_mode_mapping_remains_available_for_custom_templates(self):
338
+ assert determine_legacy_template_mode("low") == "lite"
339
+ assert determine_legacy_template_mode("medium") == "lite"
340
+ assert determine_legacy_template_mode("high") == "standard"
341
+ assert determine_legacy_template_mode("critical") == "full"
342
+ assert determine_legacy_template_mode("banana") == "lite"
349
343
 
350
344
 
351
345
  # ---------------------------------------------------------------------------
@@ -807,10 +801,6 @@ class TestHeadlessRecoveryReframing:
807
801
  deleted_title = "Session " + "Checkpoint Awareness"
808
802
  active_paths = [
809
803
  Path("dev-pipeline/scripts/generate-bootstrap-prompt.py"),
810
- Path("dev-pipeline/scripts/generate-bugfix-prompt.py"),
811
- Path("dev-pipeline/scripts/generate-refactor-prompt.py"),
812
- Path("dev-pipeline/templates/bootstrap-tier1.md"),
813
- Path("dev-pipeline/templates/bootstrap-tier2.md"),
814
804
  Path("dev-pipeline/templates/bootstrap-tier3.md"),
815
805
  Path("dev-pipeline/templates/bugfix-bootstrap-prompt.md"),
816
806
  Path("dev-pipeline/templates/refactor-bootstrap-prompt.md"),
@@ -894,33 +884,32 @@ class TestDirectOrchestratorImplementationPrompts:
894
884
  assert FORBIDDEN_TWENTY_STEP not in rendered
895
885
  assert "Reviewer Agent → filter → orchestrator fix" in rendered
896
886
 
897
- def test_legacy_tier_templates_use_direct_orchestrator_implementation(self):
898
- for template_name in ("bootstrap-tier2.md", "bootstrap-tier3.md"):
899
- rendered = (Path("dev-pipeline/templates") / template_name).read_text(encoding="utf-8")
900
-
901
- assert "/prizmkit-implement" in rendered
902
- assert "Implement Orchestrator Direct" in rendered
903
- assert "Spawn Dev subagent" not in rendered
904
- assert "Spawn Dev agent" not in rendered
905
- assert "Spawn Reviewer agent" not in rendered
906
- assert "Reviewer Agent Def" not in rendered
907
- assert "subagent_type=\"prizm-dev-team-reviewer\"" not in rendered
908
- assert "Implement — Dev" not in rendered
909
- assert "{{AGENT_PROMPT_DEV_IMPLEMENT}}" not in rendered
910
- assert "{{AGENT_PROMPT_REVIEWER_REVIEW}}" not in rendered
911
- assert "reviewer-review.md" not in rendered
912
- assert "dev-implement.md" not in rendered
913
- assert "Bug Fix Documentation Policy" not in rendered
914
- assert "For bug-fix sessions" not in rendered
915
- assert "fix(<scope>)" not in rendered
916
- assert "port check 3000" not in rendered
917
- assert "localhost:3000" not in rendered
918
- assert FORBIDDEN_REVIEW_DEV_FIX not in rendered
919
- assert FORBIDDEN_REVIEWER_DEV_SPAWN not in rendered
920
- assert FORBIDDEN_EXPLORE_SUBAGENT not in rendered
921
- assert FORBIDDEN_TEST_CMD_PLACEHOLDER not in rendered
922
- assert FORBIDDEN_THREE_STRIKE not in rendered
923
- assert FORBIDDEN_TWENTY_STEP not in rendered
887
+ def test_retained_tier3_fallback_template_uses_direct_orchestrator_implementation(self):
888
+ rendered = Path("dev-pipeline/templates/bootstrap-tier3.md").read_text(encoding="utf-8")
889
+
890
+ assert "/prizmkit-implement" in rendered
891
+ assert "Implement — Orchestrator Direct" in rendered
892
+ assert "Spawn Dev subagent" not in rendered
893
+ assert "Spawn Dev agent" not in rendered
894
+ assert "Spawn Reviewer agent" not in rendered
895
+ assert "Reviewer Agent Def" not in rendered
896
+ assert "subagent_type=\"" + "-".join(["prizm", "dev", "team", "reviewer"]) + "\"" not in rendered
897
+ assert "Implement — Dev" not in rendered
898
+ assert "{{AGENT_PROMPT_DEV_IMPLEMENT}}" not in rendered
899
+ assert "{{AGENT_PROMPT_REVIEWER_REVIEW}}" not in rendered
900
+ assert "reviewer-review.md" not in rendered
901
+ assert "dev-implement.md" not in rendered
902
+ assert "Bug Fix Documentation Policy" not in rendered
903
+ assert "For bug-fix sessions" not in rendered
904
+ assert "fix(<scope>)" not in rendered
905
+ assert "port check 3000" not in rendered
906
+ assert "localhost:3000" not in rendered
907
+ assert FORBIDDEN_REVIEW_DEV_FIX not in rendered
908
+ assert FORBIDDEN_REVIEWER_DEV_SPAWN not in rendered
909
+ assert FORBIDDEN_EXPLORE_SUBAGENT not in rendered
910
+ assert FORBIDDEN_TEST_CMD_PLACEHOLDER not in rendered
911
+ assert FORBIDDEN_THREE_STRIKE not in rendered
912
+ assert FORBIDDEN_TWENTY_STEP not in rendered
924
913
 
925
914
 
926
915
  # ---------------------------------------------------------------------------
@@ -1008,23 +997,18 @@ def _write_feature_list(path, feature):
1008
997
  path.write_text(json.dumps({"features": [feature], "global_context": {"language": "Python"}}), encoding="utf-8")
1009
998
 
1010
999
 
1011
- def _render_feature_prompt(tmp_path, mode="standard", template=None, platform="claude", browser_interaction=None):
1000
+ def _render_feature_prompt(tmp_path, mode="standard", template=None, platform="claude", browser_interaction=None, complexity=None):
1012
1001
  project = tmp_path / "project"
1013
1002
  project.mkdir(parents=True)
1014
1003
  (project / ".prizmkit" / "plans").mkdir(parents=True)
1015
1004
  (project / ".prizmkit" / "config.json").write_text(
1016
1005
  json.dumps({"platform": platform, "ai_cli": platform}), encoding="utf-8"
1017
1006
  )
1018
- for platform_dir, suffix in ((".claude", ".md"), (".codex", ".toml")):
1019
- agents_dir = project / platform_dir / "agents"
1020
- agents_dir.mkdir(parents=True)
1021
- for name in ("dev", "reviewer"):
1022
- (agents_dir / f"prizm-dev-team-{name}{suffix}").write_text("agent\n", encoding="utf-8")
1023
1007
  feature = {
1024
1008
  "id": "F-123",
1025
1009
  "title": "Prompt Cleanup",
1026
1010
  "description": "Clean prompt text",
1027
- "estimated_complexity": {"lite": "low", "standard": "medium", "full": "high"}[mode],
1011
+ "estimated_complexity": complexity or {"lite": "low", "standard": "medium", "full": "high"}[mode],
1028
1012
  "acceptance_criteria": ["Prompts are clean"],
1029
1013
  }
1030
1014
  if browser_interaction is not None:
@@ -1046,7 +1030,10 @@ def _render_feature_prompt(tmp_path, mode="standard", template=None, platform="c
1046
1030
  "--mode", mode,
1047
1031
  ]
1048
1032
  if template:
1049
- args.extend(["--template", str(Path("dev-pipeline/templates") / template)])
1033
+ template_path = Path(template)
1034
+ if not template_path.is_absolute():
1035
+ template_path = Path("dev-pipeline/templates") / template_path
1036
+ args.extend(["--template", str(template_path)])
1050
1037
  old_argv = os.sys.argv
1051
1038
  old_platform = os.environ.get("PRIZMKIT_PLATFORM")
1052
1039
  try:
@@ -1065,14 +1052,23 @@ def _render_feature_prompt(tmp_path, mode="standard", template=None, platform="c
1065
1052
  return output.read_text(encoding="utf-8")
1066
1053
 
1067
1054
 
1068
- def _ensure_agent_files(project, platforms=("claude", "codex")):
1069
- for platform in platforms:
1070
- platform_dir = ".codex" if platform == "codex" else ".claude"
1071
- suffix = ".toml" if platform == "codex" else ".md"
1072
- agents_dir = project / platform_dir / "agents"
1073
- agents_dir.mkdir(parents=True, exist_ok=True)
1074
- for name in ("dev", "reviewer"):
1075
- (agents_dir / f"prizm-dev-team-{name}{suffix}").write_text("agent\n", encoding="utf-8")
1055
+ def _ensure_skill_files(project, platforms=None):
1056
+ """Create minimal skill files so platform resolution succeeds."""
1057
+ if platforms is None:
1058
+ platforms = ("claude", "codex")
1059
+ for plat in platforms:
1060
+ if plat == "codex":
1061
+ skill_dir = project / ".agents" / "skills" / "prizmkit"
1062
+ skill_dir.mkdir(parents=True, exist_ok=True)
1063
+ (skill_dir / "SKILL.md").write_text("skill\n", encoding="utf-8")
1064
+ elif plat == "codebuddy":
1065
+ skill_dir = project / ".codebuddy" / "skills" / "prizmkit"
1066
+ skill_dir.mkdir(parents=True, exist_ok=True)
1067
+ (skill_dir / "SKILL.md").write_text("skill\n", encoding="utf-8")
1068
+ else:
1069
+ command_dir = project / ".claude" / "commands"
1070
+ command_dir.mkdir(parents=True, exist_ok=True)
1071
+ (command_dir / "prizmkit.md").write_text("skill\n", encoding="utf-8")
1076
1072
 
1077
1073
 
1078
1074
  def _render_bugfix_prompt(
@@ -1087,7 +1083,7 @@ def _render_bugfix_prompt(
1087
1083
  (project / ".prizmkit" / "config.json").write_text(
1088
1084
  json.dumps({"platform": platform, "ai_cli": platform}), encoding="utf-8"
1089
1085
  )
1090
- _ensure_agent_files(project)
1086
+ _ensure_skill_files(project)
1091
1087
  bug_list = project / ".prizmkit" / "plans" / "bug-fix-list.json"
1092
1088
  bug_list.parent.mkdir(parents=True)
1093
1089
  bug = {"id": "B-001", "title": "Broken", "description": "Fix it", "acceptance_criteria": ["Works"]}
@@ -1140,7 +1136,7 @@ def _render_refactor_prompt(tmp_path, platform="claude", explicit_platform=None,
1140
1136
  (project / ".prizmkit" / "config.json").write_text(
1141
1137
  json.dumps({"platform": platform, "ai_cli": platform}), encoding="utf-8"
1142
1138
  )
1143
- _ensure_agent_files(project)
1139
+ _ensure_skill_files(project)
1144
1140
  refactor_list = project / ".prizmkit" / "plans" / "refactor-list.json"
1145
1141
  refactor_list.parent.mkdir(parents=True)
1146
1142
  refactor = {
@@ -1190,6 +1186,100 @@ def _render_refactor_prompt(tmp_path, platform="claude", explicit_platform=None,
1190
1186
  return output.read_text(encoding="utf-8")
1191
1187
 
1192
1188
 
1189
+ class TestFeaturePromptUnifiedFullGuidance:
1190
+ def test_default_sections_prompt_uses_full_guidance_for_all_complexities(self, tmp_path):
1191
+ prompts = {
1192
+ complexity: _render_feature_prompt(
1193
+ tmp_path / f"complexity-{complexity}",
1194
+ mode="lite",
1195
+ complexity=complexity,
1196
+ )
1197
+ for complexity in ("low", "medium", "high", "critical")
1198
+ }
1199
+
1200
+ for complexity, prompt in prompts.items():
1201
+ assert f"**Complexity**: {complexity}" in prompt
1202
+ assert "## Task Contract" in prompt
1203
+ assert "## Workflow Checkpoint System" in prompt
1204
+ assert "### Specify + Plan (Full Workflow)" in prompt
1205
+ assert "### Plan Self-Check — Orchestrator Direct" in prompt
1206
+ assert "### Scoped Feature Test Gate — PrizmKit Test" in prompt
1207
+ assert "## Test Failure Recovery Protocol" in prompt
1208
+ assert "Boundary Matrix" in prompt
1209
+ assert "### Browser Verification — MANDATORY" in prompt
1210
+ assert "### TERMINAL STOP — Commit Completed" in prompt
1211
+ assert "# Dev-Pipeline Session Bootstrap — Tier 1" not in prompt
1212
+ assert "# Dev-Pipeline Session Bootstrap — Tier 2" not in prompt
1213
+ assert "### Phase 0: SKIP (already initialized)" not in prompt
1214
+
1215
+ # The complexity value remains planning metadata, but guidance markers are
1216
+ # the same full/tier3-equivalent composition for every complexity.
1217
+ def test_cli_mode_override_does_not_downgrade_default_sections_guidance(self, tmp_path):
1218
+ prompt = _render_feature_prompt(tmp_path / "mode-lite", mode="lite", complexity="low")
1219
+
1220
+ assert "{{PIPELINE_MODE}}" not in prompt
1221
+ assert "### Specify + Plan (Full Workflow)" in prompt
1222
+ assert "### Plan Self-Check — Orchestrator Direct" in prompt
1223
+ assert "### Phase 0: SKIP (already initialized)" not in prompt
1224
+
1225
+ def test_explicit_custom_template_override_still_renders(self, tmp_path):
1226
+ custom = tmp_path / "custom-template.md"
1227
+ custom.write_text(
1228
+ "CUSTOM {{FEATURE_ID}} {{FEATURE_TITLE}} {{COMPLEXITY}} {{IF_FRESH_START}}fresh{{END_IF_FRESH_START}}",
1229
+ encoding="utf-8",
1230
+ )
1231
+
1232
+ prompt = _render_feature_prompt(
1233
+ tmp_path / "custom-template-project",
1234
+ mode="lite",
1235
+ complexity="low",
1236
+ template=custom,
1237
+ )
1238
+
1239
+ assert prompt == "CUSTOM F-123 Prompt Cleanup low fresh"
1240
+
1241
+ def test_fallback_without_sections_prefers_tier3_then_bootstrap_prompt(self, tmp_path, monkeypatch):
1242
+ import generate_bootstrap_prompt as gbp
1243
+
1244
+ original_isdir = os.path.isdir
1245
+ original_isfile = os.path.isfile
1246
+ requested = []
1247
+
1248
+ def fake_isdir(path):
1249
+ if str(path).endswith(os.path.join("templates", "sections")):
1250
+ return False
1251
+ return original_isdir(path)
1252
+
1253
+ def fake_isfile(path):
1254
+ requested.append(Path(path).name)
1255
+ return original_isfile(path)
1256
+
1257
+ monkeypatch.setattr(gbp.os.path, "isdir", fake_isdir)
1258
+ monkeypatch.setattr(gbp.os.path, "isfile", fake_isfile)
1259
+ prompt = _render_feature_prompt(tmp_path / "fallback-tier3", mode="lite", complexity="low")
1260
+
1261
+ assert requested.index("bootstrap-tier3.md") < requested.index("bootstrap-prompt.md") if "bootstrap-prompt.md" in requested else True
1262
+ assert "# Dev-Pipeline Session Bootstrap — Tier 3" in prompt
1263
+ assert "bootstrap-tier1.md" not in requested
1264
+ assert "bootstrap-tier2.md" not in requested
1265
+
1266
+ requested.clear()
1267
+
1268
+ def fake_isfile_without_tier3(path):
1269
+ requested.append(Path(path).name)
1270
+ if Path(path).name == "bootstrap-tier3.md":
1271
+ return False
1272
+ return original_isfile(path)
1273
+
1274
+ monkeypatch.setattr(gbp.os.path, "isfile", fake_isfile_without_tier3)
1275
+ prompt = _render_feature_prompt(tmp_path / "fallback-bootstrap-prompt", mode="lite", complexity="low")
1276
+
1277
+ assert "bootstrap-tier3.md" in requested
1278
+ assert "bootstrap-tier1.md" not in requested
1279
+ assert "bootstrap-tier2.md" not in requested
1280
+ assert "# Dev-Pipeline Fallback Bootstrap Prompt" in prompt
1281
+
1282
+
1193
1283
  class TestBrowserBlockingPromptPolicy:
1194
1284
  def test_feature_bugfix_refactor_blocking_browser_policy_stops_before_commit(self, tmp_path):
1195
1285
  browser_interaction = {
@@ -1282,21 +1372,24 @@ class TestHeadlessPromptCleanupF033:
1282
1372
  assert "which " not in prompt # no which-command shell glue
1283
1373
  assert "python3 {{INIT_SCRIPT_PATH}}" not in prompt
1284
1374
 
1285
- def test_legacy_feature_templates_are_clean_when_rendered(self, tmp_path):
1286
- for template, mode in (("bootstrap-tier1.md", "lite"), ("bootstrap-tier2.md", "standard"), ("bootstrap-tier3.md", "full")):
1287
- prompt = _render_feature_prompt(tmp_path / template, mode=mode, template=template)
1288
- for forbidden in HEADLESS_FORBIDDEN_PROMPT_STRINGS:
1289
- assert forbidden not in prompt
1290
- assert "prizmkit-test-gate.py" not in prompt
1291
- assert "python3 {{INIT_SCRIPT_PATH}}" not in prompt
1292
- assert "which playwright-cli" not in prompt
1293
- assert "lsof -ti" not in prompt
1294
- assert "sed -nE" not in prompt
1295
- assert ".prizmkit-test-started" in prompt
1296
- assert "{{RUNTIME_HELPER_CMD}}" not in prompt
1297
- assert "prizmkit-runtime-helper.py" in prompt
1298
-
1299
- def test_legacy_feature_templates_with_browser_blocks_are_shell_free(self, tmp_path):
1375
+ def test_retained_tier3_template_is_clean_when_rendered(self, tmp_path):
1376
+ prompt = _render_feature_prompt(tmp_path / "bootstrap-tier3.md", mode="full", template="bootstrap-tier3.md")
1377
+ for forbidden in HEADLESS_FORBIDDEN_PROMPT_STRINGS:
1378
+ assert forbidden not in prompt
1379
+ assert "prizmkit-test-gate.py" not in prompt
1380
+ assert "python3 {{INIT_SCRIPT_PATH}}" not in prompt
1381
+ assert "which playwright-cli" not in prompt
1382
+ assert "lsof -ti" not in prompt
1383
+ assert "sed -nE" not in prompt
1384
+ assert ".prizmkit-test-started" in prompt
1385
+ assert "{{RUNTIME_HELPER_CMD}}" not in prompt
1386
+ assert "prizmkit-runtime-helper.py" in prompt
1387
+
1388
+ def test_retired_tier1_tier2_templates_are_removed(self):
1389
+ assert not Path("dev-pipeline/templates/bootstrap-tier1.md").exists()
1390
+ assert not Path("dev-pipeline/templates/bootstrap-tier2.md").exists()
1391
+
1392
+ def test_retained_tier3_template_with_browser_blocks_is_shell_free(self, tmp_path):
1300
1393
  forbidden = [
1301
1394
  "python3 {{INIT_SCRIPT_PATH}}",
1302
1395
  "which playwright-cli",
@@ -1308,21 +1401,15 @@ class TestHeadlessPromptCleanupF033:
1308
1401
  "opencli doctor 2>/dev/null ||",
1309
1402
  "echo \"=== playwright-cli ===\" &&",
1310
1403
  ]
1311
- cases = [
1312
- ("bootstrap-tier1.md", "lite"),
1313
- ("bootstrap-tier2.md", "standard"),
1314
- ("bootstrap-tier3.md", "full"),
1315
- ]
1316
- for template, mode in cases:
1317
- prompt = _render_feature_prompt(
1318
- tmp_path / f"browser-{template}",
1319
- mode=mode,
1320
- template=template,
1321
- browser_interaction={"tool": "auto", "verify_steps": ["Open the page"]},
1322
- )
1323
- assert "prizmkit-runtime-helper.py" in prompt
1324
- for snippet in forbidden:
1325
- assert snippet not in prompt
1404
+ prompt = _render_feature_prompt(
1405
+ tmp_path / "browser-bootstrap-tier3.md",
1406
+ mode="full",
1407
+ template="bootstrap-tier3.md",
1408
+ browser_interaction={"tool": "auto", "verify_steps": ["Open the page"]},
1409
+ )
1410
+ assert "prizmkit-runtime-helper.py" in prompt
1411
+ for snippet in forbidden:
1412
+ assert snippet not in prompt
1326
1413
 
1327
1414
  def test_bugfix_refactor_share_claude_platform_resolution(self, tmp_path, monkeypatch):
1328
1415
  from generate_bugfix_prompt import build_replacements as bugfix_build_replacements
@@ -1334,7 +1421,7 @@ class TestHeadlessPromptCleanupF033:
1334
1421
  (bug_project / ".prizmkit" / "config.json").write_text(
1335
1422
  json.dumps({"platform": "claude", "ai_cli": "claude"}), encoding="utf-8"
1336
1423
  )
1337
- _ensure_agent_files(bug_project)
1424
+ _ensure_skill_files(bug_project)
1338
1425
  args = Namespace(
1339
1426
  bug_id="B-001", session_id="session-1", run_id="run-1",
1340
1427
  retry_count="0", resume_phase="null", state_dir=None,
@@ -1346,15 +1433,15 @@ class TestHeadlessPromptCleanupF033:
1346
1433
  )
1347
1434
  refactor_prompt = _render_refactor_prompt(tmp_path / "refactor-mixed", platform="claude")
1348
1435
 
1349
- assert replacements["{{REVIEWER_SUBAGENT_PATH}}"].endswith(".claude/agents/prizm-dev-team-reviewer.md")
1350
- assert ".codex/agents/prizm-dev-team-reviewer.toml" not in refactor_prompt
1436
+ assert "{{" + "REVIEWER_" + "SUBAGENT_PATH" + "}}" not in replacements
1437
+ assert "reviewer-agent-prompt.md" in refactor_prompt
1351
1438
 
1352
1439
  def test_bugfix_refactor_explicit_codex_override(self, tmp_path, monkeypatch):
1353
1440
  from generate_bugfix_prompt import build_replacements as bugfix_build_replacements
1354
1441
 
1355
1442
  bug_project = tmp_path / "bugfix-codex-replacements"
1356
1443
  bug_project.mkdir()
1357
- _ensure_agent_files(bug_project)
1444
+ _ensure_skill_files(bug_project)
1358
1445
  monkeypatch.setenv("PRIZMKIT_PLATFORM", "codex")
1359
1446
  args = Namespace(
1360
1447
  bug_id="B-001", session_id="session-1", run_id="run-1",
@@ -1367,8 +1454,8 @@ class TestHeadlessPromptCleanupF033:
1367
1454
  )
1368
1455
  refactor_prompt = _render_refactor_prompt(tmp_path / "refactor-codex", platform="claude", explicit_platform="codex")
1369
1456
 
1370
- assert replacements["{{REVIEWER_SUBAGENT_PATH}}"].endswith(".codex/agents/prizm-dev-team-reviewer.toml")
1371
- assert ".claude/agents/prizm-dev-team-reviewer.md" not in refactor_prompt
1457
+ assert "{{" + "REVIEWER_" + "SUBAGENT_PATH" + "}}" not in replacements
1458
+ assert "reviewer-agent-prompt.md" in refactor_prompt
1372
1459
 
1373
1460
 
1374
1461
  class TestFeatureBootstrapShellExtraction:
@@ -1427,49 +1514,25 @@ class TestFeatureBootstrapShellExtraction:
1427
1514
  assert "port check 3000" not in prompt
1428
1515
  assert "localhost:3000" not in prompt
1429
1516
 
1430
- def test_rendered_legacy_tier_feature_prompts_use_runtime_helper_not_extracted_bash(self, tmp_path):
1431
- cases = [
1432
- ("bootstrap-tier1.md", "lite"),
1433
- ("bootstrap-tier2.md", "standard"),
1434
- ("bootstrap-tier3.md", "full"),
1435
- ]
1436
- for template, mode in cases:
1437
- prompt = _render_feature_prompt(
1438
- tmp_path / f"legacy-{template}",
1439
- mode=mode,
1440
- template=template,
1441
- browser_interaction={"tool": "playwright-cli", "verify_steps": ["Open the page"]},
1442
- )
1443
-
1444
- self.assert_shell_extracted_operations_removed(prompt)
1445
- assert "process start --pid-file .prizmkit/state/browser-dev-server.pid" in prompt
1446
- assert "process cleanup-pid <pid-from-.prizmkit/state/browser-dev-server.pid>" in prompt
1447
- assert "port check 3000" not in prompt
1448
- assert "localhost:3000" not in prompt
1449
-
1450
- def test_legacy_tier_specific_extracted_operations_map_to_helper_commands(self, tmp_path):
1451
- tier1 = _render_feature_prompt(
1452
- tmp_path / "legacy-tier1-helper-map",
1453
- mode="lite",
1454
- template="bootstrap-tier1.md",
1455
- )
1456
- assert "artifact tree . --max-depth 2" in tier1
1457
- assert "text contains .gitignore --pattern \"/binary-name\"" in tier1
1458
- assert "NEEDS_IGNORE_ENTRY" in tier1
1459
-
1460
- tier2 = _render_feature_prompt(
1461
- tmp_path / "legacy-tier2-helper-map",
1462
- mode="standard",
1463
- template="bootstrap-tier2.md",
1517
+ def test_rendered_retained_tier3_feature_prompt_uses_runtime_helper_not_extracted_bash(self, tmp_path):
1518
+ prompt = _render_feature_prompt(
1519
+ tmp_path / "legacy-bootstrap-tier3.md",
1520
+ mode="full",
1521
+ template="bootstrap-tier3.md",
1522
+ browser_interaction={"tool": "playwright-cli", "verify_steps": ["Open the page"]},
1464
1523
  )
1465
- assert "artifact exists .prizmkit/specs/123-prompt-cleanup/failure-log.md" in tier2
1466
- assert "artifact tree . --max-depth 2" in tier2
1467
- assert "text count .prizmkit/specs/123-prompt-cleanup/plan.md --pattern \"- [ ]\"" in tier2
1468
1524
 
1525
+ self.assert_shell_extracted_operations_removed(prompt)
1526
+ assert "process start --pid-file .prizmkit/state/browser-dev-server.pid" in prompt
1527
+ assert "process cleanup-pid <pid-from-.prizmkit/state/browser-dev-server.pid>" in prompt
1528
+ assert "port check 3000" not in prompt
1529
+ assert "localhost:3000" not in prompt
1530
+
1531
+ def test_retained_tier3_specific_extracted_operations_map_to_helper_commands(self, tmp_path):
1469
1532
  tier3 = _render_feature_prompt(
1470
1533
  tmp_path / "legacy-tier3-helper-map",
1471
1534
  mode="full",
1472
- template="bootstrap-tier3.md",
1535
+ template="bootstrap-tier3.md",
1473
1536
  )
1474
1537
  assert "text search . --pattern \"123-prompt-cleanup\" --json" in tier3
1475
1538
  assert "text count .prizmkit/specs/123-prompt-cleanup/plan.md --pattern \"- [ ]\"" in tier3
@@ -196,7 +196,7 @@ class TestExplicitProjectRoot:
196
196
  "sessions" / "session-1" / "session-status.json"
197
197
  )
198
198
  assert not replacements["{{SESSION_STATUS_PATH}}"].startswith(str(execution_root.resolve()))
199
- assert replacements["{{DEV_SUBAGENT_PATH}}"].startswith(str(execution_root.resolve()))
199
+ assert "{{" + "DEV_" + "SUBAGENT_PATH" + "}}" not in replacements
200
200
  assert replacements["{{SESSION_LOG_PATH}}"].endswith(
201
201
  ".prizmkit/state/bugfix/B-001/sessions/session-1/logs/session.log"
202
202
  )
@@ -360,7 +360,7 @@ def _render_bugfix_prompt(tmp_path, platform="claude"):
360
360
  (project / ".prizmkit" / "config.json").write_text(
361
361
  json.dumps({"platform": platform, "ai_cli": platform}), encoding="utf-8"
362
362
  )
363
- _ensure_agent_files(project)
363
+ _ensure_skill_files(project)
364
364
  bug_list = project / ".prizmkit" / "plans" / "bug-fix-list.json"
365
365
  bug_list.parent.mkdir(parents=True)
366
366
  bug_list.write_text(json.dumps({
@@ -399,17 +399,23 @@ def _render_bugfix_prompt(tmp_path, platform="claude"):
399
399
  return output.read_text(encoding="utf-8")
400
400
 
401
401
 
402
- def _ensure_agent_files(project, platforms=None):
403
- """Create minimal agent files so platform resolution succeeds."""
402
+ def _ensure_skill_files(project, platforms=None):
403
+ """Create minimal skill files so platform resolution succeeds."""
404
404
  if platforms is None:
405
405
  platforms = ("claude", "codex")
406
406
  for plat in platforms:
407
- platform_dir = ".codex" if plat == "codex" else ".claude"
408
- suffix = ".toml" if plat == "codex" else ".md"
409
- agents_dir = project / platform_dir / "agents"
410
- agents_dir.mkdir(parents=True, exist_ok=True)
411
- for name in ("dev", "reviewer"):
412
- (agents_dir / f"prizm-dev-team-{name}{suffix}").write_text("agent\n", encoding="utf-8")
407
+ if plat == "codex":
408
+ skill_dir = project / ".agents" / "skills" / "prizmkit"
409
+ skill_dir.mkdir(parents=True, exist_ok=True)
410
+ (skill_dir / "SKILL.md").write_text("skill\n", encoding="utf-8")
411
+ elif plat == "codebuddy":
412
+ skill_dir = project / ".codebuddy" / "skills" / "prizmkit"
413
+ skill_dir.mkdir(parents=True, exist_ok=True)
414
+ (skill_dir / "SKILL.md").write_text("skill\n", encoding="utf-8")
415
+ else:
416
+ command_dir = project / ".claude" / "commands"
417
+ command_dir.mkdir(parents=True, exist_ok=True)
418
+ (command_dir / "prizmkit.md").write_text("skill\n", encoding="utf-8")
413
419
 
414
420
 
415
421
  class TestBugfixBootstrapShellExtraction:
@@ -82,10 +82,7 @@ class TestExplicitProjectRoot:
82
82
  )
83
83
 
84
84
  assert replacements["{{PROJECT_ROOT}}"] == str(project.resolve())
85
- assert replacements["{{REVIEWER_SUBAGENT_PATH}}"].endswith(
86
- ".claude/agents/prizm-dev-team-reviewer.md"
87
- )
88
- assert replacements["{{REVIEWER_SUBAGENT_PATH}}"].startswith(str(project.resolve()))
85
+ assert "{{" + "REVIEWER_" + "SUBAGENT_PATH" + "}}" not in replacements
89
86
  assert replacements["{{SESSION_STATUS_PATH}}"] == str(
90
87
  project / ".prizmkit" / "state" / "refactor" / "R-001" /
91
88
  "sessions" / "session-1" / "session-status.json"
@@ -126,7 +123,7 @@ class TestExplicitProjectRoot:
126
123
  "sessions" / "session-1" / "session-status.json"
127
124
  )
128
125
  assert not replacements["{{SESSION_STATUS_PATH}}"].startswith(str(execution_root.resolve()))
129
- assert replacements["{{DEV_SUBAGENT_PATH}}"].startswith(str(execution_root.resolve()))
126
+ assert "{{" + "DEV_" + "SUBAGENT_PATH" + "}}" not in replacements
130
127
  assert "### Checkpoint Update Helper" in replacements["{{CHECKPOINT_SYSTEM}}"]
131
128
  assert "{{CHECKPOINT_PYTHON_CMD}}" in replacements["{{CHECKPOINT_SYSTEM}}"]
132
129
  assert "pipeline progress mechanism" not in replacements["{{CHECKPOINT_SYSTEM}}"]
@@ -234,14 +231,6 @@ def _render_refactor_prompt_full(tmp_path, platform="claude"):
234
231
  (project / ".prizmkit" / "config.json").write_text(
235
232
  json.dumps({"platform": platform, "ai_cli": platform}), encoding="utf-8"
236
233
  )
237
- # Ensure agent files
238
- for plat in ("claude", "codex"):
239
- platform_dir = ".codex" if plat == "codex" else ".claude"
240
- suffix = ".toml" if plat == "codex" else ".md"
241
- agents_dir = project / platform_dir / "agents"
242
- agents_dir.mkdir(parents=True, exist_ok=True)
243
- for name in ("dev", "reviewer"):
244
- (agents_dir / f"prizm-dev-team-{name}{suffix}").write_text("agent\n", encoding="utf-8")
245
234
 
246
235
  refactor_list = project / ".prizmkit" / "plans" / "refactor-list.json"
247
236
  refactor_list.parent.mkdir(parents=True)