codebyplan 1.13.49 → 1.13.50

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 (25) hide show
  1. package/dist/cli.js +2 -1
  2. package/package.json +1 -1
  3. package/templates/agents/cbp-round-executor.md +1 -6
  4. package/templates/agents/cbp-task-planner.md +2 -2
  5. package/templates/hooks/cbp-skill-context-guard.sh +52 -0
  6. package/templates/hooks/cbp-test-hooks.sh +144 -0
  7. package/templates/hooks/hooks.json +9 -0
  8. package/templates/rules/model-invocation-convention.md +40 -0
  9. package/templates/rules/parallel-waves.md +1 -1
  10. package/templates/rules/task-routing-recommendation.md +1 -1
  11. package/templates/settings.project.base.json +2 -1
  12. package/templates/skills/cbp-build-cc-settings/reference/cbp-permission-policy.md +42 -0
  13. package/templates/skills/cbp-clear-continue/SKILL.md +86 -0
  14. package/templates/skills/cbp-clear-prep/SKILL.md +121 -0
  15. package/templates/skills/cbp-round-start/SKILL.md +1 -1
  16. package/templates/skills/cbp-task-check/SKILL.md +12 -5
  17. package/templates/skills/cbp-task-complete/SKILL.md +9 -11
  18. package/templates/skills/cbp-task-complete/reference/checkpoint-done-branching.md +14 -21
  19. package/templates/skills/cbp-task-complete/reference/next-step-heuristic.md +4 -6
  20. package/templates/skills/cbp-task-testing/SKILL.md +9 -14
  21. package/templates/skills/cbp-frontend-a11y/SKILL.md +0 -108
  22. package/templates/skills/cbp-frontend-a11y/reference/aria-roles-states.md +0 -130
  23. package/templates/skills/cbp-frontend-a11y/reference/contrast-visual.md +0 -122
  24. package/templates/skills/cbp-frontend-a11y/reference/keyboard-patterns.md +0 -154
  25. package/templates/skills/cbp-frontend-a11y/reference/semantic-html.md +0 -111
package/dist/cli.js CHANGED
@@ -39,7 +39,7 @@ var VERSION, PACKAGE_NAME;
39
39
  var init_version = __esm({
40
40
  "src/lib/version.ts"() {
41
41
  "use strict";
42
- VERSION = "1.13.49";
42
+ VERSION = "1.13.50";
43
43
  PACKAGE_NAME = "codebyplan";
44
44
  }
45
45
  });
@@ -639,6 +639,7 @@ var init_gitignore_block = __esm({
639
639
  ".codebyplan/statusline.local.json",
640
640
  ".codebyplan/worktree.local.json",
641
641
  ".codebyplan/state/",
642
+ ".codebyplan/clear/",
642
643
  ".codebyplan/todo/",
643
644
  ".codebyplan/claude-status.local.json",
644
645
  ".codebyplan.local.json"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codebyplan",
3
- "version": "1.13.49",
3
+ "version": "1.13.50",
4
4
  "description": "CLI for CodeByPlan — AI-powered development planning and tracking",
5
5
  "type": "module",
6
6
  "bin": {
@@ -239,18 +239,13 @@ When the executor received a `wave` input with a non-empty `wave.skill_preloads[
239
239
  For each entry in `wave.skill_preloads[]`, invoke the named skill via the Skill tool BEFORE Step 3 (Execute). Invoke in order:
240
240
 
241
241
  1. `cbp-frontend-design` — if present, invoke FIRST (aesthetic direction before code)
242
- 2. `cbp-frontend-a11y` if present, invoke AFTER `cbp-frontend-design` (accessibility obligations)
243
- 3. Any other skill preload — invoke in list order
242
+ 2. Any other skill preload invoke in list order
244
243
 
245
244
  Record completion:
246
245
  ```yaml
247
246
  round.context.frontend_design_loaded: true # if cbp-frontend-design was preloaded
248
- round.context.frontend_a11y_loaded: true # if cbp-frontend-a11y was preloaded
249
- round.context.frontend_a11y_checklist: [items from cbp-frontend-a11y/SKILL.md Phase 6 output] # only when cbp-frontend-a11y was preloaded for this wave
250
247
  ```
251
248
 
252
- When cbp-frontend-a11y is preloaded, capture its Phase 6 per-component checklist output verbatim into `round.context.frontend_a11y_checklist`. Step 3 reads this for accessibility enforcement during code emission.
253
-
254
249
  If `wave` is absent or `wave.skill_preloads[]` is empty, skip this step — Step 2.7 handles the non-wave UI pre-read path.
255
250
 
256
251
  **Why step 2.6 and 2.7 coexist**: Step 2.7 fires for non-wave rounds when the executor detects UI files directly. Step 2.6 fires for wave rounds where the planner already determined the preloads. They cover the same skill but via different trigger paths; the round.context recording is identical so downstream steps behave uniformly.
@@ -533,7 +533,7 @@ After Phase 5 (solution design) and before Phase 6 (context summary), decompose
533
533
  1. **Identify natural cut points**: look for cross-app boundaries (files in `apps/web/` vs `apps/backend/` vs `apps/desktop/`), packages with no shared state, or dependency ordering (DB migration must precede app code using the new schema).
534
534
  2. **Check disjoint-files invariant**: no file may appear in two waves. If a shared file is needed by two waves, assign it to the earlier wave and make the later wave `depends_on` the earlier.
535
535
  3. **Check DAG invariant**: `depends_on[]` must be acyclic. Any cycle is a plan error — resolve by merging the cyclic waves.
536
- 4. **Populate `skill_preloads[]`**: for each wave whose `files[]` contains UI-bearing paths (`*.tsx`, `*.jsx`, `*.scss`, etc.), add `"frontend-design"` and `"frontend-a11y"` to `skill_preloads[]` (in that order).
536
+ 4. **Populate `skill_preloads[]`**: for each wave whose `files[]` contains UI-bearing paths (`*.tsx`, `*.jsx`, `*.scss`, etc.), add `"frontend-design"` to `skill_preloads[]`.
537
537
  5. **Single-wave default**: if no independence is found, produce ONE wave covering all files. Parallel waves add orchestration overhead — only decompose when the benefit is clear.
538
538
  6. **15-file cap**: after decomposition (including the single-wave default), count files in each wave. If any wave would exceed 15 files, auto-split it using the proximity-split algorithm in priority order: (a) **shared directory subtree** — split at the deepest common ancestor that produces two groups each ≥3 files; (b) **shared module** — split at the next directory level below the common ancestor; (c) **arbitrary boundary** — split at the 15-file boundary and add a one-line `note` on the continuation wave explaining the boundary. Split siblings are **independent**: do NOT add `depends_on` between them unless a real shared-file or data dependency requires ordering. **Tail rule**: choose boundaries so every resulting wave holds 3–15 files. A split must never leave a wave with <3 files; rebalance the boundary rather than absorbing a tail into a sibling in a way that pushes it above 15. The 3–15 range is a hard invariant — there is no exception above 15. **Apply the cap iteratively**: after a split, re-check each resulting wave and split again any that still exceeds 15 — a 40-file single-concern plan therefore yields ≥3 waves. When no natural boundary yields groups each ≥3 files, take the smallest ≥3-file prefix as one wave and apply the same procedure to the remainder. The single-wave default is itself subject to this cap. See `rules/parallel-waves.md` for the full algorithm and invariants.
539
539
 
@@ -559,7 +559,7 @@ printf '%s' "$PLAN_JSON" | codebyplan validate-waves --json
559
559
 
560
560
  (`$PLAN_JSON` is the `{ "waves": [...] }` structure; pass a file path as the first argument instead of stdin if preferred.) Exit 0 = invariants I–III satisfied. Exit non-zero = one or more violations — the `--json` `violations[]` array names the failing invariant (`I`/`II`/`III`) and offending wave/file; fix the decomposition and re-run before emitting the plan. The validator does NOT check invariant IV (UI skill preloads) — that remains a manual step:
561
561
 
562
- - [ ] UI-bearing waves have `frontend-design` + `frontend-a11y` in `skill_preloads[]` (invariant IV — not covered by `validate-waves`)
562
+ - [ ] UI-bearing waves have `frontend-design` in `skill_preloads[]` (invariant IV — not covered by `validate-waves`)
563
563
 
564
564
  ### Phase 6: Build Context Summary
565
565
 
@@ -0,0 +1,52 @@
1
+ #!/bin/bash
2
+ # @scope: org-shared
3
+ # Hook: PreToolUse (Skill)
4
+ # Purpose: Deny heavy close-out skills when context window > CBP_CONTEXT_WARN_TOKENS (default 200000).
5
+ # Reads transcript_path from stdin, sums the latest assistant message.usage — same logic
6
+ # as cbp-context-window-notify.sh. If total exceeds threshold AND the skill is in the
7
+ # heavy close-out allowlist, emits hookSpecificOutput.permissionDecision=deny directing
8
+ # Claude to run /cbp-clear-prep. Always exits 0 — fail-open.
9
+
10
+ set -euo pipefail
11
+
12
+ INPUT=$(cat)
13
+ SKILL_NAME=$(echo "$INPUT" | jq -r '.tool_input.skill // .tool_input.skill_name // ""' 2>/dev/null) || SKILL_NAME=""
14
+ TRANSCRIPT=$(echo "$INPUT" | jq -r '.transcript_path // ""' 2>/dev/null) || TRANSCRIPT=""
15
+
16
+ # Fast-path: no transcript → pass through
17
+ [ -z "$TRANSCRIPT" ] && exit 0
18
+ [ ! -f "$TRANSCRIPT" ] && exit 0
19
+
20
+ THRESHOLD="${CBP_CONTEXT_WARN_TOKENS:-200000}"
21
+
22
+ # Heavy close-out allowlist (cbp-clear-prep + cbp-clear-continue deliberately excluded so
23
+ # they always run even when context > threshold).
24
+ HEAVY_SKILLS="cbp-round-execute cbp-task-testing cbp-standalone-task-testing cbp-checkpoint-check cbp-checkpoint-end"
25
+
26
+ # Cheap allowlist check before summing tokens
27
+ IS_HEAVY=false
28
+ for heavy in $HEAVY_SKILLS; do
29
+ if [ "$SKILL_NAME" = "$heavy" ]; then
30
+ IS_HEAVY=true
31
+ break
32
+ fi
33
+ done
34
+ [ "$IS_HEAVY" = "false" ] && exit 0
35
+
36
+ # Token sum — same logic as cbp-context-window-notify.sh
37
+ TOTAL=$(tail -n 400 "$TRANSCRIPT" \
38
+ | jq -rR 'fromjson? | select(.message.usage != null)
39
+ | (.message.usage
40
+ | ((.input_tokens // 0) + (.cache_creation_input_tokens // 0) + (.cache_read_input_tokens // 0)))' \
41
+ 2>/dev/null | tail -1) || TOTAL=0
42
+ TOTAL="${TOTAL:-0}"
43
+
44
+ if [ "$TOTAL" -ge "$THRESHOLD" ] 2>/dev/null; then
45
+ jq -n \
46
+ --argjson tokens "$TOTAL" \
47
+ --argjson threshold "$THRESHOLD" \
48
+ --arg skill "$SKILL_NAME" \
49
+ '{hookSpecificOutput:{permissionDecision:"deny",permissionDecisionReason:("Context window at \($tokens) tokens (threshold \($threshold)) is too large to safely run /\($skill). Run /cbp-clear-prep now to capture a handoff, then /clear, then /cbp-clear-continue to resume.")}}'
50
+ fi
51
+
52
+ exit 0
@@ -527,6 +527,150 @@ fi
527
527
 
528
528
  echo ""
529
529
 
530
+ # ===== HOOK SMOKE TESTS — cbp-skill-context-guard =====
531
+ echo "## Hook Smoke Tests — cbp-skill-context-guard (CHK-217)"
532
+
533
+ GUARD_HOOK="$HOOKS_DIR/cbp-skill-context-guard.sh"
534
+ FIXTURES_GUARD="$HOOKS_DIR/__test-fixtures__/cbp-context-window-notify"
535
+
536
+ if [ ! -f "$GUARD_HOOK" ]; then
537
+ test_result "cbp-skill-context-guard.sh present" "passed" "missing"
538
+ else
539
+
540
+ # Case 1: over-threshold + cbp-round-execute (heavy) → permissionDecision=deny
541
+ STDIN=$(jq -n \
542
+ --arg t "$FIXTURES_GUARD/over-threshold.jsonl" \
543
+ --arg s "cbp-round-execute" \
544
+ '{transcript_path:$t,tool_input:{skill:$s}}')
545
+ OUTPUT=$(echo "$STDIN" | CBP_CONTEXT_WARN_TOKENS=200000 bash "$GUARD_HOOK" 2>/dev/null)
546
+ EXIT_CODE=$?
547
+ if [ "$EXIT_CODE" = "0" ] \
548
+ && echo "$OUTPUT" | jq -e '.hookSpecificOutput.permissionDecision == "deny"' >/dev/null 2>&1; then
549
+ test_result "cbp-skill-context-guard.sh over-threshold + cbp-round-execute → deny" "passed" "passed"
550
+ else
551
+ test_result "cbp-skill-context-guard.sh over-threshold + cbp-round-execute → deny" "passed" "failed (exit=$EXIT_CODE output=$(echo "$OUTPUT" | head -c 80))"
552
+ fi
553
+
554
+ # Case 2: over-threshold + cbp-clear-prep (exempt) → empty stdout, exit 0
555
+ STDIN=$(jq -n \
556
+ --arg t "$FIXTURES_GUARD/over-threshold.jsonl" \
557
+ --arg s "cbp-clear-prep" \
558
+ '{transcript_path:$t,tool_input:{skill:$s}}')
559
+ OUTPUT=$(echo "$STDIN" | CBP_CONTEXT_WARN_TOKENS=200000 bash "$GUARD_HOOK" 2>/dev/null)
560
+ EXIT_CODE=$?
561
+ if [ "$EXIT_CODE" = "0" ] && [ -z "$OUTPUT" ]; then
562
+ test_result "cbp-skill-context-guard.sh over-threshold + cbp-clear-prep (exempt) → empty stdout" "passed" "passed"
563
+ else
564
+ test_result "cbp-skill-context-guard.sh over-threshold + cbp-clear-prep (exempt) → empty stdout" "passed" "failed (exit=$EXIT_CODE)"
565
+ fi
566
+
567
+ # Case 3: over-threshold + cbp-clear-continue (exempt) → empty stdout, exit 0
568
+ STDIN=$(jq -n \
569
+ --arg t "$FIXTURES_GUARD/over-threshold.jsonl" \
570
+ --arg s "cbp-clear-continue" \
571
+ '{transcript_path:$t,tool_input:{skill:$s}}')
572
+ OUTPUT=$(echo "$STDIN" | CBP_CONTEXT_WARN_TOKENS=200000 bash "$GUARD_HOOK" 2>/dev/null)
573
+ EXIT_CODE=$?
574
+ if [ "$EXIT_CODE" = "0" ] && [ -z "$OUTPUT" ]; then
575
+ test_result "cbp-skill-context-guard.sh over-threshold + cbp-clear-continue (exempt) → empty stdout" "passed" "passed"
576
+ else
577
+ test_result "cbp-skill-context-guard.sh over-threshold + cbp-clear-continue (exempt) → empty stdout" "passed" "failed (exit=$EXIT_CODE)"
578
+ fi
579
+
580
+ # Case 4: under-threshold + cbp-round-execute → empty stdout, exit 0
581
+ STDIN=$(jq -n \
582
+ --arg t "$FIXTURES_GUARD/under-threshold.jsonl" \
583
+ --arg s "cbp-round-execute" \
584
+ '{transcript_path:$t,tool_input:{skill:$s}}')
585
+ OUTPUT=$(echo "$STDIN" | CBP_CONTEXT_WARN_TOKENS=200000 bash "$GUARD_HOOK" 2>/dev/null)
586
+ EXIT_CODE=$?
587
+ if [ "$EXIT_CODE" = "0" ] && [ -z "$OUTPUT" ]; then
588
+ test_result "cbp-skill-context-guard.sh under-threshold + cbp-round-execute → empty stdout" "passed" "passed"
589
+ else
590
+ test_result "cbp-skill-context-guard.sh under-threshold + cbp-round-execute → empty stdout" "passed" "failed (exit=$EXIT_CODE)"
591
+ fi
592
+
593
+ # Case 5: empty skill_name → empty stdout, exit 0
594
+ STDIN=$(jq -n \
595
+ --arg t "$FIXTURES_GUARD/over-threshold.jsonl" \
596
+ '{transcript_path:$t,tool_input:{}}')
597
+ OUTPUT=$(echo "$STDIN" | CBP_CONTEXT_WARN_TOKENS=200000 bash "$GUARD_HOOK" 2>/dev/null)
598
+ EXIT_CODE=$?
599
+ if [ "$EXIT_CODE" = "0" ] && [ -z "$OUTPUT" ]; then
600
+ test_result "cbp-skill-context-guard.sh empty skill_name → empty stdout" "passed" "passed"
601
+ else
602
+ test_result "cbp-skill-context-guard.sh empty skill_name → empty stdout" "passed" "failed (exit=$EXIT_CODE)"
603
+ fi
604
+
605
+ # Case 6: missing transcript_path → empty stdout, exit 0 (fast-path)
606
+ STDIN=$(jq -n --arg s "cbp-round-execute" '{tool_input:{skill:$s}}')
607
+ OUTPUT=$(echo "$STDIN" | CBP_CONTEXT_WARN_TOKENS=200000 bash "$GUARD_HOOK" 2>/dev/null)
608
+ EXIT_CODE=$?
609
+ if [ "$EXIT_CODE" = "0" ] && [ -z "$OUTPUT" ]; then
610
+ test_result "cbp-skill-context-guard.sh missing transcript_path → empty stdout" "passed" "passed"
611
+ else
612
+ test_result "cbp-skill-context-guard.sh missing transcript_path → empty stdout" "passed" "failed (exit=$EXIT_CODE)"
613
+ fi
614
+
615
+ fi
616
+
617
+ # ===== STRUCTURAL ASSERTIONS — cbp-clear-* skills (CHK-217) =====
618
+ echo ""
619
+ echo "## Structural Assertions — cbp-clear-* skills (CHK-217)"
620
+
621
+ # cbp-clear-prep/SKILL.md: scope: org-shared + references handoff.md
622
+ CLEAR_PREP_SKILL="$(dirname "$HOOKS_DIR")/skills/cbp-clear-prep/SKILL.md"
623
+ if [ -f "$CLEAR_PREP_SKILL" ]; then
624
+ if grep -q 'scope: org-shared' "$CLEAR_PREP_SKILL"; then
625
+ test_result "cbp-clear-prep/SKILL.md has scope: org-shared" "passed" "passed"
626
+ else
627
+ test_result "cbp-clear-prep/SKILL.md has scope: org-shared" "passed" "missing"
628
+ fi
629
+ if grep -q 'handoff\.md' "$CLEAR_PREP_SKILL"; then
630
+ test_result "cbp-clear-prep/SKILL.md references handoff.md" "passed" "passed"
631
+ else
632
+ test_result "cbp-clear-prep/SKILL.md references handoff.md" "passed" "missing"
633
+ fi
634
+ else
635
+ test_result "cbp-clear-prep/SKILL.md structural checks (file absent — skipped)" "passed" "passed"
636
+ fi
637
+
638
+ # cbp-clear-continue/SKILL.md: scope: org-shared + references handoff.md + has rm of handoff
639
+ CLEAR_CONTINUE_SKILL="$(dirname "$HOOKS_DIR")/skills/cbp-clear-continue/SKILL.md"
640
+ if [ -f "$CLEAR_CONTINUE_SKILL" ]; then
641
+ if grep -q 'scope: org-shared' "$CLEAR_CONTINUE_SKILL"; then
642
+ test_result "cbp-clear-continue/SKILL.md has scope: org-shared" "passed" "passed"
643
+ else
644
+ test_result "cbp-clear-continue/SKILL.md has scope: org-shared" "passed" "missing"
645
+ fi
646
+ if grep -q 'handoff\.md' "$CLEAR_CONTINUE_SKILL"; then
647
+ test_result "cbp-clear-continue/SKILL.md references handoff.md" "passed" "passed"
648
+ else
649
+ test_result "cbp-clear-continue/SKILL.md references handoff.md" "passed" "missing"
650
+ fi
651
+ if grep -Eq 'rm -f.*handoff' "$CLEAR_CONTINUE_SKILL"; then
652
+ test_result "cbp-clear-continue/SKILL.md has rm -f of handoff.md" "passed" "passed"
653
+ else
654
+ test_result "cbp-clear-continue/SKILL.md has rm -f of handoff.md" "passed" "missing"
655
+ fi
656
+ else
657
+ test_result "cbp-clear-continue/SKILL.md structural checks (file absent — skipped)" "passed" "passed"
658
+ fi
659
+
660
+ # .gitignore contains .codebyplan/clear/
661
+ REPO_GITIGNORE="${CLAUDE_PROJECT_DIR:-}/.gitignore"
662
+ if [ -n "${CLAUDE_PROJECT_DIR:-}" ] && [ -f "$REPO_GITIGNORE" ]; then
663
+ if grep -q '\.codebyplan/clear/' "$REPO_GITIGNORE"; then
664
+ test_result ".gitignore contains .codebyplan/clear/" "passed" "passed"
665
+ else
666
+ test_result ".gitignore contains .codebyplan/clear/" "passed" "missing"
667
+ fi
668
+ else
669
+ test_result ".gitignore check skipped (CLAUDE_PROJECT_DIR unset or no .gitignore)" "passed" "passed"
670
+ fi
671
+
672
+ echo ""
673
+
530
674
  # ===== SUMMARY =====
531
675
  echo "=== TEST SUMMARY ==="
532
676
  echo -e "Passed: ${GREEN}$PASSED${NC}"
@@ -52,6 +52,15 @@
52
52
  }
53
53
  ]
54
54
  },
55
+ {
56
+ "matcher": "Skill",
57
+ "hooks": [
58
+ {
59
+ "type": "command",
60
+ "command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/cbp-skill-context-guard.sh"
61
+ }
62
+ ]
63
+ },
55
64
  {
56
65
  "matcher": "mcp__codebyplan__(update_task|complete_task|update_checkpoint|create_checkpoint|create_task)",
57
66
  "hooks": [
@@ -0,0 +1,40 @@
1
+ # Model Invocation Convention
2
+
3
+ CBP skills are **model-invocable by default**. Authors must omit `disable-model-invocation` unless
4
+ a skill is strictly user-only (i.e. it must never auto-trigger from another skill).
5
+
6
+ ## Default: omit `disable-model-invocation`
7
+
8
+ The absence of `disable-model-invocation` (or `disable-model-invocation: false`) is the normal
9
+ state. It allows the skill to be auto-triggered via the Skill tool from within other skills —
10
+ which is how the auto-trigger close-out flow works (e.g. `cbp-task-check` → `cbp-task-testing`,
11
+ `cbp-task-testing` → `cbp-task-complete`).
12
+
13
+ ## The sole exception: `cbp-round-complete`
14
+
15
+ `cbp-round-complete` sets `disable-model-invocation: true`. It is the permission-gated round
16
+ finalizer: the user must explicitly run it after their own `git add` selections, so it must
17
+ never auto-fire from within another skill. The `ask`-tier permission prompt on
18
+ `Skill(cbp-round-complete)` is a secondary gate on top of this; the frontmatter flag is the
19
+ primary model-invocation block.
20
+
21
+ No other skill in the CBP framework sets this flag. Do NOT add it to new skills without a
22
+ clear "user-only" rationale.
23
+
24
+ ## Human gates for auto-triggering skills
25
+
26
+ For auto-trigger skills, the human checkpoint is expressed via two complementary mechanisms —
27
+ not via `disable-model-invocation`:
28
+
29
+ 1. **`ask`-tier permission entry** in `settings.json` — the harness permission prompt is the
30
+ lightweight confirm gate. Skills in `ask` auto-fire silently ONLY after the user confirms.
31
+ 2. **Routing prose** inside the triggering skill — states explicitly which skill fires next and
32
+ under what condition, so the intent is auditable and overridable.
33
+
34
+ See `.claude/skills/cbp-build-cc-settings/reference/cbp-permission-policy.md` for the full
35
+ `allow` vs `ask` split and the auto-trigger + 200K context-guard model.
36
+
37
+ ## Related
38
+
39
+ - `rules/scope-vocabulary.md` — scope marker conventions for managed vs user-created files
40
+ - `cbp-build-cc-settings/reference/cbp-permission-policy.md` — allow/ask tiers
@@ -33,7 +33,7 @@ Each entry in `plan.waves[]` carries these fields (source: `.claude/agents/cbp-t
33
33
  - Above 15: apply the proximity-split algorithm below.
34
34
  - Sole exception — trivially small plans are exempt from the lower bound: a plan with fewer than 3 total files uses one single wave, and a single-app plan with ≤5 total files MAY skip decomposition entirely (one wave, or `waves[]` omitted — see `cbp-task-planner` Phase 5.6). Zero waves (omitted `waves[]`) trivially satisfies this invariant.
35
35
 
36
- **(IV) UI skill preloads** — for each wave whose `files[]` contains UI-bearing paths (`*.tsx`, `*.jsx`, `*.scss`, etc.), add `"frontend-design"` and `"frontend-a11y"` to `skill_preloads[]` in that order (source: `.claude/agents/cbp-task-planner.md` Phase 5.6 step "Populate `skill_preloads[]`").
36
+ **(IV) UI skill preloads** — for each wave whose `files[]` contains UI-bearing paths (`*.tsx`, `*.jsx`, `*.scss`, etc.), add `"frontend-design"` to `skill_preloads[]` (source: `.claude/agents/cbp-task-planner.md` Phase 5.6 step "Populate `skill_preloads[]`").
37
37
 
38
38
  ## Proximity-Split Algorithm
39
39
 
@@ -45,7 +45,7 @@ After task completion, routes use single-directive form (never A/B/C menus):
45
45
 
46
46
  **Checkpoint-bound task complete:**
47
47
  - More tasks in checkpoint → auto-triggers next task (same context)
48
- - Last task in checkpoint → `Next: /clear, then /cbp-checkpoint-check`
48
+ - Last task in checkpoint → auto-triggers `cbp-checkpoint-check` (ask-tier permission prompt is the human gate; the 200K context guard handles oversized contexts)
49
49
 
50
50
  **Standalone task complete:**
51
51
  - Always → `Next: /cbp-session-end` (or `/cbp-standalone-task-create` for new work)
@@ -116,7 +116,8 @@
116
116
  "Skill(cbp-build-cc-skill)",
117
117
  "Skill(cbp-checkpoint-plan)",
118
118
  "Skill(cbp-checkpoint-update)",
119
- "Skill(cbp-frontend-a11y)",
119
+ "Skill(cbp-clear-continue)",
120
+ "Skill(cbp-clear-prep)",
120
121
  "Skill(cbp-frontend-design)",
121
122
  "Skill(cbp-frontend-ui)",
122
123
  "Skill(cbp-frontend-ux)",
@@ -45,6 +45,48 @@ The pre-existing dangerous-`rm -rf` blocks. This policy does not alter `deny` se
45
45
 
46
46
  When you add a skill / MCP tool / CLI subcommand, add its matching rule (`Skill(<name>)`, `mcp__codebyplan__<name>`, or `Bash(codebyplan <sub>:*)` + `Bash(npx codebyplan <sub>:*)`) to `allow` or `ask` in `templates/settings.project.base.json` — and mirror it into any dogfooding `.claude/settings.json`.
47
47
 
48
+ ## Auto-trigger + allow/ask gating model
49
+
50
+ The CBP close-out flow uses **auto-triggers** instead of manual "Next: /cbp-X" directives.
51
+ A skill invokes the next skill via the Skill tool at the appropriate routing branch.
52
+
53
+ ### How the human gate works
54
+
55
+ - **`allow`-tier** skill: the harness auto-fires it silently when the triggering skill invokes it.
56
+ No permission prompt. Use for safe, routine-flow skills (e.g. `cbp-task-testing`,
57
+ `cbp-round-input`) where the trigger condition already encodes the human intent.
58
+ - **`ask`-tier** skill: the harness pauses and shows a permission prompt before the skill runs.
59
+ **That prompt IS the human gate** — it replaces the old "Next: /cbp-X, run it yourself"
60
+ manual directive. Use for lifecycle/state-transition skills (e.g. `cbp-task-complete`,
61
+ `cbp-checkpoint-check`) where a deliberate confirmation is still desirable.
62
+
63
+ This means:
64
+ - A skill in `allow` that is auto-triggered fires silently — do NOT claim "the ask-tier prompt
65
+ is the gate" for it in routing prose.
66
+ - A skill in `ask` that is auto-triggered shows a permission prompt — that prompt is the gate;
67
+ say so in the routing prose.
68
+
69
+ ### The 200K context guard
70
+
71
+ The `cbp-skill-context-guard.sh` PreToolUse hook denies heavy close-out skills when the
72
+ context window exceeds `CBP_CONTEXT_WARN_TOKENS` (default 200 000 tokens). The heavy allowlist
73
+ is: `cbp-round-execute`, `cbp-task-testing`, `cbp-standalone-task-testing`,
74
+ `cbp-checkpoint-check`, `cbp-checkpoint-end`.
75
+
76
+ When the guard fires, it directs the model to run `/cbp-clear-prep` instead. The flow is:
77
+ `cbp-clear-prep` (captures a handoff) → `/clear` (user command) → `cbp-clear-continue`
78
+ (re-invokes the blocked skill in the fresh context).
79
+
80
+ `cbp-clear-prep` and `cbp-clear-continue` are **excluded** from the guard's allowlist so they
81
+ always run regardless of context size.
82
+
83
+ Routing prose in triggering skills should NOT mandate an unconditional `/clear` before a heavy
84
+ skill — the guard handles oversized contexts automatically. Drop "Run /clear first" directives
85
+ from auto-trigger paths; only note the guard mechanism so the author understands when it fires.
86
+
87
+ See `rules/model-invocation-convention.md` for the `disable-model-invocation` convention —
88
+ authors must omit it on all skills except `cbp-round-complete`.
89
+
48
90
  ## Scope
49
91
 
50
92
  `scope: org-shared` — CBP-framework infrastructure that lands identically in every consuming repo via the `codebyplan` package.
@@ -0,0 +1,86 @@
1
+ ---
2
+ scope: org-shared
3
+ name: cbp-clear-continue
4
+ description: Resume work after /clear by reading .codebyplan/clear/handoff.md and re-invoking the previously-blocked heavy skill. Reports a friendly error if no handoff file exists.
5
+ effort: xhigh
6
+ ---
7
+
8
+ # cbp-clear-continue
9
+
10
+ Resume a blocked heavy skill after a `/clear`. Reads `.codebyplan/clear/handoff.md`, restores
11
+ task/round context into this fresh session, re-invokes the blocked skill, then deletes the
12
+ handoff file so a stale snapshot never misleads a future session.
13
+
14
+ ## When Used
15
+
16
+ - After running `/clear` following a `/cbp-clear-prep` capture
17
+ - The user is ready to re-run the heavy skill (cbp-round-execute, cbp-task-testing,
18
+ cbp-standalone-task-testing, cbp-checkpoint-check, cbp-checkpoint-end) that was denied
19
+
20
+ ## Instructions
21
+
22
+ ### Step 1 — Read the handoff
23
+
24
+ Read `.codebyplan/clear/handoff.md`.
25
+
26
+ If the file is absent: output the following and STOP — do not attempt to infer state.
27
+
28
+ ```
29
+ No handoff found at .codebyplan/clear/handoff.md — nothing to continue.
30
+ Use /cbp-todo to find the next action.
31
+ ```
32
+
33
+ ### Step 2 — Restore context
34
+
35
+ Parse the handoff fields:
36
+ - `checkpoint_number`, `task_number`, `round_number`
37
+ - `blocked_skill` — the skill that was denied
38
+ - `next_action` — the exact skill invocation to re-run (with args)
39
+ - `in_flight_notes` — any in-progress state worth restoring
40
+
41
+ Output a brief context summary to orient the fresh session:
42
+
43
+ ```
44
+ Resuming from handoff:
45
+ CHK-<N> TASK-<N> R<N>
46
+ Blocked skill: /<blocked-skill>
47
+ Next action: /<next-action>
48
+ ```
49
+
50
+ ### Step 3 — Delete the handoff BEFORE re-invoking
51
+
52
+ Delete `.codebyplan/clear/handoff.md` once its contents have been read and displayed:
53
+
54
+ ```bash
55
+ rm -f .codebyplan/clear/handoff.md
56
+ ```
57
+
58
+ A stale handoff must not mislead a later session. Delete it here, before the skill runs,
59
+ so even if the skill fails the handoff is gone and the user starts fresh next time.
60
+
61
+ ### Step 4 — Re-invoke the blocked skill
62
+
63
+ Invoke the skill from `next_action` via the Skill tool, passing any recorded arguments.
64
+
65
+ Example: if `next_action` is `/cbp-round-execute 217-2-1`, invoke `Skill(cbp-round-execute)`
66
+ with args `217-2-1`.
67
+
68
+ If the context window is STILL above threshold after `/clear` (unusual — compact may help),
69
+ the guard will deny again. Follow the same cycle: `/cbp-clear-prep` → `/clear` →
70
+ `/cbp-clear-continue`.
71
+
72
+ ## Key Rules
73
+
74
+ - Delete `.codebyplan/clear/handoff.md` in Step 3 BEFORE invoking the next skill
75
+ - If the handoff is absent, surface the friendly error and stop — never infer state from scratch
76
+ - Re-invoke the EXACT skill and arguments from `next_action` — do not substitute or guess
77
+ - `.codebyplan/clear/` is gitignored — never commit handoff.md
78
+
79
+ ## Integration
80
+
81
+ - **Invoked by**: user after `/clear` following `/cbp-clear-prep`
82
+ - **Reads**: `.codebyplan/clear/handoff.md`
83
+ - **Deletes**: `.codebyplan/clear/handoff.md` (Step 3, before resuming)
84
+ - **Then invokes**: the skill from `next_action` via Skill tool
85
+ - **Companion**: `.claude/skills/cbp-clear-prep/SKILL.md` writes the handoff
86
+ - **Guard hook**: `.claude/hooks/cbp-skill-context-guard.sh`
@@ -0,0 +1,121 @@
1
+ ---
2
+ scope: org-shared
3
+ name: cbp-clear-prep
4
+ description: Capture a clear-context handoff when the context window is too large to run a heavy skill. Reads active task/round state, writes .codebyplan/clear/handoff.md, then instructs the user to run /clear and /cbp-clear-continue to resume.
5
+ argument-hint: "[blocked-skill]"
6
+ effort: xhigh
7
+ ---
8
+
9
+ # cbp-clear-prep
10
+
11
+ Capture a handoff snapshot before clearing context. Invoked when the `cbp-skill-context-guard`
12
+ PreToolUse hook denies a heavy skill (cbp-round-execute, cbp-task-testing,
13
+ cbp-standalone-task-testing, cbp-checkpoint-check, cbp-checkpoint-end) because the context
14
+ window exceeds the configured threshold.
15
+
16
+ ## When Used
17
+
18
+ - The hook deny message says "Run /cbp-clear-prep now to capture a handoff"
19
+ - A heavy skill was just blocked by the context guard
20
+ - The user wants to preserve current task/round state before running `/clear`
21
+
22
+ ## Instructions
23
+
24
+ ### Step 1 — Identify the blocked skill
25
+
26
+ Check `$ARGUMENTS` first. If empty, identify the blocked skill from the recent guard deny message
27
+ in context — it will be one of: `cbp-round-execute`, `cbp-task-testing`,
28
+ `cbp-standalone-task-testing`, `cbp-checkpoint-check`, `cbp-checkpoint-end`.
29
+
30
+ ### Step 2 — Resolve active task and round (local-first)
31
+
32
+ 1. Read `.codebyplan/state/session/current.json` to find the active task_id and checkpoint_id.
33
+ 2. Read `.codebyplan/state/checkpoints/<checkpoint_id>/tasks/<task_id>.json` for task details.
34
+ 3. Read the latest round file in `.codebyplan/state/checkpoints/<checkpoint_id>/tasks/<task_id>/rounds/`.
35
+ 4. On miss: run `npx codebyplan sync` once and re-read.
36
+ 5. Break-glass if state dir is absent: call `mcp__codebyplan__get_current_task` and
37
+ `mcp__codebyplan__get_rounds`.
38
+
39
+ Capture: `checkpoint_id`, `checkpoint_number`, `task_id`, `task_number`, `round_id`,
40
+ `round_number`. If no active task is found, set all to `unknown` and note the gap.
41
+
42
+ ### Step 3 — Identify the next action to resume
43
+
44
+ From context, determine:
45
+ - The exact skill the user was trying to invoke (blocked skill from Step 1)
46
+ - Any arguments it was called with (e.g. `cbp-round-execute` args: `217-2-1`)
47
+ - Any relevant in-flight state (round goal, step in progress, pending decisions)
48
+
49
+ ### Step 4 — Write the handoff file
50
+
51
+ Create the directory and write `.codebyplan/clear/handoff.md`:
52
+
53
+ ```bash
54
+ mkdir -p .codebyplan/clear
55
+ ```
56
+
57
+ File content format:
58
+
59
+ ```
60
+ # CBP Clear Handoff
61
+
62
+ ## Active Context
63
+
64
+ checkpoint_id: <id or unknown>
65
+ checkpoint_number: CHK-<N or unknown>
66
+ task_id: <id or unknown>
67
+ task_number: TASK-<N or unknown>
68
+ round_id: <id or unknown>
69
+ round_number: R<N or unknown>
70
+
71
+ ## Blocked Skill
72
+
73
+ blocked_skill: <skill-name>
74
+
75
+ ## Next Action
76
+
77
+ next_action: /<skill-name> <args if any>
78
+
79
+ ## In-Flight Notes
80
+
81
+ <any relevant state — round goal, current step, pending decisions, uncommitted work>
82
+
83
+ ## Resume Instructions
84
+
85
+ After /clear, run: /cbp-clear-continue
86
+ ```
87
+
88
+ ### Step 5 — Instruct the user
89
+
90
+ Output exactly this summary (fill in the real values):
91
+
92
+ ```
93
+ Handoff captured at .codebyplan/clear/handoff.md
94
+
95
+ Active context: CHK-<N> TASK-<N> R<N>
96
+ Blocked skill: /<blocked-skill>
97
+ Resumes with: /<next-action>
98
+
99
+ Next steps:
100
+ 1. Run /clear to free context
101
+ 2. Run /cbp-clear-continue to resume
102
+ ```
103
+
104
+ Do NOT auto-invoke `/clear` or `/cbp-clear-continue`. This is a directive-only stop.
105
+ The user must run both commands manually.
106
+
107
+ ## Key Rules
108
+
109
+ - Always write `.codebyplan/clear/handoff.md` BEFORE instructing `/clear`
110
+ - Never auto-invoke the blocked skill — the guard denied it to protect context quality
111
+ - If no active task resolves, still write the handoff with available context and note the gap
112
+ - `.codebyplan/clear/` is gitignored — never commit handoff.md
113
+ - Overwrite any existing handoff.md (each prep captures the freshest context)
114
+
115
+ ## Integration
116
+
117
+ - **Invoked when**: `cbp-skill-context-guard` PreToolUse hook emits `permissionDecision: deny`
118
+ - **Writes**: `.codebyplan/clear/handoff.md`
119
+ - **Next**: user runs `/clear`, then `/cbp-clear-continue`
120
+ - **Companion**: `.claude/skills/cbp-clear-continue/SKILL.md` reads `.codebyplan/clear/handoff.md`
121
+ - **Guard hook**: `.claude/hooks/cbp-skill-context-guard.sh` — fires when context > CBP_CONTEXT_WARN_TOKENS (default 200000)
@@ -216,7 +216,7 @@ Present the plan to user:
216
216
  ### Execution Waves
217
217
  | Wave | Agent type | Files | Depends on | Skill preloads |
218
218
  |------|-----------|-------|-----------|----------------|
219
- | web-ui | cbp-round-executor | 7 | — | cbp-frontend-design, cbp-frontend-a11y |
219
+ | web-ui | cbp-round-executor | 7 | — | cbp-frontend-design |
220
220
  | backend-api | cbp-round-executor | 4 | — | — |
221
221
  ```
222
222