| name | create-pr |
| description | Create a GitHub pull request with `gh pr create`. Title and body are English, AI-generated from the latest git commit (HEAD) plus the current branch vs the default base. Before push, rewrite commit messages with git commit-tree if they contain Cursor trailers. After create, re-apply a clean body and verify with gh pr view. Use only when the user explicitly asks to create a PR, open a pull request, run this skill, or invoke create-pr. |
| disable-model-invocation | true |
Create PR
从当前分支的 git 记录生成英文标题与正文,调用 gh pr create 开 PR。不要用 --fill / --fill-first。
对外文案(硬性)
最终对外产物必须干净,不是「自己别主动写」。
- 本环境跑
git commit 会注入 Co-authored-by: Cursor <cursoragent@cursor.com>。push 之前必须 git log -1 --format=%B(以及 base..HEAD 全部 %B)。有 cursor 就跑 scrub-commits.sh(commit-tree 重写),不要把脏 commit push 出去。不要用 git commit 重做(会再注入)。
gh pr create 之后平台可能在 body 尾部追加 Made with [Cursor](https://cursor.com)。create 之后必须立刻 gh pr view,并用 scrub-pr.sh 把 title/body 写回已知干净稿;再 view 一次,仍含 cursor 则失败,不要把 URL 当成功。
PR title/body、commit message 都不能带有任何 cursor 相关的字样(大小写均禁),包括:Cursor、cursor、.cursor、cursor.com、Cursor Agent、Made with Cursor、Generated by Cursor、Co-authored-by: Cursor。HEAD 里若已有这些字,改写时去掉,不要原样抄进 PR。
禁止把 Cursor 写成协作者:不要 --reviewer / --assignee 填 Cursor,不要在 body 里 @ Cursor。
改动若是仓库 agent skill,对外只写 skill 名(如 create-pr),不要写工具目录路径。
何时执行
仅在用户显式要求创建 PR、打开 pull request、执行本 skill 时运行。不要在提交、推送、或闲聊里主动开 PR。切分支、暂存、commit 走 create-branch skill,不要在本 skill 里做。
工作流
按顺序执行。任一步失败则停下并说明原因,不要继续 gh pr create。
- [ ] 1. 收集 git 上下文
- [ ] 2. 预检(脏工作区 / 在默认分支 / 已有 PR)
- [ ] 3. 若 commit %B 含 cursor:`scrub-commits.sh` 后重新收集
- [ ] 4. 根据 git 记录生成 title + body,写入临时文件并自检
- [ ] 5. 如未跟踪远程则 push(仅在刚 rewrite 且已有 upstream 时允许 `--force-with-lease`)
- [ ] 6. `gh pr create`(--body-file)
- [ ] 7. `scrub-pr.sh`:view → 写回干净稿 → 再 view
- [ ] 8. 只有最终 view 干净才把 PR URL 回给用户
1. 收集 git 上下文
从仓库根目录执行 .cursor/skills/create-pr/scripts/collect-context.sh。它会打印:
- HEAD:上一条 git 记录(
git log -1 --format=fuller + %B 全文含 trailer)
- 当前分支、默认 base、是否已 push、
range_has_cursor
base...HEAD 的 commit 列表与 diffstat
- 工作区是否干净
标题与正文以上一条(HEAD)提交为主。若该分支相对 base 还有更早提交,把它们并入 Changes / Test plan,不要只复述 HEAD 的 subject 而漏掉其余 diff。
需要补细节时再跑(不要打印带凭据的 remote URL):
git show --format= --no-ext-diff HEAD
git diff --stat "${BASE}...HEAD"
${BASE} 用脚本输出的 default base(通常是 origin/main)。
2. 预检
| 情况 | 动作 |
|---|
当前就在默认分支(main / master) | 停止。请用户先执行 create-branch,或切到 feature 分支后再执行。 |
| 工作区有未提交改动 | 警告用户:PR 只包含已提交内容。不要擅自 commit。 |
gh pr view 对该分支已有 OPEN 的 PR | 停止,返回已有 URL,不要再 create。MERGED / CLOSED 不挡。 |
| HEAD 与默认分支没有 diff | 停止,没有可开的 PR。 |
gh 未登录 / 无权限 | 停止,说明要用 gh auth status 检查。 |
range_has_cursor: true | 不要停止、不要 push。 进入步骤 3 用 commit-tree 清 trailer。 |
禁止:改 git config、--no-verify / --no-gpg-sign、interactive rebase、git add .、git commit(会再注入 Cursor)。--force / --force-with-lease 仅步骤 5 在刚 rewrite 且已有 upstream 时允许。
3. 清掉 commit 上的 Cursor trailer
range_has_cursor: true 时必须执行;否则跳过。
.cursor/skills/create-pr/scripts/scrub-commits.sh "${BASE_REF}"
${BASE_REF} 用 collect-context 的 base_ref(通常 origin/main)。脚本对 base..HEAD 做线性 commit-tree 重写,去掉 message 里所有 cursor 行(含 Co-authored-by: Cursor)。
失败则停下。成功后再跑一次 collect-context.sh,确认 range_has_cursor: false,并记下 rewritten: true。
不要 git commit、不要 git commit --amend、不要 soft reset 后再 git commit。
4. 生成 title 与 body
只根据收集到的 git 记录与 diff 生成,不要编造未出现的功能、文件或测试。
Language: English only. Title and body must be English, even if the git record, branch name, or user prompt is Chinese. Translate; do not copy non-English commit text into the PR.
Title
- English imperative sentence, ≤72 characters, no trailing period.
- 仓库已用 Conventional Commits(
feat: / fix: / docs: 等)则沿用;HEAD subject 已经合适就微调复用,不要为了炫技重写。若 HEAD subject 不是英文,先译成英文再套 conventional prefix。
- 范围以 HEAD 为准:HEAD 是 bugfix 就不要写成巨大 refactor。
Body(GitHub Flavored Markdown,多段式)
必须用下面结构。空段删掉,不要留占位符。语气像给 reviewer 的简报:先 What+Why,再可扫的 Changes,最后可执行的 Test plan。
## Summary
<1–3 条 bullet:做了什么、为什么。写意图,不要列文件名。>
## Changes
- <按主题分组的具体改动,点出行为 / API / schema / 兼容性>
- <必要时用 **Area:** 前缀,如 **Worker:** / **API:** / **Console:**>
## Test plan
- [ ] <可执行的验证步骤:命令、路径、手动操作>
## Notes
<可选:breaking change、rollout、follow-up、截图。没有就整段省略。>
风格约束:
- 用 GFM:
## 标题、- 列表、- [ ] task list。需要折叠大段日志时才用 <details>。
- 关联 issue 写成
Closes #123 / Fixes #123(仅当 git 记录或用户明确提到)。
- 不要写 “This PR …”、不要贴完整 diff、不要空话 checklist(“tested locally” 这种不算)。
- Test plan 要能在本仓库执行:点名
backend/、backend-java/、frontend/ 等真实路径与命令。含 cursor 的路径不要写进 PR,改用 skill 名或功能描述。
- Title 和 body 一律英文。专有名词、代码标识符、路径保持原样(例外:任何 cursor 字样都要去掉或改写);不要写中文段落或中英混排说明。
- 写入临时文件后自检:title、body 都不含
cursor(任何大小写),也没有 Cursor 协作者 / Co-authored-by。这只是输入稿;发布后还要再 view。
把 title / body 写到临时文件(不要用 --fill):
TITLE_FILE="$(mktemp)"
BODY_FILE="$(mktemp)"
printf '%s\n' "${TITLE}" > "${TITLE_FILE}"
cat > "${BODY_FILE}" <<'EOF'
- ...
- ...
- [ ] ...
EOF
5. Push
先确认 range_has_cursor: false,否则回到步骤 3。分支未跟踪远程,或 local 超前 remote 时:
git push -u origin HEAD
仅当步骤 3 打印了 rewritten: true 并且 该分支已有 upstream 时,才允许:
git push --force-with-lease
不要无条件 force。不要 push 到 main/master。
6. 创建 PR
用 --title + --body-file,不要 HEREDOC 嵌套进 --body 再以为发布稿就是它:
gh pr create --base "${BASE_NAME}" --title "$(cat "${TITLE_FILE}")" --body-file "${BODY_FILE}"
${BASE_NAME} 是短名(main),不是 origin/main。仅当用户明确要求 draft 时加 --draft。
7. 发布后立刻核对并清掉平台注入
gh pr create 返回 URL 不算完成。立刻:
.cursor/skills/create-pr/scripts/scrub-pr.sh --title-file "${TITLE_FILE}" --body-file "${BODY_FILE}"
脚本会 gh pr edit 写回干净稿,再 gh pr view。title/body 仍含 cursor 则失败,不要把 URL 发给用户当成功。
不要跳过 view。不要以为 create 时传的 body 就是线上 body。
8. 收尾
只有 scrub-pr.sh 打印 pr_clean: true 后,才把 URL 发给用户。若 create 或 scrub 失败,贴错误并停下。
示例
HEAD: feat: integrate Temporal backend for durable workflows
Title: feat: integrate Temporal backend for durable workflows
## Summary
- Add Temporal as an opt-in durable backend so agent runs survive worker restarts.
- Keep the existing Redis job path as the default when Temporal is unset.
## Changes
- **Worker:** Temporal workflow + worker process for `Run` execution.
- **API:** persist workflow id on the run; map cancel to the Temporal handle.
- **Config:** `TEMPORAL_TARGET` / task-queue settings; no change to the default adapter.
## Test plan
- [ ] `uv run pytest` in `backend/`
- [ ] Start API + Temporal worker, create a run, confirm it completes
- [ ] Kill the worker mid-run, restart, confirm the run resumes
- [ ] Cancel an in-flight run and confirm the Temporal workflow is cancelled