prizmkit 1.0.137 → 1.0.139

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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "frameworkVersion": "1.0.137",
3
- "bundledAt": "2026-03-28T13:49:17.127Z",
4
- "bundledFrom": "1cfc8e2"
2
+ "frameworkVersion": "1.0.139",
3
+ "bundledAt": "2026-03-28T16:00:11.932Z",
4
+ "bundledFrom": "ce5323e"
5
5
  }
@@ -90,22 +90,27 @@ except: pass
90
90
 
91
91
  # prizm_detect_subagents <session_log>
92
92
  #
93
- # Scan session log for subagent spawns and log the result.
94
- # Uses grep -q for early exit on first match.
93
+ # Scan session log for subagent spawns, count them, and log the result.
94
+ # Sets _SUBAGENT_COUNT to the number of Agent tool calls detected.
95
95
  # Requires: USE_STREAM_JSON (from detect_stream_json_support)
96
+ _SUBAGENT_COUNT=0
96
97
  prizm_detect_subagents() {
97
98
  local session_log="$1"
99
+ _SUBAGENT_COUNT=0
98
100
  [[ -f "$session_log" ]] || return 0
99
101
 
100
- local has_subagent=false
102
+ local count=0
101
103
  if [[ "$USE_STREAM_JSON" == "true" ]]; then
102
- grep -q '"name"[[:space:]]*:[[:space:]]*"Agent"' "$session_log" 2>/dev/null && has_subagent=true
104
+ count=$(grep -c '"name"[[:space:]]*:[[:space:]]*"Agent"' "$session_log" 2>/dev/null || echo "0")
103
105
  else
104
- grep -qE '(Tool: Agent|"tool":\s*"Agent"|tool_use.*Agent|subagent_type)' "$session_log" 2>/dev/null && has_subagent=true
106
+ count=$(grep -cE '(Tool: Agent|"tool":\s*"Agent"|tool_use.*Agent|subagent_type)' "$session_log" 2>/dev/null || echo "0")
105
107
  fi
106
108
 
107
- if [[ "$has_subagent" == true ]]; then
108
- log_info "Subagent calls detected in session"
109
+ _SUBAGENT_COUNT=$count
110
+ if [[ "$count" -gt 0 ]]; then
111
+ log_info "Subagent calls detected in session: $count"
112
+ else
113
+ log_info "Subagent calls detected in session: 0 (single-agent mode)"
109
114
  fi
110
115
  }
111
116
 
@@ -599,6 +599,7 @@ main() {
599
599
  fi
600
600
 
601
601
  local session_count=0
602
+ local total_subagent_calls=0
602
603
 
603
604
  while true; do
604
605
  # Find next bug to process
@@ -614,6 +615,7 @@ main() {
614
615
  log_success "════════════════════════════════════════════════════"
615
616
  log_success " All bugs processed! Bug fix pipeline finished."
616
617
  log_success " Total sessions: $session_count"
618
+ log_success " Total subagent calls: $total_subagent_calls"
617
619
  log_success "════════════════════════════════════════════════════"
618
620
 
619
621
  # Merge dev branch back to original
@@ -672,6 +674,10 @@ main() {
672
674
  --state-dir "$STATE_DIR" \
673
675
  --output "$bootstrap_prompt" >/dev/null 2>&1
674
676
 
677
+ # Log agent configuration (bugfix always uses dual-agent: Orchestrator + Dev + Reviewer)
678
+ log_info "Pipeline mode: ${BOLD}standard${NC} (Dual Agent — Orchestrator + Dev + Reviewer)"
679
+ log_info "Agents: 3 (critic: disabled)"
680
+
675
681
  # Spawn session
676
682
  log_info "Spawning AI CLI session: $session_id"
677
683
  _SPAWN_RESULT=""
@@ -681,6 +687,7 @@ main() {
681
687
  "$bootstrap_prompt" "$session_dir" "$MAX_RETRIES" "$_ORIGINAL_BRANCH"
682
688
 
683
689
  session_count=$((session_count + 1))
690
+ total_subagent_calls=$((total_subagent_calls + _SUBAGENT_COUNT))
684
691
 
685
692
  log_info "Pausing 5s before next bug..."
686
693
  sleep 5
@@ -647,8 +647,11 @@ sys.exit(1)
647
647
  log_error "Failed to generate bootstrap prompt for $feature_id"
648
648
  return 1
649
649
  }
650
- local feature_model
650
+ local feature_model pipeline_mode agent_count critic_enabled
651
651
  feature_model=$(echo "$gen_output" | python3 -c "import json,sys; print(json.load(sys.stdin).get('model',''))" 2>/dev/null || echo "")
652
+ pipeline_mode=$(echo "$gen_output" | python3 -c "import json,sys; print(json.load(sys.stdin).get('pipeline_mode','lite'))" 2>/dev/null || echo "lite")
653
+ agent_count=$(echo "$gen_output" | python3 -c "import json,sys; print(json.load(sys.stdin).get('agent_count',1))" 2>/dev/null || echo "1")
654
+ critic_enabled=$(echo "$gen_output" | python3 -c "import json,sys; print(json.load(sys.stdin).get('critic_enabled','false'))" 2>/dev/null || echo "false")
652
655
 
653
656
  # Dry-Run: Print info and exit
654
657
  if [[ "$dry_run" == true ]]; then
@@ -664,6 +667,8 @@ sys.exit(1)
664
667
  else
665
668
  log_info "Mode: auto-detect (from complexity)"
666
669
  fi
670
+ log_info "Pipeline mode: $pipeline_mode"
671
+ log_info "Agents: $agent_count (critic: $([ "$critic_enabled" = "true" ] && echo "enabled" || echo "disabled"))"
667
672
  if [[ -n "$feature_model" ]]; then
668
673
  log_info "Feature Model: $feature_model"
669
674
  elif [[ -n "${MODEL:-}" ]]; then
@@ -707,6 +712,15 @@ sys.exit(1)
707
712
  if [[ -n "$mode_override" ]]; then
708
713
  log_info "Mode Override: $mode_override"
709
714
  fi
715
+ local _run_one_mode_desc
716
+ case "$pipeline_mode" in
717
+ lite) _run_one_mode_desc="Tier 1 — Single Agent" ;;
718
+ standard) _run_one_mode_desc="Tier 2 — Orchestrator + Dev + Reviewer" ;;
719
+ full) _run_one_mode_desc="Tier 3 — Full Team (+ Multi-Critic)" ;;
720
+ *) _run_one_mode_desc="$pipeline_mode" ;;
721
+ esac
722
+ log_info "Pipeline mode: ${BOLD}$pipeline_mode${NC} ($_run_one_mode_desc)"
723
+ log_info "Agents: $agent_count (critic: $([ "$critic_enabled" = "true" ] && echo "enabled" || echo "disabled"))"
710
724
  if [[ $SESSION_TIMEOUT -gt 0 ]]; then
711
725
  log_info "Session timeout: ${SESSION_TIMEOUT}s"
712
726
  else
@@ -881,6 +895,7 @@ main() {
881
895
 
882
896
  # Main processing loop
883
897
  local session_count=0
898
+ local total_subagent_calls=0
884
899
 
885
900
  while true; do
886
901
  # Check for stuck features
@@ -923,6 +938,7 @@ for f in data.get('stuck_features', []):
923
938
  log_success "════════════════════════════════════════════════════"
924
939
  log_success " All features completed! Pipeline finished."
925
940
  log_success " Total sessions: $session_count"
941
+ log_success " Total subagent calls: $total_subagent_calls"
926
942
  log_success "════════════════════════════════════════════════════"
927
943
  break
928
944
  fi
@@ -999,8 +1015,22 @@ for f in data.get('stuck_features', []):
999
1015
  log_error "Failed to generate bootstrap prompt for $feature_id"
1000
1016
  continue
1001
1017
  }
1002
- local feature_model
1018
+ local feature_model pipeline_mode agent_count critic_enabled
1003
1019
  feature_model=$(echo "$gen_output" | python3 -c "import json,sys; print(json.load(sys.stdin).get('model',''))" 2>/dev/null || echo "")
1020
+ pipeline_mode=$(echo "$gen_output" | python3 -c "import json,sys; print(json.load(sys.stdin).get('pipeline_mode','lite'))" 2>/dev/null || echo "lite")
1021
+ agent_count=$(echo "$gen_output" | python3 -c "import json,sys; print(json.load(sys.stdin).get('agent_count',1))" 2>/dev/null || echo "1")
1022
+ critic_enabled=$(echo "$gen_output" | python3 -c "import json,sys; print(json.load(sys.stdin).get('critic_enabled','false'))" 2>/dev/null || echo "false")
1023
+
1024
+ # Log pipeline mode and agent configuration
1025
+ local _mode_desc
1026
+ case "$pipeline_mode" in
1027
+ lite) _mode_desc="Tier 1 — Single Agent" ;;
1028
+ standard) _mode_desc="Tier 2 — Orchestrator + Dev + Reviewer" ;;
1029
+ full) _mode_desc="Tier 3 — Full Team (+ Multi-Critic)" ;;
1030
+ *) _mode_desc="$pipeline_mode" ;;
1031
+ esac
1032
+ log_info "Pipeline mode: ${BOLD}$pipeline_mode${NC} ($_mode_desc)"
1033
+ log_info "Agents: $agent_count (critic: $([ "$critic_enabled" = "true" ] && echo "enabled" || echo "disabled"))"
1004
1034
 
1005
1035
  # Mark feature as in-progress before spawning session
1006
1036
  python3 "$SCRIPTS_DIR/update-feature-status.py" \
@@ -1042,6 +1072,7 @@ for f in data.get('stuck_features', []):
1042
1072
  fi
1043
1073
 
1044
1074
  session_count=$((session_count + 1))
1075
+ total_subagent_calls=$((total_subagent_calls + _SUBAGENT_COUNT))
1045
1076
 
1046
1077
  # Brief pause before next iteration
1047
1078
  log_info "Pausing 5s before next feature..."
@@ -723,10 +723,22 @@ def main():
723
723
 
724
724
  # Success
725
725
  feature_model = feature.get("model", "")
726
+ pipeline_mode = replacements.get("{{PIPELINE_MODE}}", "lite")
727
+ critic_enabled = replacements.get("{{CRITIC_ENABLED}}", "false") == "true"
728
+ # Map mode to agent count for logging
729
+ # lite=1 (single agent), standard/full=3 (orchestrator + dev + reviewer)
730
+ mode_agent_counts = {"lite": 1, "standard": 3, "full": 3}
731
+ agent_count = mode_agent_counts.get(pipeline_mode, 1)
732
+ critic_count_val = int(replacements.get("{{CRITIC_COUNT}}", "1"))
733
+ if critic_enabled:
734
+ agent_count += critic_count_val
726
735
  output = {
727
736
  "success": True,
728
737
  "output_path": os.path.abspath(args.output),
729
738
  "model": feature_model,
739
+ "pipeline_mode": pipeline_mode,
740
+ "agent_count": agent_count,
741
+ "critic_enabled": "true" if critic_enabled else "false",
730
742
  }
731
743
  print(json.dumps(output, indent=2, ensure_ascii=False))
732
744
  sys.exit(0)
@@ -130,7 +130,7 @@ grep -q '^/binary-name$' .gitignore || echo '/binary-name' >> .gitignore
130
130
  ```
131
131
  Never commit compiled binaries, build output, or generated artifacts.
132
132
 
133
- **Before starting**: detect the test command and record baseline:
133
+ **3a.** Detect the test command and record baseline:
134
134
  ```bash
135
135
  # Try in order, use first that exits 0
136
136
  node --test tests/**/*.test.js 2>&1 | tail -3 # Node built-in
@@ -141,26 +141,22 @@ Record the working command as `TEST_CMD`. Then record baseline failures (if any)
141
141
  $TEST_CMD 2>&1 | tee /tmp/test-baseline.txt | tail -20
142
142
  ```
143
143
 
144
- For each task in plan.md Tasks section:
145
- 1. Read the relevant section from `context-snapshot.md` (no need to re-read individual files)
146
- 2. Write/edit the code
147
- 3. Run tests after each task: `$TEST_CMD 2>&1 | tee /tmp/test-out.txt | tail -20` then grep `/tmp/test-out.txt` for failure details; never re-run just to apply a different filter
148
- 4. Mark task `[x]` in plan.md Tasks section immediately
144
+ **3b.** Run `/prizmkit-implement` this handles the full implementation cycle:
145
+ - Reads plan.md Tasks section from `.prizmkit/specs/{{FEATURE_SLUG}}/`
146
+ - Reads context from `context-snapshot.md` (Prizm docs, TRAPS, file manifest)
147
+ - Implements task-by-task with TDD, marking each `[x]` immediately
148
+ - Creates/updates L2 `.prizm` docs when creating new modules or significantly modifying existing ones — AI selectively decides which modules warrant L2 based on complexity and importance
149
+ - Runs tests using `TEST_CMD` after each task
150
+ - Writes '## Implementation Log' to `context-snapshot.md`
149
151
 
150
- After all tasks complete:
151
- 1. Run the full test suite to ensure nothing is broken
152
- 2. Verify each acceptance criterion from Section 1 of context-snapshot.md is met — check mentally, do NOT re-read files you already wrote
153
- 3. If any criterion is not met, fix it now (max 2 fix rounds)
152
+ **3c.** After implement completes, verify:
153
+ 1. All tasks in plan.md are `[x]`
154
+ 2. Run the full test suite to ensure nothing is broken
155
+ 3. Verify each acceptance criterion from Section 1 of context-snapshot.md is met — check mentally, do NOT re-read files you already wrote
156
+ 4. If any criterion is not met, fix it now (max 2 fix rounds)
154
157
 
155
158
  **CP-2**: All acceptance criteria met, all tests pass.
156
159
 
157
- After verification, append to `context-snapshot.md`:
158
- ```
159
- ## Implementation Log
160
- Files changed/created: [list]
161
- Key decisions: [list]
162
- ```
163
-
164
160
  {{IF_BROWSER_INTERACTION}}
165
161
  ### Phase 3.5: Browser Verification (playwright-cli)
166
162
 
@@ -188,7 +184,8 @@ If any step fails, log the failure and continue. Do NOT retry browser verificati
188
184
  **4a.** Run `/prizmkit-retrospective` — maintains `.prizm-docs/` (architecture index):
189
185
  1. **Structural sync**: Use `git diff --cached --name-status` to locate changed modules, update KEY_FILES/INTERFACES/DEPENDENCIES/file counts in affected `.prizm-docs/` files
190
186
  2. **Architecture knowledge** (feature sessions only): Extract TRAPS/RULES/DECISIONS from completed work into `.prizm-docs/`
191
- 3. Stage doc changes: `git add .prizm-docs/`
187
+ 3. **L2 coverage check**: For any module/sub-module with source files created or significantly modified in this session but no L2 `.prizm` doc — evaluate whether L2 is warranted and create if so. The current session has the best context for accurate KEY_FILES, TRAPS, and DECISIONS.
188
+ 4. Stage doc changes: `git add .prizm-docs/`
192
189
  ⚠️ Do NOT commit here. Only stage.
193
190
 
194
191
  **4b.** Stage all feature code explicitly (NEVER use `git add -A` or `git add .`):
@@ -194,20 +194,13 @@ Wait for Critic to return.
194
194
  Spawn Dev subagent (Agent tool, subagent_type="prizm-dev-team-dev", run_in_background=false).
195
195
 
196
196
  Prompt:
197
- > "Read {{DEV_SUBAGENT_PATH}}. Implement feature {{FEATURE_ID}} (slug: {{FEATURE_SLUG}}) using TDD.
198
- > **IMPORTANT**: Read `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` FIRST.
199
- > 1. Read `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` Section 3 has Prizm Context (TRAPS/RULES), Section 4 has File Manifest with paths and interfaces.
200
- > **⚠️ DO NOT re-read source files that are already listed in Section 4 File Manifest.** Only read a source file directly if: (a) NOT in the manifest, (b) needing an implementation detail beyond the interface summary, or (c) needing a constant/enum/field-name value not captured in the interface column.
201
- > 2. Read `plan.md` (including Tasks section) from `.prizmkit/specs/{{FEATURE_SLUG}}/`.
202
- > 3. Implement task-by-task. Mark each `[x]` in plan.md Tasks section **immediately** after completion (do NOT batch).
203
- > 4. Use `TEST_CMD=<TEST_CMD>` to run tests — do NOT explore alternative test commands. **When tests fail: run `$TEST_CMD 2>&1 | tee /tmp/test-out.txt` ONCE, then grep `/tmp/test-out.txt` for failure details. Never re-run the full suite just to apply a different filter.**
204
- > 5. After ALL tasks done, append '## Implementation Log' to context-snapshot.md with:
205
- > - Files changed/created (with paths)
206
- > - Key implementation decisions and rationale
207
- > - Deviations from plan.md (if any)
208
- > - Notable discoveries (unexpected behavior, hidden dependencies, new TRAPS)
209
- > 6. Do NOT execute any git commands (no git add/commit/reset/push).
210
- > 7. If `<TEST_CMD>` shows failures, check against BASELINE_FAILURES=`<BASELINE_FAILURES>`. Failures present in the baseline are pre-existing — list them explicitly in your COMPLETION_SIGNAL.
197
+ > "Read {{DEV_SUBAGENT_PATH}}. Implement feature {{FEATURE_ID}} (slug: {{FEATURE_SLUG}}).
198
+ > **IMPORTANT**: Read `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` FIRST — Section 3 has Prizm Context (TRAPS/RULES), Section 4 has File Manifest with paths and interfaces.
199
+ > ⚠️ DO NOT re-read source files already listed in Section 4 File Manifest unless you need implementation detail beyond the interface summary.
200
+ > 1. Read `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` for full context.
201
+ > 2. Run `/prizmkit-implement` to execute the tasks in plan.md. Use `TEST_CMD=<TEST_CMD>` for testing. Baseline failures: `BASELINE_FAILURES=<BASELINE_FAILURES>`.
202
+ > 3. After implement completes, verify the '## Implementation Log' section was written to context-snapshot.md.
203
+ > 4. Do NOT execute any git commands (no git add/commit/reset/push).
211
204
  > Do NOT exit until all tasks are [x] and the '## Implementation Log' section is written in context-snapshot.md."
212
205
 
213
206
  Wait for Dev to return. All tasks must be `[x]`, tests pass.
@@ -302,7 +295,8 @@ If any step fails, log the failure and continue. Do NOT retry browser verificati
302
295
  **6a.** Run `/prizmkit-retrospective` — maintains `.prizm-docs/` (architecture index):
303
296
  1. **Structural sync**: Use `git diff --cached --name-status` to locate changed modules, update KEY_FILES/INTERFACES/DEPENDENCIES/file counts in affected `.prizm-docs/` files
304
297
  2. **Architecture knowledge** (feature sessions only): Extract TRAPS/RULES/DECISIONS from completed work into `.prizm-docs/`
305
- 3. Stage doc changes: `git add .prizm-docs/`
298
+ 3. **L2 coverage check**: For any module/sub-module with source files created or significantly modified in this session but no L2 `.prizm` doc — evaluate whether L2 is warranted and create if so. The current session has the best context for accurate KEY_FILES, TRAPS, and DECISIONS.
299
+ 4. Stage doc changes: `git add .prizm-docs/`
306
300
  ⚠️ Do NOT commit here. Only stage.
307
301
 
308
302
  **6b.** Stage all feature code explicitly (NEVER use `git add -A` or `git add .`):
@@ -274,20 +274,13 @@ grep -c '^\- \[ \]' .prizmkit/specs/{{FEATURE_SLUG}}/plan.md 2>/dev/null || echo
274
274
  Spawn Dev agent (Agent tool, subagent_type="prizm-dev-team-dev", run_in_background=false).
275
275
 
276
276
  Prompt:
277
- > "Read {{DEV_SUBAGENT_PATH}}. Implement feature {{FEATURE_ID}} (slug: {{FEATURE_SLUG}}) using TDD.
278
- > **IMPORTANT**: Read `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` FIRST.
279
- > 1. Read `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` Section 3 has Prizm Context (TRAPS/RULES), Section 4 has File Manifest with paths and interfaces.
280
- > **⚠️ DO NOT re-read source files that are already listed in Section 4 File Manifest.** The manifest already contains their key interfaces. Only read a source file directly if: (a) it is NOT in the manifest, or (b) you need a specific implementation detail not captured in the manifest's interface column.
281
- > 2. Read `plan.md` (including Tasks section) from `.prizmkit/specs/{{FEATURE_SLUG}}/`.
282
- > 3. Implement task-by-task. Mark each `[x]` in plan.md Tasks section **immediately** after completion (do NOT batch).
283
- > 4. Use `TEST_CMD=<TEST_CMD>` to run tests — do NOT explore alternative test commands. **When tests fail: run `$TEST_CMD 2>&1 | tee /tmp/test-out.txt` ONCE, then grep `/tmp/test-out.txt` for failure details. Never re-run the full suite just to apply a different filter.**
284
- > 5. After ALL tasks done, append '## Implementation Log' to context-snapshot.md with:
285
- > - Files changed/created (with paths)
286
- > - Key implementation decisions and rationale
287
- > - Deviations from plan.md (if any)
288
- > - Notable discoveries (unexpected behavior, hidden dependencies, new TRAPS)
289
- > 6. Do NOT execute any git commands (no git add/commit/reset/push).
290
- > 7. If `<TEST_CMD>` shows failures, check against BASELINE_FAILURES=`<BASELINE_FAILURES>`. Failures present in the baseline are pre-existing — list them explicitly in your COMPLETION_SIGNAL.
277
+ > "Read {{DEV_SUBAGENT_PATH}}. Implement feature {{FEATURE_ID}} (slug: {{FEATURE_SLUG}}).
278
+ > **IMPORTANT**: Read `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` FIRST — Section 3 has Prizm Context (TRAPS/RULES), Section 4 has File Manifest with paths and interfaces.
279
+ > ⚠️ DO NOT re-read source files already listed in Section 4 File Manifest unless you need implementation detail beyond the interface summary.
280
+ > 1. Read `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` for full context.
281
+ > 2. Run `/prizmkit-implement` to execute the tasks in plan.md. Use `TEST_CMD=<TEST_CMD>` for testing. Baseline failures: `BASELINE_FAILURES=<BASELINE_FAILURES>`.
282
+ > 3. After implement completes, verify the '## Implementation Log' section was written to context-snapshot.md.
283
+ > 4. Do NOT execute any git commands (no git add/commit/reset/push).
291
284
  > Do NOT exit until all tasks are [x] and the '## Implementation Log' section is written in context-snapshot.md."
292
285
 
293
286
  **Gate Check — Implementation Log**:
@@ -303,10 +296,8 @@ Wait for Dev to return. **If Dev times out before all tasks are `[x]`**:
303
296
  > "Read {{DEV_SUBAGENT_PATH}}. You are resuming implementation of feature {{FEATURE_ID}} (slug: {{FEATURE_SLUG}}).
304
297
  > 1. Read `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` — Section 4 has File Manifest, 'Implementation Log' (if present) shows what was already done.
305
298
  > 2. Run `git diff HEAD` to see actual code changes already made.
306
- > 3. Read plan.md Tasks section — complete ONLY the remaining `[ ]` tasks. Do NOT redo completed `[x]` tasks.
307
- > 4. Use `TEST_CMD=<TEST_CMD>` to run tests.
308
- > 5. Append progress to '## Implementation Log' in context-snapshot.md.
309
- > 6. Do NOT execute any git commands."
299
+ > 3. Run `/prizmkit-implement` to complete the remaining `[ ]` tasks. Use `TEST_CMD=<TEST_CMD>` for testing.
300
+ > 4. Do NOT execute any git commands."
310
301
  3. Max 2 recovery retries. After 2 failures, orchestrator implements remaining tasks directly.
311
302
 
312
303
  All tasks `[x]`, tests pass.
@@ -412,6 +403,7 @@ git log --oneline | grep "{{FEATURE_ID}}" | head -3
412
403
  **6b.** Run `/prizmkit-retrospective` (**before commit**, maintains `.prizm-docs/` architecture index):
413
404
  - **Structural sync**: update KEY_FILES/INTERFACES/DEPENDENCIES/file counts for changed modules
414
405
  - **Architecture knowledge** (feature sessions only): extract TRAPS, RULES, DECISIONS from completed work into `.prizm-docs/`
406
+ - **L2 coverage check**: For any module/sub-module with source files created or significantly modified in this session but no L2 `.prizm` doc — evaluate whether L2 is warranted and create if so. The current session has the best context for accurate KEY_FILES, TRAPS, and DECISIONS.
415
407
  - Stage doc changes: `git add .prizm-docs/`
416
408
  ⚠️ Do NOT commit here. Only stage.
417
409
  - **For bug-fix sessions**: structural sync only, skip knowledge injection unless a genuinely new pitfall was discovered
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.0.137",
2
+ "version": "1.0.138",
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.",
@@ -39,7 +39,10 @@ Execute implementation by following the task breakdown in plan.md. Respects task
39
39
  3. Check if checkpoint tasks are complete before proceeding to next phase
40
40
  4. For each unchecked task in order:
41
41
  a. If task has `[P]` marker, it can run in parallel with other `[P]` tasks in the same group
42
- b. Read L2 doc for target file's module (if exists) — TRAPS save you from repeating known mistakes
42
+ b. Read L2 doc for target file's module. TRAPS save you from repeating known mistakes.
43
+ - If L2 exists: check TRAPS and DECISIONS before modifying files.
44
+ - If L2 does not exist and this task creates a new module directory or adds significant source files: create L2 using the L2 GENERATION TEMPLATE (see PRIZM-SPEC). Seed KEY_FILES and DEPENDENCIES from the files being created. TRAPS and DECISIONS can be minimal initially — `/prizmkit-retrospective` will enrich them.
45
+ - Judgment call: not every directory needs L2. Create L2 when the module has meaningful logic, non-obvious coupling, or design decisions worth preserving. Skip for trivial wrapper directories or single-config modules.
43
46
  c. Apply TDD where applicable: write a failing test first, then implement until it passes. For UI components or configuration changes where unit tests don't apply, skip the test-first step.
44
47
  d. Mark task as `[x]` in `plan.md` Tasks section immediately — not batched at the end. Immediate marking means the plan always reflects true progress, even if the session is interrupted.
45
48
  e. After all tasks, append '## Implementation Log' to `context-snapshot.md` (if running in pipeline context): files changed/created, key decisions, notable discoveries.
@@ -76,7 +76,7 @@ STEPS:
76
76
  3. Classify each change: A (added) -> new KEY_FILES entries. D (deleted) -> remove entries, update counts. M (modified) -> check dependency changes. R (renamed) -> update all path references.
77
77
  4. Update affected docs: L2 first (KEY_FILES, INTERFACES, DATA_FLOW, DEPENDENCIES, TRAPS, CHANGELOG), then L1 (FILES count, KEY_FILES, DEPENDENCIES — L1 does NOT contain INTERFACES/DATA_FLOW/TRAPS/DECISIONS), then L0 (MODULE_INDEX counts, CROSS_CUTTING) only if structural change. No UPDATED timestamps — git tracks modification times.
78
78
  5. Skip updates if: only internal implementation changed (no interface/dependency change), only comments/whitespace/formatting, only .prizm files changed. DO NOT skip test file changes or bug fixes — they may reveal TRAPS worth capturing in L2.
79
- 6. If new directory qualifies as a module (per MODULE_DISCOVERY_CRITERIA) and matches no existing module: create L1 immediately, add to MODULE_INDEX, defer L2.
79
+ 6. If new directory qualifies as a module (per MODULE_DISCOVERY_CRITERIA) and matches no existing module: create L1 immediately, add to MODULE_INDEX. If the current diff includes Added or Modified source files in this module → also create L2 immediately using the L2 GENERATION TEMPLATE. Otherwise defer L2.
80
80
  7. Append entries to changelog.prizm using format: `- YYYY-MM-DD | <module-path> | <verb>: <description>`
81
81
  8. Enforce size limits: L0 > 4KB -> consolidate. L1 > 4KB -> trim KEY_FILES descriptions, ensure RULES <= 3 entries. L2 > 5KB -> split or archive.
82
82
  9. Stage updated .prizm files via `git add .prizm-docs/`
@@ -162,7 +162,7 @@ When working in a project with .prizm-docs/:
162
162
 
163
163
  - ON SESSION START: Always read .prizm-docs/root.prizm (L0). This is the project map.
164
164
  - ON TASK: Read L1 docs for relevant modules referenced in MODULE_INDEX.
165
- - ON FILE EDIT: Read L2 doc before modifying files. Check TRAPS and DECISIONS sections.
165
+ - ON FILE EDIT: Read L2 doc before modifying files. Check TRAPS and DECISIONS sections. If L2 does not exist and you are creating/modifying significant source files in this module → generate L2 using the L2 GENERATION TEMPLATE before proceeding.
166
166
  - ON DEEP READ: If you need deep understanding of a module without modifying it, generate L2 if it doesn't exist.
167
167
  - NEVER load all .prizm docs at once. Progressive loading saves tokens.
168
168
  - BUDGET: Typical task should consume 3000-5000 tokens of Prizm docs total.
@@ -59,14 +59,16 @@ git diff --name-status
59
59
 
60
60
  **1d.** Update affected docs (bottom-up: L2 → L1 → L0):
61
61
 
62
- - **L2** (if exists): Update KEY_FILES, INTERFACES, DATA_FLOW, DEPENDENCIES, CHANGELOG, TRAPS, DECISIONS
62
+ - **L2**: If L2 exists update KEY_FILES, INTERFACES, DATA_FLOW, DEPENDENCIES, CHANGELOG, TRAPS, DECISIONS. If L2 does NOT exist AND the module has Added or Modified source files in the current diff with meaningful logic (not trivial config) → create L2 using the L2 GENERATION TEMPLATE, then populate from source.
63
63
  - **L1**: Update FILES count, KEY_FILES (if major files added/removed), DEPENDENCIES (if module-level deps changed). **L1 does NOT contain INTERFACES, DATA_FLOW, TRAPS, or DECISIONS** — those belong in L2 only.
64
64
  - **L0 root.prizm**: Update MODULE_INDEX file counts only if counts changed. Update CROSS_CUTTING if cross-module concerns changed. Update only if structural change (module added/removed).
65
65
 
66
66
  **1d-migrate.** Legacy TRAPS format migration (opportunistic):
67
67
  While updating an affected L1/L2 doc, if you encounter TRAPS entries **without** a severity prefix (e.g., `- foo | FIX: bar` instead of `- [LOW] foo | FIX: bar`), prepend `[LOW]` as a conservative default. This clears legacy format debt incrementally — only in files already being touched, never as a bulk operation.
68
68
 
69
- **1e.** If new directory qualifies as a module (per MODULE_DISCOVERY_CRITERIA in PRIZM-SPEC Section 9.1 Step 2) and matches no existing module: create L1 doc immediately, add to MODULE_INDEX, defer L2.
69
+ **1e.** If new directory qualifies as a module (per MODULE_DISCOVERY_CRITERIA in PRIZM-SPEC Section 9.1 Step 2) and matches no existing module:
70
+ 1. Create L1 doc immediately, add to MODULE_INDEX.
71
+ 2. If the current diff includes Added or Modified source files with meaningful logic in this module → create L2 immediately using the L2 GENERATION TEMPLATE. Otherwise defer L2 to the next session that touches this module.
70
72
 
71
73
  **1f.** Enforce size limits:
72
74
  - L0 > 4KB → consolidate MODULE_INDEX
@@ -143,7 +145,7 @@ When writing TRAPS:
143
145
  **QUALITY GATE**: Every item must answer: "If a new AI session reads only `.prizm-docs/` and this entry, does it gain actionable understanding?" If not, discard. Do not record trivially observable code patterns — the AI can read the code directly.
144
146
 
145
147
  **2c.** Inject into the correct `.prizm-docs/` file:
146
- - Module-level TRAPS/RULES/DECISIONS → the affected **L2** `.prizm` file's corresponding section (TRAPS/DECISIONS/RULES belong in L2, not L1)
148
+ - Module-level TRAPS/RULES/DECISIONS → the affected **L2** `.prizm` file. If the target L2 does not exist, create it first using the L2 GENERATION TEMPLATE before injecting knowledge. (TRAPS/DECISIONS/RULES belong in L2, not L1.)
147
149
  - Project-level RULES/PATTERNS → `root.prizm`
148
150
  - Cross-module concerns spanning 2+ modules → `root.prizm` CROSS_CUTTING section
149
151
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prizmkit",
3
- "version": "1.0.137",
3
+ "version": "1.0.139",
4
4
  "description": "Create a new PrizmKit-powered project with clean initialization — no framework dev files, just what you need.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/manifest.js CHANGED
@@ -99,7 +99,7 @@ export function buildManifest({
99
99
  * Diff two manifests and return added/removed items.
100
100
  * @param {Object} oldManifest - previous manifest
101
101
  * @param {Object} newManifest - new manifest to compare against
102
- * @returns {Object} { skills: {added, removed}, agents: {added, removed}, rules: {added, removed} }
102
+ * @returns {Object} { skills: {added, removed}, agents: {added, removed}, rules: {added, removed}, pipeline: {added, removed}, extras: {added, removed} }
103
103
  */
104
104
  export function diffManifest(oldManifest, newManifest) {
105
105
  function diffArrays(oldArr, newArr) {
@@ -119,5 +119,6 @@ export function diffManifest(oldManifest, newManifest) {
119
119
  Array.isArray(oldManifest?.files?.pipeline) ? oldManifest.files.pipeline : [],
120
120
  Array.isArray(newManifest?.files?.pipeline) ? newManifest.files.pipeline : [],
121
121
  ),
122
+ extras: diffArrays(oldManifest?.files?.extras, newManifest?.files?.extras),
122
123
  };
123
124
  }
package/src/scaffold.js CHANGED
@@ -692,7 +692,8 @@ export async function installGitignore(projectRoot, options, dryRun) {
692
692
 
693
693
  if (missing.length > 0) {
694
694
  const separator = existing.endsWith('\n') ? '' : '\n';
695
- await fs.appendFile(targetPath, separator + '\n# PrizmKit\n' + missing.join('\n') + '\n');
695
+ const header = existingLines.has('# PrizmKit') ? '' : '# PrizmKit\n';
696
+ await fs.appendFile(targetPath, separator + '\n' + header + missing.join('\n') + '\n');
696
697
  console.log(chalk.green(` ✓ .gitignore (added ${missing.length} entries)`));
697
698
  } else {
698
699
  console.log(chalk.green(' ✓ .gitignore (up-to-date)'));
@@ -894,15 +895,15 @@ export async function scaffold(config) {
894
895
  }
895
896
  }
896
897
 
897
- // 11. Git pre-commit hook
898
+ // 12. Git pre-commit hook
898
899
  console.log(chalk.blue(' Git Hook:'));
899
900
  await installGitHook(projectRoot, dryRun);
900
901
 
901
- // 12. PrizmKit scripts (always installed)
902
+ // 13. PrizmKit scripts (always installed)
902
903
  console.log(chalk.blue(' PrizmKit 脚本:'));
903
904
  await installPrizmkitScripts(projectRoot, dryRun);
904
905
 
905
- // 13. Write installation manifest
906
+ // 14. Write installation manifest
906
907
  if (!dryRun) {
907
908
  const agentsDir = getAgentsDir();
908
909
  const agentFileNames = (await fs.readdir(agentsDir)).filter(f => f.endsWith('.md'));
package/src/upgrade.js CHANGED
@@ -272,7 +272,7 @@ export async function runUpgrade(directory, options = {}) {
272
272
  newManifest.installedAt = oldManifest.installedAt;
273
273
  }
274
274
 
275
- const diff = oldManifest ? diffManifest(oldManifest, newManifest) : { skills: { added: [], removed: [] }, agents: { added: [], removed: [] }, rules: { added: [], removed: [] }, pipeline: { added: [], removed: [] } };
275
+ const diff = oldManifest ? diffManifest(oldManifest, newManifest) : { skills: { added: [], removed: [] }, agents: { added: [], removed: [] }, rules: { added: [], removed: [] }, pipeline: { added: [], removed: [] }, extras: { added: [], removed: [] } };
276
276
 
277
277
  // 5. Display upgrade summary
278
278
  const oldVersion = oldManifest?.version || 'unknown';
@@ -282,8 +282,8 @@ export async function runUpgrade(directory, options = {}) {
282
282
  console.log(` Suite: ${suite}`);
283
283
  console.log('');
284
284
 
285
- const totalAdded = diff.skills.added.length + diff.agents.added.length + diff.rules.added.length + diff.pipeline.added.length;
286
- const totalRemoved = diff.skills.removed.length + diff.agents.removed.length + diff.rules.removed.length + diff.pipeline.removed.length;
285
+ const totalAdded = diff.skills.added.length + diff.agents.added.length + diff.rules.added.length + diff.pipeline.added.length + diff.extras.added.length;
286
+ const totalRemoved = diff.skills.removed.length + diff.agents.removed.length + diff.rules.removed.length + diff.pipeline.removed.length + diff.extras.removed.length;
287
287
  const totalUpdated = newSkillList.length + newAgentFiles.length + newRuleFiles.length;
288
288
 
289
289
  if (diff.skills.added.length) console.log(chalk.green(` + Skills added: ${diff.skills.added.join(', ')}`));
@@ -294,6 +294,8 @@ export async function runUpgrade(directory, options = {}) {
294
294
  if (diff.rules.removed.length) console.log(chalk.red(` - Rules removed: ${diff.rules.removed.join(', ')}`));
295
295
  if (diff.pipeline.added.length) console.log(chalk.green(` + Pipeline files added: ${diff.pipeline.added.length} file(s)`));
296
296
  if (diff.pipeline.removed.length) console.log(chalk.red(` - Pipeline files removed: ${diff.pipeline.removed.length} file(s)`));
297
+ if (diff.extras.added.length) console.log(chalk.green(` + Extras added: ${diff.extras.added.join(', ')}`));
298
+ if (diff.extras.removed.length) console.log(chalk.red(` - Extras removed: ${diff.extras.removed.join(', ')}`));
297
299
 
298
300
  if (totalAdded === 0 && totalRemoved === 0 && oldVersion === pkg.version) {
299
301
  console.log(chalk.gray(' No changes detected. Re-installing all files to ensure consistency.'));