diff --git a/plugins/compound-engineering/README.md b/plugins/compound-engineering/README.md index cb23972bd..89c016030 100644 --- a/plugins/compound-engineering/README.md +++ b/plugins/compound-engineering/README.md @@ -11,7 +11,7 @@ After installing, run `/ce-setup` in any project. It diagnoses your environment, | Component | Count | |-----------|-------| | Agents | 50+ | -| Skills | 41+ | +| Skills | 42+ | ## Skills @@ -44,9 +44,10 @@ For `/ce-optimize`, see [`skills/ce-optimize/README.md`](./skills/ce-optimize/RE | Skill | Description | |-------|-------------| +| `ce-pr-description` | Write or regenerate a value-first PR title and body from the current branch or a specified PR; used directly or by other skills | | `git-clean-gone-branches` | Clean up local branches whose remote tracking branch is gone | | `git-commit` | Create a git commit with a value-communicating message | -| `git-commit-push-pr` | Commit, push, and open a PR with an adaptive description; also update an existing PR description | +| `git-commit-push-pr` | Commit, push, and open a PR with an adaptive description; also update an existing PR description (delegates title/body generation to `ce-pr-description`) | | `git-worktree` | Manage Git worktrees for parallel development | ### Workflow Utilities diff --git a/plugins/compound-engineering/skills/ce-pr-description/SKILL.md b/plugins/compound-engineering/skills/ce-pr-description/SKILL.md new file mode 100644 index 000000000..018a188f7 --- /dev/null +++ b/plugins/compound-engineering/skills/ce-pr-description/SKILL.md @@ -0,0 +1,369 @@ +--- +name: ce-pr-description +description: "Write or regenerate a value-first pull-request description (title + body) for the current branch's commits or for a specified PR. Use when the user says 'write a PR description', 'refresh the PR description', 'regenerate the PR body', 'rewrite this PR', 'freshen the PR', 'update the PR description', 'draft a PR body for this diff', 'describe this PR properly', 'generate the PR title', or pastes a GitHub PR URL / #NN / number. Also used internally by git-commit-push-pr (single-PR flow) and ce-pr-stack (per-layer stack descriptions) so all callers share one writing voice. Input is a natural-language prompt. A PR reference (a full GitHub PR URL, `pr:561`, `#561`, or a bare number alone) picks a specific PR; anything else is treated as optional steering for the default 'describe my current branch' mode. Returns structured {title, body} for the caller to apply via gh pr edit or gh pr create — this skill never edits the PR itself and never prompts for confirmation." +argument-hint: "[PR ref e.g. pr:561 | #561 | URL] [free-text steering]" +--- + +# CE PR Description + +Generate a conventional-commit-style title and a value-first body describing a pull request's work. Returns structured `{title, body}` for the caller to apply — this skill never invokes `gh pr edit` or `gh pr create`, and never prompts for interactive confirmation. + +Why a separate skill: several callers need the same writing logic without the single-PR interactive scaffolding that lives in `git-commit-push-pr`. `ce-pr-stack`'s splitting workflow runs this once per layer as a batch; `git-commit-push-pr` runs it inside its full-flow and refresh-mode paths. Extracting keeps one source of truth for the writing principles. + +**Naming rationale:** `ce-pr-description`, not `git-pr-description`. Stacking and PR creation are GitHub features; the "PR" in the name refers to the GitHub artifact. Using the `ce-` prefix matches the future convention for plugin skills; sibling `git-*` skills will rename to `ce-*` later, and this skill starts there directly. + +--- + +## Inputs + +Input is a free-form prompt. Parse it into two parts: + +- **A PR reference, if present.** Any of these patterns counts: a full GitHub PR URL (`https://github.com/owner/repo/pull/NN`), `pr:` or `pr:`, a bare hashmark form (`#NN`), or the argument being just a number (`561`). Extract the PR reference and treat the rest of the argument as steering text. +- **Everything else is steering text** (a "focus" hint like "emphasize the benchmarks" or "do a good job with the perf story"). It may be combined with a PR reference or stand alone. + +No specific grammar is required — read the argument as natural language and identify whichever PR reference is present. If no PR reference is present, default to describing the current branch. + +### Mode selection + +| What the caller passes | Mode | +|---|---| +| No PR reference (empty argument or steering text only) | **Current-branch mode** — describe the commits on HEAD vs the repo's default base | +| A PR reference (URL, `pr:`, `#NN`, or bare number) | **PR mode** — describe the specified PR | + +Steering text is always optional. If present, incorporate it alongside the diff-derived narrative; do not let it override the value-first principles or fabricate content unsupported by the diff. + +**Optional `base:` override (current-branch mode only).** When a caller already knows the intended base branch (e.g., `git-commit-push-pr` has detected `origin/develop` or `origin/release/2026-04` as the target), it can pass `base:` to pin the base explicitly. The ref must resolve locally. This overrides auto-detection for current-branch mode; PR mode ignores it (PRs already define their own base via `baseRefName`). Most invocations don't need this — auto-detection (existing PR's `baseRefName` → `origin/HEAD`) covers the common case. + +**Examples**: + +- `ce-pr-description` → current-branch, no focus, auto-detect base +- `ce-pr-description emphasize the benchmarks` → current-branch, focus = "emphasize the benchmarks" +- `ce-pr-description base:origin/develop` → current-branch, base pinned to `origin/develop` +- `ce-pr-description base:origin/develop emphasize perf` → same + focus +- `ce-pr-description pr:561` → PR #561, no focus +- `ce-pr-description #561 do a good job with the perf story` → PR #561, focus = "do a good job with the perf story" +- `ce-pr-description https://github.com/foo/bar/pull/561 emphasize safety` → PR #561 in foo/bar, focus = "emphasize safety" + +## Output + +Return a structured result with two fields: + +- **`title`** -- conventional-commit format: `type: description` or `type(scope): description`. Under 72 characters. Choose `type` based on intent (feat/fix/refactor/docs/chore/perf/test), not file type. Pick the narrowest useful `scope` (skill or agent name, CLI area, or shared label); omit when no single label adds clarity. +- **`body`** -- markdown following the writing principles below. + +The caller decides whether to apply via `gh pr edit`, `gh pr create`, or discard. This skill does NOT call those commands itself. + +--- + +## What this skill does not do + +- No interactive confirmation prompts. If the diff is ambiguous about something important (e.g., the focus hint conflicts with the actual changes), surface the ambiguity in the returned output or raise it to the caller — do not prompt the user directly. +- No branch checkout. Current-branch mode describes the HEAD in the user's current checkout; PR mode describes the specified PR. Neither mode checks out a different branch. +- No compare-and-confirm narrative ("here's what changed since the last version"). The description describes the end state; the caller owns any compare-and-confirm framing. +- No auto-apply via `gh pr edit` or `gh pr create`. Return the output and stop. + +Interactive scaffolding (confirmation prompts, compare-and-confirm, apply step) is the caller's responsibility. + +--- + +## Step 1: Resolve the diff and commit list + +Parse the input (see Inputs above) and branch on which mode it selects. + +### Current-branch mode (default when no PR reference was given) + +Determine the base against which to compare, in this priority order: + +1. **Caller-supplied `base:`** — if present, use it verbatim. The caller is asserting the correct base. The ref must resolve locally. +2. **Existing PR's `baseRefName`** — if the current branch already has an open PR on this repo, use that PR's base. Handles feature branches targeting non-default bases (e.g., `develop`) when the PR is already open. +3. **Repo default (`origin/HEAD`)** — fall back for branches with no PR yet and no caller-supplied base. + +```bash +# Detect current branch (fail if detached HEAD) +CURRENT_BRANCH=$(git branch --show-current) +if [ -z "$CURRENT_BRANCH" ]; then + echo "Detached HEAD — current-branch mode requires a branch. Pass a PR reference instead." + exit 1 +fi + +# Priority: caller-supplied base: > existing PR's baseRefName > origin/HEAD +if [ -n "$CALLER_BASE" ]; then + BASE_REF="$CALLER_BASE" +else + EXISTING_PR_BASE=$(gh pr view --json baseRefName --jq '.baseRefName' 2>/dev/null) + if [ -n "$EXISTING_PR_BASE" ]; then + BASE_REF="origin/$EXISTING_PR_BASE" + else + BASE_REF=$(git rev-parse --abbrev-ref origin/HEAD 2>/dev/null) + BASE_REF="${BASE_REF:-origin/main}" + fi +fi +``` + +If `$BASE_REF` does not resolve locally (`git rev-parse --verify "$BASE_REF"` fails), the caller (or the user) needs to fetch it first. Exit gracefully with `"Base ref $BASE_REF does not resolve locally. Fetch it before invoking the skill."` — do not attempt recovery. + +Gather merge base, commit list, and full diff: + +```bash +MERGE_BASE=$(git merge-base "$BASE_REF" HEAD) && echo "MERGE_BASE=$MERGE_BASE" && echo '=== COMMITS ===' && git log --oneline $MERGE_BASE..HEAD && echo '=== DIFF ===' && git diff $MERGE_BASE...HEAD +``` + +If the commit list is empty, report `"No commits between $BASE_REF and HEAD"` and exit gracefully — there is nothing to describe. + +If an existing PR was found in step 1, also capture its body for evidence preservation in Step 3. + +### PR mode (when the input contained a PR reference) + +Normalize the reference into a form `gh pr view` accepts: a bare number (`561`), a full URL (`https://github.com/owner/repo/pull/561`), or the number extracted from `pr:561` or `#561`. `gh pr view`'s positional argument accepts bare numbers, URLs, and branch names — not `owner/repo#NN` shorthand. For a cross-repo number reference without a URL, the caller would use `-R owner/repo`; this skill accepts a full URL as the simplest cross-repo path, and that's what most callers use. + +```bash +gh pr view --json number,state,title,body,baseRefName,baseRefOid,headRefName,headRefOid,headRepository,headRepositoryOwner,isCrossRepository,commits,url +``` + +Key JSON fields: `headRefOid` (PR head SHA — prefer over indexing into `commits`), `baseRefOid` (base-branch SHA), `headRepository` + `headRepositoryOwner` (PR source repo), `isCrossRepository`. There is no `baseRepository` field — the base repo is the one queried by `gh pr view` itself. + +If the returned `state` is not `OPEN`, report `"PR is (not open); cannot regenerate description"` and exit gracefully without output. Callers expecting `{title, body}` must handle this empty case. + +**Determine whether the PR lives in the current working directory's repo** by parsing the URL's `/` path segments and comparing against `git remote get-url origin` (strip `.git` suffix; handle both `git@github.com:owner/repo` and `https://github.com/owner/repo` forms). If the URL repo matches `origin`'s repo, route to the local-git path (Case A). Otherwise route to the API-only path (Case B). Bare numbers and `#NN` forms implicitly target the current repo → Case A. + +**Case A → Case B fallback:** Even when the URL repo matches `origin`, the local clone may not be usable for this PR's refs — shallow clone, detached state missing the base branch, offline, auth issues, GHES quirks. If Case A's fetch or `git merge-base` fails, fall back to Case B rather than failing the skill. Note the fallback in the caller-facing output. + +**Case A — PR is in the current repo:** + +Read the PR head SHA directly from `headRefOid` in the JSON response above. Fetch the base ref and the head SHA in one call (the fetch is idempotent when refs are already local): + +```bash +PR_HEAD_SHA= +git fetch --no-tags origin $PR_HEAD_SHA +``` + +Using the explicit `$PR_HEAD_SHA` in downstream commands avoids `FETCH_HEAD`'s multi-ref ordering problem (`git rev-parse FETCH_HEAD` returns only the first fetched ref's SHA, which silently breaks a multi-ref fetch). + +```bash +MERGE_BASE=$(git merge-base origin/ $PR_HEAD_SHA) && echo "MERGE_BASE=$MERGE_BASE" && echo '=== COMMITS ===' && git log --oneline $MERGE_BASE..$PR_HEAD_SHA && echo '=== DIFF ===' && git diff $MERGE_BASE...$PR_HEAD_SHA +``` + +If the explicit-SHA fetch is rejected (rare on GitHub, possible on some GHES configurations that disallow fetching non-tip SHAs), fall back to fetching `refs/pull//head` and reading the PR head SHA from `.git/FETCH_HEAD` by pull-ref pattern: + +```bash +git fetch --no-tags origin "refs/pull//head" +PR_HEAD_SHA=$(awk '/refs\/pull\/[0-9]+\/head/ {print $1; exit}' "$(git rev-parse --git-dir)/FETCH_HEAD") +``` + +**Case B — PR is in a different repo:** + +Skip local git entirely. Read the diff and commit list from the API: + +```bash +gh pr diff +gh pr view --json commits --jq '.commits[] | [.oid[0:7], .messageHeadline] | @tsv' +``` + +Same classification/framing/writing pipeline. Note in the caller-facing output that the API fallback was used. + +Also capture the existing PR body for evidence preservation in Step 3 (both cases). + +--- + +## Step 2: Classify commits before writing + +Scan the commit list and classify each commit: + +- **Feature commits** -- implement the PR's purpose (new functionality, intentional refactors, design changes). These drive the description. +- **Fix-up commits** -- iteration work (code review fixes, lint fixes, test fixes, rebase resolutions, style cleanups). Invisible to the reader. + +When sizing the description, mentally subtract fix-up commits: a branch with 12 commits but 9 fix-ups is a 3-commit PR. + +--- + +## Step 3: Decide on evidence + +Decide whether evidence capture is possible from the full branch diff. + +**Evidence is possible** when the diff changes observable behavior demonstrable from the workspace: UI, CLI output, API behavior with runnable code, generated artifacts, or workflow output. + +**Evidence is not possible** for: +- Docs-only, markdown-only, changelog-only, release metadata, CI/config-only, test-only, or pure internal refactors +- Behavior requiring unavailable credentials, paid/cloud services, bot tokens, deploy-only infrastructure, or hardware not provided + +**This skill does NOT prompt the user** to capture evidence. The decision logic is: + +1. **PR mode invocation** (any form: bare number, `#NN`, `pr:`, or a full URL — anything that resolves to an existing PR whose body we fetched) **and the existing body contains a `## Demo` or `## Screenshots` section with image embeds:** preserve it verbatim unless the steering text asks to refresh or remove it. Include the preserved block in the returned body. This applies regardless of which input shape the caller used; what matters is that a PR exists and its body was read. +2. **Current-branch mode or PR mode without an evidence block:** omit the evidence section entirely. If the caller wants to capture evidence, the caller is responsible for invoking `ce-demo-reel` separately and splicing the result in, or for asking this skill to regenerate with updated steering text after capture. + +Do not label test output as "Demo" or "Screenshots". Place any preserved evidence block before the Compound Engineering badge. + +--- + +## Step 4: Frame the narrative before sizing + +Articulate the PR's narrative frame: + +1. **Before**: What was broken, limited, or impossible? (One sentence.) +2. **After**: What's now possible or improved? (One sentence.) +3. **Scope rationale** (only if 2+ separable-looking concerns): Why do these ship together? (One sentence.) + +This frame becomes the opening. For small+simple PRs, the "after" sentence alone may be the entire description. + +--- + +## Step 5: Size the change + +Assess size (files, diff volume) and complexity (design decisions, trade-offs, cross-cutting concerns) to select description depth: + +| Change profile | Description approach | +|---|---| +| Small + simple (typo, config, dep bump) | 1-2 sentences, no headers. Under ~300 characters. | +| Small + non-trivial (bugfix, behavioral change) | Short narrative, ~3-5 sentences. No headers unless two distinct concerns. | +| Medium feature or refactor | Narrative frame (before/after/scope), then what changed and why. Call out design decisions. | +| Large or architecturally significant | Full narrative: problem context, approach (and why), key decisions, migration/rollback if relevant. | +| Performance improvement | Include before/after measurements if available. Markdown table works well. | + +When in doubt, shorter is better. Match description weight to change weight. + +--- + +## Step 6: Apply writing principles + +### Writing voice + +If the repo has documented style preferences in context, follow those. Otherwise: + +- Active voice. No em dashes or `--` substitutes; use periods, commas, colons, or parentheses. +- Vary sentence length. Never three similar-length sentences in a row. +- Do not make a claim and immediately explain it. Trust the reader. +- Plain English. Technical jargon fine; business jargon never. +- No filler: "it's worth noting", "importantly", "essentially", "in order to", "leverage", "utilize." +- Digits for numbers ("3 files"), not words ("three files"). + +### Writing principles + +- **Lead with value**: Open with what's now possible or fixed, not what was moved around. The subtler failure is leading with the mechanism ("Replace the hardcoded capture block with a tiered skill") instead of the outcome ("Evidence capture now works for CLI tools and libraries, not just web apps"). +- **No orphaned opening paragraphs**: If the description uses `##` headings anywhere, the opening must also be under a heading (e.g., `## Summary`). For short descriptions with no sections, a bare paragraph is fine. +- **Describe the net result, not the journey**: The description covers the end state, not how you got there. No iteration history, debugging steps, intermediate failures, or bugs found and fixed during development. This applies equally when regenerating for an existing PR: rewrite from the current state, not as a log of what changed since the last version. Exception: process details critical to understand a design choice. +- **When commits conflict, trust the final diff**: The commit list is supporting context, not the source of truth. If commits describe intermediate steps later revised or reverted, describe the end state from the full branch diff. +- **Explain the non-obvious**: If the diff is self-explanatory, don't narrate it. Spend space on things the diff doesn't show: why this approach, what was rejected, what the reviewer should watch. +- **Use structure when it earns its keep**: Headers, bullets, and tables aid comprehension, not mandatory template sections. +- **Markdown tables for data**: Before/after comparisons, performance numbers, or option trade-offs communicate well as tables. +- **No empty sections**: If a section doesn't apply, omit it. No "N/A" or "None." +- **Test plan — only when non-obvious**: Include when testing requires edge cases the reviewer wouldn't think of, hard-to-verify behavior, or specific setup. Omit when "run the tests" is the only useful guidance. When the branch adds test files, name them with what they cover. + +### Visual communication + +Include a visual aid only when the change is structurally complex enough that a reviewer would struggle to reconstruct the mental model from prose alone. + +**The core distinction — structure vs. parallel variation:** + +- Use a **Mermaid diagram** when the change has **topology** — components with directed relationships (calls, flows, dependencies, state transitions, data paths). Diagrams express "A talks to B, B talks to C, C does not talk back to A" in a way tables cannot. +- Use a **markdown table** when the change has **parallel variation of a single shape** — N things that share the same attributes but differ in their values. Tables express "option 1 costs X, option 2 costs Y, option 3 costs Z" cleanly. + +Architecture changes are almost always topology (components + edges), so Mermaid is usually the right call — a table of "components that interact" loses the edges and becomes a flat list. Reserve tables for genuinely parallel data: before/after measurements, option trade-offs, flag matrices, config enumerations. + +**When to include (prefer Mermaid, not a table, for architecture/flow):** + +| PR changes... | Visual aid | +|---|---| +| Architecture touching 3+ interacting components (the components have *directed relationships* — who calls whom, who owns what, which skill delegates to which) | **Mermaid** component or interaction diagram. Do not substitute a table — tables cannot show edges. | +| Multi-step workflow or data flow with non-obvious sequencing | **Mermaid** flow diagram | +| State machine with 3+ states and non-trivial transitions | **Mermaid** state diagram | +| Data model changes with 3+ related entities | **Mermaid** ERD | +| Before/after performance or behavioral measurements (same metric, different values) | **Markdown table** | +| Option or flag trade-offs (same attributes evaluated across variants) | **Markdown table** | +| Feature matrix / compatibility grid | **Markdown table** | + +**When in doubt, ask: "Does the information have edges (A → B) or does it have rows (attribute × variant)?"** Edges → Mermaid. Rows → table. Architecture has edges almost by definition. + +**When to skip any visual:** +- Sizing routes to "1-2 sentences" +- Prose already communicates clearly +- The diagram would just restate the diff visually +- Mechanical changes (renames, dep bumps, config, formatting) + +**Format details:** +- **Mermaid** (default for topology). 5-10 nodes typical, up to 15 for genuinely complex changes. Use `TB` direction. Source should be readable as fallback. +- **ASCII diagrams** for annotated flows needing rich in-box content. 80-column max. +- **Markdown tables** for parallel-variation data only. +- Place inline at point of relevance, not in a separate section. +- Prose is authoritative when it conflicts with a visual. + +Verify generated diagrams against the change before including. + +### Numbering and references + +Never prefix list items with `#` in PR descriptions — GitHub interprets `#1`, `#2` as issue references and auto-links them. + +When referencing actual GitHub issues or PRs, use `org/repo#123` or the full URL. Never use bare `#123` unless verified. + +### Applying the focus hint + +If a `focus:` hint was provided, incorporate it alongside the diff-derived narrative. Treat focus as steering, not override: do not invent content the diff does not support, and do not suppress important content the diff demands simply because focus did not mention it. When focus and diff materially disagree (e.g., focus says "include benchmarking" but the diff has no benchmarks), note the conflict in a way the caller can see (leave a brief inline note or raise to the caller) rather than fabricating content. + +--- + +## Step 7: Compose the title + +Title format: `type: description` or `type(scope): description`. + +- **Type** is chosen by intent, not file extension. `feat` for new functionality, `fix` for a bug fix, `refactor` for a behavior-preserving change, `docs` for doc-only, `chore` for tooling/maintenance, `perf` for performance, `test` for test-only. +- **Scope** (optional) is the narrowest useful label: a skill/agent name, CLI area, or shared area. Omit when no single label adds clarity. +- **Description** is imperative, lowercase, under 72 characters total. No trailing period. +- If the repo has commit-title conventions visible in recent commits, match them. + +Breaking changes use `!` (e.g., `feat!: ...`) or document in the body with a `BREAKING CHANGE:` footer. + +--- + +## Step 8: Compose the body + +Assemble the body in this order: + +1. **Opening** -- the narrative frame from Step 4, at the depth chosen in Step 5. Under a heading (e.g., `## Summary`) if the description uses any `##` headings elsewhere; a bare paragraph otherwise. +2. **Body sections** -- only the sections that earn their keep for this change: what changed and why, design decisions, tables for data, visual aids when complexity warrants. Skip empty sections entirely. +3. **Test plan** -- only when non-obvious per the writing principles. Omit otherwise. +4. **Evidence block** -- only the preserved block from Step 3, if one exists. Do not fabricate or placeholder. +5. **Compound Engineering badge** -- append a badge footer separated by a `---` rule. Skip if the existing body (for `pr:` input) already contains the badge. + +**Badge:** + +```markdown +--- + +[![Compound Engineering](https://img.shields.io/badge/Built_with-Compound_Engineering-6366f1)](https://github.com/EveryInc/compound-engineering-plugin) +![HARNESS](https://img.shields.io/badge/MODEL_SLUG-COLOR?logo=LOGO&logoColor=white) +``` + +**Harness lookup:** + +| Harness | `LOGO` | `COLOR` | +|---------|--------|---------| +| Claude Code | `claude` | `D97757` | +| Codex | (omit logo param) | `000000` | +| Gemini CLI | `googlegemini` | `4285F4` | + +**Model slug:** Replace spaces with underscores. Append context window and thinking level in parentheses if known. Examples: `Opus_4.6_(1M,_Extended_Thinking)`, `Sonnet_4.6_(200K)`, `Gemini_3.1_Pro`. + +--- + +## Step 9: Return `{title, body}` + +Return the composed title and body to the caller. Do not call `gh pr edit`, `gh pr create`, or any other mutating command. Do not ask the user to confirm. The caller owns apply. + +Format the return as a clearly labeled block so the caller can extract cleanly: + +``` +=== TITLE === + + +=== BODY === +<body markdown> +``` + +If Step 1 exited gracefully (closed/merged PR, invalid range, empty commit list), return no title or body — just the reason string. + +--- + +## Cross-platform notes + +This skill does not ask questions directly. If the diff is ambiguous about something the caller should decide (e.g., focus conflicts with the actual changes, or evidence is technically capturable but the caller did not pre-stage it), surface the ambiguity in the returned output or a short note to the caller — do not invoke a platform question tool. + +Callers that need to ask the user are responsible for using their own platform's blocking question tool (`AskUserQuestion` in Claude Code, `request_user_input` in Codex, `ask_user` in Gemini) before or after invoking this skill. diff --git a/plugins/compound-engineering/skills/git-commit-push-pr/SKILL.md b/plugins/compound-engineering/skills/git-commit-push-pr/SKILL.md index 70e8f7b24..8c1cde616 100644 --- a/plugins/compound-engineering/skills/git-commit-push-pr/SKILL.md +++ b/plugins/compound-engineering/skills/git-commit-push-pr/SKILL.md @@ -59,32 +59,32 @@ Ask the user: "Update the PR description for this branch?" If declined, stop. ### DU-2: Find the PR -Use the current branch and existing PR check from context. If the current branch is empty (detached HEAD), report no branch and stop. If the PR check returned `state: OPEN`, proceed to DU-3. Otherwise, report no open PR and stop. +Use the current branch and existing PR check from context. If the current branch is empty (detached HEAD), report no branch and stop. If the PR check returned `state: OPEN`, note the PR `url` from the context block — this is the unambiguous reference to pass downstream — and proceed to DU-3. Otherwise, report no open PR and stop. ### DU-3: Write and apply the updated description -Read the current PR description: +Read the current PR description to drive the compare-and-confirm step later: ```bash gh pr view --json body --jq '.body' ``` -Build the updated description: +**Generate the updated title and body** — load the `ce-pr-description` skill with the PR URL from DU-2 (e.g., `https://github.com/owner/repo/pull/123`). The URL preserves repo/PR identity even when invoked from a worktree or subdirectory where the current repo is ambiguous. If the user provided a focus (e.g., "include the benchmarking results"), append it as free-text steering after the URL. The skill returns a `{title, body}` block without applying or prompting. -1. **Get the full branch diff** -- follow "Detect the base branch and remote" and "Gather the branch scope" in Step 6. Use the PR found in DU-2 for base branch detection. -2. **Classify commits** -- follow "Classify commits before writing" in Step 6. -3. **Decide on evidence** -- if the current description already has a `## Demo` or `## Screenshots` section with image embeds, preserve it unless the user's focus asks to refresh or remove it. If no evidence exists, follow "Evidence for PR descriptions" in Step 6. -4. **Rewrite the description from scratch** -- follow the writing principles in Step 6, driven by feature commits, final diff, and evidence decision. Do not layer changes onto the old description or document what changed since the last version. Write as if describing the PR for the first time. - - If the user provided a focus, incorporate it alongside the branch diff context. -5. **Compare and confirm** -- briefly explain what the new description covers differently from the old one. This helps the user decide whether to apply; the description itself does not narrate these differences. - - If the user provided a focus, confirm it was addressed. - - Ask the user to confirm before applying. +If `ce-pr-description` returns a "not open" or other graceful-exit message instead of a `{title, body}` pair, report that message and stop. -If confirmed, apply: +**Evidence decision:** `ce-pr-description` preserves any existing `## Demo` or `## Screenshots` block from the current body by default. If the user's focus asks to refresh or remove evidence, pass that intent as steering text — the skill will honor it. If no evidence block exists and one would benefit the reader, invoke `ce-demo-reel` separately to capture, then re-invoke `ce-pr-description` with updated steering that references the captured evidence. + +**Compare and confirm** — briefly explain what the new description covers differently from the old one. This helps the user decide whether to apply; the description itself does not narrate these differences. + +- If the user provided a focus, confirm it was addressed. +- Ask the user to confirm before applying. + +If confirmed, apply with the returned title and body: ```bash -gh pr edit --body "$(cat <<'EOF' -Updated description here +gh pr edit --title "<returned title>" --body "$(cat <<'EOF' +<returned body> EOF )" ``` @@ -137,7 +137,7 @@ Priority order for commit messages and PR titles: Use the current branch and existing PR check from context. If the branch is empty, report detached HEAD and stop. -If the PR check returned `state: OPEN`, note the URL -- continue to Step 4 and 5, then skip to Step 7 (existing PR flow). Otherwise, continue through Step 8. +If the PR check returned `state: OPEN`, note the URL -- this is the existing-PR flow. Continue to Step 4 and 5 (commit any pending work and push), then go to Step 7 to ask whether to rewrite the description. Only run Step 6 (which generates a new description via `ce-pr-description`) if the user confirms the rewrite; Step 7's existing-PR sub-path consumes the `{title, body}` that Step 6 produces. Otherwise (no open PR), continue through Steps 6, 7, and 8 in order. ### Step 4: Branch, stage, and commit @@ -157,13 +157,11 @@ If the PR check returned `state: OPEN`, note the URL -- continue to Step 4 and 5 git push -u origin HEAD ``` -### Step 6: Write the PR description +### Step 6: Generate the PR title and body The working-tree diff from Step 1 only shows uncommitted changes at invocation time. The PR description must cover **all commits** in the PR. -#### Detect the base branch and remote - -Resolve both the base branch and the remote (fork-based PRs may use a remote other than `origin`). Stop at the first that succeeds: +**Detect the base branch and remote.** Resolve both the base branch and the remote (fork-based PRs may use a remote other than `origin`). Stop at the first that succeeds: 1. **PR metadata** (if existing PR found in Step 3): ```bash @@ -184,193 +182,62 @@ Resolve both the base branch and the remote (fork-based PRs may use a remote oth If none resolve, ask the user to specify the target branch. -#### Gather the branch scope - -Verify the remote-tracking ref exists and fetch if needed: +**Gather the full branch diff (before evidence decision).** The working-tree diff from Step 1 only reflects uncommitted changes at invocation time — on the common "feature branch, all pushed, open PR" path, Step 1 skips the commit/push steps and the working-tree diff is empty. The evidence decision below needs the real branch diff to judge whether behavior is observable, so compute it explicitly against the base resolved above. Only fetch when the local ref isn't available — if `<base-remote>/<base-branch>` already resolves locally, run the diff from local state so offline / restricted-network / expired-auth environments don't hard-fail: ```bash -git rev-parse --verify <base-remote>/<base-branch> 2>/dev/null || git fetch --no-tags <base-remote> <base-branch> +git rev-parse --verify <base-remote>/<base-branch> >/dev/null 2>&1 \ + || git fetch --no-tags <base-remote> <base-branch> +git diff <base-remote>/<base-branch>...HEAD ``` -Gather merge base, commit list, and full diff in a single call: - -```bash -MERGE_BASE=$(git merge-base <base-remote>/<base-branch> HEAD) && echo "MERGE_BASE=$MERGE_BASE" && echo '=== COMMITS ===' && git log --oneline $MERGE_BASE..HEAD && echo '=== DIFF ===' && git diff $MERGE_BASE...HEAD -``` - -Use the full branch diff and commit list as the basis for the description. - -#### Evidence for PR descriptions - -Decide whether evidence capture is possible from the full branch diff. - -**Evidence is possible** when the diff changes observable behavior demonstrable from the workspace: UI, CLI output, API behavior with runnable code, generated artifacts, or workflow output. - -**Evidence is not possible** for: -- Docs-only, markdown-only, changelog-only, release metadata, CI/config-only, test-only, or pure internal refactors -- Behavior requiring unavailable credentials, paid/cloud services, bot tokens, deploy-only infrastructure, or hardware not provided - -When not possible, skip without asking. When possible, ask: "This PR has observable behavior. Capture evidence for the PR description?" - -1. **Capture now** -- load the `ce-demo-reel` skill with a target description inferred from the branch diff. ce-demo-reel returns `Tier`, `Description`, and `URL`. Build a `## Demo` or `## Screenshots` section (browser-reel/terminal-recording/screenshot-reel use "Demo", static uses "Screenshots"). -2. **Use existing evidence** -- ask for the URL or markdown embed. -3. **Skip** -- no evidence section. - -If capture returns `Tier: skipped` or `URL: "none"`, do not add a placeholder. Summarize in the final report. - -Place evidence before the Compound Engineering badge. Do not label test output as "Demo" or "Screenshots". - -#### Classify commits before writing - -Scan the commit list and classify each commit: - -- **Feature commits** -- implement the PR's purpose (new functionality, intentional refactors, design changes). These drive the description. -- **Fix-up commits** -- iteration work (code review fixes, lint fixes, test fixes, rebase resolutions, style cleanups). Invisible to the reader. - -When sizing the description, mentally subtract fix-up commits: a branch with 12 commits but 9 fix-ups is a 3-commit PR. - -#### Frame the narrative before sizing - -Articulate the PR's narrative frame: - -1. **Before**: What was broken, limited, or impossible? (One sentence.) -2. **After**: What's now possible or improved? (One sentence.) -3. **Scope rationale** (only if 2+ separable-looking concerns): Why do these ship together? (One sentence.) - -This frame becomes the opening. For small+simple PRs, the "after" sentence alone may be the entire description. - -#### Sizing the change +Use this branch diff (not the working-tree diff) for the evidence decision. If the branch diff is empty (e.g., HEAD is already merged into the base or the branch has no unique commits), skip the evidence prompt and continue to delegation. -Assess size (files, diff volume) and complexity (design decisions, trade-offs, cross-cutting concerns) to select description depth: +**Evidence decision (before delegation).** If the branch diff changes observable behavior (UI, CLI output, API behavior with runnable code, generated artifacts, workflow output) and evidence is not otherwise blocked (unavailable credentials, paid services, deploy-only infrastructure, hardware), ask: "This PR has observable behavior. Capture evidence for the PR description?" -| Change profile | Description approach | -|---|---| -| Small + simple (typo, config, dep bump) | 1-2 sentences, no headers. Under ~300 characters. | -| Small + non-trivial (bugfix, behavioral change) | Short narrative, ~3-5 sentences. No headers unless two distinct concerns. | -| Medium feature or refactor | Narrative frame (before/after/scope), then what changed and why. Call out design decisions. | -| Large or architecturally significant | Full narrative: problem context, approach (and why), key decisions, migration/rollback if relevant. | -| Performance improvement | Include before/after measurements if available. Markdown table works well. | +- **Capture now** -- load the `ce-demo-reel` skill with a target description inferred from the branch diff. ce-demo-reel returns `Tier`, `Description`, and `URL`. Note the captured evidence so it can be passed as free-text steering to `ce-pr-description` (e.g., "include the captured demo: <URL> as a `## Demo` section") or spliced into the returned body before apply. If capture returns `Tier: skipped` or `URL: "none"`, proceed with no evidence. +- **Use existing evidence** -- ask for the URL or markdown embed, then pass it as free-text steering to `ce-pr-description` or splice in before apply. +- **Skip** -- proceed with no evidence section. -When in doubt, shorter is better. Match description weight to change weight. +When evidence is not possible (docs-only, markdown-only, changelog-only, release metadata, CI/config-only, test-only, or pure internal refactors), skip without asking. -#### Writing voice +**Delegate title and body generation to `ce-pr-description`.** Load the `ce-pr-description` skill: -If the user has documented style preferences, follow those. Otherwise: +- **For a new PR** (no existing PR found in Step 3): invoke with `base:<base-remote>/<base-branch>` using the already-resolved base from earlier in this step, so `ce-pr-description` describes the correct commit range even when the branch targets a non-default base (e.g., `develop`, `release/*`). Append any captured-evidence context or user focus as free-text steering (e.g., "include the captured demo: <URL> as a `## Demo` section"). +- **For an existing PR** (found in Step 3): invoke with the full PR URL from the Step 3 context (e.g., `https://github.com/owner/repo/pull/123`). The URL preserves repo/PR identity even when invoked from a worktree or subdirectory; the skill reads the PR's own `baseRefName` so no `base:` override is needed. Append any focus steering as free text after the URL. -- Active voice. No em dashes or `--` substitutes; use periods, commas, colons, or parentheses. -- Vary sentence length. Never three similar-length sentences in a row. -- Do not make a claim and immediately explain it. Trust the reader. -- Plain English. Technical jargon fine; business jargon never. -- No filler: "it's worth noting", "importantly", "essentially", "in order to", "leverage", "utilize." -- Digits for numbers ("3 files"), not words ("three files"). +`ce-pr-description` returns a `{title, body}` block. It applies the value-first writing principles, commit classification, sizing, narrative framing, writing voice, visual communication, numbering rules, and the Compound Engineering badge footer internally. Use the returned values verbatim in Step 7; do not layer manual edits onto them unless a focused adjustment is required (e.g., splicing an evidence block captured in this step that was not passed as steering text). -#### Writing principles - -- **Lead with value**: Open with what's now possible or fixed, not what was moved around. The subtler failure is leading with the mechanism ("Replace the hardcoded capture block with a tiered skill") instead of the outcome ("Evidence capture now works for CLI tools and libraries, not just web apps"). -- **No orphaned opening paragraphs**: If the description uses `##` headings anywhere, the opening must also be under a heading (e.g., `## Summary`). For short descriptions with no sections, a bare paragraph is fine. -- **Describe the net result, not the journey**: The description covers the end state, not how you got there. No iteration history, debugging steps, intermediate failures, or bugs found and fixed during development. This applies equally to description updates: rewrite from the current state, not as a log of what changed since the last version. Exception: process details critical to understand a design choice. -- **When commits conflict, trust the final diff**: The commit list is supporting context, not the source of truth. If commits describe intermediate steps later revised or reverted, describe the end state from the full branch diff. -- **Explain the non-obvious**: If the diff is self-explanatory, don't narrate it. Spend space on things the diff doesn't show: why this approach, what was rejected, what the reviewer should watch. -- **Use structure when it earns its keep**: Headers, bullets, and tables aid comprehension, not mandatory template sections. -- **Markdown tables for data**: Before/after comparisons, performance numbers, or option trade-offs communicate well as tables. -- **No empty sections**: If a section doesn't apply, omit it. No "N/A" or "None." -- **Test plan -- only when non-obvious**: Include when testing requires edge cases the reviewer wouldn't think of, hard-to-verify behavior, or specific setup. Omit when "run the tests" is the only useful guidance. When the branch adds test files, name them with what they cover. - -#### Visual communication - -Include a visual aid only when the change is structurally complex enough that a reviewer would struggle to reconstruct the mental model from prose alone. - -**When to include:** - -| PR changes... | Visual aid | -|---|---| -| Architecture touching 3+ interacting components | Mermaid component or interaction diagram | -| Multi-step workflow or data flow with non-obvious sequencing | Mermaid flow diagram | -| 3+ behavioral modes, states, or variants | Markdown comparison table | -| Before/after performance or behavioral data | Markdown table | -| Data model changes with 3+ related entities | Mermaid ERD | - -**When to skip:** -- Sizing routes to "1-2 sentences" -- Prose already communicates clearly -- The diagram would just restate the diff visually -- Mechanical changes (renames, dep bumps, config, formatting) - -**Format:** -- **Mermaid** (default) for flows, interactions, dependencies. 5-10 nodes typical, up to 15 for genuinely complex changes. Use `TB` direction. Source should be readable as fallback. -- **ASCII diagrams** for annotated flows needing rich in-box content. 80-column max. -- **Markdown tables** for comparisons and decision matrices. -- Place inline at point of relevance, not in a separate section. -- Prose is authoritative when it conflicts with a visual. - -Verify generated diagrams against the change before including. - -#### Numbering and references - -Never prefix list items with `#` in PR descriptions -- GitHub interprets `#1`, `#2` as issue references and auto-links them. - -When referencing actual GitHub issues or PRs, use `org/repo#123` or the full URL. Never use bare `#123` unless verified. - -#### Compound Engineering badge - -Append a badge footer separated by a `---` rule. Skip if a badge already exists. - -**Badge:** - -```markdown ---- - -[![Compound Engineering](https://img.shields.io/badge/Built_with-Compound_Engineering-6366f1)](https://github.com/EveryInc/compound-engineering-plugin) -![HARNESS](https://img.shields.io/badge/MODEL_SLUG-COLOR?logo=LOGO&logoColor=white) -``` - -**Harness lookup:** - -| Harness | `LOGO` | `COLOR` | -|---------|--------|---------| -| Claude Code | `claude` | `D97757` | -| Codex | (omit logo param) | `000000` | -| Gemini CLI | `googlegemini` | `4285F4` | - -**Model slug:** Replace spaces with underscores. Append context window and thinking level in parentheses if known. Examples: `Opus_4.6_(1M,_Extended_Thinking)`, `Sonnet_4.6_(200K)`, `Gemini_3.1_Pro`. +If `ce-pr-description` returns a graceful-exit message instead of `{title, body}` (e.g., closed PR, no commits to describe, base ref unresolved), report the message and stop — do not create or edit the PR. ### Step 7: Create or update the PR #### New PR (no existing PR from Step 3) -```bash -gh pr create --title "the pr title" --body "$(cat <<'EOF' -PR description here - ---- +Using the `{title, body}` returned by `ce-pr-description`: -[![Compound Engineering](https://img.shields.io/badge/Built_with-Compound_Engineering-6366f1)](https://github.com/EveryInc/compound-engineering-plugin) -![Claude Code](https://img.shields.io/badge/Opus_4.6_(1M,_Extended_Thinking)-D97757?logo=claude&logoColor=white) +```bash +gh pr create --title "<returned title>" --body "$(cat <<'EOF' +<returned body> EOF )" ``` -Use the badge from the Compound Engineering badge section. Replace harness and model values from the lookup tables. Keep the PR title under 72 characters, following Step 2 conventions. +Keep the title under 72 characters; `ce-pr-description` already emits a conventional-commit title in that range. #### Existing PR (found in Step 3) The new commits are already on the PR from Step 5. Report the PR URL, then ask whether to rewrite the description. -- If **yes**: - 1. Classify commits -- new commits since last push are often fix-up work and should not appear as distinct items - 2. Size the full PR (not just new commits) using the sizing table - 3. **Rewrite from scratch** to describe the PR's net result as of now, following Step 6's writing principles. Do not append, amend, or layer onto the old description. The description is not a changelog. - 4. Include the Compound Engineering badge unless already present - 5. Apply: +- If **yes**, run Step 6 now to generate `{title, body}` via `ce-pr-description` (passing the existing PR URL as `pr:`), then apply the returned title and body: ```bash - gh pr edit --body "$(cat <<'EOF' - Updated description here + gh pr edit --title "<returned title>" --body "$(cat <<'EOF' + <returned body> EOF )" ``` -- If **no** -- done. +- If **no** -- skip Step 6 entirely and finish. Do not run delegation or evidence capture when the user declined the rewrite. ### Step 8: Report