box-it-up
Box the pie and hand it across the counter - per slice, commit + push only (no PR, CI stays quiet); at the pie boundary, open one PR, watch CI once (auto-fix on red), merge on approval preserving every slice commit, sync main, delete the branch, remove the pie worktree. Opt-in merge-per-slice mode (--merge-slice, run internally by the conductor) opens, CI-checks and merges one PR per slice with a merge commit instead. Opt-in ship-once delivery (set by /pizza-party) uses --pie-local at each pie boundary (full local check, local --no-ff merge into the ship branch, no PR) and --ship once after the last pie (one PR ship branch to main, CI once, merge on green).
- License 许可
- MIT
- 最近更新
- 2026-11-12
- Stars
- ★ 0
- Forks
- 1
01 前言 Front Matter
- name
- box-it-up
- triggers
- [ "/bytheslice:box-it-up", "/box-it-up", "box up the pie", "box up the slice", "hand it over", "close out the pie", "/bytheslice:ship-pr", "/ship-pr", "ship the pr", "submit the pr", "open and merge the pr", "ship this branch", "ship this pie" ]
- description
- Box the pie and hand it across the counter - per slice, commit + push only (no PR, CI stays quiet); at the pie boundary, open one PR, watch CI once (auto-fix on red), merge on approval preserving every slice commit, sync main, delete the branch, remove the pie worktree. Opt-in merge-per-slice mode (--merge-slice, run internally by the conductor) opens, CI-checks and merges one PR per slice with a merge commit instead. Opt-in ship-once delivery (set by /pizza-party) uses --pie-local at each pie boundary (full local check, local --no-ff merge into the ship branch, no PR) and --ship once after the last pie (one PR ship branch to main, CI once, merge on green).
- user-invocable
- true
02 资源文件 3
- 参考文档agents/ci-fix-attempter.md10.1 KB
- 脚本pick-merge-strategy.js3.0 KB
- 脚本record-kitchen-merge.js2.4 KB
03 SKILL.md 正文
<!-- skills/box-it-up/SKILL.md --> <!-- Standalone closeout skill, re-scoped pie-level for v5 (spec §1.10). Pizza-shop framing: the pie cooled slice by slice - box it and hand it over. TWO call shapes: (1) per-slice, invoked repeatedly by /sell-pie's loop after each slice → commit + push only, no PR opened so CI does not fire; (2) pie-completion, invoked once when every slice in the active Pie is [x] → open one PR "Pie N", CI runs once, HITL review, merge PRESERVING per-slice commits (rebase/merge-commit, never squash), sync main --ff-only, delete branch, remove the pie worktree. Universal closeout safety preserved: a hand-rolled branch with no checklist still ships through the pie-completion path (no pie-status flip, project-default merge strategy). Decoupled from /sell-pie and /sell-slice so the operator can review / UAT before the boundary PR. Ship-once delivery adds --pie-local (local check + local --no-ff merge of the pie into the ship branch) and --ship (the one ship PR to main, merged on green with no human gate). -->
/box-it-up
In v5 a Pie (a coherent chapter, usually 3 to 8 slices; a small app's pie may hold 1 or 2) is the unit of PR, CI, and review. /box-it-up carries both halves of the pie's git lifecycle:
- Per slice -
/sell-pie's loop calls/box-it-up --sliceafter each slice clears its gates. The skill commits the slice on the pie branch and pushes. No PR is opened, so CI does not fire - per-slice pushes stay cheap. - At the pie boundary - when every slice in the active Pie is
[x],/box-it-upopens one PRPie N: <name>, lets CI run once, gets your merge approval, merges preserving every per-slice commit (rebase or merge-commit, never squash), syncsmainfast-forward-only, deletes the branch, and removes the pie worktree. - Merge per slice (opt-in) - when
delivery.moderesolves tomerge-per-slice(an explicit autonomous-delivery run instruction, or the config), the conductor runs/box-it-up --merge-sliceinternally after each slice: one PRSlice N.M: <name>, CI, up to 3 fix rounds, merge on green with a merge commit, cleanup from the primary checkout. No per-slice merge approval; the operator gets one notice when the pie finishes. The two bullets above describe the default (pie-pr) mode. - Ship once (opt-in) - when
delivery.moderesolves toship-once(/pizza-partysets it), per-slice commits stay local (no push). At each pie boundary the conductor runs/box-it-up --pie-local: confirm every slice was verified, re-run the full local check once, merge the pie branch into the long-lived local ship branch withgit merge --no-ff, remove the pie worktree and branch. After the last pie,/box-it-up --shippushes the ship branch, opens one PR tomain, watches CI once and merges on green with a merge commit. Neither step has a human merge gate: choosing ship-once authorized it.
It is intentionally a separate skill so you can review the whole pie locally, run a manual visual UAT, or rebase against fresh main before deciding to ship the boundary PR. The closeout path is universal - safe to run on a hand-rolled branch that never touched the ByTheSlice delivery loop. Pre-flight checks and the merge/cleanup pattern do not assume a checklist or a pie.
Mode detection
/box-it-up is always standalone and operates on whatever feature branch is currently checked out (in slice-merge mode, the slice branch in the slice worktree the conductor names). It resolves one of six modes before doing anything:
| Mode | How it's detected | What it does |
|---|---|---|
| per-slice | Invoked with --slice (how /sell-pie's loop calls it), or the operator explicitly asks to "box up the slice" mid-pie. |
Phase 1 only - commit the slice on the pie branch + push. No PR, no CI watch, no merge, no cleanup. Returns immediately so the loop continues to the next slice. |
| pie-completion | Default. A master checklist exists, the current branch matches a pie-<n>-<scope> row, and every ### Slice N.M under that ## Pie N is [x]. Also the shape /sell-pie hands off at the boundary. |
Full closeout - Phases 0 → 6: open one PR Pie N, CI once, HITL merge gate, merge preserving slice commits, sync main, delete branch, remove worktree, flip the pie's checklist status. |
| universal (hand-rolled) | No master checklist, or the branch doesn't map to a pie row (a feedback round, a fix on a delivered slice). | Same closeout as pie-completion (Phases 0 → 6) minus the pie-status flip, and merge strategy falls back to the project default. The universal-closeout safety net - never assumes ByTheSlice ran. |
| slice-merge (merge per slice) | Invoked with --merge-slice by the /sell-pie or /sell-slice conductor when delivery.mode resolves to merge-per-slice and the pie is not review: continuous. Always an internal invocation: the conductor sits on main between slices by design and follows this skill's phases itself rather than typing the command, so the on-main precondition question below does not apply to it. |
One slice, one PR - see "Merge-per-slice closeout" below: PR Slice N.M: <name>, CI, up to 3 ci-fix-attempter rounds, merge on green with a merge commit (no human merge gate), cleanup from the primary checkout. |
| pie-local (ship-once boundary) | Invoked with --pie-local by the /sell-pie conductor at the pie boundary when delivery.mode resolves to ship-once. Internal, like --merge-slice. |
No PR, no push, no CI - see "Pie-local closeout" below: verified-slice check, the full local check once (up to 3 fix-attempter rounds), git merge --no-ff of the pie branch into the ship branch in the primary checkout, worktree and branch removal. |
| ship (ship-once finish) | Invoked with --ship after the last pie of a ship-once build: by /sell-pie in an interactive run, or by the /pizza-party conductor in an unattended one. Runs from the primary checkout on the ship branch. |
One ship PR - see "Ship closeout" below: push the ship branch, PR Ship <app>: <pies> pies, <slices> slices with every pie's evidence, CI once, up to 3 ci-fix-attempter rounds, merge on green with a merge commit (no human gate), sync main, delete the ship branch. |
Refusal guards:
- In per-slice mode, if the active Pie still has unfinished slices the skill must NOT try to open a PR - that is correct, expected mid-pie behavior, not an error.
- In pie-completion mode, if the master checklist shows the active Pie still has unchecked slices (
### Slice N.Mis[ ]), STOP and surface asneeds_human: truewithhitl_category: prd_ambiguity: "Pie N still has unfinished slices - finish them via /sell-pie before boxing the pie, or confirm you want to ship a partial pie." Never silently ship an incomplete pie. In pie-local mode the same guard applies, except that an unattended run (run.unattended: true) treats a slice whose status readsdeferred: <reason>as finished for this merge (its commits already left the pie branch), and a slicewaiting until <YYYY-MM-DD>as finished too (its commits passedslice-verifierand merge with the pie; the row stays[ ]), and lists both inblocked. A slice whose**Status:**readswaiting until <YYYY-MM-DD>: <criterion>is unfinished too: refuse with "Pie N is waiting on Slice N.M until <YYYY-MM-DD> (<criterion>). Re-run /sell-pie on or after that date; the boundary PR opens once it closes." No HITL is needed for a waiting slice, since the date is the only blocker; setstatus: needs_humanonly if the operator asked to ship anyway.
If a master checklist exists and the branch maps to a pie row, /box-it-up flips that Pie's status from In Progress to Completed and commits the flip on the pie branch before the PR opens (Phase 1 step 4), so the status reaches main with the merge and never as an uncommitted edit on main. That is the only sequential-flavored behavior - best-effort enhancement, never a precondition.
Subagent Roster
| Phase | Agent file | Model | Effort | Mode |
|---|---|---|---|---|
| 3 (on CI fail, pie-completion / slice-merge / ship) | agents/ci-fix-attempter.md | sonnet | high | write |
| pie-local check (on red, pie-local only) | ../sell-slice/agents/fix-attempter.md | sonnet | high | write |
CI watching itself is inline (gh pr checks <pr> --watch blocks until checks settle). No separate watcher subagent. Per-slice mode dispatches no subagents - there is no PR and therefore no CI to fix.
Inputs and Preconditions
This skill checks its own preconditions inline at the start, via tools (current branch,
gh auth statuswhen the mode needs PR work). If one fails, raise the problem to the operator as a question with a recommended next step, never a refusal. Onmain/master, say so and ask how to proceed (usually: switch to the pie branch or its worktree); the merge-per-slice closeout (--merge-slice) runs frommainby design, so this check is skipped there. Never narrate passing checks in chat. No ByTheSlice hook blocks a prompt.
- Working tree on a feature branch (not
main/master) - for a v5 pie this ispie-<n>-<scope>. - Per-slice mode: the slice's changes are committed locally OR present as uncommitted changes the skill should commit.
ghis not required (no PR work). - Pie-completion / universal mode:
ghCLI installed and authenticated (gh auth statusreturns "Logged in"); the repository has a remote (git remote -vreturns at leastorigin). - One worktree per pie (default mode) - created upstream by
/sell-piewhen the pie branch is cut, removed here at the boundary. Inslice-mergemode it is one worktree per slice, created by the conductor and removed here after that slice merges./box-it-upnever creates a worktree; it only removes one. - Slice-merge mode:
ghauthenticated, and the repo allows merge commits (gh repo view --json mergeCommitAllowed). - Pie-local mode: the primary checkout is clean and on the ship branch; the pie worktree is clean.
ghis not required (no PR work), and nothing is pushed. - Ship mode: the primary checkout is clean and on the ship branch;
ghauthenticated (the only ship-once step that needs it); anoriginremote; the repo allows merge commits.
Workflow
At every phase boundary, if the bts_status tool is available call it instead of re-reading the checklist; if it is not, read the checklist as before.
Per-slice mode runs Phase 1 only, then returns. Phases 0 and 2-6 are pie-completion / universal closeout.
slice-mergemode runs Phases 0 → 6 with the overrides in "Merge-per-slice closeout" below. The phase numbering is shared so the commit logic is defined once.
Phase 0 - Pre-flight Safety Checks (pie-completion / universal)
The skill refuses to proceed past Phase 0 if any check fails. The point is to avoid a destructive accident on main or an accidental push to a stale branch.
git rev-parse --abbrev-ref HEAD- capture current branch asBRANCH.- If
BRANCHismainormaster, STOP. Surface asneeds_human: truewithhitl_category: destructive_operationand message: "Refusing to ship from main. Switch to a pie / feature branch first." Do not push, do not commit. git worktree list- capture worktree state asWORKTREE_PATH(the path matching the current working directory) andIS_WORKTREE(trueif cwd is not the main worktree). For a v5 pie this is the pie worktree slated for removal in Phase 5.gh pr list --state merged --limit 1 --base main --json headRefName,number,mergedAt- capture the most recently merged PR. IfBRANCHmatches itsheadRefName(an already-shipped pie branch reused without renaming), STOP and surface asneeds_human: truewithhitl_category: destructive_operation. Ask whether to rename or proceed.gh pr list --state open --head "$BRANCH" --json number,url --jq '.[0]'- check whether an open PR for this branch already exists. If yes, capture its number and URL asEXISTING_PR_NUMBER/EXISTING_PR_URL. The skill reuses it (watch CI on the existing PR) rather than create a duplicate. Because per-slice pushes never open a PR, the first boundary run normally finds none.gh auth status- confirm gh is authenticated. If not, surface asexternal_credentialsHITL and stop.- Pie-completeness check (pie-completion mode only): confirm every
### Slice N.Munder the active## Pie Nindocs/plans/00_master_checklist.mdis[x]. If any is[ ], STOP per the Mode-detection refusal guard (prd_ambiguity, or the waiting-slice refusal when its status readswaiting until <date>).
Phase 1 - Commit + Push (both modes; the per-slice entry point)
git status --short- if there are uncommitted changes, handle them per the batched-approvals rule: when a conductor invoked this skill (--slice,--merge-slice, or the/sell-pieboundary handoff) and every changed path came from agents'files_changedor the checklist, commit without asking (the conductor already owns those paths). Ask only when something is unexpected, and then put this question in one batch with every other approval already known at this point (for example a squash-only repo from the Phase 4 strategy check, run early), one decision per question, each with a recommended answer. The Phase 4 merge gate needs CI's result, so it is its own later batch. The commit question:- "Stage and commit these changes? (yes / let me write the message / cancel)"
- Always provide a recommended answer in the available options. Default recommendation: yes if the diff looks like the in-scope slice; "let me write" if it includes unexpected files.
- On
yes: stage selectively, nevergit add -Aorgit add .. Stage only the paths the conductor recorded from agents'files_changedand the checklist; anything else is an unexpected file, so recommend "let me write" and list it. Then derive the commit message by mode:- Per-slice mode - the slice's task commits (
feat(pie-N): N.M task K <task name>) are already pushed. This is the slice's final commit, using the v5 slice commit convention:feat(pie-N): N.M <slice name>(swapfeatforfix/chore/docswhen the diff is purely a fix / infra-config / docs). One-line subject; short body listing touched files grouped by package/app. If the slice touched UI and/sell-slice//sell-pieproduced a closing-narrative paragraph (one paragraph: what was built · why this shape · what was left out · what reviewers should pay attention to), include it verbatim in the commit body before the file list. These task and slice commit messages are what the boundary PR preserves - they become the PR's commit-by-commit story, so keep each one self-describing. When nothing is left to stage (the checklist is gitignored, as it is by default, and no fix patch or state file is pending), make the final commit withgit commit --allow-empty: its subject is the slice's record in the history, and Phase 4 merges a branch holding an empty commit with a merge commit so it survives. After the push,git status --shortmust be empty: the slice may not leave an untracked or modified file it created. - Pie-completion / universal mode - only reached here when the boundary run finds straggler uncommitted changes (most slices are already committed by the per-slice runs). Derive a conventional type from the diff (
feat:/fix:/chore:/docs:) with a one-line subject and a file-list body.
- Per-slice mode - the slice's task commits (
- On
let me write: prompt for the message. - On
cancel: stop here. Working tree unchanged.
git push origin "$BRANCH"- push to the pie branch. If the remote rejects (non-fast-forward, etc.), STOP and surface asdestructive_operationHITL - never auto force-push. Ship-once: skip the push; the pie branch stays local until--pie-localmerges it into the ship branch, and only--shippushes anything.- Per-slice mode ends here. Return the per-slice contract (
status: complete, the commit SHA + branch). Do not open a PR, do not watch CI, do not merge. The/sell-pieloop advances to the next slice; CI fires only at the pie boundary. - Flip the Pie's checklist status (pie-completion mode only), before the PR opens. In
docs/plans/00_master_checklist.md, set the active## Pie Nstatus fromIn ProgresstoCompleted, commit it on the pie branch aschore(pie-N): mark Pie N completed, and push. The flip rides intomainwith the merge, somainnever carries an uncommitted checklist edit (the pre-commit guard blocks commits onmain, and Phase 5 requires a clean tree). If the operator holds or cancels the PR, the flip stays on the unmerged branch only. When the checklist is gitignored (git check-ignore -q docs/plans/00_master_checklist.md, the default), flip the primary checkout's copy ($PLANS/00_master_checklist.md, pergit-worktree-standard.md, "Where the plans live"; a worktree has no copy) and make no commit. Skip silently in universal mode (no checklist / no pie row). - Reconcile the checklist before any PR opens (every mode that opens one: pie-completion, universal, slice-merge and ship). Before Phase 2 runs
gh pr create, readdocs/plans/00_master_checklist.md(the primary checkout's$PLANScopy when it is gitignored) against the branch diff,git diff --name-only origin/main...HEAD. Every slice the branch delivers or changes, including a feedback round, a review follow-up or a CI fix made outside/sell-sliceand/sell-pie, gets its**Status:**line set to what the branch leaves it at (Completed,In Progress, orPartial: <what is owed>), and its pie heading readsCompletedonce every slice in it does. Commit that on the branch asdocs(pie-N): update the checklist for <scope>and push; with gitignored plans, edit the primary checkout's copy and commit nothing. In universal mode a project that has a master checklist is no exception: map the changed files to slices through the slice plans that name them. A branch that touches no slice leaves the checklist alone. Use only the status words the parsers read (Completed, In Progress, Not Started, Partial,waiting until <date>: <criterion>); the checklist edit hook reports any line they cannot read. If this step is skipped, thegh pr createhook (hooks/checklist-check.sh pr) adds a warning; it never blocks.
Phase 2 - Open the Pie PR (or Reuse Existing) (pie-completion / universal)
- If
EXISTING_PR_NUMBERfrom Phase 0 is set, skip to Phase 3 - the existing PR already tracks this branch. - Otherwise, open one PR for the whole pie:
- Title: for a pie,
Pie N: <name>(liftNand the name from the## Pie N - <name>checklist header). For a hand-rolled branch, fall back togh pr create --fill(latest commit subject). gh pr create --base main --head "$BRANCH" --fill- the--fillbody lifts the accumulated slice commit subjects/bodies, so the per-slice closing-narrative paragraphs carry the design story into the PR description without a separate step. For a named pie, set the title explicitly (--title "Pie N: <name>") and keep--fillfor the body.- Evidence section (the Pass ledger): when
bts_pr_bodyis available, write its output into the PR body under## Evidenceafter the--fillcontent; the section is generated, do not edit it by hand. Call it once with{ "pie": N }beforegh pr create. A--bodyor--body-fileoverwrites what--fillwould write, so build the body file yourself: the--fillcontent (git log --reverse --format='%s%n%n%b' origin/main..HEAD), then a blank line and## Evidence, then the tool's output verbatim; pass it with--body-fileand keep--title. When the tool is absent, or answers its one-linebts_pr_body:message (no ledger, nonode), open the PR with--fillalone and leave the section out. It warns and never blocks: a missing section is not a reason to stop. - Capture the returned URL as
PR_URLand the number asPR_NUMBER.
- Title: for a pie,
- Output the PR URL to the user immediately so they can open it in a browser if they want to skim the pie.
- No failing gate rides in the body as an open item. Every enabled gate passed before the pie reached this phase (
quality-gates.md), so the body never lists one as a follow-up, "for your decision" or out of scope. Advisory-class findings (gates.advisory) may be listed, labeled advisory.
Phase 3 - Watch CI (pie-completion / universal - CI's single run for the pie)
In the default pie-pr mode this is the one time CI fires for the entire pie - per-slice pushes opened no PR. In slice-merge mode it is the slice PR's CI run. gh pr checks "$PR_NUMBER" --watch blocks until every check finishes. Capture the exit code:
- Exit 0 → all checks passed. Continue to Phase 4.
- Non-zero → at least one check failed. Capture the output (
gh pr checks "$PR_NUMBER" --json name,state,bucket,workflow) and the required set (gh pr checks "$PR_NUMBER" --required --json name), then classify each failed check. It is advisory when its gate class is ingates.advisory(quality-gates.md; the class comes from the job name:lint,typecheck,build, unit or integration tests aretests, any e2e jobe2e,visualvisual,design-system-compliancedesign-system, an accessibility jobaccessibility, anything elseci) and it is not a required check. Every other failure is binding, and a failed required check is always binding, whatevergates.advisorysays.- Any binding failure → Phase 3a, the auto-fix loop, with the binding failures only.
- Only advisory failures left → CI counts as green: continue to Phase 4, listing each advisory failure by name, labeled advisory, in the merge prompt and the PR body. Never fix one.
The skill caps total CI watch time at 30 minutes per attempt. If --watch does not return within 30 minutes (e.g. self-hosted runner hung), surface as external_credentials HITL.
Phase 3a - CI Fix Loop (on red)
Loop counter starts at 1. Cap at 3 attempts.
Every red check is a binding gate. Dispatch the fix without asking the operator first, and never offer "merge anyway", "fix in a follow-up" or "the cause is outside this pie" as an answer: ci-fix-attempter fixes the root cause where it lives, a shared design token or a file the pie only consumes included. A non-required check in a class listed in gates.advisory is the one exception (Phase 3 classified it): report it, labeled advisory, and do not fix it; it never enters this loop or counts against its cap. The operator hears about a red required check only at the cap-exhaustion HITL below, or when its fix is destructive or needs a secret.
- Capture the failed-check rollup:
gh pr checks "$PR_NUMBER" --json name,state,link,workflow, keeping the binding failures only (Phase 3's classification; re-run it after each round). - For each failed check, retrieve logs:
gh run view <run-id> --log-failedfor workflow runs, ORgh pr view "$PR_NUMBER" --commentsfor non-Actions checks (e.g. external services posting back).
- Dispatch
bytheslice:ci-fix-attempter(definition; fallback on hosts without plugin agents: Read the file and dispatch it perloop-workflow-fallback-pattern.md"Agent shape on the fallback path": its frontmatter goes first as a header (model tier and effort, the normalized tool allowlist, the read-only line for an agent without write tools, the no-git-writes line), then its body, then the inputs; log one self-check line per dispatch in the run log). Pass:PR_NUMBER,PR_URL,BRANCH- The failed-check rollup
- Truncated log excerpts (last 200 lines per failed job) - let the agent ask for more on demand
- The pie diff (
git diff origin/main...HEAD) - The attempt number
previous_signature: thesignaturethe previous round returned, ornullon attempt 1
- The agent makes no git writes: it returns
files_changedand a proposed commit subject and body. This skill stages exactly those paths (git add -- <paths>), commits with the proposed message, and pushes toorigin "$BRANCH"(never forced; a rejected push is adestructive_operationHITL). Do not call--watchfrom inside the dispatch - the skill returns to Phase 3 (top) after its push lands and re-invokesgh pr checks --watchagainst the new head SHA. When a round's fix changes what a slice delivers, update that slice's**Status:**line in the same commit (Phase 1 step 5). If the agent returnsbail_reason: repeated_signature, it patched nothing because the identical failure survived the last round: stop the loop now, commit and push nothing, and surface thecreative_directionHITL below. The bail counts as that round and never extends the 3. - Increment the counter. If it would exceed 3, STOP. Surface as
creative_directionHITL with the full failure history, naming each check still failing, so the user can decide whether to grant more rounds, debug manually, retry CI, or close the PR. This cap-exhaustion HITL is the only place a failing gate is put to the user.
The 3-attempt cap is a hard rule and is not overridable by the run instruction: "continue until CI is green", "never stop", "fully automated" or an autonomous-delivery instruction do not add rounds. Only the operator's explicit reply at this HITL can grant more. The CI counter is per PR and separate from the conductor's 3 local fix loops per slice; neither borrows from the other. One identical repeat already signals a structural problem (flaky test, missing secret, infra outage) that needs human judgment, so the loop stops at the first repeated signature (normalize(first_error_line) + " | " + file + " | " + job_name, a plain string compared by equality and never persisted) instead of counting to three.
Phase 4 - Merge Authorization Gate (pie-completion / universal - the kept pie-boundary HITL)
CI is green, or only advisory, non-required checks are red (Phase 3). Stop and prompt the user (this is the §1.8 pie-boundary checkpoint - in the default pie-pr mode, the one HITL the loop never auto-approves; slice-merge mode has no per-slice merge gate, see "Merge-per-slice closeout"):
"CI is green on PR
<PR_URL>(Pie N)<; advisory checks red, not fixed: <names>, when any>. Approve merge?"Options (always include a recommended answer):
- Approve and merge now (recommended if you've already reviewed the pie) - the skill merges preserving every per-slice commit (see strategy below) and proceeds to Phase 5.
- Hold - keep the PR open for manual review - the skill exits, leaving the PR open. You merge via the GitHub UI when ready (with the strategy the helper picked: "Create a merge commit" when the pie holds empty commits), then re-run
/box-it-up --resumeto do cleanup.- Cancel - leave the PR open and stop - the skill exits without merging.
Merge strategy - preserve per-slice commits (never squash). The whole point of the per-slice commits is that they survive the merge as the pie's history. These rules - merge preserving per-slice commits (never squash), --ff-only sync, git worktree remove/prune cleanup, and the boundary-PR body shape - come from ../cook-pizzas/references/git-worktree-standard.md (Phase 3 + Invariants §5 + the PR template §6). Resolve the strategy with the helper, from the pie branch: gh repo view --json rebaseMergeAllowed,mergeCommitAllowed,squashMergeAllowed | node "<this-skill-directory>/pick-merge-strategy.js" --base origin/main (after git fetch origin), and capture the branch's commit subjects for Phase 5 with SUBJECTS=$(git log --format=%s origin/main..HEAD). The helper prints one JSON line, { strategy, reason, emptyCommits }, by these rules (with --mode slice-merge or --mode ship it skips them and always answers a merge commit, reason: merge-commit-required, or strategy: none, reason: merge-commits-disallowed):
- Empty commits force a merge commit. GitHub's rebase-merge drops a commit whose tree equals its parent's, so a slice-close commit made with
--allow-emptywould vanish frommain. When the branch holds one (reason: empty-commits), use a merge commit (gh pr merge "$PR_NUMBER" --merge). If merge commits are disallowed (strategy: none,reason: empty-commits-need-merge-commit), STOP and surfaceprd_ambiguity: "This pie has N empty slice-close commits that a rebase-merge would drop. Enable merge commits, or confirm you accept losing them." - Otherwise prefer rebase-merge for a pie PR (
gh pr merge "$PR_NUMBER" --rebase; a slice PR inslice-mergemode always uses a merge commit instead) - replays each slice commit onto main, linear history, everyfeat(pie-N): N.Mpreserved. - If rebase is disallowed (
reason: rebase-disallowed), use a merge commit (gh pr merge "$PR_NUMBER" --merge) - also preserves the individual commits under a merge node. - Never
--squashfor a pie - squashing collapses the per-slice commits into one and destroys the boundary contract. If a project's settings allow only squash (the helper'sreason: squash-only), STOP and surface asneeds_human: truewithhitl_category: prd_ambiguity: "This repo only permits squash merges, which would collapse the pie's per-slice commits. Enable rebase or merge-commit merges, or confirm you accept a squash for this pie." For a hand-rolled branch with no per-slice contract, the project default (including squash) is acceptable - the preserve-commits rule binds pies, not arbitrary branches.
Never force-merge a PR with non-required failing checks unless the user explicitly authorizes via the HITL prompt.
Phase 5 - Post-merge Cleanup (pie-completion / universal)
Only runs after the PR is merged (by this skill in Phase 4 option 1, or by the user manually before /box-it-up --resume).
-
gh pr view "$PR_NUMBER" --json state,number,mergedAt- confirm state isMERGED. If not, STOP. Don't pull or delete branches on a falsely-assumed merge.- Pie-completion mode only, before cleanup: record the confirmed merge for the local kitchen. Pipe a fresh successful
gh pr view "$PR_NUMBER" --json state,number,mergedAtresponse tonode "<this-skill-directory>/record-kitchen-merge.js" --mode pie --pie "<active-pie-number>" --project "${CLAUDE_PROJECT_DIR:-$PWD}". The helper validatesMERGED, a PR number and a merge timestamp, then atomically replaces the single bounded.claude/.bytheslice-state/kitchen/merged-pie.jsonrecord with only version, pie, PR number and merge time. Use this skill's installed absolute directory for the helper path. If the read or write fails, report missing kitchen evidence; do not invent success. - Slice-merge mode: run the same writer exactly once per pie, after the pie's last slice PR merges, piping that PR's
gh pr viewresponse with--mode pie --pie "<active-pie-number>". Never per slice. - Never run this writer in
--sliceor universal mode, for any slice-merge slice but the pie's last, before merge confirmation, or from skill/Stop log events. A skill finish cannot prove a PR merged. The kitchen reader makes no network calls and ignores malformed, stale, future or wrong-pie records. Every step after the merge check runs from the primary checkout, never from the pie worktree.mainis checked out in the primary checkout, sogit checkout maininside the pie worktree fails, and git refuses to delete a branch a worktree still holds. Resolve the primary checkout once:PRIMARY=$(git worktree list --porcelain | sed -n '1s/^worktree //p')(the first entry is always the main working tree). The Pie's checklist flip is already committed on the branch (Phase 1 step 4), so nothing here edits a tracked file.
- Pie-completion mode only, before cleanup: record the confirmed merge for the local kitchen. Pipe a fresh successful
-
cd "$PRIMARY"so the shell is not inside the worktree about to be removed. IfIS_WORKTREEwas false (the branch was checked out in the primary checkout itself), rungit -C "$PRIMARY" checkout main; if that would overwrite uncommitted changes, STOP and surface asdestructive_operationHITL. Then confirmgit -C "$PRIMARY" rev-parse --abbrev-ref HEADismainandgit -C "$PRIMARY" status --shortis empty. If the primary checkout sits on another branch or is dirty, STOP (destructive_operation): never switch, stash or overwrite a checkout the operator may be using. -
git -C "$PRIMARY" pull --ff-only origin main- fast-forward only. If this fails (history diverged), STOP and surface asdestructive_operationHITL. -
Confirm the PR's merge result is now in local main:
git -C "$PRIMARY" log --oneline | grep -q "$PR_NUMBER\|<merge sha>", then confirm every branch commit subject captured in Phase 4 (SUBJECTS) appears ingit -C "$PRIMARY" log --format=%s. If any is absent, STOP and surface - something's odd. -
Remove the pie worktree first (if
IS_WORKTREEfrom Phase 0 was true):git -C "$PRIMARY" worktree remove "$WORKTREE_PATH"(neverrm -rf). This must precede the branch delete: git refuses to delete a branch that a worktree still has checked out. -
git -C "$PRIMARY" branch -d "$BRANCH"- delete the local pie branch (safe delete; refuses if unmerged commits exist, which is what we want). After a rebase-merge the commits onmaincarry new SHAs, so-dpasses only while the branch's upstream ref still exists; if it refuses, confirm step 4 found every slice commit subject onmainand surfacedestructive_operationbefore any-D. -
git push origin --delete "$BRANCH"- delete the remote branch. If GitHub auto-deleted it on merge (orgh pr merge --delete-branchdid), this returns "remote ref does not exist" - fine; record it but don't fail. From a worktree, rungh pr mergewithout--delete-branch: that flag also tries to switch the local checkout tomain, which the primary checkout holds. -
git -C "$PRIMARY" worktree prune- clear stale worktree metadata. -
git -C "$PRIMARY" status --short- must be empty.git -C "$PRIMARY" rev-parse --abbrev-ref HEAD- must bemain.git -C "$PRIMARY" status -uno- confirm fully synced with remote. The pie is closed; the next pie starts in a fresh chat with a fresh worktree.
Phase 6 - Final Report (pie-completion / universal)
Surface to the user:
- PR URL + merge commit SHA (+ note the merge strategy used: rebase / merge-commit, and why when the helper picked a merge commit for empty commits)
- Pie name + branch name (now deleted) + worktree path (now removed)
- Slice and task commit count preserved on main
- Total CI attempts (1 if green on first run; up to 3 if the fix loop ran) + ci-fix-attempter dispatch count / per-attempt summary if applicable
- Final state: "On main, clean tree, fully synced with origin/main. Pie N closed - start the next pie in a fresh chat."
Merge-per-slice closeout (slice-merge mode, --merge-slice)
Runs once per slice when delivery.mode resolves to merge-per-slice. The conductor (/sell-pie or /sell-slice) invokes it internally and passes BRANCH (pie-N-sN.M-<scope>), WORKTREE_PATH (the slice worktree), the slice id and name, and whether this is the pie's last slice. Phases 0 → 6 apply with these overrides:
- Phase 0. Run steps 1-6 against the slice worktree (
git -C "$WORKTREE_PATH" ...). Skip step 7 (pie completeness). Add:gh repo view --json mergeCommitAllowed --jq .mergeCommitAllowedmust printtrue. If it does not, STOP the loop withneeds_human: true,hitl_category: prd_ambiguity: "This repo disallows merge commits, which merge-per-slice delivery requires. Enable merge commits, or rerun this pie in the default one-PR-per-pie mode?" Never fall back to squash or rebase on its own. - Phase 1. The slice's work is already committed and pushed on
BRANCH. On the pie's last slice, Phase 1 step 4 applies: flip## Pie NtoCompleted, commit, push, so the flip reachesmainwith this slice's merge. With a gitignored checklist (the default) there is nothing to commit: flip$PLANS/00_master_checklist.mdin the primary checkout only after the Phase 4 merge, so a slice that stays red never marks its pie done. If any slice of the pie is stillwaiting until <YYYY-MM-DD>(calendar-gated), this is not the last slice: do not flip the pie and do not write the kitchen merge record; the slice PR that later closes the waiting slice is the pie's last. - Phase 2. Title the PR
Slice N.M: <name>:gh pr create --base main --head "$BRANCH" --title "Slice N.M: <name>" --fill. - Phase 3 / 3a. Watch CI as usual, classifying failed checks as Phase 3 does. On a binding failure, up to 3
ci-fix-attempterrounds (the CI fix counter is per slice); advisory, non-required failures alone count as green and are listed in the slice notice. Still red after the 3rd round, or a round that bails on a repeated signature: halt the loop with acreative_directionHITL carrying the failure history. Never skip the slice, never merge it red, never start the next slice. - Phase 4. No human merge gate: the run instruction or
delivery.modealready authorized autonomous delivery. On green, merge with a merge commit:gh pr merge "$PR_NUMBER" --merge(never--squash, never--rebase, never--delete-branchfrom the worktree). - Phase 5. Identical cleanup from the primary checkout:
git -C "$PRIMARY" pull --ff-only origin main,git -C "$PRIMARY" worktree remove "$WORKTREE_PATH",git -C "$PRIMARY" branch -d "$BRANCH",git push origin --delete "$BRANCH",git -C "$PRIMARY" worktree prune. Write the kitchen merge record only after the pie's last slice (see Phase 5 step 1). Append one line to the run log.claude/.bytheslice-state/run-log.md(gitignored): slice id, PR URL, merge commit SHA, merge time. - Phase 6. Return a short per-slice result to the conductor (PR URL, merge SHA, CI rounds). The conductor cuts the next slice from the freshly synced
main; on the pie's last slice it sends the operator one notice listing every slice PR from the run log.
Pie-local closeout (pie-local mode, --pie-local)
Runs once per pie when delivery.mode resolves to ship-once. The /sell-pie conductor invokes it internally and passes BRANCH (pie-<n>-<scope>), WORKTREE_PATH (the pie worktree), SHIP (the ship branch), the pie number and name, run.unattended, and any slices it deferred. Phases 2-4 do not run: there is no PR, no push and no CI. All gates are local.
- Pre-flight. Resolve
PRIMARY=$(git worktree list --porcelain | sed -n '1s/^worktree //p')and$PLANSpergit-worktree-standard.md, "Where the plans live". Confirmgit -C "$PRIMARY" rev-parse --abbrev-ref HEADisSHIP,git -C "$PRIMARY" status --shortis empty,git -C "$WORKTREE_PATH" status --shortis empty, andBRANCHis neithermainnorSHIP. A failure is adestructive_operationHITL (never switch, stash or overwrite the primary checkout). - Verified-slice check. Every
### Slice N.Munder## Pie Nin$PLANS/00_master_checklist.mdmust be[x]and have aslice-verifierpass in the Pass ledger (bts_statusshows each slice's last verdicts; without the tool, look for the slice'sslice-verifierpass in$PRIMARY/.bytheslice/ledger.jsonl). With no ledger at all, trust the checklist and say so in the report. Adeferred:slice (unattended only) must have no commit on the branch: no subject ingit -C "$PRIMARY" log --format=%s "$SHIP".."$BRANCH"namesN.M. A slice that fails this check means the merge would carry unverified work into the ship PR. - Full local check, once, on the pie branch. In
WORKTREE_PATH, run the same commandsslice-verifierruns on its first pass under ship-once (definition, "Which commands run"): the CI command list parsed from the project's generated.github/workflows/ci.ymland then, when it exists,.github/workflows/e2e.yml(everyrun:step, jobs inneeds:order, environment setup skipped, a literalorigin/main...HEADreplaced with"$SHIP"...HEAD), so this check and the ship PR's CI run the same commands, every one of them, never a subset. Readquality.tierfrombytheslice.config.json(autoresolves as/final-quality-check"Quality tier" documents). Underleanthat list is lint, typecheck, unit tests, build,check:design-systemonly when a design system exists, andtest:e2e:smoke; never runtest:e2e:feature,test:e2e:regressionortest:e2e:visualunder lean, since lean CI does not. Understandard, that list includes every e2e suitee2e.ymlruns (@feature,@regression-coreand@visual), in full:verification.e2e.*does not narrow it, because CI does not read those thresholds. With noci.ymlyet, fall back to<pm> lint,<pm> typecheck,<pm> build,<pm> test,<pm> check:design-systemwhen it exists and the tier's e2e gate, with the package manager from the lockfile (pnpm-lock.yaml,package-lock.json,yarn.lock,bun.lock/bun.lockb) and the actual script names frompackage.json(they may be non-standard, e.g.check-types), and say so. Skip a script the project does not define and say so. Run each once and continue past a failure so the full picture is known. All green: go to step 5. Every other generated workflow that runs on pull requests (e2e-coverage.yml,db-schema-drift.yml,design-system-compliance.yml, when present) runs too, so nothing can fail only in CI on the ship PR. - Fix rounds (on red). First classify each failed command as Phase 3 classifies a check, by the job it came from: one whose gate class is in
gates.advisoryis advisory (listed, labeled advisory, in the ship PR body, never fixed, outside this cap) unless branch protection onmainrequires that job (gh api repos/{owner}/{repo}/branches/main/protection --jq '.required_status_checks.contexts', when readable), which keeps it binding. Only advisory failures left: the check counts as green, go to step 5. Counter starts at 1, cap 3, separate from every slice's local fix loops and from the CI rounds. Dispatchbytheslice:fix-attempter(definition; fallback perloop-workflow-fallback-pattern.md"Agent shape on the fallback path") with the failing checks as its verdict (check, command, exit code, last ~50 lines of output), the pie diff (git -C "$WORKTREE_PATH" diff "$SHIP"...HEAD), the round number andprevious_signature(normalize(first_error_line) + " | " + file + " | " + check, never persisted). It returnsfiles_changed; this skill stages exactly those paths, commits them onBRANCHasfix(pie-N): pie-local check round K <check>(no push), and re-runs the full local check (a round is one fix plus one full check, like a CI round). Arepeated_signaturebail ends the loop at once and counts as that round. Still red after round 3:- Interactive:
creative_directionHITL with the failure history; the pie is not merged. - Unattended (
run.unattended: true): do not ask. Leave the pie branch and worktree in place, unmerged, record the blocker{pie: "N", reason: "pie-local check red after 3 rounds: <checks>", attempts: 3}with onebts_note, and returnstatus: complete_with_deferrals.
- Interactive:
- Flip the pie status. Tracked plans: set
## Pie NtoCompletedonBRANCH, commitchore(pie-N): mark Pie N completed. Gitignored plans (the default): flip$PLANS/00_master_checklist.mdafter step 6 succeeds, no commit. With deferred slices (unattended) the status readsCompleted (deferred: N.M, N.K). - Merge into the ship branch, preserving every slice commit. Capture
SUBJECTS=$(git -C "$PRIMARY" log --format=%s "$SHIP".."$BRANCH"), then from the primary checkout:git -C "$PRIMARY" merge --no-ff -m "merge(pie-N): Pie N <name> into $SHIP" "$BRANCH". Never squash, never rebase, never fast-forward. The subject names no slice id, so the PR evidence does not read the merge commit as an unverified slice. Confirm every line ofSUBJECTSappears ingit -C "$PRIMARY" log --format=%s "$SHIP". A conflict (unexpected: the ship branch moves only through these merges, and the pie was cut from its tip) isgit -C "$PRIMARY" merge --abort, then adestructive_operationHITL (interactive) or a pie blocker (unattended); never auto-resolve. - Cleanup from the primary checkout.
git -C "$PRIMARY" worktree remove "$WORKTREE_PATH", thengit -C "$PRIMARY" branch -d "$BRANCH"(safe: it is merged into the checked-out ship branch), thengit -C "$PRIMARY" worktree prune. No remote delete: the pie branch was never pushed. Leave anydeferred/pie-N-sN.Mbranch in place for the conductor. Append one line to the run log.claude/.bytheslice-state/run-log.md: pie, ship-branch merge SHA, check rounds, deferred slices. No kitchen merge record here (no PR merged);--shipwrites it. - Return a short result to the conductor: merge SHA, check rounds, deferred slices and blockers, and whether this was the checklist's last pie.
Ship closeout (ship mode, --ship)
Runs once, after the last pie of a ship-once build has merged into the ship branch. An interactive /sell-pie invokes it after its last --pie-local; in an unattended run the /pizza-party conductor invokes it after its replan. The caller passes SHIP, the app name (default: SHIP without its ship/ prefix), run.unattended, and the blocked list collected across the build. Phases 0 → 6 apply from the primary checkout with these overrides:
- Phase 0.
BRANCHisSHIP; confirm the primary checkout is on it and clean. Skip step 7 (pie completeness); instead confirm every## Pie Nin$PLANS/00_master_checklist.mdisCompleted(interactive: an unmerged pie is aprd_ambiguityHITL, "ship without Pie N?"; unattended: proceed and list it as a blocker). Run steps 4-6 as written (gh auth statusis the one ship-onceghcheck). Resolve the merge strategy now:gh repo view --json rebaseMergeAllowed,mergeCommitAllowed,squashMergeAllowed | node "<this-skill-directory>/pick-merge-strategy.js" --base origin/main --mode ship(aftergit fetch origin) always picks a merge commit;reason: merge-commits-disallowedis aprd_ambiguityHITL (interactive) or a blocker returned before anything is pushed (unattended). - Phase 1. Nothing to commit.
git -C "$PRIMARY" push -u origin "$SHIP"; a rejected push is adestructive_operationHITL (interactive) or a blocker (unattended), never a force-push. - Phase 2. Title
Ship <app>: <pies> pies, <slices> slices, counting the pies merged into the ship branch (merge(pie-N)merge commits inorigin/main..$SHIP) and the slices[x]. Build the body file: the commit story (git log --reverse --no-merges --format='%s%n%n%b' origin/main.."$SHIP"), a blank line,## Evidence, then for every merged pie a### Pie Nheading andbts_pr_body({ "pie": N })output verbatim (omit the section when the tool is absent), then## Deferredlisting everyblockedentry and the design-critique findings recorded as deferred (omit when empty).gh pr create --base main --head "$SHIP" --title "<title>" --body-file <file>. Every slice named on the branch must carry aslice-verifierpass in the ledger, which deferral guarantees (it keeps unverified commits off the branch). If one does not, surface its slice list (prd_ambiguity, interactive) or return it as a blocker (unattended) instead of opening the PR. - Phase 3 / 3a. Watch CI once (30-minute cap per attempt), classifying failed checks as Phase 3 does; on a binding failure, up to 3
ci-fix-attempterrounds committed and pushed onSHIPfrom the primary checkout (advisory, non-required failures alone count as green and are listed in the ship PR body). Still red after round 3, or arepeated_signaturebail: interactive, thecreative_directionHITL as usual; unattended, leave the PR open, record the blocker{pie: "ship", reason: "ship PR CI red after 3 rounds: <checks>", attempts: 3, pr: "<PR_URL>"}and returnstatus: complete_with_deferralswithout merging. A PR GitHub reports as conflicting withmain(gh pr view --json mergeableisCONFLICTING) is handled the same way, as adestructive_operationHITL or a blocker; never auto-resolve. - Phase 4. No human merge gate: choosing ship-once authorized the merge. On green,
gh pr merge "$PR_NUMBER" --merge(the strategy from Phase 0; never--squash, never--rebase, which would drop the pie merge commits; never--delete-branch, since the primary checkout holdsSHIP). - Phase 5. Capture
SUBJECTS=$(git -C "$PRIMARY" log --format=%s origin/main.."$SHIP")before the merge. Aftergh pr viewconfirmsMERGED, write the kitchen merge record once with--mode pie --pie "<last pie number>". Then, from the clean primary checkout:git -C "$PRIMARY" switch main,git -C "$PRIMARY" pull --ff-only origin main, confirm everySUBJECTSline is ingit -C "$PRIMARY" log --format=%s,git -C "$PRIMARY" branch -d "$SHIP",git push origin --delete "$SHIP",git -C "$PRIMARY" worktree prune. Pie worktrees are already gone; any pie left unmerged by an unattended blocker keeps its worktree and is listed in the report.deferred/*branches stay for the conductor. - Phase 6. Report the ship PR URL, the merge SHA and strategy, pies and slices shipped, CI rounds, and every blocker; return
status: complete, orcomplete_with_deferralswhenblockedis not empty.
HITL Handling
Agents and this skill never call ask_user_input_v0. At every elicitation point - the Phase 1 commit prompt and the Phase 4 merge-authorization gate - the skill sets needs_human: true plus the hitl_* fields in its return contract and lets the invoking orchestrator (/sell-pie's loop, or the operator's session) surface the prompt. The phase descriptions above show the question text; the skill emits it as hitl_question, not as a direct tool call.
For sub-agent failures (e.g. ci-fix-attempter returns needs_human: true), the skill bubbles the structured fields up via its own return contract - it does not retry indefinitely.
Unattended ship-once runs never ask. In pie-local and ship mode with run.unattended: true, every point below that would set needs_human instead records a blocker in blocked ({slice | pie, reason, attempts}, plus pr when a ship PR is left open), leaves the git state as it is (an unmerged pie keeps its branch and worktree; a red ship PR stays open), and returns status: complete_with_deferrals to the conductor. Fix caps never rise. Interactive runs behave exactly as described below.
HITL categories the skill produces:
destructive_operation- about to push from main, force-push detected, merge-conflict pull, branch-reuse without rename, would-overwrite uncommitted changes on checkout.external_credentials-ghnot authenticated, CI watch timeout (likely runner / secrets issue).creative_direction- ci-fix-attempter exhausted 3 attempts or bailed on a repeated signature; user decides whether to debug, retry, or close the PR. Inslice-mergemode this halts the delivery loop. Inpie-localmode, the full local check still red after 3fix-attempterrounds.prd_ambiguity- boxing a pie with unfinished slices; a squash-only repo that would collapse per-slice commits; a repo that disallows merge commits inslice-mergemode; a precondition that needs the user to tell the skill how to interpret state.
Hard Constraints
- Per-slice mode opens no PR and watches no CI. Commit + push only, then return. In the default
pie-prmode CI fires exactly once per pie, at the boundary, and no PR opens mid-pie. Exception:slice-mergemode (delivery.mode: merge-per-slice) opens, CI-checks and merges one PR per slice. - Preserve per-slice commits on a pie merge - never
--squash. Default mode: rebase-merge for the pie PR, merge-commit as fallback, and always a merge commit when the branch holds an empty commit (rebase-merge drops it;pick-merge-strategy.jsdecides).slice-mergemode: always a merge commit; a repo that disallows merge commits is aprd_ambiguityHITL. A squash-only repo is aprd_ambiguityHITL, not a silent squash. - Ship-once: no human merge gate, local gates per pie, CI once at the end.
pie-localmerges the pie into the ship branch only after every non-deferred slice has aslice-verifierpass and the full local check is green (at most 3fix-attempterrounds), withgit merge --no-ff(never squash, rebase or fast-forward), and never pushes.shippushes the ship branch, opens one PR, merges it with a merge commit only on green CI (at most 3ci-fix-attempterrounds), then syncsmainand deletes the ship branch. Unattended runs return blockers instead of asking, and leave a red ship PR open. - No per-slice merge approval in
slice-mergemode; never merge red. The slice merges only on green CI, after at most 3ci-fix-attempterrounds; still red halts the loop. There is never an integration branch. - One worktree per pie (default and ship-once) or per slice (
slice-merge);/box-it-uponly removes it. The worktree is created upstream by the conductor. This skill removes it after the merge (viagit worktree remove+prune, neverrm -rf) and never creates one. The merge/cleanup rules here are the standard's - see../cook-pizzas/references/git-worktree-standard.md(Phase 3 + Invariants §5). - Never ship from
main/master. Phase 0 step 2 is a stop-everything check.--shipships from the ship branch;--pie-localwrites only the pie merge commit on it. - Never force-push. If
git pushis rejected for non-fast-forward, STOP. The user resolves on a fresh branch. - Only the conductor makes git writes,
git addincluded.ci-fix-attempterreturnsfiles_changed; this skill stages those paths selectively, commits and pushes, on the registered and fallback paths alike. Nevergit add -A. - Never auto-merge a PR with failing required checks. Phase 4 only runs when CI is green on the latest head SHA.
- Never box an incomplete pie. If any slice under the active Pie is still
[ ], STOP (prd_ambiguity). - Never
git stashon the user's behalf. Ifgit checkout mainwould overwrite uncommitted changes, STOP. - Clean up from the primary checkout, in order. Sync
mainwithgit -C "$PRIMARY" pull --ff-only, thenworktree remove, thenbranch -d, then the remote delete, thenworktree prune. Never check outmaininside a worktree, and never delete a branch a worktree still holds. - Never edit a tracked file on
main. The Pie's checklist flip is committed on the pie branch before the PR opens. - Never auto-resolve merge conflicts during cleanup pull.
--ff-onlyfails fast; the user resolves. - Red checks are binding gates. Fix them through Phase 3a without asking, root cause fixed where it lives; never merge red, never park a failing check as a follow-up or "out of scope". Only a class in
gates.advisoryis reported instead of fixed. - Cap the CI fix loop at 3 attempts. Beyond that → HITL
creative_direction. No "one more try." No run instruction raises the cap; only the operator's explicit reply at the HITL does. Separate from the 3 local fix loops per slice. Thepie-localcheck rounds are their own counter with the same cap of 3 and the same rule. - Cap CI watch at 30 minutes per attempt. Beyond that → HITL
external_credentials. - Reuse existing PRs. If an open PR already tracks the branch, watch its CI; never create a duplicate.
- Never call
ask_user_input_v0. Setneeds_human+hitl_*and let the orchestrator prompt. - Subagent prompts live in
./agents/*.md. This SKILL.md is workflow only - never inline subagent prompts here. - Always provide a recommended answer in available options at every elicitation point.
Triggers
Follow this skill whenever the user (or /sell-pie's loop):
- runs
/box-it-up(pie-completion / universal closeout) or/box-it-up --slice(per-slice commit + push) - is a ship-once conductor at a pie boundary (
--pie-local) or after the last pie (--ship) - says "box up the pie", "close out the pie", "ship the pr", "submit the pr", "open and merge the pr", "ship this branch", "ship this pie"
- has finished every slice of a Pie under
/sell-pieand reached the pie boundary - has a hand-rolled feature branch ready to ship (universal closeout)
If the working tree is on main with no feature branch in sight, redirect to /sell-pie (autonomous, whole pie) or /sell-slice (one careful slice) first.
If the user wants to open the boundary PR but pause before merging for code review, they should pick option 2 (Hold) at the Phase 4 gate.
Completion Checklist
Walk the checklist that matches the mode. Do not report done until every applicable box is [x].
Per-slice mode
- [ ] Current branch confirmed not
main/master(it is the pie branch). - [ ] Slice closed with a
feat(pie-N): N.M <name>(or fix/chore/docs) final commit on top of its pushed task commits; tree clean. - [ ] Branch pushed to
origin. - [ ] No PR opened, no CI watched - returned cleanly so the loop continues.
Slice-merge mode
- [ ] Repo allows merge commits (
mergeCommitAllowedtrue), or the loop halted and asked. - [ ] Checklist reconciled before the PR opened (Phase 1 step 5): the slice reads
Completed. - [ ] PR
Slice N.M: <name>opened againstmain. - [ ] CI green on the latest head SHA (at most 3
ci-fix-attempterrounds; still red halted the loop). - [ ] Merged with a merge commit, no squash, no rebase.
- [ ] Cleanup ran from the primary checkout:
pull --ff-only,worktree remove,branch -d, remote delete,worktree prune. - [ ] Run-log line appended; kitchen merge record written only after the pie's last slice.
Pie-local mode (ship-once)
- [ ] Primary checkout clean and on the ship branch; pie worktree clean.
- [ ] Every slice
[x]with aslice-verifierpass (or, unattended,deferred:with no commit on the branch). - [ ] Full local check ran once on the pie branch (every command
ci.ymland, under standard,e2e.ymlrun, in full; lean: smoke spec only, never@feature/@regression-core/@visual) and is green (at most 3fix-attempterrounds), or the pie was left unmerged with a HITL (interactive) or a blocker (unattended). - [ ] Pie merged into the ship branch with
git merge --no-ff; every pie commit subject found on the ship branch; nothing pushed. - [ ] Pie worktree removed, pie branch deleted with
-d,worktree pruneran; pie status flipped; run-log line appended.
Ship mode (ship-once)
- [ ] Every pie
Completedon the ship branch (or, unattended, listed as a blocker), and the checklist reconciled before the PR opened (Phase 1 step 5). - [ ] Repo allows merge commits (
pick-merge-strategy.js --mode shippickedmerge). - [ ] Ship branch pushed; one PR
Ship <app>: <pies> pies, <slices> slicesopened againstmainwith a### Pie Nevidence block per pie and a## Deferredsection when anything was deferred. - [ ] CI green (at most 3
ci-fix-attempterrounds) and merged with a merge commit, no human gate; or, unattended and still red, the PR left open and reported as a blocker. - [ ] Kitchen merge record written once;
mainsynced--ff-onlyin the primary checkout; ship branch deleted local and remote;worktree pruneran.
Pie-completion / universal mode
1. Pre-flight passed
- [ ] Current branch confirmed not
main/master. - [ ] Worktree state captured (path + IS_WORKTREE flag).
- [ ] No accidental reuse of a recently-merged branch.
- [ ]
ghauthenticated. - [ ] (pie mode) Every slice under the active Pie is
[x].
2. Pie PR open
- [ ] Checklist reconciled before the PR opened (Phase 1 step 5): every slice the diff delivers or changes carries its true
**Status:**, also in universal mode when a checklist exists. - [ ] Any straggler changes committed; branch pushed to
origin. - [ ] (pie mode) Pie status flipped
In Progress→Completedand committed on the pie branch before the PR opened. - [ ] One PR open against
main- titledPie N: <name>for a pie (or reused existing). - [ ] PR URL surfaced to the user.
3. CI green on the merged head SHA
- [ ]
gh pr checks <pr> --watchreturned exit 0 (CI's single run for the pie). - [ ] If the auto-fix loop ran, the final attempt cleared green; ci-fix-attempter dispatch history captured.
- [ ] No required check skipped or pending.
4. Merge authorized + completed (preserving slice commits)
- [ ] Phase 4 user prompt surfaced (via
needs_human/hitl_*) and answered. - [ ] Merge used rebase or merge-commit - not squash for a pie; per-slice commits preserved on main.
- [ ] PR state is
MERGEDpergh pr view.
5. Branch + worktree cleanup
- [ ] Cleanup ran from the primary checkout (
git -C "$PRIMARY" ...), which is onmain. - [ ]
git -C "$PRIMARY" pull --ff-only origin mainsucceeded. - [ ] Pie worktree removed via
git worktree remove(if a worktree was used), before the branch delete. - [ ] Local pie branch deleted (
git branch -d). - [ ] Remote pie branch deleted (or already auto-deleted by GitHub).
- [ ]
git worktree pruneran. - [ ]
git status --shortempty in the primary checkout;git status -unoconfirms fully synced withorigin/main.
6. Final report emitted
- [ ] User received the report (PR URL, merge SHA + strategy, slice-commit count, attempt counts, "Pie N closed - next pie in a fresh chat").
Sub-agent return contract
/box-it-up returns structured fields whether it ran per-slice or boxed the whole pie (e.g. when /sell-pie's loop invokes it). It never prompts the user directly - the orchestrator reads needs_human + hitl_* and surfaces any question.
status: complete | complete_with_deferrals | failed | needs_human # complete_with_deferrals: unattended pie-local / ship recorded a blocker instead of asking
mode: slice | slice-merge | pie | universal | pie-local | ship
summary: <one paragraph - mode; for slice: commit sha + branch; for slice-merge: slice PR URL + number, CI rounds, merge commit SHA, cleanup state; for pie: pie name, PR URL + number, CI attempt count, merge strategy + SHA, per-slice-commit count preserved, cleanup state; for pie-local: pie name, local check rounds, ship-branch merge SHA, deferred slices, cleanup state; for ship: ship PR URL + number, pies and slices shipped, CI rounds, merge SHA, cleanup state>
artifacts:
- <commit sha (slice mode)>
- <pr url (slice-merge/pie/universal/ship mode)>
- <merge commit sha (slice-merge/pie/universal/pie-local/ship mode)>
local_check_rounds: null | <int> # pie-local only: fix rounds used (0 when green on the first run)
last_pie: null | false | true # pie-local only: every pie in the checklist is now merged into the ship branch (or deferred, unattended)
blocked: [] | [{slice: "<N.M>", reason: "<one line>", attempts: <int>} | {pie: "<N>" | "ship", reason: "<one line>", attempts: <int>, pr: "<url, ship only>"}] # unattended pie-local / ship only
needs_human: false | true
hitl_category: null | "prd_ambiguity" | "external_credentials" | "destructive_operation" | "creative_direction"
hitl_question: null | "<plain-language question>"
hitl_context: null | "<what triggered this>"
04 同仓库更多 Skills
special-order
Cook a slice with the customer's specifications on the spot: add new features mid-flight to an existing project. Auto-detects project type and extends the master checklist with new stages.
setup-shop
Start the oven, check ingredients, prep the shop. Bootstrap a new project or configure ByTheSlice in an existing one. First-time install, system-wide config, or per-project setup.
set-display-case
Build the display case the pies will sit in, bootstrap your design system: tokens, Tailwind config, design rules, and the operator-only /library preview route. Run once before /sell-slice; also invocable standalone on any project.
sell-slice
Sell a customer their slice - the high-touch single-slice delivery loop. Execute one slice from your master checklist as an interactive spine (prep gate · recon · build-plan auth · /goal · branch) + Workflow A (produce) + library gate + Workflow B (verify-once). Run me repeatedly, one fresh chat per slice. For autonomous whole-pie baking use /sell-pie.
sell-pie
Bake a whole Pie autonomously - the v5 forefront delivery loop. A /loop-driven baker that drives ONE Pie (a coherent chapter, usually 3 to 8 slices) to "ready for review" without per-slice prompting; each slice runs the context-separated build→test→verify→fix Workflow, commits + pushes (no PR), and advances; when every slice is [x] it stops at the pie boundary and opens one PR via /box-it-up. Refuses flat v4 checklists (points you at /cook-pizzas --repie). For a continuous-review pie (review=continuous) it runs in high-touch /sell-slice mode. Opt-in merge-per-slice delivery (delivery.mode, or an explicit autonomous-delivery run instruction) instead gives each slice its own branch, PR and green-CI merge; opt-in ship-once delivery (delivery.mode, set by /pizza-party) merges each pie into one local ship branch on local gates only and ships one PR at the end. The four blocking HITL categories halt the loop instead of rescheduling (an unattended ship-once run defers the slice instead). Use when the user runs /sell-pie, says "sell a pie", "bake the pie", "run the next pie", "loop the pie", or wants one whole chapter delivered hands-off. For a single careful slice use /sell-slice; for the whole app end to end use /pizza-party.
pizza-party
Cater a whole app, start to finish: from a short brief to a finished, deployed app with a URL. One interview up front (AskUserQuestion), then no human stops: /setup-shop, /create-menu, /cook-pizzas, the Prep pie, every pie through /sell-pie in ship-once delivery (all gates local), one PR that ships the app, a deploy to whatever host the operator has authorized (or an artifact or localhost link), and a run record for comparing runs over time. Every decision a sub-skill would normally ask about is decided, recorded in the order ticket, and the run continues. Use when the user runs /pizza-party, sets a /goal to build an app end to end, or says "build me this app end to end", "from scratch to production", "pizza party", "bake the whole roadmap" or "run all pies".