PR Writer
Prepare pull requests end-to-end by generating the PR description and handling the publish flow (commit -> branch -> push -> PR creation when needed).
When to Activate
- User asks to write, open, or update a PR
- User asks to commit, push, and open a PR for current branch changes
- User says "ship this", "publish this", "make a PR", or similar
End-to-End Publish Workflow
[!IMPORTANT]
If the current branch already has an open PR, always ask the user before doing anything else whether the new work should (a) be pushed as additional commits to the existing PR, or (b) go on a new branch (off the appropriate base, usually main) as a separate PR.
Never assume the user wants to extend the open PR, even if the new work feels related. Scope, review timing, and merge-queue considerations are the user's call. Do not commit, branch, or push until the user has answered.
Check repository and PR state
- Confirm current branch and dirty working tree using
git status.
- Check if branch already has an open PR:
gh pr view --json number,url,headRefName,baseRefName,state
- If an open PR exists on the current branch, stop and ask the user whether to push to that PR or start a new branch. Wait for the answer before proceeding to any other step. Quote the existing PR's number/title/URL in the question so the user can decide with full context.
- If the user picks "new branch", create it off the appropriate base (usually
main) in step 4 below before any commit.
Generate PR description body
- Produce the PR body using the template in this skill (mirrors
.github/pull_request_template.md).
- Ensure title is a clear, sentence-case description of the change (see conventions below).
Commit current changes
- Treat the current branch working tree as source of truth even if prior session history is unavailable.
- Include both staged and unstaged tracked code/doc/config changes that are relevant to the PR scope.
- Exclude obvious temporary artifacts (for example root-level screenshots, ad-hoc logs, dumps, tmp/debug files) unless explicitly requested.
- Stage relevant files and create a commit with a clear message.
- Include the standard co-author trailer unless the user opts out:
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- If there are no changes to commit, skip commit creation and continue.
Create or switch to a publish branch
- If current branch is a protected/shared branch (for example
main), create a feature branch with a hyphenated descriptive name.
- Otherwise keep using current feature branch.
Push branch
- Push with upstream tracking:
git push -u origin <branch>
- Never force-push to update a PR. Do not use
git push --force or git push --force-with-lease under any circumstance. To update a PR, always add a new commit on top — never rewrite, amend, or squash already-pushed history. If the push is rejected as non-fast-forward, stop and ask the user; do not "fix" it with force.
Create PR only if one does not already exist
- If no open PR exists for the branch, create one:
gh pr create --title "<title>" --body "<body>" --base main --head <branch>
- If PR already exists, update body/title as needed instead of creating duplicates.
- Update existing PR metadata when work is already partially published:
gh pr edit <PR_NUMBER> --title "<title>" --body "<body>"
- If branch and PR already exist and no new commit is needed, run metadata update only.
Return publication result
- Report commit SHA, branch name, push status, and PR URL.
Partial-State Handling (Some Steps Already Done)
- Existing branch + existing PR + new code changes:
- Ask the user first whether the new changes belong on this PR or on a new branch (see the IMPORTANT callout above). If "this PR": commit/push changes, then update PR body/title with
gh pr edit. If "new branch": create a fresh branch off main and run the normal flow there.
- Existing branch + existing PR + no code changes:
- Skip commit/push and update PR description/title only.
- Existing branch + no PR:
- Push branch if needed, then create PR with generated body.
- No branch/PR yet:
- Create branch, commit, push, then create PR.
- Session reset/compaction or new-agent context with unknown edit history:
- Do not rely on prior agent edit memory.
- Use the current
git status/diff as the canonical change set, apply temp-file filtering, then proceed with normal commit/push/PR flow.
Branch Naming Convention
This repo uses hyphenated descriptive branch names (no username prefix):
citation-config
citation-config-followup
configurability-followup
style-configurability
text-fonts-refactor
latex-configurability
PR Title Conventions
Use a clear, sentence-case description of the change. No [TAG] prefixes, no ticket IDs, no conventional-commit prefixes are required.
Examples (from recent merged PRs):
Convert CitationCoder to public Hashable struct on CitationConfig
Clean up InlineCitationConstants and merge citation predicates
Add CitationConfig to MarkdownRenderConfig; remove dead Typography props
Style folder; UIFont inline link/code; optional letterSpacing/lineHeight
Introduce TextFonts struct and decouple style config from Typography enum
PR Template
The repo template (.github/pull_request_template.md) has three sections plus an OSS-readiness checklist:
## Summary
<!-- What changed and why? -->
## Validation
<!-- List the checks you ran, for example: make test && make build -->
## OSS readiness
- [ ] No secrets, internal URLs, private identifiers, or product-only service names were added.
- [ ] Public docs, fixtures, or notices were updated if behavior or dependencies changed.
- [ ] Third-party dependency changes (adds, removes, version bumps) are intentional and reviewed.
- [ ] Streaming/incomplete markdown behavior remains covered by fixtures or tests.
Template Filling Guidelines
Summary
- Lead with what changed and why (one or two sentences).
- For multi-part changes, use a short bullet list of the concrete pieces (files, types, behaviors).
- Always reference the related GitHub issue. Every PR must cite the issue it addresses using a closing keyword on its own line so GitHub auto-links and auto-closes it on merge:
Closes #<issue-number> for issues this PR fully resolves
Fixes #<issue-number> for bug-fix PRs
Refs #<issue-number> when the PR is related but does not close the issue (for stacked work, partial progress, or follow-ups)
- Use the full
owner/repo#<number> form when referencing an issue in a different repository.
- If no issue exists yet, create one first with
gh issue create and reference it. Do not open a PR without a linked issue unless the user explicitly waives this (e.g. for trivial docs/typo fixes).
- For large PRs, note scope and any follow-ups at the top.
Validation
- List the actual commands you ran and their result. Common ones in this repo:
make test
make build-sample
swift build / swift test for SwiftPM-only checks
- Mention snapshot test runs explicitly when relevant (record vs validate; see the
snapshot-tests skill).
- For UI changes, mention manual verification in the sample app and any VoiceOver/accessibility checks.
- Brief is fine when no new tests apply: "Existing test suite passes locally."
OSS readiness
- Tick each box honestly. Leave unchecked items visible so the reviewer can see what still needs attention.
- If a row genuinely does not apply (for example no dependency change), tick it and append a short note like
(no dependency changes).
Screenshots (optional)
- Not part of the committed template, but add a
## Screenshots section when UI/rendering changes warrant it.
- Use GitHub's image upload format with explicit dimensions:
<img width="568" height="1084" alt="..." src="..." />
- Light and dark variants are valuable for theme-related changes.
Example PR Body
## Summary
Convert `CitationCoder` from an internal helper into a public `Hashable` struct on `CitationConfig`, so external consumers can construct and compare their own coders. Default values are unchanged behaviorally.
- Promote `CitationCoder` to `public struct: Hashable`
- Expose it on `CitationConfig` instead of the typography layer
- Update sample fixtures and tests to construct configs explicitly
Closes #42
## Validation
- `xcodebuild test -scheme SwiftStreamingMarkdown -destination "platform=iOS Simulator,OS=26.4.1,name=iPhone 17" -skipMacroValidation` — all tests pass
- `xcodebuild build` on the sample app — succeeds
- Verified citation rendering visually in the sample app's multi-paragraph demo
## OSS readiness
- [x] No secrets, internal URLs, private identifiers, or product-only service names were added.
- [x] Public docs, fixtures, or notices were updated if behavior or dependencies changed.
- [x] Third-party dependency changes (adds, removes, version bumps) are intentional and reviewed. (no dependency changes)
- [x] Streaming/incomplete markdown behavior remains covered by fixtures or tests.
Output Format
Return two parts:
- Publication summary:
- Commit created/skipped (+ SHA when created)
- Branch used/created
- Push result
- PR action: created or updated
- PR URL (if available)
- Complete PR body, following the template exactly:
## Summary
<!-- What changed and why? -->
## Validation
<!-- List the checks you ran, for example: make test && make build -->
## OSS readiness
- [ ] No secrets, internal URLs, private identifiers, or product-only service names were added.
- [ ] Public docs, fixtures, or notices were updated if behavior or dependencies changed.
- [ ] Third-party dependency changes (adds, removes, version bumps) are intentional and reviewed.
- [ ] Streaming/incomplete markdown behavior remains covered by fixtures or tests.
Guardrails
- If the current branch has an open PR, always ask the user whether the new work belongs on that PR or on a new branch — never assume. See the IMPORTANT callout at the top of the workflow.
- Every PR must reference its GitHub issue in the Summary section using a
Closes #N / Fixes #N / Refs #N line. If no issue exists, create one first with gh issue create before opening the PR. The only allowed exception is when the user explicitly waives this requirement.
- Never force-push to update a PR. Do not run
git push --force or git push --force-with-lease, and do not amend, rebase, or squash commits that have already been pushed. To update a PR, always add a new commit on top. If a push is rejected as non-fast-forward, stop and ask the user — do not "resolve" it with force.
- Do not create duplicate PRs for the same head branch.
- Keep commit scope limited to intended changes; avoid unrelated files.
- Do not omit legitimate branch changes only because they were not created in the current agent session.
- Do not commit secrets, internal-only URLs, or product-confidential identifiers — this is a public OSS repo.
1---2name: pr-writer3description: Prepare and publish SwiftStreamingMarkdown pull requests end-to-end: generate PR description, commit changes, create/push branch, and open a PR when needed.4---56# PR Writer78Prepare pull requests end-to-end by generating the PR description and handling the publish flow (commit -> branch -> push -> PR creation when needed).910## When to Activate1112- User asks to write, open, or update a PR13- User asks to commit, push, and open a PR for current branch changes14- User says "ship this", "publish this", "make a PR", or similar1516## End-to-End Publish Workflow1718> [!IMPORTANT]19> **If the current branch already has an open PR, always ask the user before doing anything else** whether the new work should (a) be pushed as additional commits to the existing PR, or (b) go on a new branch (off the appropriate base, usually `main`) as a separate PR.20>21> **Never assume the user wants to extend the open PR**, even if the new work feels related. Scope, review timing, and merge-queue considerations are the user's call. Do not commit, branch, or push until the user has answered.22231. Check repository and PR state24 - Confirm current branch and dirty working tree using `git status`.25 - Check if branch already has an open PR:26 - `gh pr view --json number,url,headRefName,baseRefName,state`27 - **If an open PR exists on the current branch, stop and ask the user** whether to push to that PR or start a new branch. Wait for the answer before proceeding to any other step. Quote the existing PR's number/title/URL in the question so the user can decide with full context.28 - If the user picks "new branch", create it off the appropriate base (usually `main`) in step 4 below before any commit.29302. Generate PR description body31 - Produce the PR body using the template in this skill (mirrors `.github/pull_request_template.md`).32 - Ensure title is a clear, sentence-case description of the change (see conventions below).33343. Commit current changes35 - Treat the current branch working tree as source of truth even if prior session history is unavailable.36 - Include both staged and unstaged tracked code/doc/config changes that are relevant to the PR scope.37 - Exclude obvious temporary artifacts (for example root-level screenshots, ad-hoc logs, dumps, tmp/debug files) unless explicitly requested.38 - Stage relevant files and create a commit with a clear message.39 - Include the standard co-author trailer unless the user opts out:40 - `Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>`41 - If there are no changes to commit, skip commit creation and continue.42434. Create or switch to a publish branch44 - If current branch is a protected/shared branch (for example `main`), create a feature branch with a hyphenated descriptive name.45 - Otherwise keep using current feature branch.46475. Push branch48 - Push with upstream tracking:49 - `git push -u origin <branch>`50 - **Never force-push to update a PR.** Do not use `git push --force` or `git push --force-with-lease` under any circumstance. To update a PR, always add a new commit on top — never rewrite, amend, or squash already-pushed history. If the push is rejected as non-fast-forward, stop and ask the user; do not "fix" it with force.51526. Create PR only if one does not already exist53 - If no open PR exists for the branch, create one:54 - `gh pr create --title "<title>" --body "<body>" --base main --head <branch>`55 - If PR already exists, update body/title as needed instead of creating duplicates.56 - Update existing PR metadata when work is already partially published:57 - `gh pr edit <PR_NUMBER> --title "<title>" --body "<body>"`58 - If branch and PR already exist and no new commit is needed, run metadata update only.59607. Return publication result61 - Report commit SHA, branch name, push status, and PR URL.6263## Partial-State Handling (Some Steps Already Done)6465- Existing branch + existing PR + new code changes:66 - **Ask the user first** whether the new changes belong on this PR or on a new branch (see the IMPORTANT callout above). If "this PR": commit/push changes, then update PR body/title with `gh pr edit`. If "new branch": create a fresh branch off `main` and run the normal flow there.67- Existing branch + existing PR + no code changes:68 - Skip commit/push and update PR description/title only.69- Existing branch + no PR:70 - Push branch if needed, then create PR with generated body.71- No branch/PR yet:72 - Create branch, commit, push, then create PR.73- Session reset/compaction or new-agent context with unknown edit history:74 - Do not rely on prior agent edit memory.75 - Use the current `git status`/diff as the canonical change set, apply temp-file filtering, then proceed with normal commit/push/PR flow.7677## Branch Naming Convention7879This repo uses hyphenated descriptive branch names (no username prefix):8081```text82citation-config83citation-config-followup84configurability-followup85style-configurability86text-fonts-refactor87latex-configurability88```8990## PR Title Conventions9192Use a clear, sentence-case description of the change. No `[TAG]` prefixes, no ticket IDs, no conventional-commit prefixes are required.9394**Examples (from recent merged PRs):**95- `Convert CitationCoder to public Hashable struct on CitationConfig`96- `Clean up InlineCitationConstants and merge citation predicates`97- `Add CitationConfig to MarkdownRenderConfig; remove dead Typography props`98- `Style folder; UIFont inline link/code; optional letterSpacing/lineHeight`99- `Introduce TextFonts struct and decouple style config from Typography enum`100101## PR Template102103The repo template (`.github/pull_request_template.md`) has three sections plus an OSS-readiness checklist:104105```markdown106## Summary107108<!-- What changed and why? -->109110## Validation111112<!-- List the checks you ran, for example: make test && make build -->113114## OSS readiness115116- [ ] No secrets, internal URLs, private identifiers, or product-only service names were added.117- [ ] Public docs, fixtures, or notices were updated if behavior or dependencies changed.118- [ ] Third-party dependency changes (adds, removes, version bumps) are intentional and reviewed.119- [ ] Streaming/incomplete markdown behavior remains covered by fixtures or tests.120```121122## Template Filling Guidelines123124### Summary125126- Lead with what changed and why (one or two sentences).127- For multi-part changes, use a short bullet list of the concrete pieces (files, types, behaviors).128- **Always reference the related GitHub issue.** Every PR must cite the issue it addresses using a closing keyword on its own line so GitHub auto-links and auto-closes it on merge:129 - `Closes #<issue-number>` for issues this PR fully resolves130 - `Fixes #<issue-number>` for bug-fix PRs131 - `Refs #<issue-number>` when the PR is related but does not close the issue (for stacked work, partial progress, or follow-ups)132 - Use the full `owner/repo#<number>` form when referencing an issue in a different repository.133 - If no issue exists yet, **create one first** with `gh issue create` and reference it. Do not open a PR without a linked issue unless the user explicitly waives this (e.g. for trivial docs/typo fixes).134- For large PRs, note scope and any follow-ups at the top.135136### Validation137138- List the actual commands you ran and their result. Common ones in this repo:139 - `make test`140 - `make build-sample`141 - `swift build` / `swift test` for SwiftPM-only checks142- Mention snapshot test runs explicitly when relevant (record vs validate; see the `snapshot-tests` skill).143- For UI changes, mention manual verification in the sample app and any VoiceOver/accessibility checks.144- Brief is fine when no new tests apply: "Existing test suite passes locally."145146### OSS readiness147148- Tick each box honestly. Leave unchecked items visible so the reviewer can see what still needs attention.149- If a row genuinely does not apply (for example no dependency change), tick it and append a short note like `(no dependency changes)`.150151### Screenshots (optional)152153- Not part of the committed template, but add a `## Screenshots` section when UI/rendering changes warrant it.154- Use GitHub's image upload format with explicit dimensions:155 - `<img width="568" height="1084" alt="..." src="..." />`156- Light and dark variants are valuable for theme-related changes.157158## Example PR Body159160```markdown161## Summary162163Convert `CitationCoder` from an internal helper into a public `Hashable` struct on `CitationConfig`, so external consumers can construct and compare their own coders. Default values are unchanged behaviorally.164165- Promote `CitationCoder` to `public struct: Hashable`166- Expose it on `CitationConfig` instead of the typography layer167- Update sample fixtures and tests to construct configs explicitly168169Closes #42170171## Validation172173- `xcodebuild test -scheme SwiftStreamingMarkdown -destination "platform=iOS Simulator,OS=26.4.1,name=iPhone 17" -skipMacroValidation` — all tests pass174- `xcodebuild build` on the sample app — succeeds175- Verified citation rendering visually in the sample app's multi-paragraph demo176177## OSS readiness178179- [x] No secrets, internal URLs, private identifiers, or product-only service names were added.180- [x] Public docs, fixtures, or notices were updated if behavior or dependencies changed.181- [x] Third-party dependency changes (adds, removes, version bumps) are intentional and reviewed. (no dependency changes)182- [x] Streaming/incomplete markdown behavior remains covered by fixtures or tests.183```184185## Output Format186187Return two parts:1881891) Publication summary:190- Commit created/skipped (+ SHA when created)191- Branch used/created192- Push result193- PR action: created or updated194- PR URL (if available)1951962) Complete PR body, following the template exactly:197198````markdown199## Summary200201<!-- What changed and why? -->202203## Validation204205<!-- List the checks you ran, for example: make test && make build -->206207## OSS readiness208209- [ ] No secrets, internal URLs, private identifiers, or product-only service names were added.210- [ ] Public docs, fixtures, or notices were updated if behavior or dependencies changed.211- [ ] Third-party dependency changes (adds, removes, version bumps) are intentional and reviewed.212- [ ] Streaming/incomplete markdown behavior remains covered by fixtures or tests.213````214215## Guardrails216217- **If the current branch has an open PR, always ask the user** whether the new work belongs on that PR or on a new branch — never assume. See the IMPORTANT callout at the top of the workflow.218- **Every PR must reference its GitHub issue** in the Summary section using a `Closes #N` / `Fixes #N` / `Refs #N` line. If no issue exists, create one first with `gh issue create` before opening the PR. The only allowed exception is when the user explicitly waives this requirement.219- **Never force-push to update a PR.** Do not run `git push --force` or `git push --force-with-lease`, and do not amend, rebase, or squash commits that have already been pushed. To update a PR, always add a new commit on top. If a push is rejected as non-fast-forward, stop and ask the user — do not "resolve" it with force.220- Do not create duplicate PRs for the same head branch.221- Keep commit scope limited to intended changes; avoid unrelated files.222- Do not omit legitimate branch changes only because they were not created in the current agent session.223- Do not commit secrets, internal-only URLs, or product-confidential identifiers — this is a public OSS repo.