codebyplan 1.13.62 → 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.
Files changed (47) hide show
  1. package/dist/cli.js +1108 -2061
  2. package/package.json +1 -1
  3. package/templates/agents/cbp-e2e-playwright.md +10 -10
  4. package/templates/hooks/cbp-mcp-round-sync.sh +4 -15
  5. package/templates/hooks/cbp-skill-context-guard.sh +33 -13
  6. package/templates/hooks/cbp-test-hooks.sh +85 -0
  7. package/templates/hooks/hooks.json +0 -9
  8. package/templates/rules/architecture-map.md +6 -0
  9. package/templates/rules/cbp-operating-gotchas.md +13 -1
  10. package/templates/rules/e2e-mandatory.md +5 -0
  11. package/templates/rules/model-invocation-convention.md +1 -1
  12. package/templates/rules/scope-vocabulary.md +5 -0
  13. package/templates/rules/supabase-branch-lifecycle.md +2 -2
  14. package/templates/rules/task-routing-recommendation.md +1 -1
  15. package/templates/rules/todo-backend.md +11 -8
  16. package/templates/settings.project.base.json +9 -12
  17. package/templates/skills/cbp-build-cc-agent/SKILL.md +3 -0
  18. package/templates/skills/cbp-build-cc-agent/reference/frontmatter-fields.md +31 -0
  19. package/templates/skills/cbp-build-cc-agent/reference/permission-modes.md +6 -0
  20. package/templates/skills/cbp-build-cc-agent/templates/agent.md +1 -0
  21. package/templates/skills/cbp-build-cc-settings/reference/cbp-permission-policy.md +11 -4
  22. package/templates/skills/cbp-build-cc-skill/SKILL.md +1 -0
  23. package/templates/skills/cbp-build-cc-skill/reference/frontmatter-fields.md +14 -0
  24. package/templates/skills/cbp-build-cc-skill/templates/skill.md +1 -0
  25. package/templates/skills/cbp-checkpoint-create/SKILL.md +12 -22
  26. package/templates/skills/cbp-checkpoint-end/SKILL.md +37 -0
  27. package/templates/skills/cbp-checkpoint-plan/SKILL.md +10 -8
  28. package/templates/skills/cbp-checkpoint-start/SKILL.md +27 -19
  29. package/templates/skills/cbp-checkpoint-update/SKILL.md +1 -1
  30. package/templates/skills/cbp-clear-prep/SKILL.md +1 -1
  31. package/templates/skills/cbp-finalize/SKILL.md +2 -2
  32. package/templates/skills/cbp-finalize/reference/checkpoint-done-branching.md +1 -1
  33. package/templates/skills/cbp-finalize/reference/next-step-heuristic.md +1 -1
  34. package/templates/skills/cbp-round-complete/SKILL.md +3 -24
  35. package/templates/skills/cbp-round-plan/SKILL.md +1 -1
  36. package/templates/skills/cbp-session-end/SKILL.md +40 -30
  37. package/templates/skills/cbp-session-start/SKILL.md +7 -7
  38. package/templates/skills/cbp-session-start/qa-regression.md +32 -25
  39. package/templates/skills/cbp-standalone-task-complete/SKILL.md +2 -5
  40. package/templates/skills/cbp-standalone-task-create/SKILL.md +5 -13
  41. package/templates/skills/cbp-standalone-task-start/SKILL.md +10 -10
  42. package/templates/skills/cbp-task-create/SKILL.md +1 -1
  43. package/templates/skills/cbp-task-start/SKILL.md +10 -10
  44. package/templates/skills/cbp-todo/SKILL.md +23 -38
  45. package/templates/skills/cbp-todo/qa-regression.md +21 -27
  46. package/templates/skills/cbp-verify/reference/round-scope.md +1 -2
  47. package/templates/hooks/cbp-mcp-caller-worktree-inject.sh +0 -78
@@ -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
@@ -60,35 +60,25 @@ Skip when the description has zero domain matches OR the user already named a ta
60
60
 
61
61
  Lightweight inference from the description — no deep analysis. **Title**: concise, ≤80 chars. **Goal**: ≤300 chars, a faithful restatement of intent (not a plan).
62
62
 
63
- ### Step 6: Claim-or-Open Prompt
64
-
65
- Ask the user via AskUserQuestion whether to claim this checkpoint now:
66
-
67
- - **Claim for me + this worktree** (default) — resolve `npx codebyplan resolve-worktree 2>/dev/null` and set it as the checkpoint `worktree_id` at create. The creator carries momentum straight through plan → start.
68
- - **Leave it open** — create with `worktree_id` null so anyone free can claim it later via `/cbp-checkpoint-start`.
69
-
70
- Record the choice; it drives both the create call (Step 7) and the plan→start routing in `/cbp-checkpoint-plan`.
71
-
72
- ### Step 7: Create Checkpoint Row
63
+ ### Step 6: Create Checkpoint Row
73
64
 
74
65
  `codebyplan checkpoint create` (CLI write-through: writes `.codebyplan/state/checkpoints/<id>.json` + REST). Pass flags:
75
66
  - `--repo-id` (from `.codebyplan/repo.json`), `--title`, `--goal`, `--deadline`, `--status pending`
76
67
  - `--ideas` JSON `[{ description: <raw user text> }]`
77
- - `--worktree-id` the resolved worktree **only if the user chose "claim"**; omit when "leave open"
78
68
 
79
- Do **not** pass `--number` — the database auto-assigns the next per-repo checkpoint number via a `BEFORE INSERT` trigger (advisory-locked `MAX(number)+1` scoped to `repo_id`). The DB-assigned number comes back on the created row (and is written into `.codebyplan/state/checkpoints/<id>.json`); read it for the branch slug (Step 8) and the result display (Step 9).
69
+ Do **not** pass `--number` — the database auto-assigns the next per-repo checkpoint number via a `BEFORE INSERT` trigger (advisory-locked `MAX(number)+1` scoped to `repo_id`). The DB-assigned number comes back on the created row (and is written into `.codebyplan/state/checkpoints/<id>.json`); read it for the branch slug (Step 7) and the result display (Step 8).
80
70
 
81
71
  Break-glass fallback: MCP `create_checkpoint` (also omit `number`) when the CLI is unavailable.
82
72
 
83
- This is the first identity-stamping point when claiming, passing `worktree_id` here engages the CHK-104 hard-lock from birth. No `context`, `research`, `plan`, or tasks are written here.
73
+ Assignment (`assigned_user_id`) is stamped server-side from the caller's JWT when the checkpoint is activated via `/cbp-checkpoint-start` it is not set at create time. No `context`, `research`, `plan`, or tasks are written here.
84
74
 
85
- ### Step 8: Create + Switch to Feat Branch
75
+ ### Step 7: Create + Switch to Feat Branch
86
76
 
87
- `{NNN}` below is the DB-assigned checkpoint number read back from the Step 7 `codebyplan checkpoint create` response.
77
+ `{NNN}` below is the DB-assigned checkpoint number read back from the Step 6 `codebyplan checkpoint create` response.
88
78
 
89
79
  Read `.codebyplan/git.json` `branch_config.production` (default `"main"`) as `BASE`. codebyplan repos are main-only — never create or branch from a `development`/integration branch.
90
80
 
91
- **8.1 — Reuse the cloud-created branch when present.** When the repo is GitHub-connected, the CHK-207 `create-feat-branch` Edge Function fires on the Step 7 row INSERT, creates `feat/CHK-{NNN}-<slug>` on origin, and writes `branch_name` back to the checkpoint row. Creating a second, differently-slugged branch here orphans the cloud one — so re-read the row first:
81
+ **7.1 — Reuse the cloud-created branch when present.** When the repo is GitHub-connected, the CHK-207 `create-feat-branch` Edge Function fires on the Step 6 row INSERT, creates `feat/CHK-{NNN}-<slug>` on origin, and writes `branch_name` back to the checkpoint row. Creating a second, differently-slugged branch here orphans the cloud one — so re-read the row first:
92
82
 
93
83
  ```bash
94
84
  sleep 5 # give the INSERT webhook a moment to write branch_name back
@@ -96,14 +86,14 @@ npx codebyplan sync 2>/dev/null || true
96
86
  BRANCH=$(jq -r '.branch_name // empty' ".codebyplan/state/checkpoints/{checkpoint-id}.json" 2>/dev/null)
97
87
  ```
98
88
 
99
- (Break-glass: MCP `get_checkpoints` and read the row's `branch_name`.) If `BRANCH` is non-empty, check out the existing remote branch and skip 8.2 entirely — do NOT push (it already exists on origin) and do NOT persist `--branch-name` (the Edge Function already recorded it):
89
+ (Break-glass: MCP `get_checkpoints` and read the row's `branch_name`.) If `BRANCH` is non-empty, check out the existing remote branch and skip 7.2 entirely — do NOT push (it already exists on origin) and do NOT persist `--branch-name` (the Edge Function already recorded it):
100
90
 
101
91
  ```bash
102
92
  git fetch origin "$BRANCH"
103
93
  git checkout -b "$BRANCH" --track "origin/$BRANCH"
104
94
  ```
105
95
 
106
- **8.2 — Fallback: create the branch locally.** Only when `BRANCH` is empty (repo not GitHub-connected, or the webhook hasn't landed). Compute the slug deterministically:
96
+ **7.2 — Fallback: create the branch locally.** Only when `BRANCH` is empty (repo not GitHub-connected, or the webhook hasn't landed). Compute the slug deterministically:
107
97
 
108
98
  ```bash
109
99
  SLUG=$(codebyplan slug "{checkpoint title}")
@@ -122,13 +112,13 @@ Persist the branch via `codebyplan checkpoint update --id <checkpoint-id> --bran
122
112
 
123
113
  **Note — Supabase preview branch**: no Supabase branch is created here. Creation is lazy — it happens on the first DB change when `/cbp-supabase-migrate` runs on this feat branch, which provisions a Supabase branch named identically to the git branch. See `cbp-supabase-migrate` Step 2.3 for the creation protocol.
124
114
 
125
- ### Step 9: Show Result + Auto-Trigger Plan
115
+ ### Step 8: Show Result + Auto-Trigger Plan
126
116
 
127
117
  ```
128
118
  ## Checkpoint Created
129
119
 
130
120
  **CHK-NNN**: [title] • **Deadline**: [date] • **Branch**: feat/CHK-NNN-slug
131
- **Claim**: [claimed by this worktree / left open]
121
+ **Assignment**: stamped on activation via /cbp-checkpoint-start
132
122
  **Worktree**: `npx codebyplan worktree add CHK-{NNN}`
133
123
 
134
124
  Now planning CHK-NNN… handing off to /cbp-checkpoint-plan.
@@ -139,6 +129,6 @@ Auto-trigger `/cbp-checkpoint-plan {NNN}` in the same context. This skill create
139
129
  ## Integration
140
130
 
141
131
  - **Runs inline**: mechanical setup only — no assessment, research, Q&A, plan, or tasks
142
- - **Reads**: `.codebyplan/state/checkpoints/*.json` (local-first; `npx codebyplan sync` if stale; MCP `get_checkpoints` break-glass); `.codebyplan/repo.json`, `.codebyplan/git.json`; `npx codebyplan resolve-worktree`
143
- - **Writes**: `codebyplan checkpoint create` (description-only ideas + deadline + optional worktree_id), `codebyplan checkpoint update --branch-name` (break-glass: MCP `create_checkpoint` / `update_checkpoint`)
132
+ - **Reads**: `.codebyplan/state/checkpoints/*.json` (local-first; `npx codebyplan sync` if stale; MCP `get_checkpoints` break-glass); `.codebyplan/repo.json`, `.codebyplan/git.json`
133
+ - **Writes**: `codebyplan checkpoint create` (description-only ideas + deadline), `codebyplan checkpoint update --branch-name` (break-glass: MCP `create_checkpoint` / `update_checkpoint`)
144
134
  - **Triggers**: `/cbp-checkpoint-plan` (auto)
@@ -265,6 +265,41 @@ After the feat branch git delete, run the same conditional Supabase teardown for
265
265
  - If not found: no-op silently — idempotent, not-found is success.
266
266
  - If the `list_branches` call itself fails (network, auth, or a non-success response — distinct from a successful lookup that returns no match): emit a non-blocking warning that the Supabase preview branch for `$FEAT_BRANCH` may still exist and should be verified in the dashboard. Do not treat an API failure as a not-found success.
267
267
 
268
+ ### Step 9.5: Physical Git-Worktree Cleanup
269
+
270
+ After the feat branch has been git-deleted (Step 9), check whether a git worktree is still
271
+ checked out to that now-deleted branch and clean it up if safe.
272
+
273
+ ```bash
274
+ git worktree list --porcelain
275
+ ```
276
+
277
+ Scan the output for any `worktree` entry whose `branch` field matches `refs/heads/$FEAT_BRANCH`
278
+ (i.e. the feat branch just deleted in Step 9). For each matching worktree path:
279
+
280
+ **Case A — the current session is NOT inside that worktree path:**
281
+
282
+ ```bash
283
+ codebyplan worktree remove <path>
284
+ git worktree prune
285
+ ```
286
+
287
+ Record the removed path in `WORKTREES_REMOVED[]`. If `codebyplan worktree remove` exits
288
+ non-zero, emit a non-blocking warning and continue — a failed removal does not halt shipment.
289
+
290
+ **Case B — the current session IS inside that worktree path (i.e. `$PWD` starts with
291
+ `<path>`):**
292
+
293
+ Do NOT self-remove. Surface a single directive (no A/B/C menu):
294
+
295
+ > "This session is inside the worktree at `<path>`. After switching to your main checkout,
296
+ > run `codebyplan worktree remove <path>` to clean it up."
297
+
298
+ Record the path in `WORKTREES_REMOVED[]` as `{ path, status: 'pending_manual_cleanup' }`.
299
+
300
+ If `git worktree list --porcelain` finds no worktree checked out to the deleted feat branch,
301
+ skip this step silently — `WORKTREES_REMOVED` stays empty.
302
+
268
303
  ### Step 10: Save Shipment Results and Summary
269
304
 
270
305
  Update checkpoint context via `codebyplan checkpoint update <id> --context '{"shipment": {...}}'` (CLI write-through); use MCP `update_checkpoint` as documented break-glass when the CLI is unavailable. The `shipment` block contains both branch promotion AND runtime surface results (from `/cbp-ship` Step 7):
@@ -280,6 +315,7 @@ context.shipment: {
280
315
  stale_branches_cleaned: [list of deleted git branches],
281
316
  feat_branch_deleted: true/false,
282
317
  supabase_branches_deleted: [list of Supabase preview branch names removed in Steps 8–9],
318
+ worktrees_removed: WORKTREES_REMOVED, // from Step 9.5 — paths removed or pending manual cleanup
283
319
  e2e_images_uploaded: E2E_IMAGES_UPLOADED // from Step 7.5 — { count, stored_paths, skipped, error? } (CHK-171)
284
320
  }
285
321
  ```
@@ -310,6 +346,7 @@ Present summary:
310
346
  - Stale branches deleted: [N] ([list])
311
347
  - Feat branch: [deleted/kept]
312
348
  - Supabase preview branches deleted: [N] ([list from supabase_branches_deleted], or "none")
349
+ - Git worktrees cleaned: [N] ([paths from worktrees_removed], or "none")
313
350
 
314
351
  ### Before/After Branch State
315
352
  - Before: [list of feat/* branches]
@@ -8,7 +8,7 @@ effort: xhigh
8
8
 
9
9
  # Checkpoint Plan Command
10
10
 
11
- Runs INLINE (no subagent) — all analysis and Q&A stay in the main session. This is the rigour stage that prevents half-baked plans: it discovers shortcomings, decides whether existing dependencies suffice or a new one is warranted, compares competing approaches, and only THEN creates tasks. It produces `plan.steps[]` + tasks but **never activates the checkpoint and never claims a user/worktree** — that is `/cbp-checkpoint-start`.
11
+ Runs INLINE (no subagent) — all analysis and Q&A stay in the main session. This is the rigour stage that prevents half-baked plans: it discovers shortcomings, decides whether existing dependencies suffice or a new one is warranted, compares competing approaches, and only THEN creates tasks. It produces `plan.steps[]` + tasks but **never activates the checkpoint and never claims a user** — that is `/cbp-checkpoint-start`.
12
12
 
13
13
  ## Pipeline
14
14
 
@@ -37,7 +37,7 @@ Malformed (non-numeric, contains `-`): surface `checkpoint-plan: invalid argumen
37
37
  2. Read task files under `.codebyplan/state/checkpoints/<id>/tasks/*.json` (fallback: MCP `get_tasks(checkpoint_id)`) — load existing tasks. This sets the mode:
38
38
  - **fresh** — zero tasks: full plan + create all tasks.
39
39
  - **additive re-plan** — tasks exist: gap-analyse against them; only ADD new tasks or refine requirements for gaps. NEVER delete or overwrite an in-flight task.
40
- 3. Note whether `worktree_id` is set (claimed at create) — drives routing in Step 11.
40
+ 3. Note whether `assigned_user_id` is set (claimed at activation) — drives routing in Step 11.
41
41
 
42
42
  ### Step 2: Assess Ideas + Codebase
43
43
 
@@ -134,16 +134,18 @@ Final write of the complete `checkpoint.context` JSONB via `codebyplan checkpoin
134
134
  ...
135
135
  ```
136
136
 
137
- This skill does **NOT** activate the checkpoint and does **NOT** claim a user/worktree.
137
+ This skill does **NOT** activate the checkpoint and does **NOT** claim a user.
138
138
 
139
- - **Claimed by THIS session** — `worktree_id` is set AND equals `npx codebyplan resolve-worktree 2>/dev/null`: auto-trigger `/cbp-checkpoint-start` in the same context (the creator carries momentum into activation).
140
- - **Otherwise** — `worktree_id` is null, set to a different worktree, or `resolve-worktree` is empty: surface a single directive — `Next: /cbp-checkpoint-start` — so the owning session (or anyone free, if open) claims and starts it. Never auto-activate a checkpoint owned by a different worktree.
139
+ Resolve the current user: `npx codebyplan whoami --json` `user_id`.
140
+
141
+ - **Open or yours** — `whoami` returns a `user_id` AND `assigned_user_id` is either null (unclaimed) or equals caller `user_id`: auto-trigger `/cbp-checkpoint-start` in the same context. `assigned_user_id` is stamped on activation, so a freshly-created checkpoint (null) is claimed by `/cbp-checkpoint-start` itself — the creator carries momentum into activation.
142
+ - **Owned by another, or no identity** — `assigned_user_id` is non-null and differs from caller `user_id`, or `whoami` returns no `user_id`: surface a single directive — `Next: /cbp-checkpoint-start` — so the owning session (or anyone free, if open) claims and starts it. Never auto-activate a checkpoint owned by a different user.
141
143
 
142
144
  ## Integration
143
145
 
144
- - **Reads**: `.codebyplan/state/checkpoints/<id>.json`, `checkpoints/<id>/tasks/*.json`, `session/current.json` (local-first; `npx codebyplan sync` if stale; break-glass: MCP `get_current_task`, `get_checkpoints`, `get_tasks`)
146
+ - **Reads**: `.codebyplan/state/checkpoints/<id>.json`, `checkpoints/<id>/tasks/*.json`, `session/current.json` (local-first; `npx codebyplan sync` if stale; break-glass: MCP `get_current_task`, `get_checkpoints`, `get_tasks`); `npx codebyplan whoami --json`
145
147
  - **Writes**: `codebyplan checkpoint update` (ideas assessment, context, plan, research), `codebyplan task create` (break-glass: MCP `update_checkpoint`, `create_task`)
146
148
  - **Spawns**: `cbp-research` (level 2+ only), config-matched `cbp-e2e-*` specialist (opt-in discovery probe, `whole_checkpoint_mode` — see `context/testing/e2e.md` dispatch contract)
147
149
  - **Triggered by**: `/cbp-checkpoint-create` (auto), or user directly
148
- - **Triggers**: `/cbp-checkpoint-start` (auto when claimed at create; directive when left open)
149
- - **Never**: activates the checkpoint or claims a user/worktree — that is `/cbp-checkpoint-start`
150
+ - **Triggers**: `/cbp-checkpoint-start` (auto when open/unclaimed or assigned to the current user; directive when owned by another or no identity)
151
+ - **Never**: activates the checkpoint or claims a user — that is `/cbp-checkpoint-start`
@@ -8,7 +8,7 @@ effort: high
8
8
 
9
9
  # Checkpoint Start Command
10
10
 
11
- The activation + claim gate of the checkpoint pipeline. `/cbp-checkpoint-plan` produces tasks but deliberately leaves the checkpoint `pending` and possibly unclaimed so it can sit in a team queue. This skill flips it to `active`, claims it for the caller's worktree if still open, and routes into the first task.
11
+ The activation + claim gate of the checkpoint pipeline. `/cbp-checkpoint-plan` produces tasks but deliberately leaves the checkpoint `pending` and unclaimed so it can sit in a team queue. This skill flips it to `active` the server auto-stamps `assigned_user_id` from the caller's JWT on activation and routes into the first task.
12
12
 
13
13
  ## Pipeline
14
14
 
@@ -20,7 +20,13 @@ The activation + claim gate of the checkpoint pipeline. `/cbp-checkpoint-plan` p
20
20
 
21
21
  ### Step 0: Parse `$ARGUMENTS`
22
22
 
23
- Source `repo_id` from `.codebyplan/repo.json`. Resolve caller worktree once for the whole skill: `CALLER_WT=$(npx codebyplan resolve-worktree 2>/dev/null)`.
23
+ Source `repo_id` from `.codebyplan/repo.json`. Resolve the current user once for the whole skill:
24
+
25
+ ```bash
26
+ npx codebyplan whoami --json # → {"user_id":"<uuid>","email":"…"} or null
27
+ ```
28
+
29
+ `USER_ID` = `user_id` from the result (may be null for anonymous/keychain-empty callers).
24
30
 
25
31
  | Shape | Resolves to |
26
32
  |-------|-------------|
@@ -31,55 +37,57 @@ Malformed (non-numeric, contains `-`): surface `checkpoint-start: invalid argume
31
37
 
32
38
  ### Step 1: Load Checkpoint + Tasks
33
39
 
34
- Read `.codebyplan/state/checkpoints/<id>.json` for `status`, `worktree_id`, `plan` (local-first; if missing/stale run `npx codebyplan sync` once; break-glass: MCP `get_checkpoints`). Read task files under `.codebyplan/state/checkpoints/<id>/tasks/*.json` (fallback: MCP `get_tasks(checkpoint_id)`).
40
+ Read `.codebyplan/state/checkpoints/<id>.json` for `status`, `assigned_user_id`, `plan` (local-first; if missing/stale run `npx codebyplan sync` once; break-glass: MCP `get_checkpoints`). Read task files under `.codebyplan/state/checkpoints/<id>/tasks/*.json` (fallback: MCP `get_tasks(checkpoint_id)`).
35
41
 
36
42
  ### Step 2: Planned-Gate
37
43
 
38
44
  A checkpoint must be planned before it can start.
39
45
 
40
- - **No tasks AND empty `plan.steps[]`** → refuse: surface `CHK-NNN is not planned yet.` and auto-trigger `/cbp-checkpoint-plan {NNN}`. STOP. (An unplanned checkpoint is `worktree_id`-null, so there is nothing to own yet — always kick off planning, matching `/cbp-todo` Rule A.)
46
+ - **No tasks AND empty `plan.steps[]`** → refuse: surface `CHK-NNN is not planned yet.` and auto-trigger `/cbp-checkpoint-plan {NNN}`. STOP. (An unplanned checkpoint is unassigned, so there is nothing to own yet — always kick off planning, matching `/cbp-todo` Rule A.)
41
47
  - **Already `active`** → no activation needed; skip to Step 3 for a claim-check only, then Step 5.
42
48
  - **`pending` with tasks** → proceed.
43
49
 
44
50
  ### Step 3: Claim Logic
45
51
 
46
- Compare the checkpoint's `worktree_id` against `CALLER_WT`:
52
+ Compare the checkpoint's `assigned_user_id` against `USER_ID`:
47
53
 
48
- | Checkpoint `worktree_id` | Action |
49
- |--------------------------|--------|
50
- | null (left open at create) | Claim it: in Step 4 pass `worktree_id: CALLER_WT`. If `CALLER_WT` is empty, warn the checkpoint will stay unclaimed and proceed without it. |
51
- | equals `CALLER_WT` | Already yours — no-op. |
52
- | a DIFFERENT worktree | STOP. Surface: `CHK-NNN is claimed by worktree {other}; current worktree is {CALLER_WT}. If {other} is dead, a maintainer can release it via the release_assignment MCP tool, then re-run /cbp-checkpoint-start.` Do not activate. |
54
+ | Checkpoint `assigned_user_id` | Action |
55
+ |-------------------------------|--------|
56
+ | null (open not yet claimed) | Proceed to Step 4 activation. The server will stamp `assigned_user_id = USER_ID` (from JWT) on `status=active`. If `USER_ID` is null (anonymous caller), warn the checkpoint will stay unclaimed and proceed. |
57
+ | equals `USER_ID` | Already yours — no-op. Proceed to Step 5. |
58
+ | a DIFFERENT user (non-null) | STOP. Surface: `CHK-NNN is assigned to user <assigned_user_id-email-or-uuid>; you are <USER_ID-email-or-uuid>. Ask the owner to release the assignment, or a maintainer can use the release_assignment tool, then re-run /cbp-checkpoint-start.` Do not activate. |
53
59
 
54
- This mirrors the CHK-104 hard-lock model — never wrest a checkpoint from a live worktree.
60
+ Never wrest a checkpoint from another user.
55
61
 
56
62
  ### Step 4: Activate
57
63
 
58
- If the checkpoint is already `active` AND `worktree_id` already equals `CALLER_WT` (the Step 3 no-op row), skip this step entirely and proceed to Step 5 — nothing to write.
64
+ If the checkpoint is already `active` AND `assigned_user_id` already equals `USER_ID` (the Step 3 no-op row), skip this step entirely and proceed to Step 5 — nothing to write.
65
+
66
+ Otherwise set the checkpoint `active` via `codebyplan checkpoint update --id <checkpoint-id> --status active` (CLI write-through; break-glass: MCP `update_checkpoint`). The server auto-stamps `assigned_user_id = ctx.userId` (from the JWT) on activation — no client-side user param required. After the write, read the row back to confirm `assigned_user_id` is non-null.
59
67
 
60
- Otherwise set the checkpoint `active` via `codebyplan checkpoint update --id <checkpoint-id> --status active` (CLI write-through; break-glass: MCP `update_checkpoint`), plus `--worktree-id CALLER_WT` when claiming per Step 3. For MCP break-glass path: `caller_worktree_id` identifies the calling worktree and 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. If the checkpoint was already `active` but a claim is still needed, skip the status write and only write `worktree_id`.
68
+ If the checkpoint was already `active` but `assigned_user_id` is still null (edge case: prior activation without a valid JWT), re-read and surface a warning rather than silently proceeding.
61
69
 
62
70
  ### Step 5: Route
63
71
 
64
72
  Follow the close-out routing convention — auto-trigger the next same-context step, never an A/B/C menu. `{first-pending-task}` is the lowest-numbered pending task from Step 1 (not necessarily TASK-1, since additive re-planning may have completed earlier ones):
65
73
 
66
- - **Claimed by THIS session** (`CALLER_WT` now owns the checkpoint): auto-trigger `/cbp-task-start {chk}-{first-pending-task}` in the same context.
67
- - **`CALLER_WT` empty / unresolved**: surface a single directive — `Next: /cbp-task-start {chk}-{first-pending-task}` — and let the user proceed.
74
+ - **Claimed by THIS session** (`USER_ID` is non-null and now owns the checkpoint): auto-trigger `/cbp-task-start {chk}-{first-pending-task}` in the same context.
75
+ - **`USER_ID` null / anonymous**: surface a single directive — `Next: /cbp-task-start {chk}-{first-pending-task}` — and let the user proceed.
68
76
 
69
77
  Show a one-line confirmation before routing:
70
78
 
71
79
  ```
72
80
  ## Checkpoint Started
73
81
 
74
- **CHK-NNN**: [title] • **Status**: active • **Claimed by**: [worktree or "open"]
82
+ **CHK-NNN**: [title] • **Status**: active • **Claimed by**: [user email or "open"]
75
83
  **Next task**: TASK-[N] — [title]
76
84
  **Worktree**: `npx codebyplan worktree add CHK-{NNN}`
77
85
  ```
78
86
 
79
87
  ## Integration
80
88
 
81
- - **Reads**: `.codebyplan/state/checkpoints/<id>.json`, `checkpoints/<id>/tasks/*.json` (local-first; `npx codebyplan sync` if stale; break-glass: MCP `get_checkpoints`, `get_tasks`); `npx codebyplan resolve-worktree`
82
- - **Writes**: `codebyplan checkpoint update --status active [--worktree-id <id>]` (CLI write-through; break-glass: MCP `update_checkpoint`; `caller_worktree_id` auto-injected by cbp-mcp-caller-worktree-inject.sh hook on the MCP path)
83
- - **Triggered by**: `/cbp-checkpoint-plan` (auto when claimed at create), `/cbp-todo` (planned-but-pending gate), or user directly
89
+ - **Reads**: `.codebyplan/state/checkpoints/<id>.json`, `checkpoints/<id>/tasks/*.json` (local-first; `npx codebyplan sync` if stale; break-glass: MCP `get_checkpoints`, `get_tasks`); `npx codebyplan whoami --json`
90
+ - **Writes**: `codebyplan checkpoint update --status active` (CLI write-through; break-glass: MCP `update_checkpoint`; server auto-stamps `assigned_user_id` from JWT on activation)
91
+ - **Triggered by**: `/cbp-checkpoint-plan` (auto when open/unclaimed or assigned to the current user), `/cbp-todo` (planned-but-pending gate), or user directly
84
92
  - **Triggers**: `/cbp-task-start` (auto when claimed), or `/cbp-checkpoint-plan` (when the checkpoint is unplanned)
85
93
  - **Never**: plans or creates tasks — that is `/cbp-checkpoint-plan`
@@ -43,7 +43,7 @@ Given the parse from Step 0.5:
43
43
  | Parse | Resolution path |
44
44
  |-------|-----------------|
45
45
  | `{chk}` | Scan `.codebyplan/state/checkpoints/*.json` for `number === {chk}` (local-first; if missing/stale run `npx codebyplan sync` once; break-glass: MCP `get_checkpoints`). |
46
- | _(empty)_ | Read `.codebyplan/state/session/current.json` (with worktree_id from `npx codebyplan resolve-worktree`) to find the active checkpoint (fallback: MCP `get_current_task`). If no active checkpoint, scan local state for `pending` checkpoints (fallback: MCP `get_checkpoints` filtered by `pending`). |
46
+ | _(empty)_ | Read `.codebyplan/state/session/current.json` to find the active checkpoint (fallback: MCP `get_current_task`). If no active checkpoint, scan local state for `pending` checkpoints (fallback: MCP `get_checkpoints` filtered by `pending`). |
47
47
 
48
48
  ### Step 1.5: Detect Entry Context (from `/cbp-finalize` expand path)
49
49
 
@@ -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).
@@ -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
@@ -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
 
@@ -25,7 +25,7 @@ Set `KIND` for the rest of this skill. MCP tool names vary by KIND:
25
25
  | Get task | local state (break-glass: `get_current_task`) | `get_current_standalone_task(repo_id)` |
26
26
  | Get rounds | local state (break-glass: `get_rounds`) | `get_standalone_rounds(standalone_task_id)` |
27
27
  | Update round | `update_round(round_id, ...)` | `update_standalone_round(standalone_round_id, ...)` |
28
- | Complete round | `complete_round(round_id, duration_minutes?)` | `complete_standalone_round(standalone_round_id, duration_minutes?, caller_worktree_id)` ⚠️ `caller_worktree_id` is REQUIRED for standalone |
28
+ | Complete round | `complete_round(round_id, duration_minutes?)` | `complete_standalone_round(standalone_round_id, duration_minutes?)` |
29
29
 
30
30
  # Round Complete Command
31
31
 
@@ -84,20 +84,7 @@ Reconcile which files the user has approved by staging them. Run:
84
84
  npx codebyplan round sync-approvals --round-id <round_id> --task-id <task_id>
85
85
  ```
86
86
 
87
- The CLI auto-resolves the caller worktree id with the following precedence:
88
- 1. `--caller-worktree-id <uuid>` override (if passed — skips all resolution)
89
- 2. Per-device branch-keyed cache (`.codebyplan/worktree.local.json`)
90
- 3. In-process tuple API call: `POST /worktrees/resolve` using `(device_id, repo_path, branch)`
91
-
92
- On the write path (non `--dry-run`), if the worktree id cannot be resolved the CLI **hard-fails with exit 1** and prints an actionable message. To pre-populate the cache:
93
-
94
- ```
95
- npx codebyplan resolve-worktree --cache
96
- ```
97
-
98
- If this worktree is not yet registered, run `npx codebyplan setup` first, then re-run `/cbp-round-complete`.
99
-
100
- The CLI parses `git status --short`, merges drift + staging + web-UI flag, and writes both round and task (forwarding `caller_worktree_id` on both writes so the server honors the feat-worktree lock). A **cleanly staged** file (`git add`-ed, no further unstaged changes) becomes `user_approved: true`.
87
+ The CLI parses `git status --short`, merges drift + staging + web-UI flag, and writes both round and task. A **cleanly staged** file (`git add`-ed, no further unstaged changes) becomes `user_approved: true`.
101
88
 
102
89
  Read the stdout JSON: `{ added, stale_marked, reactivated, total_files }`.
103
90
 
@@ -110,14 +97,7 @@ This is the **single** explicit reconcile owned by this skill. (The `cbp-mcp-rou
110
97
  Calculate duration from the round's `started_at` to now in minutes.
111
98
 
112
99
  - **checkpoint KIND**: `codebyplan round complete --id <round_id> --task-id <task_id> --checkpoint-id <checkpoint_id>` (CLI write-through: local state file + REST). Break-glass fallback: MCP `complete_round(round_id, duration_minutes)` when the CLI is unavailable. Note: the CLI does not accept `duration_minutes`; the backend computes duration server-side.
113
- - **standalone KIND**: MCP `complete_standalone_round(standalone_round_id, duration_minutes, caller_worktree_id)`. ⚠️ `caller_worktree_id` is REQUIRED resolve via `CALLER_WT=$(npx codebyplan resolve-worktree 2>/dev/null)`. If `CALLER_WT` is empty, surface this warning and ask the user to confirm before proceeding:
114
-
115
- ```
116
- Warning: could not resolve caller_worktree_id (npx codebyplan resolve-worktree returned empty).
117
- The complete_standalone_round call may be rejected by the pre-guard. Proceed anyway? (yes / no)
118
- ```
119
-
120
- If the user confirms yes, proceed with `caller_worktree_id: ""`. If no, stop.
100
+ - **standalone KIND**: MCP `complete_standalone_round(standalone_round_id, duration_minutes)`. The server keys on the JWT user (`ctx.userId`) no worktree param needed or accepted.
121
101
 
122
102
  `complete_round` / `complete_standalone_round` sets the round `completed`, locks all `file_changes` for the round (`approval_locked: true`), and returns `unapproved_files[]` + `unapproved_count`. Hold those for routing.
123
103
 
@@ -158,7 +138,6 @@ Payload: `round.context.round_complete = { staged_count, unstaged_count, route,
158
138
  - **Permission prompt = confirmation** — gated by `ask`-tier `Skill(cbp-round-complete)`. Because the skill is `disable-model-invocation: true`, this gate applies to the user's **direct** `/cbp-round-complete` invocation. NEVER add an AskUserQuestion to confirm running; the harness prompt is the gate. A declined permission is a clean no-op.
159
139
  - **Step 2 (CLI) must exit 0** — if it fails, STOP before `complete_round`. The merge semantics are enforced by the CLI.
160
140
  - **NEVER ask the user to git add files** — Step 2 only reads staging status. **NEVER stage files** — Claude does not touch the git staging area; the user's `git add` is the approval signal.
161
- - **standalone KIND Step 3**: `caller_worktree_id` is REQUIRED for `complete_standalone_round` — always resolve and pass it.
162
141
 
163
142
  ## Integration
164
143
 
@@ -25,7 +25,7 @@ Set `KIND` for the rest of this skill. Read/write sources vary by KIND:
25
25
  | Get rounds | local state (break-glass: `get_rounds`) | `get_standalone_rounds(standalone_task_id)` |
26
26
  | Add round | `codebyplan round add` (break-glass: `add_round`) | `add_standalone_round(standalone_task_id, ...)` |
27
27
  | Update round | `codebyplan round update` (break-glass: `update_round`) | `update_standalone_round(standalone_round_id, ...)` |
28
- | Complete round | `complete_round(round_id, duration_minutes?)` | `complete_standalone_round(standalone_round_id, duration_minutes?, caller_worktree_id)` ⚠️ `caller_worktree_id` is REQUIRED for standalone |
28
+ | Complete round | `complete_round(round_id, duration_minutes?)` | `complete_standalone_round(standalone_round_id, duration_minutes?)` |
29
29
  | Update task | `codebyplan task update` (break-glass: `update_task`) | `update_standalone_task(standalone_task_id, ...)` |
30
30
 
31
31
  > **Note**: The `standalone` KIND column uses MCP tools unchanged — standalone local-first migration is out of scope and will be addressed in a later task.
@@ -22,35 +22,46 @@ Always write a session log for this session — **even if empty**. `/cbp-session
22
22
  2. Pull facts from local state files rather than narrating from memory:
23
23
  - Rounds added/completed, tasks advanced/completed during this session (read from `.codebyplan/state/checkpoints/` subtree)
24
24
  - Decisions, blockers, or discoveries recorded in checkpoint/task context
25
-
26
- ### Step 1.3: Capture Handoff Snapshot
27
-
28
- Snapshot the current next-action so the next `/cbp-session-start` (Step 4.5) can auto-resume. The handoff write-path + payload shape are specified inline here and in `/cbp-session-start` Step 4.5 (freshness gate).
29
-
30
- 1. Read `.codebyplan/state/todos.json` (local-first) and take the queue head `rows[0]` (rows are ordered by `sort_order`; `rows[0]` is the current next-action). If missing/stale, run `npx codebyplan sync` once and re-read. Break-glass fallback: MCP `get_todos({ repo_id, worktree_id })` when the state dir is absent and sync fails. The worker stamps `command`, `instructions`, `state`, and the entity ids `checkpoint_id` / `task_id` / `round_id` on every row.
31
- 2. If `rows[0]` exists and its `command` is non-empty (active work in flight):
32
- ```yaml
33
- handoff:
34
- command: <rows[0].command> # e.g. "/cbp-verify"
35
- instructions: <rows[0].instructions> # human-readable trigger reason
36
- state: <rows[0].state> # workflow state label
37
- context: # entity ids used by the Step 4.5 freshness probe
38
- checkpoint_id: <rows[0].checkpoint_id>
39
- task_id: <rows[0].task_id>
40
- round_id: <rows[0].round_id>
41
- captured_at: <ISO now> # for entity-drift freshness comparison
42
- captured_session_log_id: <current session log id>
43
- ```
44
- 3. If the queue is empty or `rows[0].command` is empty / idle: set `handoff = null` so the next session's probe falls through to `/cbp-todo`.
45
- 4. Hold `handoff` in context for Step 1's `update_session_log` call below — it ships in the same write as `ended_at` and `summary`.
46
-
47
- Continuing Step 1:
48
-
49
- 3. Run `codebyplan session update-log --id <log-id> --ended-at <now> --summary <text> --pending <text> --handoff <json>` (CLI write-through: updates `.codebyplan/state/session/current.json` + REST). Break-glass fallback: MCP `update_session_log` when the CLI is unavailable. Fields:
25
+ 3. Run `codebyplan session update-log --id <log-id> --ended-at <now> --summary <text> --pending <text> --git-branch <current-branch>` (CLI write-through: updates `.codebyplan/state/session/current.json` + REST). Break-glass fallback: MCP `update_session_log` when the CLI is unavailable. Fields:
50
26
  - `ended_at`: now (maps to the `closed_at` column per TASK-2 alias)
51
- - `handoff`: from Step 1.3 (jsonb or `null`; MCP write surface aliases to the `content` column transparently per CHK-111 Migration A — `handoff` wins over `content` when both are passed)
52
27
  - `summary`: concise — may be empty if nothing happened
53
28
  - `pending`: open items the next session should see first
29
+ - `git_branch`: the current git branch (informational; `git rev-parse --abbrev-ref HEAD`)
30
+ - **Do NOT pass `--handoff` / `handoff` field.** The DB handoff field is no longer written here. Omit entirely — never pass `handoff:null` (it clobbers summary/pending content).
31
+
32
+ ### Step 1.3: Optional Handoff File (mid-work only)
33
+
34
+ When an active in-progress task or round exists, offer to write a handoff file so the next session can auto-resume. Skip entirely when not mid-work.
35
+
36
+ 1. Read `.codebyplan/state/todos.json` (local-first) and check `rows[0]` (queue head, ordered by `sort_order`). If missing/stale, run `npx codebyplan sync` once and re-read. Break-glass fallback: MCP `get_todos({ repo_id })` when the state dir is absent and sync fails. The worker stamps `command`, `instructions`, `state`, and entity ids `checkpoint_id` / `task_id` / `round_id` on every row.
37
+
38
+ 2. **If `rows[0]` exists and its `command` is non-empty** (active work in flight):
39
+ - Determine the handoff file path. The directory is keyed by the human-facing **number** (`<NNN>` checkpoint number / `<N>` standalone task number) — matching the committed `.codebyplan/checkpoint/<NNN>/` plan-artifact convention and the session-start resume probe (which globs by number). Resolve the number from local state (break-glass: MCP):
40
+ - Checkpoint work: read `.codebyplan/state/checkpoints/<rows[0].checkpoint_id>.json` → `number` (break-glass: MCP `get_checkpoints`). Path: `.codebyplan/checkpoint/<NNN>/handoff.md`.
41
+ - Standalone work: read the standalone task's `number` from local standalone state (break-glass: MCP `get_standalone_tasks`). Path: `.codebyplan/standalone/<N>/handoff.md`.
42
+ - Offer to write the file:
43
+ ```
44
+ Write handoff file for next session?
45
+ <path>
46
+
47
+ Reply: yes | no
48
+ ```
49
+ - On `yes`: write the file with this structure:
50
+ ```markdown
51
+ ---
52
+ command: <rows[0].command>
53
+ state: <rows[0].state>
54
+ captured_at: <ISO now>
55
+ checkpoint_id: <rows[0].checkpoint_id or null>
56
+ task_id: <rows[0].task_id or null>
57
+ round_id: <rows[0].round_id or null>
58
+ ---
59
+
60
+ <rows[0].instructions — human-readable trigger reason>
61
+ ```
62
+ - The file is committed with the session's final commit (Step 1.5) or the user can stage it manually.
63
+
64
+ 3. **If the queue is empty or `rows[0].command` is empty/idle**: skip — no handoff file is written.
54
65
 
55
66
  ### Step 1.5: Commit Non-Task Files
56
67
 
@@ -117,7 +128,7 @@ Stop this worktree's Realtime watch daemon, non-blocking and non-fatal:
117
128
  npx codebyplan watch stop 2>/dev/null || true
118
129
  ```
119
130
 
120
- This SIGTERMs the per-worktree pidfile daemon started by `cbp-session-start-hook.sh`. Silently ignored when no daemon is running for this worktree. If there is no daemon to stop (e.g. session-start was skipped), `watch stop` itself exits 0 — the `|| true` guard is defense-in-depth only, so Step 3's session-state write never sees a failure from this step.
131
+ This SIGTERMs the per-worktree pidfile daemon started by `cbp-session-start-hook.sh`. Silently ignored when no daemon is running. If there is no daemon to stop (e.g. session-start was skipped), `watch stop` itself exits 0 — the `|| true` guard is defense-in-depth only, so Step 3's session-state write never sees a failure from this step.
121
132
 
122
133
  ### Step 3: Update Session State
123
134
 
@@ -134,9 +145,8 @@ You can close this window.
134
145
  ## Integration
135
146
 
136
147
  - **Triggered by**: user invocation (prompted by `/cbp-todo` when no work remains)
137
- - **Reads**: `.codebyplan/repo.json`; local-first reads (with `npx codebyplan sync` + MCP break-glass): `.codebyplan/state/session/current.json` (Step 1 resolve log), `.codebyplan/state/todos.json` (Step 1.3 handoff snapshot + Step 1.5 active-task lookup), `.codebyplan/state/checkpoints/<id>/tasks/<id>/rounds/` (Step 1.5 task-file resolution); `codebyplan session freshness-gate` (Step 1.7 package-freshness gate, without --halt-on-update); `codebyplan session infra-files --json --task-files <csv>` (Step 1.5 infra-file set math)
138
- - **Writes**: `codebyplan session update-log --id <id> ...` (Step 1 finalize — CLI write-through to `.codebyplan/state/session/current.json`; break-glass: MCP `update_session_log`), `codebyplan session create-log` (Step 1 fallback when no log exists; break-glass: MCP `create_session_log`), `codebyplan session update-state --action deactivate` (Step 3 — CLI write-through to `.codebyplan/state/session/state.json`; break-glass: MCP `update_session_state`)
148
+ - **Reads**: `.codebyplan/repo.json`; local-first reads (with `npx codebyplan sync` + MCP break-glass): `.codebyplan/state/session/current.json` (Step 1 resolve log), `.codebyplan/state/todos.json` (Step 1.3 mid-work detection + Step 1.5 active-task lookup), `.codebyplan/state/checkpoints/<id>/tasks/<id>/rounds/` (Step 1.5 task-file resolution); `codebyplan session freshness-gate` (Step 1.7 package-freshness gate, without --halt-on-update); `codebyplan session infra-files --json --task-files <csv>` (Step 1.5 infra-file set math)
149
+ - **Writes**: `codebyplan session update-log --id <id> --git-branch <branch> ...` (Step 1 finalize — CLI write-through to `.codebyplan/state/session/current.json`; break-glass: MCP `update_session_log`; handoff field never passed), `codebyplan session create-log` (Step 1 fallback when no log exists; break-glass: MCP `create_session_log`), optional handoff file at `.codebyplan/checkpoint/<NNN>/handoff.md` or `.codebyplan/standalone/<N>/handoff.md` (Step 1.3, mid-work only), `codebyplan session update-state --action deactivate` (Step 3 — CLI write-through to `.codebyplan/state/session/state.json`; break-glass: MCP `update_session_state`)
139
150
  - **Spawns**: none
140
151
  - **Triggers**: none at the skill-contract level. Step 1.5 may invoke `/cbp-git-commit` inline on user approval; Step 1.7 may invoke `/cbp-git-commit` on the `result === 'updated'` path (committing changed `.claude/` and `.codebyplan/` paths).
141
152
  - **Paired with**: `/cbp-session-start`
142
- - **Pairs with**: `/cbp-session-start` Step 4.5 (handoff payload shape + freshness-gate contract; specified inline — no separate rule file)