@pareto4/pp-core 1.7.1 → 1.8.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.
Files changed (51) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/bin/install.js +197 -81
  3. package/commands/pp-build-handoff.md +8 -2
  4. package/commands/pp-discovery-to-build.md +40 -0
  5. package/commands/pp-ns-project.md +3 -1
  6. package/gemini-extension.json +1 -1
  7. package/package.json +2 -1
  8. package/pareto-skills/_shared/create-project-board.sh +195 -0
  9. package/pareto-skills/_shared/pp-claude-md-protocol.md +306 -0
  10. package/pareto-skills/_shared/sync-phase-status.sh +139 -0
  11. package/pareto-skills/pp-brand/SKILL.md +644 -0
  12. package/pareto-skills/pp-brand/assets/crew/ParetoAgent.inline.html +120 -0
  13. package/pareto-skills/pp-brand/assets/crew/ParetoAgent.tsx +239 -0
  14. package/pareto-skills/pp-brand/assets/crew/build.svg +11 -0
  15. package/pareto-skills/pp-brand/assets/crew/deploy.svg +11 -0
  16. package/pareto-skills/pp-brand/assets/crew/discovery.svg +11 -0
  17. package/pareto-skills/pp-brand/assets/crew/plan.svg +11 -0
  18. package/pareto-skills/pp-brand/assets/crew/run.svg +11 -0
  19. package/pareto-skills/pp-brand/assets/crew/validate.svg +11 -0
  20. package/pareto-skills/pp-brand/assets/pareto-brand-preview.html +547 -0
  21. package/pareto-skills/pp-obsidian-notes/SKILL.md +127 -0
  22. package/pareto-skills/pp-obsidian-notes/templates/CLAUDE.md +29 -0
  23. package/pareto-skills/pp-obsidian-notes/templates/client-context.md +116 -0
  24. package/pareto-skills/pp-obsidian-notes/templates/meeting-note.md +66 -0
  25. package/pareto-skills/pp-obsidian-notes/templates/pareto-context.md +102 -0
  26. package/pareto-skills/pp-obsidian-notes/templates/proposal.md +117 -0
  27. package/pareto-skills/pp-project-setup/SKILL.md +1364 -0
  28. package/pp-core/bin/lib/clusters.cjs +4 -0
  29. package/pp-core/bin/lib/intel.cjs +1 -1
  30. package/pp-core/bin/lib/io.cjs +120 -0
  31. package/pp-core/bin/lib/profile-pipeline-command-router.cjs +1 -1
  32. package/pp-core/bin/lib/roadmap-parser.cjs +1 -1
  33. package/pp-core/bin/lib/runtime-artifact-conversion.cjs +2 -2
  34. package/pp-core/bin/lib/surface.cjs +1 -1
  35. package/pp-core/bin/lib/worktree-safety.cjs +2 -2
  36. package/pp-core/bin/pp-tools.cjs +23 -0
  37. package/pp-core/references/ui-brand.md +73 -11
  38. package/pp-core/templates/codebase/structure.md +5 -5
  39. package/pp-core/templates/spec.md +7 -7
  40. package/pp-core/workflows/add-backlog.md +1 -1
  41. package/pp-core/workflows/autonomous.md +4 -4
  42. package/pp-core/workflows/debug.md +1 -1
  43. package/pp-core/workflows/{build-handoff.md → discovery-to-build.md} +6 -3
  44. package/pp-core/workflows/execute-phase.md +9 -1
  45. package/pp-core/workflows/plan-phase.md +14 -12
  46. package/pp-core/workflows/pr-branch.md +5 -4
  47. package/pp-core/workflows/reapply-patches.md +1 -1
  48. package/pp-core/workflows/ship.md +1 -1
  49. package/pp-core/workflows/thread.md +1 -1
  50. package/pp-core/workflows/verify-work.md +6 -5
  51. package/scripts/lint-allow-test-rule-refs.allowlist.json +1 -0
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: pp:build-handoff
3
- description: Transition a completed Pareto Discovery Sprint into a pp-core-ready project — synthesize sessions into .planning/ and wire cross-references.
3
+ description: "[DEPRECATED] Alias for /pp-discovery-to-build; removed in a future major."
4
4
  argument-hint: "[--skip-validation] [--scaffold]"
5
5
  allowed-tools:
6
6
  - Read
@@ -18,6 +18,12 @@ requires: [new-project]
18
18
  **Copilot (VS Code):** Use `vscode_askquestions` wherever this workflow calls `AskUserQuestion`. They are equivalent — `vscode_askquestions` is the VS Code Copilot implementation of the same interactive question API.
19
19
  </runtime_note>
20
20
 
21
+ <deprecation_note>
22
+ **Deprecated:** `/pp-build-handoff` was renamed to `/pp-discovery-to-build` in v1.8.0. This
23
+ alias runs the identical workflow and is kept for back-compat with v1.7.x. Prefer
24
+ `/pp-discovery-to-build`; this alias will be removed in a future major release.
25
+ </deprecation_note>
26
+
21
27
  <objective>
22
28
  Bridge the gap between a completed Pareto Discovery Sprint and pp-core execution.
23
29
 
@@ -32,7 +38,7 @@ execution, or `/pp-autonomous` to run all phases.
32
38
  </objective>
33
39
 
34
40
  <execution_context>
35
- @~/.claude/pp-core/workflows/build-handoff.md
41
+ @~/.claude/pp-core/workflows/discovery-to-build.md
36
42
  </execution_context>
37
43
 
38
44
  <process>
@@ -0,0 +1,40 @@
1
+ ---
2
+ name: pp:discovery-to-build
3
+ description: Transition a completed Pareto Discovery Sprint into a pp-core-ready project.
4
+ argument-hint: "[--skip-validation] [--scaffold]"
5
+ allowed-tools:
6
+ - Read
7
+ - Write
8
+ - Edit
9
+ - Bash
10
+ - Glob
11
+ - Grep
12
+ - Agent
13
+ - AskUserQuestion
14
+ requires: [new-project]
15
+ ---
16
+
17
+ <runtime_note>
18
+ **Copilot (VS Code):** Use `vscode_askquestions` wherever this workflow calls `AskUserQuestion`. They are equivalent — `vscode_askquestions` is the VS Code Copilot implementation of the same interactive question API.
19
+ </runtime_note>
20
+
21
+ <objective>
22
+ Bridge the gap between a completed Pareto Discovery Sprint and pp-core execution.
23
+
24
+ Validates all 13 Discovery sessions are complete, synthesizes their outputs into a
25
+ single structured handoff document, bootstraps the `.planning/` project state
26
+ (PROJECT.md, REQUIREMENTS.md, ROADMAP.md, STATE.md, config.json), and wires up
27
+ cross-references so pp-core agents can trace every decision back to the Discovery
28
+ session that produced it.
29
+
30
+ **After this command:** pp-core is initialized. Run `/pp-plan-phase 1` to start
31
+ execution, or `/pp-autonomous` to run all phases.
32
+ </objective>
33
+
34
+ <execution_context>
35
+ @~/.claude/pp-core/workflows/discovery-to-build.md
36
+ </execution_context>
37
+
38
+ <process>
39
+ Execute end-to-end.
40
+ </process>
@@ -5,7 +5,7 @@ argument-hint: ""
5
5
  allowed-tools:
6
6
  - Read
7
7
  - Skill
8
- requires: [init, new-project, new-milestone, complete-milestone, audit-milestone, milestone-summary, import, ingest-docs, profile-user, review-backlog]
8
+ requires: [init, new-project, discovery-to-build, build-handoff, new-milestone, complete-milestone, audit-milestone, milestone-summary, import, ingest-docs, profile-user, review-backlog]
9
9
  ---
10
10
 
11
11
  Route to the appropriate project / milestone skill based on the user's intent.
@@ -16,6 +16,8 @@ inline as part of `pp-audit-milestone`'s output.
16
16
  |---|---|
17
17
  | Initialize a project (canonical front door) | pp-init |
18
18
  | Start a new project | pp-new-project |
19
+ | Hand off a completed Discovery Sprint into the build flow | pp-discovery-to-build |
20
+ | (deprecated) Discovery→build handoff alias | pp-build-handoff |
19
21
  | Create a new milestone | pp-new-milestone |
20
22
  | Complete the current milestone | pp-complete-milestone |
21
23
  | Audit a milestone for issues | pp-audit-milestone |
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pp-core",
3
- "version": "1.7.1",
3
+ "version": "1.8.1",
4
4
  "description": "PP Core — a meta-prompting, context engineering, and spec-driven development system for AI coding agents. Loads pp-core's operating context into every Gemini CLI session.",
5
5
  "contextFileName": "GEMINI.md"
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pareto4/pp-core",
3
- "version": "1.7.1",
3
+ "version": "1.8.1",
4
4
  "description": "Pareto pp-core — The Pareto Project's AI-assisted engineering framework: meta-prompting, context engineering, and spec-driven development for AI coding agents.",
5
5
  "bin": {
6
6
  "pp-core": "bin/install.js",
@@ -13,6 +13,7 @@
13
13
  "pp-core",
14
14
  "assets",
15
15
  "agents",
16
+ "pareto-skills",
16
17
  ".claude-plugin",
17
18
  "gemini-extension.json",
18
19
  "GEMINI.md",
@@ -0,0 +1,195 @@
1
+ #!/usr/bin/env bash
2
+ # create-project-board.sh
3
+ #
4
+ # Canonical GitHub Project v2 board creation for Pareto skills.
5
+ # Creates (or updates) a project board for a given owner/repo with the
6
+ # standard Pareto status columns, custom fields, and label palette.
7
+ #
8
+ # Used by:
9
+ # - pareto-project-setup (initial scaffold)
10
+ # - pareto-build-handoff (Discovery → pp-core handoff)
11
+ # - pareto-push-issues (standalone requirements push)
12
+ #
13
+ # Single source of truth — edit here, not in the skills.
14
+ #
15
+ # Usage:
16
+ # source _shared/create-project-board.sh
17
+ # create_project_board "<owner>" "<project_title>" "<repo_slug>"
18
+ #
19
+ # Example:
20
+ # create_project_board "pareto-project" "my-app" "pareto-project/my-app"
21
+ #
22
+ # Environment variables honored:
23
+ # BOARD_OWNER_FALLBACK (default: "@me") — used if org create fails
24
+ #
25
+ # Returns (via stdout, space-separated): <board_number> <owner>
26
+ # Exits non-zero on fatal error.
27
+
28
+ set -euo pipefail
29
+
30
+ # -----------------------------------------------------------------------------
31
+ # Canonical column schema
32
+ # -----------------------------------------------------------------------------
33
+ # Any change here propagates to every skill that sources this file.
34
+ #
35
+ # Status flow:
36
+ # Backlog → Discuss → Planned → In Progress → Verification → PR Raised → Done
37
+ #
38
+ # Each column maps 1:1 to a pp-core workflow step:
39
+ # Discuss = /pp-discuss-phase (CONTEXT.md written)
40
+ # Planned = /pp-plan-phase (PLAN.md created)
41
+ # In Progress = /pp-execute-phase (branch active, executing)
42
+ # Verification = VERIFICATION.md written, tests passing
43
+ # PR Raised = PR created from phase branch, awaiting merge
44
+ # Done = PR merged, issue closed
45
+ #
46
+ PARETO_STATUS_OPTIONS='[
47
+ {name: "Backlog", color: GRAY, description: "Not yet started"},
48
+ {name: "Discuss", color: PINK, description: "Context gathering via /pp-discuss-phase"},
49
+ {name: "Planned", color: BLUE, description: "Plans created via /pp-plan-phase"},
50
+ {name: "In Progress", color: YELLOW, description: "Executing via /pp-execute-phase"},
51
+ {name: "Verification", color: ORANGE, description: "Verification passed — VERIFICATION.md written"},
52
+ {name: "PR Raised", color: PURPLE, description: "PR created from phase branch, awaiting merge"},
53
+ {name: "Done", color: GREEN, description: "PR merged, issue closed"}
54
+ ]'
55
+
56
+ # Label color palette for per-EPIC labels. Cycle through these in order.
57
+ PARETO_EPIC_COLORS=(
58
+ "0E8A16" "1AA393" "D93F0B" "B44EFF"
59
+ "4A9EFF" "EF4444" "F5C842" "8B5CF6"
60
+ )
61
+
62
+ # -----------------------------------------------------------------------------
63
+ # create_project_board <owner> <title> <owner/repo>
64
+ # -----------------------------------------------------------------------------
65
+ create_project_board() {
66
+ local OWNER="$1"
67
+ local TITLE="$2"
68
+ local REPO="$3"
69
+ local BOARD_NUM
70
+
71
+ # 1. Check for existing board matching title
72
+ BOARD_NUM=$(gh project list --owner "$OWNER" --format json 2>/dev/null \
73
+ | jq -r ".projects[] | select(.title==\"$TITLE\") | .number" || true)
74
+
75
+ if [ -z "$BOARD_NUM" ]; then
76
+ # 2. Try to create under the given owner
77
+ BOARD_NUM=$(gh project create --owner "$OWNER" --title "$TITLE" \
78
+ --format json 2>/dev/null | jq -r '.number' || true)
79
+
80
+ # 3. Fall back to personal projects if org creation failed
81
+ if [ -z "$BOARD_NUM" ]; then
82
+ OWNER="${BOARD_OWNER_FALLBACK:-@me}"
83
+ BOARD_NUM=$(gh project create --owner "$OWNER" --title "$TITLE" \
84
+ --format json | jq -r '.number')
85
+ fi
86
+
87
+ # 4. Link board to repo
88
+ gh project link "$BOARD_NUM" --owner "$OWNER" --repo "$REPO" >/dev/null
89
+ fi
90
+
91
+ # 5. Configure Status field with Pareto schema (idempotent — safe to re-run)
92
+ configure_status_field "$BOARD_NUM" "$OWNER"
93
+
94
+ # 6. Ensure custom fields exist (Priority, Sprint, Estimate, Phase)
95
+ ensure_custom_fields "$BOARD_NUM" "$OWNER"
96
+
97
+ echo "$BOARD_NUM $OWNER"
98
+ }
99
+
100
+ # -----------------------------------------------------------------------------
101
+ # configure_status_field <board_num> <owner>
102
+ # -----------------------------------------------------------------------------
103
+ configure_status_field() {
104
+ local BOARD_NUM="$1"
105
+ local OWNER="$2"
106
+ local STATUS_FIELD_ID
107
+
108
+ STATUS_FIELD_ID=$(gh project field-list "$BOARD_NUM" --owner "$OWNER" --format json \
109
+ --jq '.fields[] | select(.name=="Status") | .id')
110
+
111
+ if [ -z "$STATUS_FIELD_ID" ]; then
112
+ echo "ERROR: Status field not found on board $BOARD_NUM" >&2
113
+ return 1
114
+ fi
115
+
116
+ gh api graphql -f query="
117
+ mutation {
118
+ updateProjectV2Field(input: {
119
+ fieldId: \"$STATUS_FIELD_ID\"
120
+ singleSelectOptions: $PARETO_STATUS_OPTIONS
121
+ }) {
122
+ projectV2Field { ... on ProjectV2SingleSelectField { id name } }
123
+ }
124
+ }
125
+ " >/dev/null
126
+ }
127
+
128
+ # -----------------------------------------------------------------------------
129
+ # ensure_custom_fields <board_num> <owner>
130
+ # -----------------------------------------------------------------------------
131
+ ensure_custom_fields() {
132
+ local BOARD_NUM="$1"
133
+ local OWNER="$2"
134
+
135
+ # Priority (single-select)
136
+ gh project field-create "$BOARD_NUM" --owner "$OWNER" \
137
+ --name "Priority" --data-type "SINGLE_SELECT" \
138
+ --single-select-options "Must Have,Should Have,Could Have,Won't Have" \
139
+ 2>/dev/null || true
140
+
141
+ # Sprint (iteration — created manually in UI if needed)
142
+ gh project field-create "$BOARD_NUM" --owner "$OWNER" \
143
+ --name "Sprint" --data-type "ITERATION" 2>/dev/null || true
144
+
145
+ # Estimate (number)
146
+ gh project field-create "$BOARD_NUM" --owner "$OWNER" \
147
+ --name "Estimate" --data-type "NUMBER" 2>/dev/null || true
148
+
149
+ # Phase (text — pp-core phase number reference, e.g. "3" or "3.1")
150
+ gh project field-create "$BOARD_NUM" --owner "$OWNER" \
151
+ --name "Phase" --data-type "TEXT" 2>/dev/null || true
152
+ }
153
+
154
+ # -----------------------------------------------------------------------------
155
+ # ensure_core_labels <owner/repo>
156
+ # -----------------------------------------------------------------------------
157
+ # Idempotent — uses --force so existing labels get updated.
158
+ ensure_core_labels() {
159
+ local REPO="$1"
160
+
161
+ gh label create "epic" -c "3E4B9E" -d "Epic — high-level feature group" --force -R "$REPO"
162
+ gh label create "user-story" -c "1D76DB" -d "User story" --force -R "$REPO"
163
+ gh label create "must-have" -c "B60205" -d "Must Have — MVP required" --force -R "$REPO"
164
+ gh label create "should-have" -c "FBCA04" -d "Should Have — important" --force -R "$REPO"
165
+ gh label create "could-have" -c "0E8A16" -d "Could Have — nice to have" --force -R "$REPO"
166
+ gh label create "in-progress" -c "FBCA04" -d "Phase branch actively executing" --force -R "$REPO"
167
+ gh label create "verification" -c "D93F0B" -d "In pp-core verification + PR review" --force -R "$REPO"
168
+ }
169
+
170
+ # -----------------------------------------------------------------------------
171
+ # create_epic_label <owner/repo> <slug> <epic_id> <epic_title> <index>
172
+ # -----------------------------------------------------------------------------
173
+ # Color cycles through PARETO_EPIC_COLORS by index.
174
+ create_epic_label() {
175
+ local REPO="$1"
176
+ local SLUG="$2"
177
+ local EPIC_ID="$3"
178
+ local TITLE="$4"
179
+ local IDX="$5"
180
+ local COLOR="${PARETO_EPIC_COLORS[$((IDX % ${#PARETO_EPIC_COLORS[@]}))]}"
181
+
182
+ gh label create "epic:${SLUG}" -c "$COLOR" -d "${EPIC_ID}: ${TITLE}" --force -R "$REPO"
183
+ }
184
+
185
+ # -----------------------------------------------------------------------------
186
+ # If sourced, functions above are exported to the caller. If executed directly,
187
+ # run create_project_board with positional args.
188
+ # -----------------------------------------------------------------------------
189
+ if [ "${BASH_SOURCE[0]}" = "$0" ]; then
190
+ if [ $# -lt 3 ]; then
191
+ echo "Usage: $0 <owner> <title> <owner/repo>" >&2
192
+ exit 1
193
+ fi
194
+ create_project_board "$@"
195
+ fi
@@ -0,0 +1,306 @@
1
+ <!--
2
+ pp-claude-md-protocol.md
3
+
4
+ Canonical pp-core ↔ GitHub protocol injected into a project's CLAUDE.md.
5
+
6
+ Used by:
7
+ - pareto-build-handoff (Step 6b: CLAUDE.md update)
8
+ - pareto-push-issues (Step 5.5: CLAUDE.md injection)
9
+
10
+ To inject: append the block below `## GitHub Board Sync` (if a section of
11
+ that name already exists, replace it — idempotent).
12
+
13
+ Single source of truth — edit here, not in the skills. Every repo that
14
+ runs build-handoff or push-issues gets the same protocol.
15
+ -->
16
+
17
+ ## GitHub Board Sync
18
+
19
+ Requirements are tracked as GitHub issues on a project board. The mapping
20
+ between pp-core requirement IDs (EPIC-xxx, US-xxx, FR-xxx) and GitHub issue
21
+ numbers lives in `.planning/github-issues.json`.
22
+
23
+ **Status flow:**
24
+
25
+ ```
26
+ Backlog → Discuss → Planned → In Progress → Verification → PR Raised → Done
27
+ ```
28
+
29
+ Every phase runs on its own branch and merges to `main` via a pull request
30
+ after verification passes. Stories only close when their phase PR is merged.
31
+
32
+ ### Per-phase lifecycle
33
+
34
+ **1. Phase starts (executing begins)**
35
+
36
+ Create a branch from `main` named `phase/{N}-{slug}` (slug from ROADMAP.md
37
+ phase title, kebab-case). All phase commits — code AND `.planning/` artifacts
38
+ — land on this branch.
39
+
40
+ ```bash
41
+ git checkout main && git pull
42
+ git checkout -b "phase/${N}-${SLUG}"
43
+ ```
44
+
45
+ Move each story issue covered by the phase to **In Progress**:
46
+
47
+ ```bash
48
+ gh issue edit {number} --add-label "in-progress,phase:{N}" \
49
+ --remove-label "verification" -R {repo}
50
+ ```
51
+
52
+ Also set the `Phase` custom field on the board item to the phase number.
53
+
54
+ **2. Phase implementation complete (SUMMARY.md written)**
55
+
56
+ Push the branch (first push uses `-u origin HEAD`) and move the stories to
57
+ **Verification**:
58
+
59
+ ```bash
60
+ git push -u origin HEAD
61
+ gh issue edit {number} --add-label "verification" \
62
+ --remove-label "in-progress" -R {repo}
63
+ ```
64
+
65
+ **3. Verification passes (VERIFICATION.md result = PASS)**
66
+
67
+ Open a pull request from the phase branch to `main`. The PR body MUST use
68
+ `Closes #N` for every story issue so GitHub auto-closes them on merge.
69
+
70
+ ```bash
71
+ PR_BODY=$(cat <<EOF
72
+ # Phase ${N}: ${PHASE_TITLE}
73
+
74
+ ## Summary
75
+ ${SUMMARY_FROM_SUMMARY_MD}
76
+
77
+ ## Requirements delivered
78
+ Closes #${ISSUE1} — ${US_ID_1}: ${STORY_TITLE_1}
79
+ Closes #${ISSUE2} — ${US_ID_2}: ${STORY_TITLE_2}
80
+
81
+ ## Verification
82
+ VERIFICATION.md result: PASS
83
+ - ${KEY_OUTCOMES}
84
+
85
+ ## Phase artifacts
86
+ - \`.planning/phases/${N}-${SLUG}/PLAN.md\`
87
+ - \`.planning/phases/${N}-${SLUG}/SUMMARY.md\`
88
+ - \`.planning/phases/${N}-${SLUG}/VERIFICATION.md\`
89
+
90
+ ---
91
+ Generated by pp-core phase execution.
92
+ EOF
93
+ )
94
+
95
+ gh pr create \
96
+ --base main \
97
+ --head "phase/${N}-${SLUG}" \
98
+ --title "Phase ${N}: ${PHASE_TITLE}" \
99
+ --body "$PR_BODY" \
100
+ --label "phase:${N}"
101
+ ```
102
+
103
+ **Do not close the story issues at this step.** They stay in Verification
104
+ until the PR merges. Keeping them open until merge is what makes the board
105
+ reflect *merged* reality, not just *verified* intent.
106
+
107
+ If verification fails: fix the code on the same phase branch, re-run
108
+ verification, update the PR (it auto-updates from new commits). No new
109
+ branch.
110
+
111
+ **4. PR merged**
112
+
113
+ GitHub auto-closes linked issues. The sync protocol then reconciles:
114
+
115
+ ```bash
116
+ # Sync loop — run after merge (or via /pareto-sync-board)
117
+ gh issue edit {number} --remove-label "in-progress,verification" -R {repo}
118
+ ```
119
+
120
+ Update `.planning/github-issues.json`: set each story's `status` to `"Done"`
121
+ and each EPIC's `status` based on whether all its stories are now closed.
122
+
123
+ If the merged phase closed ALL stories under an EPIC, also close the EPIC
124
+ issue with a delivery note:
125
+
126
+ ```bash
127
+ gh issue close {epic_number} -R {repo} \
128
+ -c "All stories delivered across phases {list}."
129
+ ```
130
+
131
+ ### Status map for .planning/github-issues.json
132
+
133
+ ```json
134
+ "status_map": {
135
+ "Backlog": "Backlog",
136
+ "discussing": "Discuss",
137
+ "planned": "Planned",
138
+ "executing": "In Progress",
139
+ "verifying": "Verification",
140
+ "pr_open": "PR Raised",
141
+ "complete": "Done"
142
+ }
143
+ ```
144
+
145
+ ### Filtered code-only PRs (optional)
146
+
147
+ If the team wants PR diffs without `.planning/` noise, run `/pp-pr-branch`
148
+ after Step 3 to produce a filtered branch. The filtered branch becomes the
149
+ PR head instead of `phase/{N}-{slug}`. The original phase branch stays as
150
+ the auditable work record.
151
+
152
+ ### MANDATORY: Board sync after pp-core phase transitions
153
+
154
+ **These instructions are project-level overrides.** When `.planning/github-issues.json`
155
+ exists, you MUST run the sync script and issue updates at each lifecycle transition
156
+ below. Sync is non-blocking — failures must never stop the pp-core workflow (always
157
+ append `|| true`).
158
+
159
+ **After `/pp-discuss-phase` completes** (CONTEXT.md written):
160
+
161
+ Move stories to **Discuss** and comment on each with key decisions:
162
+
163
+ ```bash
164
+ [ -f ".planning/github-issues.json" ] && bash "$HOME/.claude/skills/pareto/_shared/sync-phase-status.sh" "${PHASE_NUMBER}" "Discuss" 2>&1 || true
165
+ ```
166
+
167
+ Comment on each story issue for this phase with key decisions that affect it:
168
+
169
+ ```bash
170
+ if [ -f ".planning/github-issues.json" ]; then
171
+ REPO=$(jq -r '.repo' .planning/github-issues.json)
172
+ # For each story in the phase, add a comment with relevant decisions from CONTEXT.md
173
+ jq -r --argjson p "${PHASE_NUMBER}" '.issues | to_entries[] | select(.value.phase == $p and .value.type == "story") | "\(.key) \(.value.number)"' .planning/github-issues.json | while read REQ_ID ISSUE_NUM; do
174
+ gh issue comment "$ISSUE_NUM" -R "$REPO" --body "## Phase ${PHASE_NUMBER} — Context gathered
175
+
176
+ Decisions from \`/pp-discuss-phase\` that affect ${REQ_ID}:
177
+
178
+ ${DECISIONS_RELEVANT_TO_THIS_STORY}
179
+
180
+ ---
181
+ _Auto-posted by pp-core discuss-phase_" 2>/dev/null || true
182
+ done
183
+ fi
184
+ ```
185
+
186
+ Replace `${DECISIONS_RELEVANT_TO_THIS_STORY}` with the actual decisions from CONTEXT.md
187
+ that are relevant to each story. Extract from `<decisions>` section.
188
+
189
+ **After `/pp-plan-phase` completes planning** (plans pass all gates, STATE.md updated):
190
+
191
+ Move stories to **Planned** and comment with plan assignment:
192
+
193
+ ```bash
194
+ [ -f ".planning/github-issues.json" ] && bash "$HOME/.claude/skills/pareto/_shared/sync-phase-status.sh" "${PHASE_NUMBER}" "Planned" 2>&1 || true
195
+ ```
196
+
197
+ Then comment on each story issue with which plan covers it:
198
+
199
+ ```bash
200
+ if [ -f ".planning/github-issues.json" ]; then
201
+ REPO=$(jq -r '.repo' .planning/github-issues.json)
202
+ # For each story, find which PLAN.md references its requirement ID and comment
203
+ jq -r --argjson p "${PHASE_NUMBER}" '.issues | to_entries[] | select(.value.phase == $p and .value.type == "story") | "\(.key) \(.value.number)"' .planning/github-issues.json | while read REQ_ID ISSUE_NUM; do
204
+ gh issue comment "$ISSUE_NUM" -R "$REPO" --body "## Phase ${PHASE_NUMBER} — Planned
205
+
206
+ Covered by: \`${PLAN_FILE}\` (Wave ${WAVE})
207
+ Key tasks: ${TASK_SUMMARY}
208
+
209
+ ---
210
+ _Auto-posted by pp-core plan-phase_" 2>/dev/null || true
211
+ done
212
+ fi
213
+ ```
214
+
215
+ Replace `${PLAN_FILE}`, `${WAVE}`, and `${TASK_SUMMARY}` with actual values from the
216
+ PLAN.md that contains this story's requirement ID in its `requirements` frontmatter field.
217
+
218
+ **After `/pp-execute-phase` begins execution** (branch created, STATE.md shows phase active):
219
+
220
+ ```bash
221
+ [ -f ".planning/github-issues.json" ] && bash "$HOME/.claude/skills/pareto/_shared/sync-phase-status.sh" "${PHASE_NUMBER}" "In Progress" --label-add "in-progress" --label-remove "verification" 2>&1 || true
222
+ ```
223
+
224
+ **After `/pp-execute-phase` verification passes** (VERIFICATION.md written, ROADMAP.md updated):
225
+
226
+ Move stories to **Verification**:
227
+
228
+ ```bash
229
+ [ -f ".planning/github-issues.json" ] && bash "$HOME/.claude/skills/pareto/_shared/sync-phase-status.sh" "${PHASE_NUMBER}" "Verification" --label-add "verification" --label-remove "in-progress" 2>&1 || true
230
+ ```
231
+
232
+ **After PR is created** (push branch, create PR):
233
+
234
+ Push the branch and create a PR, then move stories to **PR Raised**:
235
+
236
+ ```bash
237
+ # 1. Push the phase branch
238
+ git push -u origin HEAD 2>&1 || true
239
+ ```
240
+
241
+ ```bash
242
+ # 2. Build PR body with Closes links for every story in this phase
243
+ if [ -f ".planning/github-issues.json" ]; then
244
+ REPO=$(jq -r '.repo' .planning/github-issues.json)
245
+ CLOSES_LINES=$(jq -r --argjson p "${PHASE_NUMBER}" '
246
+ .issues | to_entries[]
247
+ | select(.value.phase == $p and .value.type == "story")
248
+ | "Closes #\(.value.number) — \(.key): \(.value.title)"
249
+ ' .planning/github-issues.json)
250
+
251
+ gh pr create \
252
+ --base main \
253
+ --head "phase/${PHASE_NUMBER}-${PHASE_SLUG}" \
254
+ --title "Phase ${PHASE_NUMBER}: ${PHASE_NAME}" \
255
+ --body "$(cat <<EOF
256
+ ## Summary
257
+
258
+ ${SUMMARY_FROM_VERIFICATION_MD}
259
+
260
+ ## Requirements delivered
261
+
262
+ ${CLOSES_LINES}
263
+
264
+ ## Verification
265
+
266
+ VERIFICATION.md result: PASS
267
+
268
+ ## Phase artifacts
269
+
270
+ - \`.planning/phases/${PADDED_PHASE}-${PHASE_SLUG}/PLAN.md\`
271
+ - \`.planning/phases/${PADDED_PHASE}-${PHASE_SLUG}/SUMMARY.md\`
272
+ - \`.planning/phases/${PADDED_PHASE}-${PHASE_SLUG}/VERIFICATION.md\`
273
+
274
+ ---
275
+ Generated by pp-core phase execution.
276
+ EOF
277
+ )" 2>/dev/null || true
278
+ fi
279
+ ```
280
+
281
+ ```bash
282
+ # 4. Move stories to PR Raised
283
+ [ -f ".planning/github-issues.json" ] && bash "$HOME/.claude/skills/pareto/_shared/sync-phase-status.sh" "${PHASE_NUMBER}" "PR Raised" 2>&1 || true
284
+ ```
285
+
286
+ Stories stay in **PR Raised** until the PR is merged. GitHub auto-closes
287
+ the linked issues via `Closes #N`, which moves them to **Done** on the board.
288
+
289
+ After PR merge, clean up labels:
290
+
291
+ ```bash
292
+ [ -f ".planning/github-issues.json" ] && bash "$HOME/.claude/skills/pareto/_shared/sync-phase-status.sh" "${PHASE_NUMBER}" "Done" --label-remove "in-progress,verification" 2>&1 || true
293
+ ```
294
+
295
+ If any sync is missed or the board drifts, use the recovery steps below.
296
+
297
+ ### Recovery
298
+
299
+ If any step is missed, run `/pareto-sync-board` to reconcile. It:
300
+ - Reads `.planning/STATE.md`, `ROADMAP.md`, and every phase directory
301
+ - Checks `gh pr list --head phase/{N}-*` for PR state
302
+ - Only closes stories whose phase PR shows state `MERGED`
303
+ - Rewrites `github-issues.json` to match live board state
304
+
305
+ If `.planning/github-issues.json` is missing entirely, run
306
+ `/pareto-push-issues` to rebuild it from `.planning/REQUIREMENTS.md`.