codebyplan 1.13.63 → 1.13.64

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.
package/dist/cli.js CHANGED
@@ -48,7 +48,7 @@ var VERSION, PACKAGE_NAME;
48
48
  var init_version = __esm({
49
49
  "src/lib/version.ts"() {
50
50
  "use strict";
51
- VERSION = "1.13.63";
51
+ VERSION = "1.13.64";
52
52
  PACKAGE_NAME = "codebyplan";
53
53
  }
54
54
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codebyplan",
3
- "version": "1.13.63",
3
+ "version": "1.13.64",
4
4
  "description": "CLI for CodeByPlan — AI-powered development planning and tracking",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,11 +1,16 @@
1
1
  #!/bin/bash
2
2
  # @scope: org-shared
3
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.
4
+ # Purpose: Deny heavy close-out skills when context window exceeds the model-aware threshold:
5
+ # 200K tokens for standard models (CBP_CONTEXT_WARN_TOKENS, default 200000);
6
+ # 800K tokens for 1M-context models whose id contains "[1m]"
7
+ # (CBP_CONTEXT_WARN_TOKENS_1M, default 800000).
8
+ # Reads transcript_path from stdin, extracts the latest assistant message.usage
9
+ # AND model id in one pass — same logic as cbp-context-window-notify.sh.
10
+ # If total exceeds the tier threshold AND the skill is in the heavy close-out
11
+ # allowlist, emits hookSpecificOutput.permissionDecision=deny directing Claude
12
+ # to run /cbp-clear-prep. Always exits 0 — fail-open.
13
+ # No model id found → standard tier (fail-conservative).
9
14
 
10
15
  set -euo pipefail
11
16
 
@@ -17,8 +22,6 @@ TRANSCRIPT=$(echo "$INPUT" | jq -r '.transcript_path // ""' 2>/dev/null) || TRAN
17
22
  [ -z "$TRANSCRIPT" ] && exit 0
18
23
  [ ! -f "$TRANSCRIPT" ] && exit 0
19
24
 
20
- THRESHOLD="${CBP_CONTEXT_WARN_TOKENS:-200000}"
21
-
22
25
  # Heavy close-out allowlist (cbp-clear-prep + cbp-clear-continue deliberately excluded so
23
26
  # they always run even when context > threshold).
24
27
  HEAVY_SKILLS="cbp-round-build cbp-verify cbp-standalone-task-testing cbp-checkpoint-check cbp-checkpoint-end"
@@ -33,20 +36,37 @@ for heavy in $HEAVY_SKILLS; do
33
36
  done
34
37
  [ "$IS_HEAVY" = "false" ] && exit 0
35
38
 
36
- # Token sum same logic as cbp-context-window-notify.sh
37
- TOTAL=$(tail -n 400 "$TRANSCRIPT" \
39
+ # Extract model id AND token sum from the latest assistant message with usage, in one pass.
40
+ # Outputs two tab-separated fields: MODEL_ID <tab> TOTAL.
41
+ # Use cut -f1/f2 (not read -r A B) to correctly handle an empty first field (no .message.model).
42
+ _TSV=$(tail -n 400 "$TRANSCRIPT" \
38
43
  | 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
44
+ | [ (.message.model // ""),
45
+ ((.message.usage.input_tokens // 0)
46
+ + (.message.usage.cache_creation_input_tokens // 0)
47
+ + (.message.usage.cache_read_input_tokens // 0)) ]
48
+ | @tsv' 2>/dev/null | tail -1) || _TSV=""
49
+ MODEL_ID=$(printf '%s' "${_TSV:-}" | cut -f1)
50
+ TOTAL=$(printf '%s' "${_TSV:-}" | cut -f2)
51
+ MODEL_ID="${MODEL_ID:-}"
42
52
  TOTAL="${TOTAL:-0}"
43
53
 
54
+ # Tier selection: [1m] in model id → 1M tier; otherwise standard (fail-conservative)
55
+ if printf '%s' "$MODEL_ID" | grep -qF '[1m]'; then
56
+ THRESHOLD="${CBP_CONTEXT_WARN_TOKENS_1M:-800000}"
57
+ TIER="1M"
58
+ else
59
+ THRESHOLD="${CBP_CONTEXT_WARN_TOKENS:-200000}"
60
+ TIER="standard"
61
+ fi
62
+
44
63
  if [ "$TOTAL" -ge "$THRESHOLD" ] 2>/dev/null; then
45
64
  jq -n \
46
65
  --argjson tokens "$TOTAL" \
47
66
  --argjson threshold "$THRESHOLD" \
48
67
  --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.")}}'
68
+ --arg tier "$TIER" \
69
+ '{hookSpecificOutput:{permissionDecision:"deny",permissionDecisionReason:("Context window at \($tokens) tokens (\($tier) tier, 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
70
  fi
51
71
 
52
72
  exit 0
@@ -374,6 +374,87 @@ fi
374
374
 
375
375
  echo ""
376
376
 
377
+ # ===== HOOK SMOKE TESTS — cbp-mcp-caller-worktree-inject =====
378
+ echo "## Hook Smoke Tests — cbp-mcp-caller-worktree-inject (CHK-198)"
379
+
380
+ INJECT_HOOK="$HOOKS_DIR/cbp-mcp-caller-worktree-inject.sh"
381
+ # Absolute path — the fail-open test runs the hook from a temp cwd (to isolate it
382
+ # from this repo's git context), where the relative "$HOOKS_DIR" no longer resolves.
383
+ INJECT_HOOK_ABS="$(cd "$HOOKS_DIR" 2>/dev/null && pwd)/cbp-mcp-caller-worktree-inject.sh"
384
+
385
+ if [ ! -f "$INJECT_HOOK" ]; then
386
+ test_result "cbp-mcp-caller-worktree-inject.sh present" "passed" "missing"
387
+ else
388
+ test_result "cbp-mcp-caller-worktree-inject.sh present" "passed" "passed"
389
+
390
+ FIRST_LINE=$(head -1 "$INJECT_HOOK")
391
+ if echo "$FIRST_LINE" | grep -q '^#!/'; then
392
+ test_result "cbp-mcp-caller-worktree-inject.sh has shebang" "passed" "passed"
393
+ else
394
+ test_result "cbp-mcp-caller-worktree-inject.sh has shebang" "passed" "missing"
395
+ fi
396
+
397
+ if grep -q '@scope: org-shared' "$INJECT_HOOK"; then
398
+ test_result "cbp-mcp-caller-worktree-inject.sh has @scope: org-shared" "passed" "passed"
399
+ else
400
+ test_result "cbp-mcp-caller-worktree-inject.sh has @scope: org-shared" "passed" "missing"
401
+ fi
402
+
403
+ # Fail-open: run from a non-repo temp dir with no worktree cache and no
404
+ # CLAUDE_PROJECT_DIR — neither the cache nor the CLI fallback can resolve a
405
+ # worktree, so the hook must exit 0 with empty stdout (no updatedInput).
406
+ ISO=$(mktemp -d)
407
+ OUTPUT=$( (cd "$ISO" && env -u CLAUDE_PROJECT_DIR bash "$INJECT_HOOK_ABS" <<< '{"tool_input":{"task_id":"x"}}') 2>/dev/null )
408
+ EXIT_CODE=$?
409
+ if [ "$EXIT_CODE" = "0" ] && [ -z "$OUTPUT" ]; then
410
+ test_result "cbp-mcp-caller-worktree-inject.sh fail-open (unresolvable) exits 0 + empty stdout" "passed" "passed"
411
+ else
412
+ test_result "cbp-mcp-caller-worktree-inject.sh fail-open (unresolvable) exits 0 + empty stdout" "passed" "failed (exit=$EXIT_CODE)"
413
+ fi
414
+ rm -rf "$ISO"
415
+
416
+ # C6 — input already carries a non-empty caller_worktree_id → never overwrite;
417
+ # early-return with exit 0 and empty stdout (no resolution attempted).
418
+ OUTPUT=$(echo '{"tool_input":{"caller_worktree_id":"11111111-1111-1111-1111-111111111111"}}' | bash "$INJECT_HOOK" 2>/dev/null)
419
+ EXIT_CODE=$?
420
+ if [ "$EXIT_CODE" = "0" ] && [ -z "$OUTPUT" ]; then
421
+ test_result "cbp-mcp-caller-worktree-inject.sh C6 keeps existing caller_worktree_id (exit 0 + empty stdout)" "passed" "passed"
422
+ else
423
+ test_result "cbp-mcp-caller-worktree-inject.sh C6 keeps existing caller_worktree_id (exit 0 + empty stdout)" "passed" "failed (exit=$EXIT_CODE)"
424
+ fi
425
+
426
+ # Injection — a worktree.local.json whose .branch matches the current git branch
427
+ # makes the cache fast-path resolve. Use a synthetic UUID so the assertion proves
428
+ # the cache value (not the live CLI) was injected. Skipped when no concrete git
429
+ # branch resolves (detached HEAD / non-git checkout) or jq is unavailable.
430
+ CUR_BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
431
+ if [ -n "$CUR_BRANCH" ] && [ "$CUR_BRANCH" != "HEAD" ] && command -v jq >/dev/null 2>&1; then
432
+ ISO=$(mktemp -d)
433
+ mkdir -p "$ISO/.codebyplan"
434
+ FAKE_WT="abcdef01-2345-6789-abcd-ef0123456789"
435
+ jq -n --arg b "$CUR_BRANCH" --arg w "$FAKE_WT" \
436
+ '{worktree_id:$w, branch:$b}' > "$ISO/.codebyplan/worktree.local.json"
437
+ OUTPUT=$(CLAUDE_PROJECT_DIR="$ISO" bash "$INJECT_HOOK" <<< '{"tool_input":{"task_id":"x"}}' 2>/dev/null)
438
+ EXIT_CODE=$?
439
+ INJECTED=$(echo "$OUTPUT" | jq -r '.hookSpecificOutput.updatedInput.caller_worktree_id // empty' 2>/dev/null)
440
+ # Sibling-key survival — CC's updatedInput REPLACES tool_input wholesale (it is
441
+ # not a partial merge), so the hook must echo back every original field merged
442
+ # with caller_worktree_id. Assert the non-target sibling key (task_id) survives;
443
+ # this is the assertion gap that let the replace-vs-merge bug ship in round 2.
444
+ PRESERVED=$(echo "$OUTPUT" | jq -r '.hookSpecificOutput.updatedInput.task_id // empty' 2>/dev/null)
445
+ if [ "$EXIT_CODE" = "0" ] && [ "$INJECTED" = "$FAKE_WT" ] && [ "$PRESERVED" = "x" ]; then
446
+ test_result "cbp-mcp-caller-worktree-inject.sh injects caller_worktree_id AND preserves sibling keys" "passed" "passed"
447
+ else
448
+ test_result "cbp-mcp-caller-worktree-inject.sh injects caller_worktree_id AND preserves sibling keys" "passed" "failed (exit=$EXIT_CODE injected=$INJECTED preserved=$PRESERVED)"
449
+ fi
450
+ rm -rf "$ISO"
451
+ else
452
+ test_result "cbp-mcp-caller-worktree-inject.sh injection test (no branch resolvable — skipped)" "passed" "passed"
453
+ fi
454
+ fi
455
+
456
+ echo ""
457
+
377
458
  # ===== HOOK SMOKE TESTS — cbp-session-start-hook =====
378
459
  echo "## Hook Smoke Tests — cbp-session-start-hook (CHK-178)"
379
460
 
@@ -533,6 +614,91 @@ else
533
614
 
534
615
  fi
535
616
 
617
+ echo ""
618
+
619
+ # ===== HOOK SMOKE TESTS — cbp-skill-context-guard model-aware tier (CHK-224) =====
620
+ echo "## Hook Smoke Tests — cbp-skill-context-guard model-aware tier (CHK-224)"
621
+
622
+ FIXTURES_GUARD_MODEL="$HOOKS_DIR/__test-fixtures__/cbp-skill-context-guard"
623
+
624
+ # Case M1: standard model @201K → deny (standard tier, 200K threshold)
625
+ if [ -f "$FIXTURES_GUARD_MODEL/over-threshold-standard.jsonl" ]; then
626
+ STDIN=$(jq -n \
627
+ --arg t "$FIXTURES_GUARD_MODEL/over-threshold-standard.jsonl" \
628
+ --arg s "cbp-round-build" \
629
+ '{transcript_path:$t,tool_input:{skill:$s}}')
630
+ OUTPUT=$(echo "$STDIN" | CBP_CONTEXT_WARN_TOKENS=200000 bash "$GUARD_HOOK" 2>/dev/null)
631
+ EXIT_CODE=$?
632
+ if [ "$EXIT_CODE" = "0" ] \
633
+ && echo "$OUTPUT" | jq -e '.hookSpecificOutput.permissionDecision == "deny"' >/dev/null 2>&1; then
634
+ test_result "cbp-skill-context-guard.sh standard model @201K → deny (standard tier)" "passed" "passed"
635
+ else
636
+ test_result "cbp-skill-context-guard.sh standard model @201K → deny (standard tier)" "passed" "failed (exit=$EXIT_CODE output=$(echo "$OUTPUT" | head -c 80))"
637
+ fi
638
+ fi
639
+
640
+ # Case M2: [1m] model @201K → empty stdout (allowed; 201K is below 800K 1M-tier threshold)
641
+ if [ -f "$FIXTURES_GUARD_MODEL/over-threshold-1m.jsonl" ]; then
642
+ STDIN=$(jq -n \
643
+ --arg t "$FIXTURES_GUARD_MODEL/over-threshold-1m.jsonl" \
644
+ --arg s "cbp-round-build" \
645
+ '{transcript_path:$t,tool_input:{skill:$s}}')
646
+ OUTPUT=$(echo "$STDIN" | CBP_CONTEXT_WARN_TOKENS_1M=800000 bash "$GUARD_HOOK" 2>/dev/null)
647
+ EXIT_CODE=$?
648
+ if [ "$EXIT_CODE" = "0" ] && [ -z "$OUTPUT" ]; then
649
+ test_result "cbp-skill-context-guard.sh [1m] model @201K → empty stdout (under 800K 1M tier)" "passed" "passed"
650
+ else
651
+ test_result "cbp-skill-context-guard.sh [1m] model @201K → empty stdout (under 800K 1M tier)" "passed" "failed (exit=$EXIT_CODE output=$(echo "$OUTPUT" | head -c 80))"
652
+ fi
653
+ fi
654
+
655
+ # Case M3: [1m] model @850K → deny (1M tier, 800K threshold)
656
+ if [ -f "$FIXTURES_GUARD_MODEL/over-threshold-1m-denied.jsonl" ]; then
657
+ STDIN=$(jq -n \
658
+ --arg t "$FIXTURES_GUARD_MODEL/over-threshold-1m-denied.jsonl" \
659
+ --arg s "cbp-round-build" \
660
+ '{transcript_path:$t,tool_input:{skill:$s}}')
661
+ OUTPUT=$(echo "$STDIN" | CBP_CONTEXT_WARN_TOKENS_1M=800000 bash "$GUARD_HOOK" 2>/dev/null)
662
+ EXIT_CODE=$?
663
+ if [ "$EXIT_CODE" = "0" ] \
664
+ && echo "$OUTPUT" | jq -e '.hookSpecificOutput.permissionDecision == "deny"' >/dev/null 2>&1; then
665
+ test_result "cbp-skill-context-guard.sh [1m] model @850K → deny (1M tier)" "passed" "passed"
666
+ else
667
+ test_result "cbp-skill-context-guard.sh [1m] model @850K → deny (1M tier)" "passed" "failed (exit=$EXIT_CODE output=$(echo "$OUTPUT" | head -c 80))"
668
+ fi
669
+ fi
670
+
671
+ # Case M4: env override CBP_CONTEXT_WARN_TOKENS=150000 + standard model @201K → deny
672
+ if [ -f "$FIXTURES_GUARD_MODEL/over-threshold-standard.jsonl" ]; then
673
+ STDIN=$(jq -n \
674
+ --arg t "$FIXTURES_GUARD_MODEL/over-threshold-standard.jsonl" \
675
+ --arg s "cbp-round-build" \
676
+ '{transcript_path:$t,tool_input:{skill:$s}}')
677
+ OUTPUT=$(echo "$STDIN" | CBP_CONTEXT_WARN_TOKENS=150000 bash "$GUARD_HOOK" 2>/dev/null)
678
+ EXIT_CODE=$?
679
+ if [ "$EXIT_CODE" = "0" ] \
680
+ && echo "$OUTPUT" | jq -e '.hookSpecificOutput.permissionDecision == "deny"' >/dev/null 2>&1; then
681
+ test_result "cbp-skill-context-guard.sh env CBP_CONTEXT_WARN_TOKENS=150000 + standard @201K → deny" "passed" "passed"
682
+ else
683
+ test_result "cbp-skill-context-guard.sh env CBP_CONTEXT_WARN_TOKENS=150000 + standard @201K → deny" "passed" "failed (exit=$EXIT_CODE output=$(echo "$OUTPUT" | head -c 80))"
684
+ fi
685
+ fi
686
+
687
+ # Case M5: env override CBP_CONTEXT_WARN_TOKENS_1M=900000 + [1m] model @850K → empty stdout (allowed)
688
+ if [ -f "$FIXTURES_GUARD_MODEL/over-threshold-1m-denied.jsonl" ]; then
689
+ STDIN=$(jq -n \
690
+ --arg t "$FIXTURES_GUARD_MODEL/over-threshold-1m-denied.jsonl" \
691
+ --arg s "cbp-round-build" \
692
+ '{transcript_path:$t,tool_input:{skill:$s}}')
693
+ OUTPUT=$(echo "$STDIN" | CBP_CONTEXT_WARN_TOKENS_1M=900000 bash "$GUARD_HOOK" 2>/dev/null)
694
+ EXIT_CODE=$?
695
+ if [ "$EXIT_CODE" = "0" ] && [ -z "$OUTPUT" ]; then
696
+ test_result "cbp-skill-context-guard.sh env CBP_CONTEXT_WARN_TOKENS_1M=900000 + [1m] @850K → empty stdout (override keeps allowed)" "passed" "passed"
697
+ else
698
+ test_result "cbp-skill-context-guard.sh env CBP_CONTEXT_WARN_TOKENS_1M=900000 + [1m] @850K → empty stdout (override keeps allowed)" "passed" "failed (exit=$EXIT_CODE output=$(echo "$OUTPUT" | head -c 80))"
699
+ fi
700
+ fi
701
+
536
702
  # ===== STRUCTURAL ASSERTIONS — cbp-clear-* skills (CHK-217) =====
537
703
  echo ""
538
704
  echo "## Structural Assertions — cbp-clear-* skills (CHK-217)"
@@ -1,3 +1,9 @@
1
+ ---
2
+ paths:
3
+ - "apps/**"
4
+ - "packages/**"
5
+ ---
6
+
1
7
  # Architecture Map
2
8
 
3
9
  When `.claude/architecture/` exists in this repo, per-module map files may be present.
@@ -25,13 +25,11 @@ SHARED tooling behavior only — repo-specific gotchas belong in that repo's own
25
25
  clobbers existing `decisions` / `discoveries` / `check_results`. Always read the current row,
26
26
  merge your change into the full object/array, then write the whole thing back.
27
27
 
28
- - **User-level locks are invisible until a mutation they block.** `get_checkpoints` /
29
- `get_tasks` succeed even when another user holds the assignment; the 403 fires only on
30
- `update_*` / `complete_*`. The lock keys on the JWT user (`ctx.userId`) vs the row's
31
- `assigned_user_id` (null = open). `caller_worktree_id` / `worktree_id` params are
32
- accepted-and-ignored — do not thread them. Verify `assigned_user_id` matches
33
- `npx codebyplan whoami` before mutating; recover a stale assignment with
34
- `release_assignment` (maintainer).
28
+ - **`resolve-worktree` empty output = a NULL `(device, path, branch)` tuple, not a broken
29
+ resolver.** When identity is unresolved the server can collapse the caller to the repo's main
30
+ worktree, so feat-locked writes get rejected. Pass `caller_worktree_id` on every MCP mutation,
31
+ and confirm ownership by matching the row's repo path + branch to the current directory before
32
+ mutating.
35
33
 
36
34
  - **Full-repo lint/type baselines are often pre-existing red.** A round must gate on the files
37
35
  it changed, not the whole-repo baseline — scope lint/tsc checks to the round's changed set so a
@@ -40,14 +38,30 @@ SHARED tooling behavior only — repo-specific gotchas belong in that repo's own
40
38
  - **`complete_task` checks file approval on the round's `files_changed`, not the task's.**
41
39
  Reconcile approvals via `update_round` (set each entry `user_approved: true`), not
42
40
  `update_task` alone — updating only the task leaves the round entries unapproved and
43
- `complete_task` rejects with "files are not approved".
41
+ `complete_task` rejects with "files are not approved". After a merge-main pulls in foreign
42
+ files or carried directory-slash round artifacts, `complete_task` can hard-fail "N files not
43
+ approved"; fix by re-writing each affected round's `files_changed` via `update_round`.
44
44
 
45
- - **CLI transport uses REST (reads) and OAuth+MCP (writes) — a 502 from `codebyplan round sync-approvals` is transient MCP churn, not an outage.** The CLI exits 0 with a warning and MCP tools still work. A missing `CODEBYPLAN_API_KEY` surfaces as an `ApiError`, not a 502. `sync-approvals` can also drag untracked per-device dirs into `files_changed` — run it from the repo root.
45
+ - **CLI transport uses REST (reads) and OAuth+MCP (writes) — a 502 from `codebyplan round sync-approvals` is transient MCP churn, not an outage.** The CLI exits 0 with a warning and MCP tools still work. A missing `CODEBYPLAN_API_KEY` surfaces as an `ApiError`, not a 502. `sync-approvals` can also drag untracked per-device dirs into `files_changed` — run it from the repo root or pass `--caller-worktree-id`.
46
46
 
47
47
  - **`codebyplan claude update` requires a TTY.** On non-TTY stdin (CI, piped) it half-applies then errors. Re-run with `--yes` to accept defaults non-interactively.
48
48
 
49
+ - **Checkpoint locks are invisible until a mutation they block.** `get_checkpoints` / `get_tasks` succeed even when another worktree holds the lock; the 403 fires only on `update_*` / `complete_*`. Verify the row's `worktree_id` matches the caller before mutating. A null-`worktree_id` checkpoint can still be actively shipped by whichever worktree physically holds its feat branch — check `git worktree list` first.
50
+
51
+ - **`update_task` accepts `caller_worktree_id` for lock-verify only — it does NOT assign ownership.** Ownership assignment goes through the web UI or the dedicated assignment path. Don't conflate `caller_worktree_id` with `assigned_worktree_id`.
52
+
49
53
  - **Re-run config-driven gates after merging main into a feat branch.** A merge can add or change `.codebyplan/shipment.json`, ports, branch config, `e2e.json`, and `eslint.json` — treat the post-merge state as a fresh baseline before continuing.
50
54
 
55
+ - **MCP write calls can return 403 via Cloudflare WAF when the JSONB payload contains DDL
56
+ keywords (table-drop statements, function-drop statements, or raw query clauses).** Paraphrase
57
+ or base64-encode any user-provided SQL content before embedding it in a JSONB field — never
58
+ pass raw DDL verbatim in MCP context payloads.
59
+
60
+ - **A "Merge origin/main" commit can integrate ZERO commits if it merged a stale local ref.**
61
+ Always `git fetch` and re-check the behind-count before treating a merge as complete — a
62
+ clean merge with no new commits is a sign the local ref was stale, not that the branch was
63
+ already up to date.
64
+
51
65
  ## Behavioral Preferences
52
66
 
53
67
  - **Never `git stash`** — for any reason. To inspect or compare other state use
@@ -1,3 +1,8 @@
1
+ ---
2
+ paths:
3
+ - "apps/**"
4
+ ---
5
+
1
6
  # E2E Mandatory Run Contract
2
7
 
3
8
  E2E is **opt-out, not opt-in**. Whenever a framework configured in `.codebyplan/e2e.json`
@@ -32,7 +32,7 @@ not via `disable-model-invocation`:
32
32
  under what condition, so the intent is auditable and overridable.
33
33
 
34
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.
35
+ `allow` vs `ask` split and the auto-trigger + model-aware context-guard (200K standard / 800K on `[1m]` sessions).
36
36
 
37
37
  ## Related
38
38
 
@@ -1,3 +1,8 @@
1
+ ---
2
+ paths:
3
+ - ".claude/**"
4
+ ---
5
+
1
6
  # Scope Vocabulary
2
7
 
3
8
  Canonical scope-marker enum for `.claude/` files. The marker classifies a structural file's distribution scope — but it is **required only on user-created files**, not on the assets the `codebyplan` package distributes.
@@ -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 → auto-triggers `cbp-checkpoint-check` (ask-tier permission prompt is the human gate; the 200K context guard handles oversized contexts)
48
+ - Last task in checkpoint → auto-triggers `cbp-checkpoint-check` (ask-tier permission prompt is the human gate; the model-aware context guard handles oversized contexts — 200K standard, 800K on `[1m]` sessions)
49
49
 
50
50
  **Standalone task complete:**
51
51
  - Always → `Next: /cbp-session-end` (or `/cbp-standalone-task-create` for new work)
@@ -147,22 +147,16 @@
147
147
  "mcp__codebyplan__get_checkpoints",
148
148
  "mcp__codebyplan__get_current_task",
149
149
  "mcp__codebyplan__get_eslint_presets",
150
- "mcp__codebyplan__get_eslint_repo_config",
151
150
  "mcp__codebyplan__get_file_changes",
152
- "mcp__codebyplan__get_library_doc_job",
153
151
  "mcp__codebyplan__get_repos",
154
152
  "mcp__codebyplan__get_rounds",
155
153
  "mcp__codebyplan__get_server_config",
156
154
  "mcp__codebyplan__get_session_log",
157
155
  "mcp__codebyplan__get_session_logs",
158
156
  "mcp__codebyplan__get_session_state",
159
- "mcp__codebyplan__get_task_template",
160
- "mcp__codebyplan__get_task_templates",
161
157
  "mcp__codebyplan__get_tasks",
162
158
  "mcp__codebyplan__get_todos",
163
- "mcp__codebyplan__list_tech_stack_sync_sessions",
164
159
  "mcp__codebyplan__get_chunk",
165
- "mcp__codebyplan__get_library_toc",
166
160
  "mcp__codebyplan__list_migrations",
167
161
  "mcp__codebyplan__lookup_symbol",
168
162
  "mcp__codebyplan__resolve_library_id",
@@ -184,7 +178,15 @@
184
178
  "mcp__codebyplan__flag_stale_chunk",
185
179
  "mcp__codebyplan__update_eslint_repo_config",
186
180
  "mcp__codebyplan__update_server_config",
187
- "mcp__codebyplan__update_task_template",
181
+ "mcp__codebyplan__get_standalone_tasks",
182
+ "mcp__codebyplan__get_current_standalone_task",
183
+ "mcp__codebyplan__get_standalone_rounds",
184
+ "mcp__codebyplan__create_standalone_task",
185
+ "mcp__codebyplan__update_standalone_task",
186
+ "mcp__codebyplan__complete_standalone_task",
187
+ "mcp__codebyplan__add_standalone_round",
188
+ "mcp__codebyplan__update_standalone_round",
189
+ "mcp__codebyplan__complete_standalone_round",
188
190
  "Bash(codebyplan check:*)",
189
191
  "Bash(npx codebyplan check:*)",
190
192
  "Bash(codebyplan session:*)",
@@ -77,6 +77,7 @@ Check each against the task and include only when they add value:
77
77
  | Background execution | `background: true` | Agent should always run concurrently |
78
78
  | Bounded turns | `maxTurns: N` | Cap runaway loops |
79
79
  | Subagent spawning | `tools: Agent(worker, researcher)` | Only if run as main thread via `--agent` |
80
+ | Memory store | `memory: user \| project \| local` | Which memory store the agent reads/writes |
80
81
 
81
82
  Cross-references for complex cases:
82
83
 
@@ -136,5 +137,7 @@ Report:
136
137
  - Subagents cannot spawn other subagents — the `Agent` tool only applies when the agent runs as the main thread
137
138
  - `bypassPermissions` and `acceptEdits` inherited from the parent cannot be weakened by the child
138
139
  - Preloaded skills inject _full content_ at startup — don't preload `disable-model-invocation: true` skills
140
+ - `Task(` was renamed to `Agent(` in v2.1.63 — use `Agent(...)` in `tools:` allowlists; `Task()` is a stale alias that still works but should not appear in new agents
141
+ - Plugin agents (`.claude/agents/`) ignore `hooks`, `mcpServers`, and `permissionMode` — these fields parse without error but have no runtime effect for plugin agents
139
142
  - Restart the session or use `/agents` to load a newly written agent file
140
143
  - Flat form `.claude/agents/{name}.md` is the default and matches all 12 existing CBP agents; folder form `{name}/AGENT.md` is optional and only for agents that bundle supporting files alongside them
@@ -18,6 +18,7 @@ Source: official Claude Code sub-agents spec. Only `name` and `description` are
18
18
  | `effort` | string | `low` \| `medium` \| `high` \| `xhigh` \| `max`. **Plugin agents authored in CBP MUST set this explicitly** (no commented-out placeholder); see [/cbp-build-cc-mode](../../build-cc-mode/SKILL.md) for the matrix |
19
19
  | `isolation` | string | `worktree` — gives the agent a temporary git worktree |
20
20
  | `color` | string | `red` \| `blue` \| `green` \| `yellow` \| `purple` \| `orange` \| `pink` \| `cyan` |
21
+ | `memory` | string | Which memory store the agent reads/writes: `user` \| `project` \| `local` |
21
22
  | `initialPrompt` | string | Auto-submitted first user turn when the agent is the main session agent |
22
23
 
23
24
  ## Tool-allowlist special forms
@@ -34,3 +35,33 @@ Source: official Claude Code sub-agents spec. Only `name` and `description` are
34
35
  2. Per-invocation `model` parameter passed by Claude
35
36
  3. The `model` field in this file
36
37
  4. Main conversation's model
38
+
39
+ ## Task( → Agent( rename (v2.1.63)
40
+
41
+ The `Agent` tool replaces the older `Task` tool. `Task()` still works as a stale alias but new agents should use `Agent(...)` in their `tools:` allowlists. Example: `tools: Agent(worker, researcher)` — not `Task(worker, researcher)`. The runtime accepts both forms; prefer `Agent`.
42
+
43
+ ## Plugin agent limitations
44
+
45
+ Plugin agents (those defined in `.claude/agents/`) ignore the following fields — they are parsed without error but have **no runtime effect**:
46
+
47
+ - `hooks` — lifecycle hooks are silently no-opped for plugin agents
48
+ - `mcpServers` — scoped MCP server definitions are ignored
49
+ - `permissionMode` — the parent session's permission mode applies unchanged; the child cannot set its own
50
+
51
+ This is distinct from agents run as the main thread via `claude --agent`, where these fields take full effect.
52
+
53
+ ## Skills-preload constraint
54
+
55
+ Skills listed in `skills:` are preloaded — their full content is injected into the agent's context at startup. Do NOT preload skills that carry `disable-model-invocation: true`. A preloaded skill with that flag is loaded at startup but can never be invoked at runtime, so its content wastes context and its intent cannot be fulfilled.
56
+
57
+ ## CBP-only fields (not read by Claude Code)
58
+
59
+ `scope:` is **CBP framework metadata** — it is NOT part of the official Claude Code sub-agents spec and is not read by the Claude Code runtime. It declares the agent's distribution class:
60
+
61
+ | Value | Meaning |
62
+ |-------|---------|
63
+ | `org-shared` | Ships identically to every consuming repo via the `codebyplan` package |
64
+ | `project-shared` | Shared across repos in a single project family |
65
+ | `repo-only:<name>` | Bound to one repo; `<name>` is the repo slug |
66
+
67
+ Required only on user-created agents (no template twin). Package-managed agents are `org-shared` by default — no marker needed. See [rules/scope-vocabulary.md](../../../../rules/scope-vocabulary.md).
@@ -16,3 +16,9 @@ Source: official Claude Code sub-agents and permission-modes specs.
16
16
  - If parent is `bypassPermissions` or `acceptEdits`, child cannot weaken it
17
17
  - If parent is `auto`, child inherits `auto` and its `permissionMode` is ignored
18
18
  - Otherwise the child's `permissionMode` takes effect as declared
19
+
20
+ ## Plugin agents
21
+
22
+ Plugin agents (those defined in `.claude/agents/` and loaded by the runtime, not run via `claude --agent`) **ignore `permissionMode` entirely**. The field is valid YAML and parses without error, but has no runtime effect — the parent session's permission mode applies unchanged.
23
+
24
+ Likewise, `hooks` and `mcpServers` are ignored for plugin agents regardless of the parent session's permission mode. These fields only take effect when the agent runs as the main thread via `claude --agent`.
@@ -6,6 +6,7 @@ tools: Read, Grep, Glob, Bash
6
6
  # disallowedTools: Write, Edit # alternative to tools — inherits then removes
7
7
  # review with /cbp-build-cc-mode if defaults don't fit this agent's purpose
8
8
  model: sonnet
9
+ # memory: user # user | project | local — which memory store this agent reads/writes
9
10
  # permissionMode: default # default | acceptEdits | auto | dontAsk | bypassPermissions | plan
10
11
  # maxTurns: 20
11
12
  effort: xhigh
@@ -24,8 +24,8 @@ Precedence is `deny > ask > allow`; arrays union across scopes (managed/user/pro
24
24
 
25
25
  - **Non-lifecycle, non-shipment `/cbp-*` skills** — authoring (`cbp-build-cc-*`), frontend (`cbp-frontend-*`), git (`cbp-git-*`, `cbp-merge-main`, `cbp-refresh-infra`), round work (`cbp-round-plan`, `cbp-verify` — `cbp-verify` is the autonomous verify stage that runs deterministic gates, proves execution, spawns the fresh-context reviewer, and routes to `cbp-round-complete` or `cbp-round-plan`, so it runs without a prompt), setup/configure (`cbp-setup-*`, `cbp-ship-configure`, `cbp-supabase-*`), task prep (`cbp-task-create`/`-start`, `cbp-standalone-task-check`/`-testing`), planning (`cbp-checkpoint-plan`/`-update`), plus `cbp-session-start` and `cbp-todo`. Invoking a skill is the intended mode of operation; the gated side effects happen inside via the Bash/MCP tools the skill calls, which carry their own tiering. The lifecycle/state-transition and plan-approval skills are the exception — they live in `ask` (next section).
26
26
  - **All `mcp__codebyplan__*` reads** (`get_*`, `list_*`, `search_*`, `health_check`, `lookup_symbol`, `resolve_library_id`, `get_chunk`).
27
- - **Routine workflow-write MCP tools** the pipeline calls many times per task: create/update/complete checkpoint, task, and round; session log + session-state writes; `create_worktree`, `add_library`, `flag_stale_chunk`, `update_server_config`, `update_eslint_repo_config`, `update_task_template`. Gating these with `ask` would make the autonomous workflow unusable.
28
- - **Read/safe CLI commands** (both `codebyplan X` and `npx codebyplan X`): `whoami`, `statusline`, `ports`, `tech-stack`, `eslint`, `round`, `help`, `--version`.
27
+ - **Routine workflow-write MCP tools** the pipeline calls many times per task: create/update/complete checkpoint, task, and round; session log + session-state writes; `create_worktree`, `add_library`, `flag_stale_chunk`, `update_server_config`, `update_eslint_repo_config`. Gating these with `ask` would make the autonomous workflow unusable.
28
+ - **Read/safe CLI commands** (both `codebyplan X` and `npx codebyplan X`): `whoami`, `resolve-worktree`, `statusline`, `ports`, `tech-stack`, `eslint`, `round`, `help`, `--version`.
29
29
 
30
30
  ### `ask` — the deliberate confirm-gate
31
31
 
@@ -66,11 +66,18 @@ This means:
66
66
  - A skill in `ask` that is auto-triggered shows a permission prompt — that prompt is the gate;
67
67
  say so in the routing prose.
68
68
 
69
- ### The 200K context guard
69
+ ### The model-aware context guard
70
70
 
71
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-build`, `cbp-verify`, `cbp-standalone-task-testing`,
72
+ context window exceeds the model-aware threshold:
73
+
74
+ - **Standard models**: `CBP_CONTEXT_WARN_TOKENS` (default 200 000 tokens)
75
+ - **1M-context models** (model id contains `[1m]`): `CBP_CONTEXT_WARN_TOKENS_1M` (default 800 000 tokens)
76
+
77
+ When no model id is found in the transcript the hook fails conservative to the standard 200K
78
+ tier. Each env var overrides only its own tier — the other tier is unaffected.
79
+
80
+ The heavy allowlist is: `cbp-round-build`, `cbp-verify`, `cbp-standalone-task-testing`,
74
81
  `cbp-checkpoint-check`, `cbp-checkpoint-end`.
75
82
 
76
83
  When the guard fires, it directs the model to run `/cbp-clear-prep` instead. The flow is:
@@ -97,6 +97,7 @@ Key fields by use case:
97
97
  | Manual-only workflow | `disable-model-invocation: true` |
98
98
  | Hide from `/` menu | `user-invocable: false` |
99
99
  | Pre-approve tools | `allowed-tools: Bash(git add *) Bash(git commit *)` |
100
+ | Block specific tools | `disallowed-tools: Write, Edit` (denylist applied before `allowed-tools`; blocks those tools for the duration of the skill) |
100
101
  | Accept arguments | `argument-hint: [file] [mode]`, optionally `arguments: [file mode]` for named `$file`/`$mode` |
101
102
  | Set model + effort | `model: inherit` (the standard value — explicitly signals session-model inheritance) and `effort: xhigh` (default for plugin skills; lower tiers `high`/`medium`/`low` per [/cbp-build-cc-mode](../build-cc-mode/SKILL.md)). A non-`inherit` model pin forces a model the user didn't choose and can carry the session's 1M `[1m]` tier onto the skill (→ "usage credits required for 1M context"), so pin only as a deliberate, documented exception |
102
103
  | Path-scoped auto-load | `paths: ["src/api/**/*.ts"]` |
@@ -12,6 +12,7 @@ Source: official Claude Code skills spec. All fields are optional; `description`
12
12
  | `disable-model-invocation` | `true` → only user can invoke (via `/name`). Upstream skills that auto-trigger this skill MUST emit a `Next: /name` directive instead — model invocation is blocked by the runtime; see SKILL.md Step 4 "Convention: User-only / permission-gated finalizer" |
13
13
  | `user-invocable` | `false` → hidden from `/` menu, Claude-only |
14
14
  | `allowed-tools` | Pre-approve tools while the skill is active |
15
+ | `disallowed-tools` | Denylist tools blocked while the skill is active — complement to `allowed-tools`. Applied before `allowed-tools`; e.g. `disallowed-tools: Write, Edit` prevents those tools even if the session allows them |
15
16
  | `model` | Model for this skill's turn. **CBP skills set `model: inherit`** (the standard value — explicitly signals session-model inheritance). A non-`inherit` pin (e.g. `sonnet`) forces that model and can carry the session's 1M `[1m]` context tier onto the skill, triggering "usage credits required for 1M context"; use only as a deliberate, documented exception — see [/cbp-build-cc-mode](../../build-cc-mode/SKILL.md) |
16
17
  | `effort` | Override effort level (`low`/`medium`/`high`/`xhigh`/`max`). **Plugin skills authored in CBP MUST set this explicitly** (no commented-out placeholder); defaults to `xhigh`. See [/cbp-build-cc-mode](../../build-cc-mode/SKILL.md) for the matrix |
17
18
  | `context` | `fork` → run in a subagent |
@@ -39,3 +40,16 @@ Total skill-description budget in context: 1% of the context window (fallback 8,
39
40
  | `user-invocable: false` | No | Yes | Description in context; body loads on auto-invoke |
40
41
 
41
42
  > **Upstream-directive rule**: a skill with `disable-model-invocation: true` cannot be invoked by another skill. Any upstream skill that auto-triggers it MUST emit a `Next: /skill-name` close-out directive and stop. See "Convention: User-only / permission-gated finalizer" in SKILL.md Step 4 for the full pattern and canonical example.
43
+
44
+ ## `context: fork` + `agent:` interplay
45
+
46
+ `agent:` is **ignored by the runtime unless `context: fork` is also set**. When both are present, the skill body runs in the named agent's context (isolated subagent). Built-in agent types: `Explore`, `Plan`, `general-purpose`, or any custom agent name. Note that `Explore`/`Plan` subagents skip the project `CLAUDE.md` — they have no inherited session context. Use `general-purpose` (or a custom agent) when the forked skill needs CLAUDE.md to be in scope.
47
+
48
+ ## CBP-only fields (not read by Claude Code)
49
+
50
+ Two fields in CBP `.claude/` structural files are **CBP framework metadata** — they are NOT part of the official Claude Code skills spec and are not read by the Claude Code runtime:
51
+
52
+ | Field | Purpose |
53
+ |-------|---------|
54
+ | `scope:` | Distribution class — `org-shared` \| `project-shared` \| `repo-only:<repo-name>`. Required only on user-created skills (no template twin). Package-managed skills are `org-shared` by default and need no marker. See [rules/scope-vocabulary.md](../../../../rules/scope-vocabulary.md) |
55
+ | `triggers:` | CBP pipeline routing documentation only — describes when the skill auto-fires in the CBP pipeline. Has no runtime effect; Claude Code does not read it |
@@ -8,6 +8,7 @@ description: What this skill does and when to use it. Front-load the key use cas
8
8
  # disable-model-invocation: false # true = only user can invoke via /name
9
9
  # user-invocable: true # false = only Claude can invoke (hidden from / menu)
10
10
  # allowed-tools: Read, Grep, Glob, Bash(git status *)
11
+ # disallowed-tools: Write, Edit # tools blocked while the skill is active (complement to allowed-tools)
11
12
  # model: # OMIT to inherit the session model (recommended). A pinned model can carry the session's 1M [1m] tier and require usage credits — pin only as a documented exception (see /cbp-build-cc-mode)
12
13
  # review effort with /cbp-build-cc-mode if the default doesn't fit this skill's purpose
13
14
  effort: xhigh
@@ -119,4 +119,4 @@ The user must run both commands manually.
119
119
  - **Writes**: `.codebyplan/clear/handoff.md`
120
120
  - **Next**: user runs `/clear`, then `/cbp-clear-continue`
121
121
  - **Companion**: `.claude/skills/cbp-clear-continue/SKILL.md` reads `.codebyplan/clear/handoff.md`
122
- - **Guard hook**: `.claude/hooks/cbp-skill-context-guard.sh` — fires when context > CBP_CONTEXT_WARN_TOKENS (default 200000)
122
+ - **Guard hook**: `.claude/hooks/cbp-skill-context-guard.sh` — fires when context exceeds the model-aware threshold: `CBP_CONTEXT_WARN_TOKENS` (default 200000) for standard models; `CBP_CONTEXT_WARN_TOKENS_1M` (default 800000) for `[1m]`-context models. No model id found → standard tier (fail-conservative).
@@ -133,7 +133,7 @@ Skip the push only when nothing was committed in Step 5 AND `/cbp-merge-main` re
133
133
 
134
134
  ### Step 7: Complete Task
135
135
 
136
- MCP `complete_task(task_id)`. The server keys on the JWT user (`ctx.userId`) no worktree param is needed. The server auto-clears `assigned_user_id` on the task; if this was the last sibling task, it also clears the parent checkpoint's assignment.
136
+ MCP `complete_task(task_id)` kept on MCP because the CLI `codebyplan task complete` sends an empty POST body and cannot forward `caller_worktree_id`, which the server uses to enforce the mutate-lock. `caller_worktree_id` is auto-injected by the `cbp-mcp-caller-worktree-inject.sh` PreToolUse hook (CHK-198 TASK-2); the server falls back to the repo `main` worktree only when it is absent, then enforces the mutate-lock. The server auto-clears `assigned_user_id` + `assigned_worktree_id` on the task; if this was the last sibling task, it also clears the parent checkpoint's assignment. (Per CHK-104 hard-lock.)
137
137
 
138
138
  ### Step 8: Run Cleanup + Migration (inline)
139
139
 
@@ -153,7 +153,7 @@ Show the completion summary:
153
153
  **Warnings**: [any QA / file-approval warnings from Step 3, or "none"]
154
154
  ```
155
155
 
156
- Then route. Same-context transitions (next task in this checkpoint) auto-trigger `cbp-task-start` via the Skill tool. Checkpoint-done (last task) also auto-triggers `cbp-checkpoint-check` via the Skill tool (`ask`-tier — the permission prompt is the human gate; the 200K context guard handles oversized contexts via the cbp-clear-prep flow). Only the no-task-anywhere session-end fallback surfaces as a single directive (`Next: Run /clear, then /cbp-session-end`) for the user to invoke.
156
+ Then route. Same-context transitions (next task in this checkpoint) auto-trigger `cbp-task-start` via the Skill tool. Checkpoint-done (last task) also auto-triggers `cbp-checkpoint-check` via the Skill tool (`ask`-tier — the permission prompt is the human gate; the model-aware context guard handles oversized contexts via the cbp-clear-prep flow — 200K standard, 800K on `[1m]` sessions). Only the no-task-anywhere session-end fallback surfaces as a single directive (`Next: Run /clear, then /cbp-session-end`) for the user to invoke.
157
157
 
158
158
  #### 9a — Determine routing context
159
159
 
@@ -182,7 +182,7 @@ If no next task is found (no pending work anywhere in the repo), emit directive
182
182
  The checkpoint has no remaining tasks. Invoke `cbp-checkpoint-check` via the Skill tool.
183
183
  `cbp-checkpoint-check` is `ask`-tier — the harness permission prompt IS the human gate; the
184
184
  user confirms (or declines) before checkpoint verification and ship begins. If the context
185
- window is above the 200K threshold the `cbp-skill-context-guard.sh` hook will block it and
185
+ window is above the model-aware threshold (200K standard, 800K for `[1m]` sessions) the `cbp-skill-context-guard.sh` hook will block it and
186
186
  direct you to run `/cbp-clear-prep` first; otherwise checkpoint-check starts on confirmation.
187
187
 
188
188
  ## Integration
@@ -190,7 +190,7 @@ direct you to run `/cbp-clear-prep` first; otherwise checkpoint-check starts on
190
190
  - **Triggered by**: `/cbp-verify` (auto, scope=task, when it writes `verify_verdict.verdict === 'READY'`)
191
191
  - **Chain**: `/cbp-verify` (scope=task READY) → `/cbp-finalize`
192
192
  - **Reads**: `.codebyplan/state/checkpoints/*.json`, `checkpoints/<id>/tasks/*.json`, `checkpoints/<id>/tasks/<id>/rounds/*.json`, `todos.json` (local-first; `npx codebyplan sync` on miss; MCP `get_current_task`/`get_rounds`/`get_tasks` break-glass) — including each round's `verify_manifest` and `task.context.verify_verdict`
193
- - **Writes**: `codebyplan task update` for `files_changed` (CLI write-through; MCP `update_task` break-glass); MCP `complete_task` for task completion
193
+ - **Writes**: `codebyplan task update` for `files_changed` (CLI write-through; MCP `update_task` break-glass); MCP `complete_task` for task completion (kept MCP — CLI cannot forward `caller_worktree_id`)
194
194
  - **Uses skills (inline, no sub-agent)**: `cleanup` (if deletions), `migration` (if exports renamed)
195
195
  - **Triggers**: Same-context transitions auto-trigger via the Skill tool (next task in checkpoint → `cbp-task-start {N}`, `allow`-tier, fires silently). Checkpoint-done → auto-triggers `cbp-checkpoint-check` via Skill tool (`ask`-tier, permission prompt IS the human gate). No-task-anywhere fallback → directive `Next: Run /clear, then /cbp-session-end.`
196
196
  - **Checkpoint-bound only** — for standalone tasks use `/cbp-standalone-task-complete`
@@ -17,7 +17,7 @@ The skill detects "checkpoint done" at Step 9 by:
17
17
  When all siblings are done, the skill invokes `cbp-checkpoint-check` via the Skill tool:
18
18
 
19
19
  - `cbp-checkpoint-check` is `ask`-tier — the harness permission prompt IS the human gate. The user confirms (or declines) before checkpoint verification and the shipment chain begin.
20
- - No `/clear` is emitted unconditionally. If the `cbp-skill-context-guard.sh` hook detects the context window is above the 200K threshold it blocks the skill and directs you to run `/cbp-clear-prep` first (which writes a handoff; the user then runs `/clear`, then `/cbp-clear-continue` resumes); otherwise checkpoint-check starts immediately on confirmation.
20
+ - No `/clear` is emitted unconditionally. If the `cbp-skill-context-guard.sh` hook detects the context window is above the model-aware threshold (200K for standard models; 800K for `[1m]`-context models; env vars `CBP_CONTEXT_WARN_TOKENS` / `CBP_CONTEXT_WARN_TOKENS_1M`) it blocks the skill and directs you to run `/cbp-clear-prep` first (which writes a handoff; the user then runs `/clear`, then `/cbp-clear-continue` resumes); otherwise checkpoint-check starts immediately on confirmation.
21
21
 
22
22
  There is no AskUserQuestion menu. Expanding the checkpoint with more tasks (`/cbp-checkpoint-update`) or wrapping up the session (`/cbp-session-end`) are no longer surfaced as inline alternatives — the deterministic next step on checkpoint-done is `cbp-checkpoint-check`. (The user can still invoke those other skills manually at any time; they are simply not part of the auto-flow.)
23
23
 
@@ -19,7 +19,7 @@ No AskUserQuestion, no `/clear`. The skill fires immediately.
19
19
 
20
20
  Two sub-cases:
21
21
 
22
- **Checkpoint done** (last task in the checkpoint complete): auto-trigger `cbp-checkpoint-check` via the Skill tool. `cbp-checkpoint-check` is `ask`-tier — the permission prompt is the human gate; the 200K context guard handles oversized contexts (via `cbp-clear-prep`) only when context is near the limit. No unconditional `/clear`. (See `checkpoint-done-branching.md`.)
22
+ **Checkpoint done** (last task in the checkpoint complete): auto-trigger `cbp-checkpoint-check` via the Skill tool. `cbp-checkpoint-check` is `ask`-tier — the permission prompt is the human gate; the model-aware context guard handles oversized contexts (via `cbp-clear-prep`) only when context is near the limit — 200K standard, 800K on `[1m]` sessions (env vars `CBP_CONTEXT_WARN_TOKENS` / `CBP_CONTEXT_WARN_TOKENS_1M`). No unconditional `/clear`. (See `checkpoint-done-branching.md`.)
23
23
 
24
24
  **Session end** (no pending tasks anywhere): emit a single directive line at the end of skill output and stop:
25
25