Command: pluck (queue → claim → plan → isolate → execute → squash merge → housekeeping → confirm)
Use for: pluck:, xp_work pluck, /xp_work pluck (optionally with a ## heading, file/line reference, **Id:** PREFIX-N, or a pasted block that matches one queued section)
Prerequisites: Read ../bootstrap.md and ../rules.md first. This command implements product/repo changes—not "record only."
Eligible source files (same as iteration): work/IMPROVEMENTS.md, work/TODO.md, work/USER_GOALS.md, work/BUGS.md, work/DEFERRED.md, work/TECH_DEBT.md.
Workflow
-
Migrate and bootstrap
work/files as needed. -
Identify the section. Try these resolution strategies in order until one succeeds:
2a. Inline pluck snapshot — If the user message contains a
<pluck-snapshot>…</pluck-snapshot>block (sent automatically by Workbench when plucking from the UI), extract the item content directly from that block. The block contains**Source:** <FILENAME>, a## Titleheading, and the full item body. Use this as the authoritative section content — do not require it to exist in the local worktree's queue file (the worktree may have been created before the item was recorded on the base branch). Derive the source file from the**Source:**line and the entry id from the**Id:** PREFIX-Nline within the body. If the block is present and well-formed, skip 2b–2d entirely.2b. Local file search — Search the eligible queue files in the local worktree per
../procedures/section-disambiguation.md(scope: all eligible queue files, id format:PREFIX-N).2c. Base-branch worktree fallback — If the item was not found locally (2b returned no match), the local worktree may have branched before the item was recorded on the base branch. Detect whether the base branch is checked out in another worktree:
BASE_BRANCH=$(git config --get git-town.main-branch 2>/dev/null || \ git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||' || \ echo "main") BASE_WORKTREE=$(git worktree list --porcelain | awk -v b="refs/heads/${BASE_BRANCH}" '/^worktree /{wt=$2} /^branch /{if($2==b) print wt}')If
BASE_WORKTREEis non-empty, search the eligible queue files under${BASE_WORKTREE}/work/using the same disambiguation procedure. If found, use that section content and note the source worktree path for the claim commit in step 4.2d. Failure — If none of 2a–2c resolved the item, stop and tell the user the item could not be found in the local worktree or the base-branch worktree. Do not attempt to record a new item.
Then backfill missing entry ids in that queue file per
../id-prefixes.md(Backfill) before copying or editing the section. -
Snapshot the block — Copy the full section text exactly as queued (from the
##line through the content up to but not including the next---or the next##at the same level—same boundary rules as other section moves). Keep this copy for the final commit body.
Preconditions before the claim commit
Before editing the queue file or switching branches for the claim:
Detect the base branch using this three-tier fallback (reuse this value for the rest of the pluck run):
git config --get git-town.main-branchgit symbolic-ref refs/remotes/origin/HEAD | sed 's|refs/remotes/origin/||'- Fallback to
main
BASE_BRANCH=$(git config --get git-town.main-branch 2>/dev/null || \
git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||' || \
echo "main")
Record the starting branch so the workflow can return to it if pluck started off-base:
STARTING_BRANCH=$(git branch --show-current)
Require a clean working tree. If the working tree has unrelated staged or unstaged changes, stop and ask the user how to proceed. Do not auto-stash, auto-reset, or silently mix unrelated local edits into the claim commit.
Refresh the base branch when an upstream exists. If the base branch has an upstream, update it with a fast-forward-only pull before checking the queue section so claim detection uses the latest known base-branch state. If the fast-forward pull fails, stop and ask the user.
-
Mark in progress on the base branch and commit the claim
4a. Ensure the workflow can edit the base branch's working tree:
- If
STARTING_BRANCHequalsBASE_BRANCH, stay there. SetBASE_WORKTREE=""(empty — operating in place). - If
STARTING_BRANCHis a non-base branch, attemptgit checkout ${BASE_BRANCH}.- If the checkout succeeds, set
BASE_WORKTREE=""and continue. - If the checkout fails because the base branch is checked out in another worktree (error contains
already used by worktree), detect the worktree path:All file edits and git commands for steps 4b–4d operate inBASE_WORKTREE=$(git worktree list --porcelain | awk -v b="refs/heads/${BASE_BRANCH}" '/^worktree /{wt=$2} /^branch /{if($2==b) print wt}')${BASE_WORKTREE}(e.g. edit${BASE_WORKTREE}/work/<SOURCEFILE>.md, rungit -C "${BASE_WORKTREE}" add …andgit -C "${BASE_WORKTREE}" commit …). Do not switch branches in the current checkout.
- If the checkout succeeds, set
4b. Check whether the target section is already claimed:
Inspect the target queue section on the base branch before writing anything.
- If no
**Pluck status:** In progressline exists on the section, continue. - If the section already contains
**Pluck status:** In progress ..., stop and tell the user the item appears to be claimed. Do not silently overwrite an existing claim marker. - Only if the user explicitly instructs the workflow to re-claim the item may the workflow replace the existing marker date and continue.
4c. Write the claim marker:
Insert directly under the section's
## Titleline:
**Pluck status:** In progress (started YYYY-MM-DD)Rules:
- Use today's date in ISO format.
- If re-claiming with explicit user approval, replace the existing in-progress line in place rather than adding a duplicate.
- Preserve all other section content exactly.
4d. Create the claim commit:
- Stage only the queue source file. If
BASE_WORKTREEis set, usegit -C "${BASE_WORKTREE}" add work/<SOURCEFILE>.md; otherwisegit add work/<SOURCEFILE>.md. - Commit: subject
xp_work: mark <PREFIX-N> in progress. IfBASE_WORKTREEis set, usegit -C "${BASE_WORKTREE}" commit …. - Do not include product code, changelog edits, or other work-file changes in this commit.
4e. Return to the starting context:
- If
BASE_WORKTREEis set, no branch switch is needed — the current checkout is still onSTARTING_BRANCH. - Otherwise, if
STARTING_BRANCHdiffers fromBASE_BRANCH, switch back:git checkout ${STARTING_BRANCH} - If pluck started on the base branch, stay there and continue to the planning gate.
- If
Planning mode gate (mandatory — do not skip)
-
Auto-route BUG items: If the plucked item's entry id has a
BUGprefix (i.e. it was sourced fromwork/BUGS.md), the planning mode issuperpowers:systematic-debuggingautomatically — skip the choice prompt and go to step 6. The user can still override this by explicitly declaring a different mode in the same message (see below).If the user already declared a mode in the same message, treat it as their choice and go to step 6. Accept plain-language equivalents, for example:
- Native / Plan → Native planning (see below).
- Brainstorm / superpowers →
superpowers:brainstorming. - Debug / systematic debugging →
superpowers:systematic-debugging.
If there is no such declaration and the item is not a BUG, you must obtain a choice before any implementation work: - Stop after step 4. The claim marker is already committed to the base branch. Do not read the codebase for implementation, do not write or change product code, and do not run tool calls whose purpose is to implement the plucked item.
- Your next message to the user must present only the planning-mode question (optional: one short line naming the section you plucked). Prefer a multiple-choice UI when the product supports it (e.g. the product's question UI with exactly two options) so the user must pick before you continue.
- Offer exactly two options (same meaning every time):
- Native planning — Use the product's built-in planning UI so a written plan exists and is visible to the user before coding. If a planning UI is not available, post a short bullet plan in chat and wait for explicit approval (e.g. "proceed," "looks good," or thumbs-up) before writing implementation code.
superpowers:brainstorming— Run thesuperpowers:brainstormingflow first, then implement.
- Wait for the user's reply that selects one option. Do not assume defaults.
-
Isolate feature work — Before implementation begins, ensure work will happen on a feature branch in a managed worktree.
Follow
../procedures/worktree-setup.mdwith branch-prefixpluck/.BASE_BRANCHwas detected in the preconditions above. If the procedure's "Decide" step (b) finds the current branch is already a non-base branch, skip to step 7 (hand off to planner). -
Hand off to the chosen planner — Read
../templates/pluck-planner-brief.mdand give the planner explicit instructions that it must:- Follow the squash-merge path via
.skills/dev/xp_work/scripts/pluck_merge.shwhich produces one atomic commit on the base branch containing both the feature delivery and the work-file yank. - The planner brief contains a top-of-file HARD STOP block that forbids non-standard completion paths after verification. Reinforce: no
superpowers:finishing-a-development-branch, no merge/PR/keep/discard options, and immediate continuation from verification success into squash merge. - Complete all implementation on the feature branch before merging.
- Follow the squash-merge path via
-
Execute on the feature branch — All non-
work/changes for the plucked item are made on the feature branch. Follow the selected planning mode: native planning means a visible plan first (Plan mode or chat plan + approval), then implement;superpowers:brainstormingmeans that flow first, then implement;superpowers:systematic-debuggingmeans run that flow first to diagnose the root cause, then implement the fix.8a. Checkpoint 1 — commit approved spec artifact: When the
superpowers:brainstormingflow completes and the user approves the written spec, check whether the spec file has uncommitted changes before invokingsuperpowers:writing-plans:git status --porcelain -- <spec-path>- If empty: the spec is clean. Continue to
superpowers:writing-plans. - If dirty: stage only the spec file and commit:
wheregit add -- <spec-path> git commit -m "docs: incorporate user revisions to <spec-filename>"<spec-filename>is the basename of the spec path. - If staging or committing fails, stop before
superpowers:writing-plans. Do not continue with an approved-but-uncommitted spec revision. - Do not broaden this commit to other dirty files — checkpoint 1 is scoped to the approved spec artifact only.
By the end of this step the feature branch contains the commits whose messages will later be harvested into the feature delivery commit body. If the implementation produces no meaningful diff relative to the base branch, stop and do not continue to merge.
- If empty: the spec is clean. Continue to
-
Run
.skills/dev/xp_work/scripts/pluck_merge.sh— After implementation is complete on the feature branch, call the deterministic merge script. The AI must construct these arguments:.skills/dev/xp_work/scripts/pluck_merge.sh \ --base-branch "$BASE_BRANCH" \ --feature-branch "$(git branch --show-current)" \ --source-file "<SOURCEFILE>.md" \ --entry-id "<PREFIX-N>" \ --summary "<concise summary of what shipped>" \ --snapshot "<path to snapshot file from step 3>" \ --verify-cmd "<repo's canonical verification command>" \ --worktree-path "<.worktrees/pluck-... path from step 6, if used>" \ --changelog "<one-line CHANGELOG entry, if the change is worth recording>"The script handles: sync with base, checkpoint commit, pre-merge verification, squash merge, section yank from the queue file, CHANGELOG update, post-merge verification, and branch/worktree cleanup — all in a single atomic commit on the base branch.
Exit codes: 0=success, 1=pre-flight, 2=sync conflict, 3=squash conflict, 4=verification failure, 5=cleanup failure. On success the script prints the squash-merge commit hash to stdout.
On failure: the script prints the phase, exit code, failed command, and recovery location to stderr. Do not invoke
superpowers:finishing-a-development-branchor present merge/PR/keep/discard options. Fix the issue and rerun the script.The
**Last id:**counter in the queue file is never lowered by the script. The counter is monotonic — once an id has been assigned and yanked, the next entry recorded in that file must get the next number. -
Ship Proof gate (conditional) — Follow
../procedures/ship-proof-gate.mdwith:
- item-title: the plucked section title
- item-id:
PREFIX-N(the plucked entry's id) - source-file: the source filename
- source-id: the plucked source id (if present)
-
Human verification gate — Follow
../procedures/human-verification-gate.mdwith:- source: the pluck queue file name (e.g.
IMPROVEMENTS.md) - source-id: the plucked section's
**Id:** PREFIX-Nif present
If an ACC-N entry is created, commit it separately:
xp_work: queue ACC-N for acceptance. - source: the pluck queue file name (e.g.
-
Confirm — Return a short summary including:
- Source file and section title
- Planning mode used
- Claim commit hash (from step 4)
- Squash merge commit hash (from step 9 script output)
- Whether
CHANGELOG.mdwas updated - Whether
ACC-Nwas created - Whether ship-proof ran, passed, or was skipped
- Whether base-branch pull was skipped (no upstream)
- Whether remote branch deletion was skipped or failed
- Whether Workbench workspace archive was triggered or skipped
-
Workbench workspace archive (conditional) — If the
mcp__workbench__archive_workspacetool is available, the session is running inside a Workbench workspace. Callmcp__workbench__archive_workspaceto archive the workspace. This must be the absolute last action — after the confirm summary has been returned to the user. The tool is irreversible: it stops processes, removes the worktree, and preserves chat history. If the tool is not available, skip this step entirely.
See ../format-guidelines.md for template paths.