@chris1807/claude-kit 2.2.4 → 2.3.1

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/README.md CHANGED
@@ -495,15 +495,18 @@ git checkout main
495
495
  ```
496
496
 
497
497
  Claude will:
498
- 1. Read the work item from Azure DevOps (extracts type, title, acceptance criteria)
499
- 2. **Summarize the work item** and ask you to confirm understanding. You can add context or corrections here
500
- 3. Create a branch automatically (e.g., `story/AB#1234-user-can-view-history`)
498
+ 1. Set up the ticket's own git worktree next to your project (`../your-project-AB1234`). Every later step runs there, so other Claude sessions in the same repo aren't disturbed
499
+ 2. Read the work item from Azure DevOps (extracts type, title, acceptance criteria)
500
+ 3. **Summarize the work item** and ask you to confirm understanding. You can add context or corrections here
501
501
  4. Explore the codebase and **present an implementation plan** showing which files will be created, modified, or deleted
502
502
  5. **Wait for your approval** before writing any code
503
- 6. Implement using backend and/or frontend agents
503
+ 6. Create the branch (e.g., `story/AB#1234-user-can-view-history`) and implement using backend and/or frontend agents
504
504
  7. Run all quality checks (build, lint, tests, review)
505
505
  8. Generate a UAT checklist and **pause for you to manually test**
506
506
  9. After you confirm "testing passed", create a PR targeting `main`, close the child Task with its hours, and move the work item to `Code Review`
507
+ 10. Remove the worktree once the branch is pushed. It's kept, with a note, if anything is uncommitted or unpushed. `/rework` recreates it from the branch
508
+
509
+ Say `/implement AB#1234 work in place` to skip the worktree and work in the current folder, as before.
507
510
 
508
511
  The PR merges into `main`. **That merge deploys nothing** — `main` is the compare branch. The work reaches Dev when `main` is promoted:
509
512
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chris1807/claude-kit",
3
- "version": "2.2.4",
3
+ "version": "2.3.1",
4
4
  "description": "Claude Code starter kit for Azure DevOps teams — agents, hooks, MCP servers, slash commands, and end-to-end work item → PR → release → deploy workflow automation",
5
5
  "type": "module",
6
6
  "bin": {
@@ -10,11 +10,121 @@ This command **can** orchestrate its analysis phases with the `Workflow` tool, b
10
10
  When recommending a default in the Step 2 prompt, suggest **yes** for multi-subsystem / multi-AC work and **no** for trivial changes.
11
11
 
12
12
  The remaining rules apply whenever Ultracode is in use:
13
- - **Never fan out an interactive gate or a write.** Every user prompt (Steps 2, 3-approval, 8-decisions, 9) and every git / work-item mutation (Steps 4, 5, 10) stays in the **main loop**. Workflow agents here are **read-only analysts** — they use MCP read tools, `Read`, and `Grep`, and return structured findings. They do not write code, create/close work items, switch branches, or ask the user anything.
13
+ - **Never fan out an interactive gate or a write.** Every user prompt (Steps 2, 3-approval, 8-decisions, 9) and every git / work-item mutation (Steps 0, 4, 5, 10, 11) stays in the **main loop**. Workflow agents here are **read-only analysts** — they use MCP read tools, `Read`, and `Grep`, and return structured findings. They do not write code, create/close work items, switch branches, or ask the user anything.
14
+ - **Give every Workflow agent the ticket's worktree path** (Step 0) — that is where the code under analysis lives, not the folder the session started in.
14
15
  - **Stay in the loop between phases** — one short workflow per phase, read its results, present/await the user, then continue.
15
16
 
16
17
  If the `Workflow` tool is unavailable, run each phase sequentially in the main loop — the output is identical, just slower.
17
18
 
19
+ ## Step 0: Set Up the Ticket's Workspace
20
+
21
+ Developers run several Claude Code sessions against the same repo at once, one per ticket. If every session `git checkout`s in the folder it started in, they clobber each other's working tree. So each ticket gets its own **git worktree** in a sibling folder, `../{repo}-AB{id}` (e.g. `../CSIPay-AB5373`), and every later step runs there. The folder the session started in is never checked out, committed to, or edited.
22
+
23
+ This step runs **first** — it needs only the ticket id — and before any git or file change. It is setup, not a gate: it prompts only where a case below says so.
24
+
25
+ **Opt-out.** If the user says **"work in place"** or **"no worktree"** — in the invocation (`/implement 1234 work in place`; strip the phrase before reading the id) or at any point before Step 4 — skip this step, skip Step 11, and ignore every worktree note below: the command runs exactly as it did before worktrees, branching in the current folder with `BASE_BRANCH` captured by Step 4's in-place rule. If Step 0 has already run, give back the worktree it made (it has no branch and no changes yet): `git worktree unlock "{WT}"`, then `git worktree remove "{WT}"`, then carry on in place.
26
+
27
+ Shell variables do not survive between Bash calls. Resolve each value once, then write the **literal absolute paths and branch names** into every later command.
28
+
29
+ ### 0a. Resolve the repo and fetch
30
+
31
+ ```bash
32
+ git worktree list --porcelain | sed -n '1s/^worktree //p' # MAIN — the main checkout
33
+ git fetch --prune origin
34
+ git worktree prune
35
+ ```
36
+
37
+ - **`MAIN`** is the first entry of `git worktree list` — the main checkout, even when the session started in a subfolder or inside another ticket's worktree (`--show-toplevel` would return that worktree, and the new one would land at `CSIPay-AB5375-AB5380`).
38
+ - **`REPO`** is `basename` of `MAIN`; **`WT`** is `{dirname of MAIN}/{REPO}-AB{id}` — always the absolute path.
39
+ - **`--prune`** matters: without it a remote branch deleted after its PR merged still looks alive locally, and 0c's "deleted on the remote" check never fires.
40
+ - **`git worktree prune`** forgets worktrees whose folders were deleted by hand, so a stale leftover can be recreated cleanly.
41
+
42
+ ### 0b. Pick `BASE_BRANCH` — the branch this ticket is cut from and its PR targets
43
+
44
+ ```bash
45
+ git symbolic-ref --quiet --short HEAD # CURRENT — empty on a detached HEAD
46
+ ```
47
+
48
+ - **`CURRENT` is empty, or starts with a ticket prefix** — `feature/`, `story/`, `bugfix/`, `hotfix/`, `work/`, `cherry-pick/`, `release/`, `revert/` → **don't use it.** This folder was left on another ticket's branch; cutting from it would put that ticket's commits in this PR and aim the PR at the wrong branch. Use the PR target the project's CLAUDE.md names (e.g. CSIPay: "PRs always target `main`"). If CLAUDE.md doesn't name one, ask:
49
+
50
+ ```
51
+ This folder is on {CURRENT}, another ticket's branch. Which branch should AB#{id}
52
+ be cut from, and its PR target? (suggested: {origin's default branch — `git symbolic-ref --short refs/remotes/origin/HEAD`})
53
+ ```
54
+ - **Otherwise** `BASE_BRANCH` is `CURRENT` — the same rule as before worktrees (start on `prod` for a production hot fix, and so on).
55
+
56
+ `origin/{BASE_BRANCH}` must exist — the worktree is cut from the remote branch, not from the local one, which may be behind or carry unpushed commits. If it doesn't, say so and ask.
57
+
58
+ ### 0c. Tidy other tickets' worktrees
59
+
60
+ Look at every **other** worktree in `git worktree list --porcelain` whose folder is named `{REPO}-AB*`. Never touch `MAIN`, this ticket's `WT`, a worktree on this ticket's branch (`*/AB#{id}-*` — 0d reuses it), or any folder outside that naming pattern.
61
+
62
+ - **Locked → skip it.** A lock means another session is working in it right now; 0d locks every worktree it hands out.
63
+ - **Otherwise remove it only if all three hold:**
64
+ 1. **Nothing uncommitted** — `git -C "{path}" status --porcelain` prints nothing.
65
+ 2. **Nothing unpushed** — its branch has an upstream, and either `git -C "{path}" rev-list --count '@{u}..HEAD'` prints `0`, or the upstream is **gone** (`git -C "{path}" for-each-ref --format='%(upstream:track)' "refs/heads/{branch}"` prints `[gone]` — its PR merged and the remote branch was deleted). For a gone upstream, also confirm nothing was committed after the last push: find the branch's pull request (`repo_pull_request`, by source branch, any status) and check its `lastMergeSourceCommit` equals `git -C "{path}" rev-parse HEAD`. A branch that was **never pushed** (no upstream), a detached HEAD, a HEAD that differs from what the PR merged, or no PR found — all fail this check.
66
+ 3. **Merged, or deleted on the remote** — the upstream is `[gone]`, or `git -C "{MAIN}" merge-base --is-ancestor "{branch}" "origin/{BASE_BRANCH}"` succeeds.
67
+
68
+ Remove with `git -C "{MAIN}" worktree remove "{path}"`, then `git -C "{MAIN}" branch -D "{branch}"`. **Never `--force`, never `rm` the folder.** If a removal fails because another session removed it first, ignore that and move on.
69
+ - **Anything else stays.** List what was kept in one line, with the reason — `Kept: ../CSIPay-AB5301 (2 uncommitted files), ../CSIPay-AB5310 (locked — another session, or abandoned: git worktree unlock "{path}")`.
70
+
71
+ ### 0d. Create or reuse the ticket's worktree
72
+
73
+ Take the first case that matches:
74
+
75
+ 1. **A worktree is already on this ticket's branch** — a `branch refs/heads/*/AB#{id}-*` line in `git worktree list --porcelain` → use that worktree as `WT`, wherever it is (a hand-made folder, or even `MAIN` itself). Don't create a second one, and don't fail because the branch is checked out elsewhere.
76
+ 2. **`WT` is already a worktree** (an earlier run stopped before Step 4 and left it detached) → reuse it.
77
+ 3. **`WT` exists but git doesn't know it** (not in the list even after 0a's prune) → stop and ask the user to delete or rename it. Its contents aren't in git, so there is no way to tell whether anything in it is worth keeping.
78
+ 4. **A local branch `*/AB#{id}-*` exists** but isn't checked out anywhere → `git -C "{MAIN}" worktree add "{WT}" "{branch}"` (this is the old "if the branch already exists, switch to it" rule). If more than one branch matches, list them and ask which.
79
+ 5. **Otherwise** create it **detached** at the base — the branch itself is created in Step 4, after the plan is approved, same as before worktrees:
80
+
81
+ ```bash
82
+ git -C "{MAIN}" worktree add --detach "{WT}" "origin/{BASE_BRANCH}"
83
+ ```
84
+
85
+ Then **lock it** so another session's 0c leaves it alone — a new, clean worktree with no commits would otherwise pass every tidy check:
86
+
87
+ ```bash
88
+ git -C "{MAIN}" worktree lock --reason "AB#{id} — /implement in progress" "{WT}"
89
+ ```
90
+
91
+ Skip the lock when `WT` is `MAIN` (the main checkout can't be locked, and 0c never touches it). If the worktree is **already locked**, another session may still be working this ticket. Say so in one line — `AB#{id}'s worktree is locked ({reason}) — if another session is still on this ticket, both will edit the same files` — and carry on in it.
92
+
93
+ ### 0e. Copy the local files git doesn't carry
94
+
95
+ A new worktree has only tracked files. Copy in `.claude/settings.local.json` (the user's local permission rules) and every gitignored `.env.local` / `*.local.json`. Copy nothing that already exists in the worktree:
96
+
97
+ ```bash
98
+ cd "{MAIN}" && {
99
+ [ -f .claude/settings.local.json ] && echo .claude/settings.local.json
100
+ git ls-files --others --ignored --exclude-standard -- ':(glob)**/.env.local' ':(glob)**/*.local.json' ':(exclude,glob)**/node_modules/**'
101
+ } | sort -u | while IFS= read -r f; do
102
+ [ -e "{WT}/$f" ] || { mkdir -p "{WT}/$(dirname "$f")" && cp "$f" "{WT}/$f"; }
103
+ done
104
+ ```
105
+
106
+ **None of these may ever be committed.** The `.env.local` / `*.local.json` files are gitignored by construction. `.claude/settings.local.json` may not be, so if `git -C "{WT}" check-ignore -q .claude/settings.local.json` fails, append `.claude/settings.local.json` to `{MAIN}/.git/info/exclude`. That file is local and shared by every worktree of the repo, so the exclude covers them all and is itself never committed.
107
+
108
+ `node_modules` is not copied. Step 5 installs it, only when the plan touches the frontend.
109
+
110
+ ### 0f. Work only in the ticket's worktree
111
+
112
+ - **Every later step runs in `WT`** — exploration, implementation, build, tests, lint, commits, review. Claude Code can reset the shell to the session's folder between calls, so run git as `git -C "{WT}" …`, run everything else as `cd "{WT}" && …`, and use absolute paths for `Read`/`Edit`/`Write`.
113
+ - **Pass `WT` to every subagent and Workflow agent**, in so many words: `The code for AB#{id} is in {WT}. Read, edit, build, and test only there — never in {MAIN}.`
114
+ - **Diff against `origin/{BASE_BRANCH}`**, not `{BASE_BRANCH}`, wherever a later step compares with the base. The worktree was cut from the remote branch, and the local one may be behind.
115
+ - **Quote every branch name** — the `#` in `story/AB#5373-…` starts a comment or a glob in some shells.
116
+ - `WT` is outside the folder the session started in, so Claude Code asks before the first edit there. Tell the user once, in the report below.
117
+ - Sessions sharing a repo still share **local ports and the Dev database**. If this ticket's dev server or integration tests collide with another session's, run them one at a time.
118
+
119
+ Report the workspace in one short block, then go on to Step 1:
120
+
121
+ ```
122
+ Workspace for AB#{id}: {WT}
123
+ {new, detached at origin/{BASE_BRANCH} | reused, on {branch}} PR target: {BASE_BRANCH}
124
+ Tidied: {removed worktrees, or "nothing to tidy"} Kept: {kept worktrees + reason, or omit}
125
+ Edits there need approval once — run `/add-dir {WT}` to allow them for this session.
126
+ ```
127
+
18
128
  ## Step 1: Read the Work Item
19
129
 
20
130
  Read the work item from Azure DevOps via MCP. Extract:
@@ -161,7 +271,7 @@ Approve this plan? (yes / no / suggest changes)
161
271
 
162
272
  Only create the branch after the plan is approved.
163
273
 
164
- Capture the current branch as the PR target — do NOT hardcode any branch name:
274
+ Capture the PR target — do NOT hardcode any branch name. **In a worktree** (the default), `BASE_BRANCH` is the branch Step 0b picked. **Working in place**, capture the current branch:
165
275
 
166
276
  ```bash
167
277
  BASE_BRANCH=$(git symbolic-ref --short HEAD)
@@ -181,12 +291,17 @@ Construct the branch name as `{prefix}AB#{id}-{sanitized-title}`:
181
291
  - Sanitize the title: lowercase, replace non-alphanumeric characters (except hyphens) with hyphens, collapse consecutive hyphens, truncate to 50 characters, trim leading/trailing hyphens
182
292
  - Example: Feature AB#1234 "Add Payment History Export" → `feature/AB#1234-add-payment-history-export`
183
293
 
184
- Create and switch to the branch:
294
+ Create and switch to the branch. **In a worktree** — Step 0 left it detached at `origin/{BASE_BRANCH}`, so the branch starts there, with no upstream until Step 10 pushes it:
185
295
  ```bash
186
- git checkout -b <branch-name>
296
+ git -C "{WT}" switch -c "<branch-name>"
187
297
  ```
188
298
 
189
- If the branch already exists, switch to it with `git checkout <branch-name>` instead of failing.
299
+ **Working in place:**
300
+ ```bash
301
+ git checkout -b "<branch-name>"
302
+ ```
303
+
304
+ If the branch already exists, switch to it with `git checkout "<branch-name>"` instead of failing. In a worktree, Step 0d has already put the worktree on an existing branch for this ticket — there is nothing to create.
190
305
 
191
306
  Remember the `BASE_BRANCH` — you will need it for the PR step.
192
307
 
@@ -289,7 +404,9 @@ Remember the Task ID. Step 10 closes it.
289
404
 
290
405
  ## Step 5: Implement
291
406
 
292
- 1. **Implement** using backend and/or frontend agents according to the approved plan
407
+ **In a worktree**, install frontend dependencies first — only if the approved plan touches the frontend. A new worktree has no `node_modules`, so run `npm install` in its client folder (`cd "{WT}/{client folder}" && npm install`). A backend-only plan skips the install; `dotnet build` restores its own packages. Steps 6–7 then skip the uninstalled client folder and report it as `frontend skipped — untouched by this change, not installed in the worktree` rather than failing on it.
408
+
409
+ 1. **Implement** using backend and/or frontend agents according to the approved plan — each agent is told to work only in `WT` (Step 0f)
293
410
  2. **Write the unit tests** listed in the plan's "Unit Tests" section alongside the implementation — not after
294
411
  3. **Generate mockup** if there are UI changes
295
412
 
@@ -387,7 +504,7 @@ Wait for the user's response before proceeding. Do NOT create a PR until confirm
387
504
 
388
505
  ## Step 10: Push, Create PR, and Update Work Item
389
506
 
390
- 1. Push the branch: `git push -u origin HEAD`
507
+ 1. Push the branch: `git push -u origin HEAD` (in a worktree: `git -C "{WT}" push -u origin HEAD`)
391
508
  2. Create a PR via Azure DevOps MCP:
392
509
  - **sourceRefName**: `refs/heads/{branch-name}`
393
510
  - **targetRefName**: `refs/heads/{BASE_BRANCH}` (the branch captured in Step 4)
@@ -401,6 +518,7 @@ Wait for the user's response before proceeding. Do NOT create a PR until confirm
401
518
  - **value**: `Code Review`
402
519
 
403
520
  If the project's process template does not have a `Code Review` state (the update call returns an invalid-state error), fall back in this order: `Resolved` → `In Review` → leave the current state and warn the user that the state could not be advanced automatically. Do not silently swallow the error.
521
+ 7. **Remove the ticket's worktree** — Step 11, once everything above is done.
404
522
 
405
523
  > **Only the Task ever gets closed — never the parent.** The child Task is closed here, at PR creation (step 5 above). When the PR is later completed/merged, do **not** enable Azure DevOps's "Complete associated work items" option: it transitions *every* linked work item, including the parent this PR is linked to. The parent User Story or Bug stays in `Code Review`: merging this PR into `main` deploys nothing, and promoting to `dev` deploys the code but **leaves the state alone** — the developer moves it to `Ready for Testing` once they have checked it on Dev. From there `/promote` and `/deploy-release` advance it to `Testing` → `Staging` → `Deployed` across `test → staging → prod` (see **Work Item States ↔ Environments** in CLAUDE.md).
406
524
 
@@ -479,6 +597,33 @@ Confirm with a summary line per task: `Closed AB#xxxx — {hours}h logged (estim
479
597
 
480
598
  **The Task closes now, at PR creation — not at merge.** The work is done and the hours are known; waiting until merge means the hours get logged days later, or not at all.
481
599
 
600
+ ## Step 11: Remove the Ticket's Worktree
601
+
602
+ Skip this step when working in place.
603
+
604
+ This runs **last**: after the PR exists and every Step 10 prompt, the Task-closing ones included, is answered. A failed push therefore never loses work, and the attachment and diff steps still have the worktree to read from. The branch is safe on origin now, and `/rework AB#{id}` recreates the worktree from it.
605
+
606
+ 1. **Unlock it** — this session is done with it: `git -C "{MAIN}" worktree unlock "{WT}"`. Unlock even if step 3 ends up keeping it, so a later Step 0c can tidy it once it's clean, pushed, and merged.
607
+ 2. **Check it's safe to remove:**
608
+
609
+ ```bash
610
+ git -C "{WT}" status --porcelain # must print nothing
611
+ git -C "{WT}" rev-list --count '@{u}..HEAD' # must print 0
612
+ ```
613
+ 3. **Both pass** → remove the worktree, then the local branch:
614
+
615
+ ```bash
616
+ git -C "{MAIN}" worktree remove "{WT}"
617
+ git -C "{MAIN}" branch -D "{branch}"
618
+ ```
619
+
620
+ Report: `Removed {WT} and local branch {branch} — the branch is on origin; /rework AB#{id} brings it back.`
621
+
622
+ **Either fails** → keep it, and say exactly what's left: the `git -C "{WT}" status --short` lines, or the unpushed commits (`git -C "{WT}" log --oneline '@{u}..HEAD'`). **Never `--force`, never `rm` the folder.**
623
+ 4. **Never remove a worktree the session is standing in.**
624
+ - If the folder this session started in is `WT` or inside it, don't remove it — that would pull the folder out from under the session. Print the command for the user to run from another folder instead: `git -C "{MAIN}" worktree remove "{WT}" && git -C "{MAIN}" branch -D "{branch}"`.
625
+ - If `WT` is `MAIN` (Step 0d reused a branch already checked out there), there is nothing to remove.
626
+
482
627
  ## Feature Workflow (ordered story waves)
483
628
 
484
629
  Used when the work item passed to `/implement` is a **Feature**. The Feature's child User Stories are implemented in **waves** driven by the custom order field (`Custom.Order`): all stories sharing the same order value run **in parallel** (one implementation agent each), and waves run sequentially in ascending order — wave 2 starts only after wave 1 is merged, built, and green, so later stories can build on earlier ones.
@@ -526,7 +671,7 @@ Include the Step 2 reasoning-effort recommendation (a multi-story Feature is alm
526
671
 
527
672
  ### F3: Create the Feature Branch
528
673
 
529
- Capture `BASE_BRANCH` and create `feature/AB#{feature-id}-{sanitized-title}` per Step 4 rules. All story work merges into this branch; the single PR in F7 targets `BASE_BRANCH`.
674
+ Capture `BASE_BRANCH` and create `feature/AB#{feature-id}-{sanitized-title}` per Step 4 rules. Step 0 ran with the **Feature's** id, so the Feature has its own ticket worktree, `../{repo}-AB{feature-id}`, and the feature branch is created there. All story work merges into this branch; the single PR in F7 targets `BASE_BRANCH`.
530
675
 
531
676
  ### F4: Execute Waves
532
677
 
@@ -547,16 +692,16 @@ For each wave in ascending order:
547
692
 
548
693
  Create these? (yes / edit N / skip N / skip all)
549
694
  ```
550
- - **Single-story wave** → implement directly on the feature branch in the main loop (Step 5).
551
- - **Multi-story wave** → isolate each story in its own worktree so parallel agents never clobber each other:
695
+ - **Single-story wave** → implement directly on the feature branch, in the Feature's worktree, in the main loop (Step 5).
696
+ - **Multi-story wave** → isolate each story in its own worktree so parallel agents never clobber each other. These branch from the feature worktree's branch and live in the scratchpad, not beside the repo, so Step 0c's tidy never touches them:
552
697
 
553
698
  ```bash
554
- git worktree add "{scratchpad}/wt-{story-id}" -b "story/AB#{story-id}-{sanitized-title}" "{feature-branch}"
699
+ git -C "{WT}" worktree add "{scratchpad}/wt-{story-id}" -b "story/AB#{story-id}-{sanitized-title}" "{feature-branch}"
555
700
  ```
556
701
 
557
702
  Launch **one implementation agent per story, all in a single message** so they run concurrently (`backend`/`frontend`/`general-purpose` per the approved plan; if a story needs both backend and frontend work, give one agent the whole story rather than splitting it). Each agent's prompt must include: the approved plan for its story, the story's full AC, its worktree path, and these rules — work **only** inside your worktree, implement the plan plus its unit tests, run the tests you added, commit to the story branch, and report what you changed. Agents never push, never create PRs, never touch work items, and never ask the user anything.
558
- - **Merge back (main loop):** merge each story branch into the feature branch (`git merge --no-ff`), resolving conflicts yourself using both stories' plans as the guide. Then `git worktree remove` and delete the story branch. Merge in `Custom.Order`-then-ID order so conflict resolution is deterministic.
559
- 3. **Wave gate:** run Step 6 (build validation) and Step 7.1–7.2 (full test suite + lint) on the merged feature branch. Fix failures before starting the next wave — the next wave branches from this merged, green state.
703
+ - **Merge back (main loop):** merge each story branch into the feature branch in the Feature's worktree (`git -C "{WT}" merge --no-ff "story/…"`), resolving conflicts yourself using both stories' plans as the guide. Then `git worktree remove` and delete the story branch. Merge in `Custom.Order`-then-ID order so conflict resolution is deterministic.
704
+ 3. **Wave gate:** run Step 6 (build validation) and Step 7.1–7.2 (full test suite + lint) on the merged feature branch, in the Feature's worktree. Fix failures before starting the next wave — the next wave branches from this merged, green state.
560
705
 
561
706
  ### F5: Feature-Level Quality and Review
562
707
 
@@ -578,3 +723,7 @@ Present **one combined UAT checklist grouped by story** (Step 9 rules). Wait for
578
723
  4. Run **Closing Related Tasks** (Step 10) once, covering the child Tasks of every implemented story — one combined table, then the usual per-task hour prompts. Every story that got a Task in F4 has one to close here; a story whose Task creation was skipped gets one created and closed now, as in Step 10.
579
724
  5. Move each implemented story to `Code Review` (same fallback rules as Step 10). **Do not change the Feature's state** — the Feature is a parent container; it advances only when its child stories are verified/closed, not when the PR goes up for review.
580
725
  6. The Step 10 closing rule applies unchanged: only child **Tasks** are ever closed — here at PR creation, never the stories and never the Feature. Don't enable "Complete associated work items" when the PR is merged; it would transition the stories and the Feature along with the Tasks.
726
+
727
+ ### F8: Remove the Feature's Worktree
728
+
729
+ Run Step 11 on the Feature's worktree, `../{repo}-AB{feature-id}`, once F7 is done and its Task-closing prompts are answered. Same checks, same rules: remove it only if it's clean and fully pushed, otherwise keep it and say what's left, and never use `--force`. The per-story worktrees are already gone; F4 removes each one at merge-back.
@@ -12,7 +12,8 @@ The one exception is Step 2 (gathering feedback), which runs **before** the Step
12
12
  When Ultracode is in use, these rules apply:
13
13
 
14
14
  - **Fan out the read / analyze / verify work** — gathering feedback (Step 2), exploring the codebase (Step 4), and reviewing + verifying the diff and AC coverage (Steps 9–10) are run as `Workflow` scripts with one agent per independent unit (per comment, per subsystem, per review dimension, per acceptance criterion). Each agent returns **structured findings** via a `schema`; you synthesize the results in the main loop.
15
- - **Never fan out an interactive gate or a write.** Every user prompt (Steps 3, 4-approval, 5, 10-decisions, 11) and every work-item or git mutation (Step 5 create, Step 6 branch, Step 7 implement, Step 12 push/close) stays in the **main loop**. Workflow agents here are **read-only analysts** — they use MCP read tools, `Read`, and `Grep`, and they return data. They do not create or close work items, switch branches, write code, or ask the user anything.
15
+ - **Never fan out an interactive gate or a write.** Every user prompt (Steps 3, 4-approval, 5, 10-decisions, 11) and every work-item or git mutation (Step 0 worktree, Step 5 create, Step 6 branch, Step 7 implement, Step 12 push/PR/close, Step 13 cleanup) stays in the **main loop**. Workflow agents here are **read-only analysts** — they use MCP read tools, `Read`, and `Grep`, and they return data. They do not create or close work items, switch branches, write code, or ask the user anything.
16
+ - **Give every Workflow agent the ticket's worktree path** (Step 0) — that is where the code under analysis lives, not the folder the session started in.
16
17
  - **Stay in the loop between phases.** Run one `Workflow` per phase, read its results, present/await the user as the steps require, then launch the next phase's workflow. This is several short workflows in sequence — not one monolithic run that tries to swallow the approval gates.
17
18
  - **Review uses the canonical find → adversarially-verify pipeline** (Step 10): fan out per dimension, then spawn skeptic verifiers per finding and drop findings the majority refute, so only confirmed issues reach the user.
18
19
 
@@ -20,7 +21,7 @@ If the `Workflow` tool is somehow unavailable, fall back to running each phase s
20
21
 
21
22
  ## Step 1: Find the Latest Pull Request
22
23
 
23
- Handle `$ARGUMENTS` as either `1234` or `AB#1234` — strip the `AB#` prefix when calling the MCP API.
24
+ Handle `$ARGUMENTS` as either `1234` or `AB#1234` — strip the `AB#` prefix when calling the MCP API. If it also says "work in place" or "no worktree", strip that and remember it for Step 0.
24
25
 
25
26
  Find the most recent PR linked to this work item:
26
27
 
@@ -28,7 +29,115 @@ Find the most recent PR linked to this work item:
28
29
  2. For each linked PR, fetch its details via `repo_get_pull_request_by_id` and record the **creationDate**
29
30
  3. Identify the **most recent PR** by creation date — this is the baseline for detecting new feedback
30
31
 
31
- Save the PR's `creationDate` as `LAST_PR_DATE` — everything after this timestamp is new feedback.
32
+ Save the PR's `creationDate` as `LAST_PR_DATE` — everything after this timestamp is new feedback. Also save its **source branch** and **target branch** (`sourceRefName` / `targetRefName`, minus `refs/heads/`) — Step 0 needs both — and its **status** (`active`, `completed`, or `abandoned`). The status decides which branch the rework builds on (Step 0c) and whether Step 12 has to open a new PR.
33
+
34
+ ## Step 0: Set Up the Ticket's Workspace
35
+
36
+ Developers run several Claude Code sessions against the same repo at once, one per ticket. If every session `git checkout`s in the folder it started in, they clobber each other's working tree. So each ticket gets its own **git worktree** in a sibling folder, `../{repo}-AB{id}` (e.g. `../CSIPay-AB5373`), and every later step runs there. The folder the session started in is never checked out, committed to, or edited.
37
+
38
+ It is Step 0 because it comes before anything touches the code. It runs **right after Step 1**, because it needs the branches of the PR Step 1 found, and Step 1 only reads Azure DevOps. It is setup, not a gate: it prompts only where a case below says so.
39
+
40
+ **Opt-out.** If the user says **"work in place"** or **"no worktree"** — in the invocation (`/rework 1234 work in place`; strip the phrase before reading the id) or at any point before Step 6 — skip this step, skip Step 13, and ignore every worktree note below: the command runs exactly as it did before worktrees, switching branches in the current folder in Step 6. If Step 0 has already run, give back the worktree it made (nothing has changed in it yet): `git worktree unlock "{WT}"`, then `git worktree remove "{WT}"`, then carry on in place.
41
+
42
+ Shell variables do not survive between Bash calls. Resolve each value once, then write the **literal absolute paths and branch names** into every later command. Below, `SOURCE` and `TARGET` are the latest PR's source and target branches from Step 1.
43
+
44
+ ### 0a. Resolve the repo and fetch
45
+
46
+ ```bash
47
+ git worktree list --porcelain | sed -n '1s/^worktree //p' # MAIN — the main checkout
48
+ git fetch --prune origin
49
+ git worktree prune
50
+ ```
51
+
52
+ - **`MAIN`** is the first entry of `git worktree list` — the main checkout, even when the session started in a subfolder or inside another ticket's worktree (`--show-toplevel` would return that worktree, and the new one would land at `CSIPay-AB5375-AB5380`).
53
+ - **`REPO`** is `basename` of `MAIN`; **`WT`** is `{dirname of MAIN}/{REPO}-AB{id}` — always the absolute path.
54
+ - **`--prune`** matters: without it a branch deleted on the remote after its PR merged still looks alive locally, so 0c would never take the merged-branch fallback and 0b's "deleted on the remote" check would never fire.
55
+ - **`git worktree prune`** forgets worktrees whose folders were deleted by hand, so a stale leftover can be recreated cleanly.
56
+
57
+ ### 0b. Tidy other tickets' worktrees
58
+
59
+ Look at every **other** worktree in `git worktree list --porcelain` whose folder is named `{REPO}-AB*`. Never touch `MAIN`, this ticket's `WT`, a worktree on `SOURCE` or on another `*/AB#{id}-*` branch (0c reuses it), or any folder outside that naming pattern.
60
+
61
+ - **Locked → skip it.** A lock means another session is working in it right now; 0c locks every worktree it hands out.
62
+ - **Otherwise remove it only if all three hold:**
63
+ 1. **Nothing uncommitted** — `git -C "{path}" status --porcelain` prints nothing.
64
+ 2. **Nothing unpushed** — its branch has an upstream, and either `git -C "{path}" rev-list --count '@{u}..HEAD'` prints `0`, or the upstream is **gone** (`git -C "{path}" for-each-ref --format='%(upstream:track)' "refs/heads/{branch}"` prints `[gone]` — its PR merged and the remote branch was deleted). For a gone upstream, also confirm nothing was committed after the last push: find the branch's pull request (`repo_pull_request`, by source branch, any status) and check its `lastMergeSourceCommit` equals `git -C "{path}" rev-parse HEAD`. A branch that was **never pushed** (no upstream), a detached HEAD, a HEAD that differs from what the PR merged, or no PR found — all fail this check.
65
+ 3. **Merged, or deleted on the remote** — the upstream is `[gone]`, or `git -C "{MAIN}" merge-base --is-ancestor "{branch}" "origin/{TARGET}"` succeeds.
66
+
67
+ Remove with `git -C "{MAIN}" worktree remove "{path}"`, then `git -C "{MAIN}" branch -D "{branch}"`. **Never `--force`, never `rm` the folder.** If a removal fails because another session removed it first, ignore that and move on.
68
+ - **Anything else stays.** List what was kept in one line, with the reason — `Kept: ../CSIPay-AB5301 (2 uncommitted files), ../CSIPay-AB5310 (locked — another session, or abandoned: git worktree unlock "{path}")`.
69
+
70
+ ### 0c. Put the worktree on the rework's branch
71
+
72
+ **First, pick `BRANCH`** — the branch this rework builds on:
73
+
74
+ - **The PR is `active` or `abandoned`, and `SOURCE` is still on origin** (`git -C "{MAIN}" rev-parse --verify --quiet "refs/remotes/origin/{SOURCE}"` succeeds) → `BRANCH` is `SOURCE`. The rework continues the unmerged work.
75
+ - **Otherwise** → `BRANCH` is a **new branch** from the PR's target. This covers a `completed` PR (merged), or `SOURCE` deleted. A completed PR's work is already in the target, so the rework starts there even if `SOURCE` still exists. Building on the merged branch would make the new PR show the old changes again after a squash merge. Name the new branch by `/implement` Step 4's convention (`{prefix}AB#{id}-{sanitized-title}`). If that name is still on origin (the merged branch was kept), append `-rework-{N}`, where `{N}` is the rework round Step 5 will use: existing `Rework AB#{id}` child Tasks + 1.
76
+
77
+ Then take the first case that matches:
78
+
79
+ 1. **A worktree is already on `BRANCH`** — a `branch refs/heads/{BRANCH}` line in `git worktree list --porcelain` → use that worktree as `WT`, wherever it is (a hand-made folder, or even `MAIN` itself). Don't create a second one, and don't fail because the branch is checked out elsewhere. If `BRANCH` is `SOURCE`, bring it up to date with `git -C "{WT}" pull --ff-only`.
80
+ 2. **`WT` is already a worktree, but on something else** (a detached HEAD, another branch) → show `git -C "{WT}" status -sb` and ask whether to switch it to `BRANCH` or stop.
81
+ 3. **`WT` exists but git doesn't know it** (not in the list even after 0a's prune) → stop and ask the user to delete or rename it. Its contents aren't in git, so there is no way to tell whether anything in it is worth keeping.
82
+ 4. **`BRANCH` is `SOURCE`** → check it out, tracking `origin/{SOURCE}`:
83
+ - **No local branch:**
84
+
85
+ ```bash
86
+ git -C "{MAIN}" worktree add --track -b "{SOURCE}" "{WT}" "origin/{SOURCE}"
87
+ ```
88
+ - **A local branch exists:** run `git -C "{MAIN}" worktree add "{WT}" "{SOURCE}"`, then `git -C "{WT}" branch --set-upstream-to "origin/{SOURCE}"`, then `git -C "{WT}" pull --ff-only`.
89
+
90
+ If `pull --ff-only` fails, the local branch and origin have diverged. Stop and show both sides (`git -C "{WT}" log --oneline --left-right '@{u}...HEAD'`). Never merge, rebase, or reset without asking.
91
+ 5. **`BRANCH` is new** → create it from the PR's **target** — the rule from before worktrees, now inside the worktree:
92
+
93
+ ```bash
94
+ git -C "{MAIN}" worktree add --no-track -b "{BRANCH}" "{WT}" "origin/{TARGET}"
95
+ ```
96
+
97
+ It has no upstream until Step 12 pushes it with `-u`, and no PR until Step 12 opens one. If `-b` fails because a leftover local branch has that name, show what it holds that the target doesn't (`git -C "{MAIN}" log --oneline "origin/{TARGET}..{BRANCH}"`). Then ask whether to delete it (`git -C "{MAIN}" branch -D "{BRANCH}"`) and retry, or reuse it.
98
+
99
+ Then **lock it** so another session's 0b leaves it alone — a clean, fully pushed worktree would otherwise pass every tidy check the moment its PR merges:
100
+
101
+ ```bash
102
+ git -C "{MAIN}" worktree lock --reason "AB#{id} — /rework in progress" "{WT}"
103
+ ```
104
+
105
+ Skip the lock when `WT` is `MAIN` (the main checkout can't be locked, and 0b never touches it). If the worktree is **already locked**, another session may still be working this ticket. Say so in one line — `AB#{id}'s worktree is locked ({reason}) — if another session is still on this ticket, both will edit the same files` — and carry on in it.
106
+
107
+ ### 0d. Copy the local files git doesn't carry
108
+
109
+ A new worktree has only tracked files. Copy in `.claude/settings.local.json` (the user's local permission rules) and every gitignored `.env.local` / `*.local.json`. Copy nothing that already exists in the worktree:
110
+
111
+ ```bash
112
+ cd "{MAIN}" && {
113
+ [ -f .claude/settings.local.json ] && echo .claude/settings.local.json
114
+ git ls-files --others --ignored --exclude-standard -- ':(glob)**/.env.local' ':(glob)**/*.local.json' ':(exclude,glob)**/node_modules/**'
115
+ } | sort -u | while IFS= read -r f; do
116
+ [ -e "{WT}/$f" ] || { mkdir -p "{WT}/$(dirname "$f")" && cp "$f" "{WT}/$f"; }
117
+ done
118
+ ```
119
+
120
+ **None of these may ever be committed.** The `.env.local` / `*.local.json` files are gitignored by construction. `.claude/settings.local.json` may not be, so if `git -C "{WT}" check-ignore -q .claude/settings.local.json` fails, append `.claude/settings.local.json` to `{MAIN}/.git/info/exclude`. That file is local and shared by every worktree of the repo, so the exclude covers them all and is itself never committed.
121
+
122
+ `node_modules` is not copied. Step 7 installs it, only when the plan touches the frontend.
123
+
124
+ ### 0e. Work only in the ticket's worktree
125
+
126
+ - **Every later step runs in `WT`** — exploration, implementation, build, tests, lint, commits, review. Claude Code can reset the shell to the session's folder between calls, so run git as `git -C "{WT}" …`, run everything else as `cd "{WT}" && …`, and use absolute paths for `Read`/`Edit`/`Write`.
127
+ - **Pass `WT` to every subagent and Workflow agent**, in so many words: `The code for AB#{id} is in {WT}. Read, edit, build, and test only there — never in {MAIN}.`
128
+ - **Diff against `origin/{TARGET}`**, not `{TARGET}`, wherever a later step compares with the PR's target — the local branch may be behind.
129
+ - **Quote every branch name** — the `#` in `story/AB#5373-…` starts a comment or a glob in some shells.
130
+ - `WT` is outside the folder the session started in, so Claude Code asks before the first edit there. Tell the user once, in the report below.
131
+ - Sessions sharing a repo still share **local ports and the Dev database**. If this ticket's dev server or integration tests collide with another session's, run them one at a time.
132
+
133
+ Report the workspace in one short block, then go on to Step 2:
134
+
135
+ ```
136
+ Workspace for AB#{id}: {WT}
137
+ {reused, on {BRANCH} | new, on {SOURCE} from origin | new branch {BRANCH} from origin/{TARGET} — PR #{n} {was completed | lost its branch}}
138
+ Tidied: {removed worktrees, or "nothing to tidy"} Kept: {kept worktrees + reason, or omit}
139
+ Edits there need approval once — run `/add-dir {WT}` to allow them for this session.
140
+ ```
32
141
 
33
142
  ## Step 2: Gather Rework Feedback
34
143
 
@@ -71,7 +180,8 @@ Present a summary of the rework feedback to the user. **Every feedback item must
71
180
  ```
72
181
  ## Rework for AB#{id}: {title}
73
182
 
74
- **Last PR:** #{pr_id} (created {date})
183
+ **Last PR:** #{pr_id} (created {date}, {status})
184
+ {only if status is not active: "PR #{pr_id} is {status} — this rework goes up as a new PR."}
75
185
  **New comments:** {count}
76
186
 
77
187
  ### Current Acceptance Criteria
@@ -279,13 +389,15 @@ If the user cancels, skip task creation and proceed — note "No rework task cre
279
389
 
280
390
  ## Step 6: Switch to Existing Branch
281
391
 
282
- The work item already has a branch from the previous PR. Switch to it:
392
+ **In a worktree** (the default), there is nothing to switch. Step 0c has already put `WT` on the previous PR's branch and pulled it. If that PR was completed or its branch deleted, Step 0c put it on a new branch from the PR's target instead. Confirm with `git -C "{WT}" status -sb` and go on to "Move the Work Item to Active".
393
+
394
+ **Working in place**, if the PR is `active` or `abandoned`, the work item already has a branch from the previous PR. Switch to it:
283
395
 
284
396
  1. Get the source branch name from the most recent PR
285
397
  2. Switch to that branch: `git checkout <branch-name>`
286
398
  3. Pull the latest: `git pull`
287
399
 
288
- If the PR was completed/merged and the branch was deleted, create a new branch from the PR's target branch following the same naming convention as `/implement` Step 4.
400
+ If the PR was completed, or its branch was deleted, create a new branch from the PR's target branch instead, following the same naming convention as `/implement` Step 4 (`git fetch --prune origin`, then `git checkout -b "<branch-name>" "origin/<target>"`). Don't build on a completed PR's branch even if it still exists. Add the `-rework-{N}` suffix when the name is still on origin. Step 0c explains both rules.
289
401
 
290
402
  ### Move the Work Item to Active
291
403
 
@@ -301,7 +413,9 @@ After the update, **read the work item back** (`wit_work_item`, action `get`) an
301
413
 
302
414
  ## Step 7: Implement
303
415
 
304
- 1. **Implement** the rework using backend and/or frontend agents according to the approved plan
416
+ **In a worktree**, install frontend dependencies first — only if the approved plan touches the frontend. A new worktree has no `node_modules`, so run `npm install` in its client folder (`cd "{WT}/{client folder}" && npm install`). A backend-only plan skips the install; `dotnet build` restores its own packages. Steps 8–9 then skip the uninstalled client folder and report it as `frontend skipped — untouched by this rework, not installed in the worktree` rather than failing on it.
417
+
418
+ 1. **Implement** the rework using backend and/or frontend agents according to the approved plan — each agent is told to work only in `WT` (Step 0e)
305
419
  2. **Write the unit tests** listed in the plan's "Unit Tests" section alongside the implementation — not after. Include any regression test that would have caught the original issue
306
420
  3. **Generate mockup** if there are UI changes
307
421
 
@@ -391,17 +505,29 @@ Wait for the user's response before proceeding. Do NOT push until confirmed.
391
505
 
392
506
  ## Step 12: Push and Update
393
507
 
394
- 1. Push the changes: `git push`
395
- 2. **Do not post a rework summary comment.** Do not add a summary of what changed to the work item Discussion (`wit_work_item_comment_write` (action `add`)) or as a PR thread. The pushed commits and the PR diff are the record of what changed — a prose summary duplicates them and clutters the work item. If the reviewer left specific PR comment threads, reply on those threads directly (that is what `/resolve-feedback` and `/fix-review` do); otherwise post nothing.
396
- 3. **Attach deployment scripts.** Run `/implement`'s **Attaching Deployment Scripts** step against this branch — diff it against the PR's target branch (`git diff --name-only --diff-filter=AM {target}...HEAD`), so a script the original PR added and never attached is caught too. A script this rework changed is already attached in its old form: replace that attachment, don't add a second copy — a promotion that lists both versions invites someone to run the stale one. Same rules and report lines as in `/implement` (see **Deployment Scripts** in CLAUDE.md).
397
- 4. **Close related Tasks and log hours** — see "Closing Related Tasks" below. This includes the rework Task created in Step 5 as well as any other child Tasks that became `Completed` as a result of this rework round.
398
- 5. **Move the work item back to `Code Review`** via `wit_work_item_write` (action `update`):
508
+ 1. Push the changes: `git push` (in a worktree: `git -C "{WT}" push`). A **new branch** from Step 0c case 5, or from the in-place fallback in Step 6, has no upstream yet, so push it with `git push -u origin HEAD` (`git -C "{WT}" push -u origin HEAD`).
509
+ 2. **Open a PR if none is active.** A push only reaches a reviewer through an active PR. Re-read the latest PR's status, since it may have changed during the rework:
510
+ - **Still `active`** → the push updated it. Nothing to create.
511
+ - **`completed` or `abandoned`, or the rework is on a new branch** → nothing is reviewing these commits yet. Create a PR the way `/implement` Step 10 does:
512
+ - **sourceRefName**: `refs/heads/{branch}` — the branch just pushed
513
+ - **targetRefName**: `refs/heads/{target}` — the latest PR's target
514
+ - **title**: `AB#{id}: {work item title} (rework round {N})`
515
+ - **description**: `Rework round {N} of AB#{id}. Follows PR #{old} ({status}).` Keep it to that one line; item 3 applies.
516
+ - **labels**: `["hotfix"]` if the work item type is Hot Fix
517
+
518
+ Link it to the work item via `wit_work_item_link_write` (action `link_to_pull_request`). Report `Opened PR #{new} → {target} (PR #{old} is {status})`. The next `/rework` finds this PR as the latest.
519
+ - **Completed during this rework** (it was `active` at Step 1, so the rework was built on the old branch) → open the new PR the same way, but warn first: if #{old} was squash-merged, the new PR shows its changes again. Offer to merge `origin/{target}` into the branch and push again before opening the PR, which clears them.
520
+ 3. **Do not post a rework summary comment.** Do not add a summary of what changed to the work item Discussion (`wit_work_item_comment_write` (action `add`)) or as a PR thread. The pushed commits and the PR diff are the record of what changed — a prose summary duplicates them and clutters the work item. If the reviewer left specific PR comment threads, reply on those threads directly (that is what `/resolve-feedback` and `/fix-review` do); otherwise post nothing.
521
+ 4. **Attach deployment scripts.** Run `/implement`'s **Attaching Deployment Scripts** step against this branch — diff it against the PR's target branch (`git diff --name-only --diff-filter=AM {target}...HEAD`), so a script the original PR added and never attached is caught too. A script this rework changed is already attached in its old form: replace that attachment, don't add a second copy — a promotion that lists both versions invites someone to run the stale one. Same rules and report lines as in `/implement` (see **Deployment Scripts** in CLAUDE.md).
522
+ 5. **Close related Tasks and log hours** — see "Closing Related Tasks" below. This includes the rework Task created in Step 5 as well as any other child Tasks that became `Completed` as a result of this rework round.
523
+ 6. **Move the work item back to `Code Review`** via `wit_work_item_write` (action `update`):
399
524
  - **path**: `/fields/System.State`
400
525
  - **value**: `Code Review`
401
526
 
402
527
  Rework is triggered by reviewer feedback, so the item was likely in `Active` / `In Progress` / `Rework` while the fixes were being made. Pushing the rework hands it back to the reviewer, so it belongs in `Code Review` again.
403
528
 
404
529
  If the project's process template does not have a `Code Review` state (the update call returns an invalid-state error), fall back in this order: `Resolved` → `In Review` → leave the current state and warn the user. Do not silently swallow the error.
530
+ 7. **Remove the ticket's worktree** — Step 13, once everything above is done.
405
531
 
406
532
  > **PR completion closes the Task only.** When the PR is later completed/merged, only the child **Task** may be closed — never the parent User Story or Bug. Azure DevOps's "Complete associated work items" option transitions *every* linked work item (including the parent the PR is linked to), so do **not** enable it when completing the PR. Close the child Task explicitly instead; the parent stays in `Code Review` until it is promoted through `dev → test → staging → prod` (see **Work Item States ↔ Environments** in CLAUDE.md).
407
533
 
@@ -464,3 +590,30 @@ Once the user has answered, update each task via `wit_work_item_write` (action `
464
590
  - `System.State` → `Closed` (fall back to `Done` if the project's task template uses Agile; warn if neither is valid)
465
591
 
466
592
  Confirm with a summary line per task: `Closed AB#xxxx — {hours}h logged`.
593
+
594
+ ## Step 13: Remove the Ticket's Worktree
595
+
596
+ Skip this step when working in place.
597
+
598
+ This runs **last**: after the push and every Step 12 prompt, the Task-closing ones included, is answered. A failed push therefore never loses work, and the attachment and diff steps still have the worktree to read from. The branch is safe on origin now, and the next `/rework AB#{id}` recreates the worktree from it.
599
+
600
+ 1. **Unlock it** — this session is done with it: `git -C "{MAIN}" worktree unlock "{WT}"`. Unlock even if step 3 ends up keeping it, so a later Step 0b can tidy it once it's clean, pushed, and merged.
601
+ 2. **Check it's safe to remove:**
602
+
603
+ ```bash
604
+ git -C "{WT}" status --porcelain # must print nothing
605
+ git -C "{WT}" rev-list --count '@{u}..HEAD' # must print 0
606
+ ```
607
+ 3. **Both pass** → remove the worktree, then the local branch:
608
+
609
+ ```bash
610
+ git -C "{MAIN}" worktree remove "{WT}"
611
+ git -C "{MAIN}" branch -D "{branch}"
612
+ ```
613
+
614
+ Report: `Removed {WT} and local branch {branch} — the branch is on origin; /rework AB#{id} brings it back.`
615
+
616
+ **Either fails** → keep it, and say exactly what's left: the `git -C "{WT}" status --short` lines, or the unpushed commits (`git -C "{WT}" log --oneline '@{u}..HEAD'`). **Never `--force`, never `rm` the folder.**
617
+ 4. **Never remove a worktree the session is standing in.**
618
+ - If the folder this session started in is `WT` or inside it, don't remove it — that would pull the folder out from under the session. Print the command for the user to run from another folder instead: `git -C "{MAIN}" worktree remove "{WT}" && git -C "{MAIN}" branch -D "{branch}"`.
619
+ - If `WT` is `MAIN` (Step 0c reused a branch already checked out there), there is nothing to remove.
@@ -97,7 +97,7 @@ Claude maintains persistent memory across sessions in `~/.claude/projects/.../me
97
97
  ### Development Workflow
98
98
 
99
99
  1. **Pick a work item** from Azure DevOps (or describe what you need)
100
- 2. **Claude implements** using `/implement AB#<id>` (auto-creates branch)
100
+ 2. **Claude implements** using `/implement AB#<id>` — in the ticket's own worktree, on an auto-created branch
101
101
  3. **Hooks guard** against secrets and bad patterns automatically
102
102
  4. **PR merges** into `main` — the compare branch. **Nothing deploys yet.** The work item stays in `Code Review` until it is promoted
103
103
  5. **Promote or release** — `/promote main dev` carries everything on `main` to Dev; `/create-release <N>` groups work items so `/deploy-release <N> test` → `staging` → `prod` can carry just those
@@ -107,6 +107,8 @@ Claude maintains persistent memory across sessions in `~/.claude/projects/.../me
107
107
  9. **Track** work items via the Azure DevOps MCP server
108
108
  10. **Learn** — Claude saves what worked for next time
109
109
 
110
+ **One worktree per ticket.** `/implement` and `/rework` never check out in the folder the session started in. Each ticket gets a sibling git worktree, `../{repo}-AB{id}` (e.g. `../CSIPay-AB5373`), where every build, test, and commit happens. It is removed once the branch is pushed, or kept with a note if anything is uncommitted or unpushed. That lets several sessions work different tickets in the same repo at once. Say **"work in place"** (or "no worktree") to opt a run out. Sessions sharing a repo still share **local ports and the Dev database** — two dev servers on one port, or two integration runs against Dev, will still collide.
111
+
110
112
  ### Story Points & Dev Ready Policy
111
113
 
112
114
  These rules apply to **every** command or flow that creates or estimates work items:
@@ -308,7 +310,7 @@ This runs pre-flight checks, commits, pushes the current branch, and triggers th
308
310
 
309
311
  #### Branch Naming Convention
310
312
 
311
- When `/implement AB#<id>` is run, a branch is created off the current branch based on the Azure DevOps work item type:
313
+ When `/implement AB#<id>` is run, a branch is created in the ticket's worktree (`../{repo}-AB{id}`, removed again once the branch is pushed — "work in place" opts out). It is cut off the current branch, or off the project's PR target when the current branch is another ticket's (see **PR Targeting**). The prefix comes from the Azure DevOps work item type:
312
314
 
313
315
  | Work Item Type | Branch Prefix | Example |
314
316
  |---|---|---|
@@ -326,13 +328,15 @@ Format: `{prefix}AB#{id}-{sanitized-title}` (title lowercased, special chars rep
326
328
 
327
329
  PRs always target the branch you were on when `/implement` was invoked. The base branch is captured dynamically at the start — no assumptions about branch names.
328
330
 
331
+ **Exception — another ticket's branch.** If that branch starts with a ticket prefix (`feature/`, `story/`, `bugfix/`, `hotfix/`, `work/`, `cherry-pick/`, `release/`, `revert/`), the new ticket is **not** cut from it. `/implement` uses the PR target this CLAUDE.md names instead, or asks. Without the exception, a folder left on one ticket's branch would put that ticket's commits in the next ticket's PR, and aim the PR at the wrong branch.
332
+
329
333
  #### Hot Fix Workflow
330
334
 
331
335
  Hot Fix work items follow the same automated checks (build, lint, tests, review) but skip manual UAT. An abbreviated confirmation is shown instead. Hot Fix PRs get a `hotfix` label. Hot Fixes target the current branch — for a production hot fix, start on `prod` so the PR merges (and deploys) straight there. **Then bring the fix back to `main`:** open a second PR from the same hotfix branch into `main` (or `/cherry-pick AB#<id> main`) so the next `main → dev` promotion doesn't overwrite it. A hot fix that lives only on `prod` is lost on the next release.
332
336
 
333
337
  #### Feature Workflow (ordered story waves)
334
338
 
335
- Running `/implement` on a **Feature** implements its child User Stories in **waves** driven by the `Custom.Order` field: stories sharing the same order value are implemented **in parallel** (one agent per story, each in an isolated git worktree), and waves run sequentially in ascending order so later stories build on earlier ones. All work merges into a single `feature/AB#<id>-...` branch; quality checks, code review, UAT, and one PR happen at the feature level, and every implemented story is linked to that PR. Stories without a `Custom.Order` value run in a final catch-all wave (flagged for confirmation first).
339
+ Running `/implement` on a **Feature** implements its child User Stories in **waves** driven by the `Custom.Order` field: stories sharing the same order value are implemented **in parallel** (one agent per story, each in an isolated git worktree), and waves run sequentially in ascending order so later stories build on earlier ones. All work merges into a single `feature/AB#<id>-...` branch; quality checks, code review, UAT, and one PR happen at the feature level, and every implemented story is linked to that PR. Stories without a `Custom.Order` value run in a final catch-all wave (flagged for confirmation first). The Feature itself gets one ticket worktree, `../{repo}-AB{feature-id}`; the per-story worktrees branch from it and are removed as each story merges back.
336
340
 
337
341
  **Work item states:** `/implement` moves the work item to `Active` when implementation starts — for a single work item (User Story, Bug, Hot Fix) right after the branch is created; for a Feature, each child story goes `Active` as its wave begins. When the PR is created, each implemented child **User Story** moves to `Code Review` — the **Feature's state is never changed**. The Feature is a parent container; it advances only as its child stories are verified/closed. Only child **Tasks** are ever closed — never the stories or the Feature. From `Code Review` onward the stories follow the **Work Item States ↔ Environments** table above as they are promoted.
338
342