codebyplan 1.13.44 → 1.13.46

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 (42) hide show
  1. package/dist/cli.js +5038 -1551
  2. package/package.json +1 -1
  3. package/templates/agents/cbp-task-check.md +1 -3
  4. package/templates/agents/cbp-task-planner.md +8 -6
  5. package/templates/github-workflows/publish.yml +3 -5
  6. package/templates/hooks/cbp-auto-test-hooks.sh +1 -0
  7. package/templates/hooks/cbp-e2e-spec-patterns.sh +100 -0
  8. package/templates/hooks/cbp-lint-format-on-edit.sh +1 -0
  9. package/templates/hooks/cbp-maestro-yaml-validate.sh +1 -0
  10. package/templates/hooks/cbp-pre-commit-quality-gate.sh +1 -0
  11. package/templates/hooks/cbp-statusline.sh +0 -0
  12. package/templates/hooks/cbp-subagent-statusline.sh +0 -0
  13. package/templates/hooks/cbp-test-coverage-gate.sh +1 -0
  14. package/templates/hooks/cbp-test-hooks.sh +1 -0
  15. package/templates/hooks/hooks.json +4 -0
  16. package/templates/hooks/verify-parity.sh +20 -0
  17. package/templates/rules/parallel-waves.md +8 -3
  18. package/templates/rules/scope-vocabulary.md +4 -3
  19. package/templates/settings.project.base.json +22 -0
  20. package/templates/skills/cbp-build-cc-claude-file/SKILL.md +11 -1
  21. package/templates/skills/cbp-build-cc-claude-file/scripts/validate-claude-file.sh +72 -0
  22. package/templates/skills/cbp-build-cc-mode/SKILL.md +12 -16
  23. package/templates/skills/cbp-build-cc-rule/SKILL.md +11 -1
  24. package/templates/skills/cbp-build-cc-rule/scripts/validate-rule.sh +69 -0
  25. package/templates/skills/cbp-build-cc-settings/SKILL.md +2 -2
  26. package/templates/skills/cbp-build-cc-settings/scripts/validate-settings.sh +67 -0
  27. package/templates/skills/cbp-checkpoint-create/SKILL.md +12 -4
  28. package/templates/skills/cbp-checkpoint-end/SKILL.md +19 -11
  29. package/templates/skills/cbp-git-commit/SKILL.md +10 -12
  30. package/templates/skills/cbp-git-worktree-create/SKILL.md +7 -48
  31. package/templates/skills/cbp-git-worktree-remove/SKILL.md +23 -40
  32. package/templates/skills/cbp-map-architecture/SKILL.md +1 -0
  33. package/templates/skills/cbp-merge-main/SKILL.md +21 -26
  34. package/templates/skills/cbp-refresh-arch-map/SKILL.md +1 -0
  35. package/templates/skills/cbp-round-check/SKILL.md +37 -36
  36. package/templates/skills/cbp-round-execute/SKILL.md +9 -3
  37. package/templates/skills/cbp-session-end/SKILL.md +27 -47
  38. package/templates/skills/cbp-session-start/SKILL.md +35 -51
  39. package/templates/skills/cbp-standalone-task-start/SKILL.md +10 -19
  40. package/templates/skills/cbp-supabase-migrate/SKILL.md +24 -27
  41. package/templates/skills/cbp-task-start/SKILL.md +9 -21
  42. package/templates/skills/cbp-task-testing/SKILL.md +18 -10
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codebyplan",
3
- "version": "1.13.44",
3
+ "version": "1.13.46",
4
4
  "description": "CLI for CodeByPlan — AI-powered development planning and tracking",
5
5
  "type": "module",
6
6
  "bin": {
@@ -82,9 +82,7 @@ Review all QA items across all rounds:
82
82
  - **Auto items**: Verify all passed (build, lint, types, tests)
83
83
  - **Default items**: Verify all resolved (pass or skipped with reason)
84
84
 
85
- **E2E pass vs skipped distinction**: When reading `auto_qa.items[]` for `check: 'e2e'`, do NOT conflate `status: 'pass'` with `status: 'skipped'`. A spec that ran with `passed === 0 && skipped > 0` for any path touching `files_changed` is a hard fail, not a pass verdict text MUST explicitly call this out: "E2E spec authored but assertions did not execute (skip-gated)." Do NOT issue a READY verdict on a zero-assertion e2e run; route to a fix round per `rules/e2e-mandatory.md`.
86
-
87
- **Committed-screenshot check**: For any round where `round.context.e2e_eligible[]` is non-empty, verify `round.context.e2e_gallery[]` is non-empty. Refuse a READY verdict when it is empty — verdict text: "E2E ran but produced zero committed screenshots — open a fix round per `rules/e2e-mandatory.md` § Committed-Screenshot Enforcement." Sole exception: when `vscode-test` is the ONLY eligible framework, an empty `e2e_gallery[]` is allowed (SD-3, behavior-only extensions).
85
+ **E2E deterministic gate**: For each round where `round.context.e2e_eligible[]` is non-empty, run `codebyplan e2e verify-round --round-id <round_id> --task-id <task_id>`. Exit 0 = pass. Exit 1 = hard-fail — refuse a READY verdict and surface the stdout JSON's `failed_checks[]` verbatim in the verdict text. The CLI deterministically evaluates all three e2e hard-fails that were previously judged manually: `e2e_eligible_skipped` (eligible framework with no specialist output and no valid skip reason), `zero_assertion_run` (`passed === 0 && skipped > 0` on a path touching `files_changed` — "E2E spec authored but assertions did not execute (skip-gated)"), and `empty_gallery` (eligible UI-touching run with zero committed screenshots, per `rules/e2e-mandatory.md` § Committed-Screenshot Enforcement; the sole vscode-test-only exception is honored by the CLI). On any exit-1, route to a fix round per `rules/e2e-mandatory.md`.
88
86
 
89
87
  List any pending or failed items. Determine if they are blockers.
90
88
 
@@ -552,13 +552,15 @@ plan.waves:
552
552
 
553
553
  If `files_to_modify[]` contains ≤5 files across a single app, skip decomposition and emit a single wave or omit `waves[]` entirely (single-wave default in `round-execute` handles this gracefully).
554
554
 
555
- **Verification checklist** before finalising waves:
555
+ **Verification** before finalising waves — invariants I (disjoint files), II (acyclic `depends_on` DAG), and III (3–15 files per wave, with the small-plan lower-bound exemption) are deterministic set/graph checks; run the validator instead of self-checking them in prose:
556
556
 
557
- - [ ] Every file in `files_to_modify[]` appears in exactly one wave
558
- - [ ] `depends_on[]` forms a DAG (no cycles)
559
- - [ ] UI-bearing waves have `frontend-design` + `frontend-a11y` in `skill_preloads[]`
560
- - [ ] Each wave has ≥3 files (if not, merge into sibling wave)
561
- - [ ] No wave has >15 files (if so, apply the proximity-split algorithm)
557
+ ```bash
558
+ printf '%s' "$PLAN_JSON" | codebyplan validate-waves --json
559
+ ```
560
+
561
+ (`$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:
562
+
563
+ - [ ] UI-bearing waves have `frontend-design` + `frontend-a11y` in `skill_preloads[]` (invariant IV — not covered by `validate-waves`)
562
564
 
563
565
  ### Phase 6: Build Context Summary
564
566
 
@@ -93,8 +93,7 @@ jobs:
93
93
  case "$VERSION" in
94
94
  *-*)
95
95
  # Prerelease — check if this exact version already exists on npm.
96
- EXACT_OUT=$(npm view "codebyplan@${VERSION}" version 2>&1)
97
- EXACT_EXIT=$?
96
+ EXACT_OUT=$(npm view "codebyplan@${VERSION}" version 2>&1) && EXACT_EXIT=0 || EXACT_EXIT=$?
98
97
  if [ "$EXACT_EXIT" -eq 0 ]; then
99
98
  echo "VERSION=${VERSION} already published — skipping (exact-version guard)."
100
99
  echo "should_publish=false" >> "$GITHUB_OUTPUT"
@@ -134,8 +133,7 @@ jobs:
134
133
  # Stable on main: compare committed version against the npm registry.
135
134
  # Distinguish "never published" (E404 → first publish) from a transient
136
135
  # registry/network error (abort rather than blindly publish).
137
- NPM_OUT=$(npm view codebyplan version 2>&1)
138
- NPM_EXIT=$?
136
+ NPM_OUT=$(npm view codebyplan version 2>&1) && NPM_EXIT=0 || NPM_EXIT=$?
139
137
  if [ "$NPM_EXIT" -ne 0 ]; then
140
138
  if echo "$NPM_OUT" | grep -q "E404"; then
141
139
  echo "Package not yet published — first publish."
@@ -147,7 +145,7 @@ jobs:
147
145
  fi
148
146
  # Extract the first semver-looking line so a registry deprecation/advisory
149
147
  # notice in NPM_OUT cannot corrupt the sort -V comparison below.
150
- PUBLISHED=$(printf '%s\n' "$NPM_OUT" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+' | head -n1)
148
+ PUBLISHED=$(printf '%s\n' "$NPM_OUT" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+' | head -n1) || true
151
149
 
152
150
  # sort -V: version-aware sort. If VERSION sorts AFTER PUBLISHED, it is greater.
153
151
  GREATER=$(printf '%s\n%s\n' "$PUBLISHED" "$VERSION" | sort -V | tail -n1)
@@ -1,4 +1,5 @@
1
1
  #!/bin/bash
2
+ # @scope: org-shared
2
3
  # @hook: PostToolUse Edit|Write
3
4
  # Hook: PostToolUse for Edit|Write on hook files
4
5
  # Purpose: Run test-hooks.sh when a plugin hook file is modified.
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env bash
2
+ # @scope: org-shared
3
+ # @event: PreToolUse
4
+ # @matcher: Edit|Write|MultiEdit
5
+ # Guard spec files against two patterns banned by rules/e2e-mandatory.md and
6
+ # context/testing/e2e.md:
7
+ #
8
+ # 1. In-spec env skip gates — test.skip(!process.env.X, ...) bypasses preflight,
9
+ # produces zero-assertion runs, and hides missing env vars behind a green check.
10
+ # (rules/e2e-mandatory.md § No In-Spec Env-Skip Gate)
11
+ #
12
+ # 2. waitForLoadState("networkidle") locators — networkidle is deprecated in
13
+ # Playwright and causes flaky / hanging tests; use load or domcontentloaded
14
+ # instead. (context/testing/e2e.md § locator hygiene)
15
+ #
16
+ # Only fires on spec files: file_path ending in .spec.ts OR containing /e2e/
17
+ # or starting with e2e/. All other file paths exit 0 immediately.
18
+ #
19
+ # Exit codes:
20
+ # 0 — no violation (or not a spec file)
21
+ # 2 — violation found; message on stderr
22
+
23
+ set -euo pipefail
24
+
25
+ INPUT_JSON="$(cat)"
26
+ TOOL_NAME="$(echo "$INPUT_JSON" | jq -r '.tool_name // empty')"
27
+ FILE_PATH="$(echo "$INPUT_JSON" | jq -r '.tool_input.file_path // empty')"
28
+
29
+ # ------------------------------------------------------------------
30
+ # Fast-path: only enforce on spec / e2e files
31
+ # ------------------------------------------------------------------
32
+ is_spec=0
33
+ case "$FILE_PATH" in
34
+ *.spec.ts) is_spec=1 ;;
35
+ */e2e/*) is_spec=1 ;;
36
+ e2e/*) is_spec=1 ;;
37
+ esac
38
+
39
+ [ "$is_spec" -eq 0 ] && exit 0
40
+
41
+ # ------------------------------------------------------------------
42
+ # Extract content depending on tool type
43
+ # ------------------------------------------------------------------
44
+ NEW_CONTENT=""
45
+ if [ "$TOOL_NAME" = "Write" ]; then
46
+ NEW_CONTENT="$(echo "$INPUT_JSON" | jq -r '.tool_input.content // empty')"
47
+ elif [ "$TOOL_NAME" = "Edit" ]; then
48
+ NEW_CONTENT="$(echo "$INPUT_JSON" | jq -r '.tool_input.new_string // empty')"
49
+ elif [ "$TOOL_NAME" = "MultiEdit" ]; then
50
+ NEW_CONTENT="$(echo "$INPUT_JSON" | jq -r '[.tool_input.edits[].new_string // ""] | join("\n")')"
51
+ fi
52
+
53
+ [ -z "$NEW_CONTENT" ] && exit 0
54
+
55
+ # ------------------------------------------------------------------
56
+ # Check 1: in-spec env-skip gate (test.skip with process.env)
57
+ # Pattern: test.skip( followed by optional whitespace and optional !
58
+ # then process.env
59
+ # ------------------------------------------------------------------
60
+ if echo "$NEW_CONTENT" | grep -qE 'test\.skip\([[:space:]]*!?process\.env'; then
61
+ cat >&2 <<'EOF'
62
+ [hook] cbp-e2e-spec-patterns: in-spec env skip gate detected
63
+
64
+ Pattern: test.skip(!process.env.X, ...) or test.skip(process.env.X, ...)
65
+
66
+ This pattern is banned by rules/e2e-mandatory.md § "No In-Spec Env-Skip Gate":
67
+ "Spec files MUST NOT contain in-spec env skip gates such as
68
+ test.skip(!process.env.X, ...). They bypass preflight, produce
69
+ zero-assertion runs, and hide missing env vars behind a green check."
70
+
71
+ The only valid mechanism for env-conditional skipping is pre-flight
72
+ (context/testing/e2e.md Step 6.5.1). Configure missing env vars in
73
+ .codebyplan/e2e.json credential_vars and let the preflight block the run.
74
+
75
+ EOF
76
+ exit 2
77
+ fi
78
+
79
+ # ------------------------------------------------------------------
80
+ # Check 2: waitForLoadState("networkidle") locator
81
+ # networkidle is deprecated and causes flaky / hanging tests.
82
+ # ------------------------------------------------------------------
83
+ if echo "$NEW_CONTENT" | grep -qE 'waitForLoadState\(["'"'"']networkidle["'"'"']\)'; then
84
+ cat >&2 <<'EOF'
85
+ [hook] cbp-e2e-spec-patterns: waitForLoadState("networkidle") detected
86
+
87
+ This locator is banned by context/testing/e2e.md locator hygiene rules.
88
+ "networkidle" is deprecated in Playwright and causes flaky or hanging tests.
89
+
90
+ Use one of the stable alternatives:
91
+ await page.waitForLoadState("load"); // waits for load event
92
+ await page.waitForLoadState("domcontentloaded"); // waits for DOM ready
93
+ await page.waitForURL("..."); // waits for navigation
94
+ await expect(locator).toBeVisible(); // waits for element
95
+
96
+ EOF
97
+ exit 2
98
+ fi
99
+
100
+ exit 0
@@ -1,4 +1,5 @@
1
1
  #!/bin/bash
2
+ # @scope: org-shared
2
3
  # @hook: PostToolUse Edit|Write
3
4
  # Hook: Auto-format and auto-fix lint on edited source files
4
5
  # Purpose: Continuous Prettier + ESLint --fix after every Edit/Write.
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env bash
2
+ # @scope: org-shared
2
3
  # @event: PreToolUse
3
4
  # @matcher: Edit|Write|MultiEdit
4
5
  # Validate maestro flow YAML against the installed CLI's accepted property set.
@@ -1,4 +1,5 @@
1
1
  #!/bin/bash
2
+ # @scope: org-shared
2
3
  # @hook: PreToolUse Bash
3
4
  # Hook: PreToolUse for Bash (git commit commands)
4
5
  # Purpose: Block git commits that violate greenfield-lint-zero-warnings,
File without changes
File without changes
@@ -1,4 +1,5 @@
1
1
  #!/bin/bash
2
+ # @scope: org-shared
2
3
  # @hook: PreToolUse Bash
3
4
  # Hook: PreToolUse for Bash (git commit commands)
4
5
  # Purpose: Block git commits when new source files lack test companions
@@ -1,4 +1,5 @@
1
1
  #!/bin/bash
2
+ # @scope: org-shared
2
3
  # @hook: NOT-A-HOOK (test suite for plugin hooks; invoked by cbp-auto-test-hooks.sh)
3
4
  # Purpose: Test suite for plugin's shipped hooks. Invoked by cbp-auto-test-hooks.sh whenever a
4
5
  # plugin hook file is edited. Not a PreToolUse/PostToolUse/Notification hook itself —
@@ -28,6 +28,10 @@
28
28
  {
29
29
  "type": "command",
30
30
  "command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/cbp-maestro-yaml-validate.sh"
31
+ },
32
+ {
33
+ "type": "command",
34
+ "command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/cbp-e2e-spec-patterns.sh"
31
35
  }
32
36
  ]
33
37
  },
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env bash
2
+ # @scope: org-shared
3
+ # @event: SessionStart
4
+ # Scope + sibling-parity sweep at session start. Calls `codebyplan claude verify-parity --warn-only`.
5
+ # Fires ONLY in the templates source monorepo (self-guards on templates/ presence); no-op for consumers.
6
+ # Always exits 0 — warn-mode, non-blocking.
7
+
8
+ set -u
9
+ REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
10
+ [ -z "$REPO_ROOT" ] && exit 0
11
+ [ -d "$REPO_ROOT/packages/codebyplan-package/templates" ] || exit 0
12
+
13
+ # Prefer the installed binary (fast); fall back to npx for fresh checkouts /
14
+ # environments where the workspace bin is not on PATH (matches cbp-mcp-round-sync.sh).
15
+ if command -v codebyplan >/dev/null 2>&1; then
16
+ codebyplan claude verify-parity --warn-only 2>&1 || true
17
+ else
18
+ npx codebyplan claude verify-parity --warn-only 2>&1 || true
19
+ fi
20
+ exit 0
@@ -12,7 +12,7 @@ Authoritative expansion of `cbp-task-planner` Phase 5.6. The planner reads this
12
12
 
13
13
  ## Wave Schema
14
14
 
15
- Each entry in `plan.waves[]` carries these fields (source: `.claude/agents/cbp-task-planner.md:540`):
15
+ Each entry in `plan.waves[]` carries these fields (source: `.claude/agents/cbp-task-planner.md` Phase 5.6 "Output" block):
16
16
 
17
17
  ```yaml
18
18
  - name: string # short identifier, e.g. "web-ui", "backend", "db"
@@ -34,7 +34,7 @@ Each entry in `plan.waves[]` carries these fields (source: `.claude/agents/cbp-t
34
34
  - Above 15: apply the proximity-split algorithm below.
35
35
  - 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.
36
36
 
37
- **(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:532`).
37
+ **(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[]`").
38
38
 
39
39
  ## Proximity-Split Algorithm
40
40
 
@@ -52,8 +52,13 @@ When a wave would exceed 15 files, split it in priority order:
52
52
 
53
53
  When no cross-app or cross-concern independence is found, the planner emits one wave covering all files. The 15-file cap applies to this single wave — if the total exceeds 15, apply the proximity-split algorithm even though the original decomposition was a single wave.
54
54
 
55
+ ## Enforcement
56
+
57
+ Invariants I (disjoint files), II (acyclic `depends_on` DAG), and III (3–15 files per wave, with the small-plan lower-bound exemption) are enforced deterministically by `codebyplan validate-waves [--json]` (`packages/codebyplan-package/src/lib/validate-waves.ts`). The planner runs it at Phase 5.6 against the `{ "waves": [...] }` structure (file-path or stdin input); a non-zero exit lists the violated invariant + offending wave/file. Invariant IV (UI skill preloads) is out of the validator's scope and stays a planner manual step.
58
+
55
59
  ## Cross-References
56
60
 
57
- - `agents/cbp-task-planner.md` Phase 5.6 — consumer of this rule; steps 1–6 and verification checklist.
61
+ - `agents/cbp-task-planner.md` Phase 5.6 — consumer of this rule; steps 1–6 and the `validate-waves` verification call.
62
+ - `packages/codebyplan-package/src/lib/validate-waves.ts` — deterministic enforcement of invariants I–III.
58
63
  - `agents/cbp-round-executor.md` Step 2.6 — wave-mode skill preloads.
59
64
  - `skills/cbp-round-execute/SKILL.md` Step 3 — per-wave executor dispatch.
@@ -4,7 +4,7 @@ scope: org-shared
4
4
 
5
5
  # Scope Vocabulary
6
6
 
7
- Canonical scope-marker enum for `.claude/` files. Every CBP-managed agent, skill, rule, and hook script must declare exactly one `scope:` value from the enum below. The marker is enforced by three validators (cross-linked at the bottom of this file).
7
+ Canonical scope-marker enum for `.claude/` files. Every CBP-managed agent, skill, rule, and hook script must declare exactly one `scope:` value from the enum below. The marker is enforced by four validators (cross-linked at the bottom of this file).
8
8
 
9
9
  ## Enum values
10
10
 
@@ -57,8 +57,9 @@ Used by `.sh` hook scripts and `.sh` tooling under `.claude/`. Place the marker
57
57
 
58
58
  ## Enforcement
59
59
 
60
- Three validators enforce this enum. A file missing the marker (or carrying a non-enum value) fails validation:
60
+ Four validators enforce this enum. A file missing the marker (or carrying a non-enum value) fails validation:
61
61
 
62
- - `.claude/hooks/validate-structure-scope.sh` — warns on missing markers across all `.claude/` files at session start.
62
+ - `.claude/hooks/validate-structure-scope.sh` — warns when a `.claude/` file being edited (PreToolUse `Edit|Write`) lacks a scope marker; sourced by `validate-structure.sh`; it is NOT a session-start sweep.
63
+ - `codebyplan claude verify-parity` — sweeps all `.claude/{rules,skills,agents,hooks}` for missing/non-enum scope markers AND runs the sibling-parity check against `templates/`; invoked automatically at session start via `.claude/hooks/verify-parity.sh` (monorepo only); run manually with `--json` for CI.
63
64
  - `.claude/skills/cbp-build-cc-agent/scripts/validate-agent.sh` — blocks agent authoring when `scope:` is absent.
64
65
  - `.claude/skills/cbp-build-cc-skill/scripts/validate-skill.sh` — blocks skill authoring when `scope:` is absent.
@@ -84,6 +84,8 @@
84
84
  "Bash(npx codebyplan upgrade-auth:*)",
85
85
  "Bash(codebyplan config:*)",
86
86
  "Bash(npx codebyplan config:*)",
87
+ "Bash(codebyplan doctor:*)",
88
+ "Bash(npx codebyplan doctor:*)",
87
89
  "Bash(codebyplan branch:*)",
88
90
  "Bash(npx codebyplan branch:*)",
89
91
  "Bash(codebyplan ship:*)",
@@ -178,12 +180,20 @@
178
180
  "mcp__codebyplan__update_eslint_repo_config",
179
181
  "mcp__codebyplan__update_server_config",
180
182
  "mcp__codebyplan__update_task_template",
183
+ "Bash(codebyplan check:*)",
184
+ "Bash(npx codebyplan check:*)",
185
+ "Bash(codebyplan session:*)",
186
+ "Bash(npx codebyplan session:*)",
187
+ "Bash(codebyplan supabase:*)",
188
+ "Bash(npx codebyplan supabase:*)",
181
189
  "Bash(codebyplan whoami:*)",
182
190
  "Bash(npx codebyplan whoami:*)",
183
191
  "Bash(codebyplan resolve-worktree:*)",
184
192
  "Bash(npx codebyplan resolve-worktree:*)",
185
193
  "Bash(codebyplan version-status:*)",
186
194
  "Bash(npx codebyplan version-status:*)",
195
+ "Bash(codebyplan worktree:*)",
196
+ "Bash(npx codebyplan worktree:*)",
187
197
  "Bash(codebyplan statusline:*)",
188
198
  "Bash(npx codebyplan statusline:*)",
189
199
  "Bash(codebyplan ports:*)",
@@ -214,6 +224,18 @@
214
224
  "Bash(npx codebyplan bump:*)",
215
225
  "Bash(codebyplan scaffold-publish-workflow:*)",
216
226
  "Bash(npx codebyplan scaffold-publish-workflow:*)",
227
+ "Bash(codebyplan claude verify-parity:*)",
228
+ "Bash(npx codebyplan claude verify-parity:*)",
229
+ "Bash(codebyplan slug:*)",
230
+ "Bash(npx codebyplan slug:*)",
231
+ "Bash(codebyplan commit:*)",
232
+ "Bash(npx codebyplan commit:*)",
233
+ "Bash(codebyplan migration-collisions:*)",
234
+ "Bash(npx codebyplan migration-collisions:*)",
235
+ "Bash(codebyplan validate-waves:*)",
236
+ "Bash(npx codebyplan validate-waves:*)",
237
+ "Bash(codebyplan e2e:*)",
238
+ "Bash(npx codebyplan e2e:*)",
217
239
  "Bash(codebyplan arch-map:*)",
218
240
  "Bash(npx codebyplan arch-map:*)"
219
241
  ]
@@ -170,7 +170,17 @@ Other teams' CLAUDE.md files in the ancestor tree get picked up by default. Excl
170
170
 
171
171
  Managed policy CLAUDE.md cannot be excluded.
172
172
 
173
- ### Step 9 — Verify with `/memory`
173
+ ### Step 9 — Validate
174
+
175
+ Run the validator:
176
+
177
+ ```bash
178
+ bash "${CLAUDE_SKILL_DIR}/scripts/validate-claude-file.sh" "{path-to-claude-file}"
179
+ ```
180
+
181
+ It checks: at least one H1 heading present, `@path` imports all resolve relative to the file's directory (or repo root), line count (warns at 200, errors at 400), warns if `scope:` marker appears in frontmatter, warns if filename is neither `CLAUDE.md` nor `CLAUDE.local.md`.
182
+
183
+ ### Step 10 — Verify with `/memory`
174
184
 
175
185
  Run `/memory` to confirm the file is loaded. The list shows all CLAUDE.md, CLAUDE.local.md, and rules files in effect.
176
186
 
@@ -0,0 +1,72 @@
1
+ #!/bin/bash
2
+ # @scope: org-shared
3
+ # Validate a CLAUDE.md or CLAUDE.local.md file.
4
+ # Usage: validate-claude-file.sh <path-to-claude-file>
5
+ # Exit 0 = valid, exit 1 = invalid (errors printed to stderr).
6
+
7
+ set -euo pipefail
8
+
9
+ FILE="${1:?Usage: validate-claude-file.sh <path-to-claude-file>}"
10
+
11
+ if [ ! -f "$FILE" ]; then
12
+ echo "ERROR: file not found: $FILE" >&2
13
+ exit 1
14
+ fi
15
+
16
+ errors=0
17
+ err() { echo " - $1" >&2; errors=$((errors + 1)); }
18
+
19
+ # Filename check — warn if not a known CLAUDE.md variant
20
+ fname=$(basename "$FILE")
21
+ if [ "$fname" != "CLAUDE.md" ] && [ "$fname" != "CLAUDE.local.md" ]; then
22
+ echo " WARN: unexpected filename '$fname' — expected CLAUDE.md or CLAUDE.local.md" >&2
23
+ fi
24
+
25
+ # At least one H1 heading must be present
26
+ if ! grep -qE '^# ' "$FILE"; then
27
+ err "missing H1 heading"
28
+ fi
29
+
30
+ # Line count thresholds
31
+ lines=$(wc -l < "$FILE")
32
+ if [ "$lines" -ge 400 ]; then
33
+ err "file is $lines lines (hard limit 400; split with @path imports or nested CLAUDE.md files)"
34
+ elif [ "$lines" -ge 200 ]; then
35
+ echo " WARN: file is $lines lines (recommended max 200; consider splitting)" >&2
36
+ fi
37
+
38
+ # @path import resolution — each @path token must resolve to an existing file.
39
+ # Tries both: relative to the file's directory, and relative to cwd (repo root).
40
+ filedir=$(dirname "$FILE")
41
+ while IFS= read -r imp; do
42
+ [ -z "$imp" ] && continue
43
+ ipath="${imp#@}"
44
+ if [ "${ipath:0:1}" = "/" ]; then
45
+ # absolute path
46
+ if [ ! -f "$ipath" ]; then
47
+ err "@import path '$ipath' does not exist"
48
+ fi
49
+ elif [ -f "$filedir/$ipath" ]; then
50
+ : # ok — resolves relative to the file's directory
51
+ elif [ -f "$ipath" ]; then
52
+ : # ok — resolves relative to cwd (repo root)
53
+ else
54
+ err "@import path '$ipath' does not exist (tried: $filedir/$ipath, $ipath)"
55
+ fi
56
+ done < <(grep -oE '^[[:space:]]*@[^[:space:]@]+' "$FILE" 2>/dev/null | sed 's/^[[:space:]]*//' 2>/dev/null || true)
57
+
58
+ # Warn if YAML frontmatter contains a scope: marker (CLAUDE.md is not a rule/skill/agent file)
59
+ if head -1 "$FILE" | grep -qE '^---[[:space:]]*$'; then
60
+ fm=$(awk '/^---[[:space:]]*$/{n++; next} n==1{print} n==2{exit}' "$FILE")
61
+ if grep -qE '^scope:[[:space:]]*' <<< "$fm"; then
62
+ echo " WARN: CLAUDE.md has a scope: frontmatter field — scope markers belong in rule/skill/agent files, not CLAUDE.md" >&2
63
+ fi
64
+ fi
65
+
66
+ if [ "$errors" -gt 0 ]; then
67
+ echo "validation FAILED ($errors issue(s)) for $FILE" >&2
68
+ exit 1
69
+ fi
70
+
71
+ echo "validation OK: $FILE"
72
+ exit 0
@@ -39,11 +39,12 @@ A skill that carries a `model:` line is a **gap** — remove it unless a deliber
39
39
 
40
40
  ### Agents — `model:` + `effort:`
41
41
 
42
- Default `model: sonnet` + `effort: xhigh`. Fifteen of the 16 authoring agents take the default (`cbp-cc-executor`, `cbp-database-agent`, `cbp-improve-claude`, `cbp-improve-round`, `cbp-research`, `cbp-round-executor`, `cbp-security-agent`, `cbp-task-check`, `cbp-task-planner`, `cbp-testing-qa-agent`, `cbp-e2e-playwright`, `cbp-e2e-maestro`, `cbp-e2e-tauri`, `cbp-e2e-vscode`, `cbp-e2e-xcuitest`). The 16th is the one exception:
42
+ Default `model: sonnet` + `effort: xhigh`. Fifteen of the 17 authoring agents take the default (`cbp-cc-executor`, `cbp-database-agent`, `cbp-improve-claude`, `cbp-improve-round`, `cbp-research`, `cbp-round-executor`, `cbp-security-agent`, `cbp-task-check`, `cbp-task-planner`, `cbp-testing-qa-agent`, `cbp-e2e-playwright`, `cbp-e2e-maestro`, `cbp-e2e-tauri`, `cbp-e2e-vscode`, `cbp-e2e-xcuitest`). The other two are exceptions:
43
43
 
44
- | agent | model | effort | reason |
45
- | -------------------- | ----- | ------ | ----------------------------------------------------------------------------------- |
46
- | cbp-mechanical-edits | haiku | low | Mechanical rename/substitution/frontmatter-edit subagent; no judgment, pure dispatch |
44
+ | agent | model | effort | reason |
45
+ | -------------------- | ------ | ------ | ----------------------------------------------------------------------------------- |
46
+ | cbp-mechanical-edits | haiku | low | Mechanical rename/substitution/frontmatter-edit subagent; no judgment, pure dispatch |
47
+ | cbp-map-architecture | sonnet | high | Read-only module analyzer; bounded structured-map generation, lighter than xhigh |
47
48
 
48
49
  `model: inherit` is NOT permitted for agents — pin an explicit alias (`sonnet` / `haiku`) or a full ID.
49
50
 
@@ -53,18 +54,13 @@ A skill's `effort:` applies to the inline-running turn (the orchestrator turn th
53
54
 
54
55
  ## Audit Mode
55
56
 
56
- Invoked with no arguments. Procedure:
57
-
58
- 1. Glob `packages/codebyplan-package/templates/agents/*.md` and `packages/codebyplan-package/templates/skills/*/SKILL.md`.
59
- 2. For each file, read the frontmatter and parse `model:` + `effort:`.
60
- 3. Apply the convention by surface:
61
- - **Skill**: `model:` MUST be ABSENT; `effort:` MUST be present and one of `low`/`medium`/`high`/`xhigh`/`max` (default `xhigh`).
62
- - **Agent**: `model:` MUST be present (per the agent table; default `sonnet`); `effort:` present (default `xhigh`).
63
- 4. Emit one pipe-delimited line per file: `path | current_model/current_effort | expected | status`.
64
- 5. Status values:
65
- - `ok` — matches the convention.
66
- - `gap` — a skill that carries a `model:` line, a skill missing `effort:`, an agent missing/incorrect `model:`, or any missing/invalid `effort:`.
67
- 6. Print a summary: total audited, count `ok`, count `gap`.
57
+ Run `codebyplan claude audit-mode` — it scans `packages/codebyplan-package/templates/agents/*.md` and `packages/codebyplan-package/templates/skills/*/SKILL.md`, applies the convention from the matrix above, and emits a pipe-delimited table:
58
+
59
+ ```
60
+ path | surface | model/effort | expected | status
61
+ ```
62
+
63
+ Plus a summary line: `N audited, N ok, N gaps`. Exits 0 when all files comply; exits 1 on any gap. Pass `--json` for a machine-readable entries array.
68
64
 
69
65
  The audit is read-only.
70
66
 
@@ -153,7 +153,17 @@ ln -s ~/company-standards/security.md .claude/rules/security.md
153
153
 
154
154
  Claude Code resolves symlinks normally. Circular symlinks are detected.
155
155
 
156
- ### Step 8 — Verify loading
156
+ ### Step 8 — Validate
157
+
158
+ Run the validator:
159
+
160
+ ```bash
161
+ bash "${CLAUDE_SKILL_DIR}/scripts/validate-rule.sh" "{scope-path}/{name}.md"
162
+ ```
163
+
164
+ It checks: YAML frontmatter present, `scope:` field present and valid enum value, H1 heading present and its kebab-case form matches the filename, `paths:` field (warns if absent — unconditional rules burn context on every session), line count (warns at 100, errors at 200).
165
+
166
+ ### Step 9 — Verify loading
157
167
 
158
168
  Run `/memory` in a fresh Claude Code session to confirm the rule is listed. If path-scoped, open a file matching the glob to confirm it triggers.
159
169
 
@@ -0,0 +1,69 @@
1
+ #!/bin/bash
2
+ # @scope: org-shared
3
+ # Validate a Claude Code rule file at .claude/rules/{name}.md.
4
+ # Usage: validate-rule.sh <path-to-rule-file>
5
+ # Exit 0 = valid, exit 1 = invalid (errors printed to stderr).
6
+
7
+ set -euo pipefail
8
+
9
+ FILE="${1:?Usage: validate-rule.sh <path-to-rule-file>}"
10
+
11
+ if [ ! -f "$FILE" ]; then
12
+ echo "ERROR: file not found: $FILE" >&2
13
+ exit 1
14
+ fi
15
+
16
+ errors=0
17
+ err() { echo " - $1" >&2; errors=$((errors + 1)); }
18
+
19
+ # Frontmatter must be present
20
+ if ! head -1 "$FILE" | grep -qE '^---[[:space:]]*$'; then
21
+ err "missing YAML frontmatter opener '---'"
22
+ fi
23
+
24
+ # Extract frontmatter block
25
+ fm=$(awk '/^---[[:space:]]*$/{n++; next} n==1{print} n==2{exit}' "$FILE")
26
+
27
+ # scope: field required + must match enum
28
+ if ! grep -qE '^scope:[[:space:]]*' <<< "$fm"; then
29
+ err "missing CBP required field: scope (org-shared|project-shared|repo-only:<repo-name>)"
30
+ else
31
+ scope_val=$(grep -E '^scope:' <<< "$fm" | head -1 | sed -E 's/^scope:[[:space:]]*//; s/[[:space:]]*$//')
32
+ if ! [[ "$scope_val" =~ ^(org-shared|project-shared|repo-only:[a-z0-9]([a-z0-9-]*[a-z0-9])?)$ ]]; then
33
+ err "scope value '$scope_val' is not a valid enum value (org-shared|project-shared|repo-only:<slug>)"
34
+ fi
35
+ fi
36
+
37
+ # H1 heading must be present and its kebab-case form must match the filename (sans .md)
38
+ h1=$(grep -m1 '^# ' "$FILE" | sed 's/^# //' || true)
39
+ if [ -z "$h1" ]; then
40
+ err "missing H1 heading"
41
+ else
42
+ # Convert H1 to kebab-case: lowercase, spaces→hyphens, strip non-alnum chars (except hyphens)
43
+ h1_kebab=$(echo "$h1" | tr '[:upper:]' '[:lower:]' | sed 's/ /-/g; s/_/-/g; s/[^a-z0-9-]//g')
44
+ fname=$(basename "$FILE" .md)
45
+ if [ "$h1_kebab" != "$fname" ]; then
46
+ err "H1 '$h1' (kebab: '$h1_kebab') does not match filename '$(basename "$FILE")'"
47
+ fi
48
+ fi
49
+
50
+ # paths: warning only — unconditional rules load at every session start (use sparingly)
51
+ if ! grep -qE '^paths:[[:space:]]*' <<< "$fm"; then
52
+ echo " WARN: no paths: field — rule loads unconditionally at session start; use sparingly" >&2
53
+ fi
54
+
55
+ # Line count thresholds (matches cbp-build-cc-rule hook: warn ≥ 100, error ≥ 200)
56
+ lines=$(wc -l < "$FILE")
57
+ if [ "$lines" -ge 200 ]; then
58
+ err "rule file is $lines lines (hard limit 200; split on topic)"
59
+ elif [ "$lines" -ge 100 ]; then
60
+ echo " WARN: rule file is $lines lines (recommended max 100; consider splitting)" >&2
61
+ fi
62
+
63
+ if [ "$errors" -gt 0 ]; then
64
+ echo "validation FAILED ($errors issue(s)) for $FILE" >&2
65
+ exit 1
66
+ fi
67
+
68
+ echo "validation OK: $FILE"
69
+ exit 0
@@ -183,8 +183,8 @@ Applied to every session. Full env-var catalogue: the official Claude Code env-v
183
183
  ### Step 9 — Validate and verify
184
184
 
185
185
  ```bash
186
- # Pretty-print and validate JSON
187
- jq . .claude/settings.json
186
+ # Validate structure, $schema, and permission-rule syntax
187
+ bash "${CLAUDE_SKILL_DIR}/scripts/validate-settings.sh" "{scope-path}/settings.json"
188
188
 
189
189
  # Ask Claude Code itself
190
190
  # (inside a session)