When to use
Use when the user asks to open a pull request, create a PR, or push their changes upstream. This
publishes the current branch to their fork if needed, then opens a PR against upstream
development.
Agents opening a pull request at the end of their own task use this too; steps 5 and 6 say what to do when there is nobody to ask. Either way the branch must be finished first - reviewed, formatted, committed - because every push after the PR opens re-runs the automated reviewers.
Procedure
Gather context. Run
git status --porcelainfirst. If anything is uncommitted, stop: ask the user to commit what belongs in the PR, or to confirm explicitly that it should be left out. A pull request is built from commits, so uncommitted work is silently absent from it.Then run
git log upstream/development..HEAD --onelinefor the commit messages,git diff upstream/development...HEADto see what actually changed, andgit branch --show-currentfor the branch name. An empty commit list means there is nothing to open a pull request for.git branch --show-currentprints nothing on a detached HEAD. If it is empty, stop and ask the user to check out a named branch — every later step needs that name, and an empty one produces a malformed push and an unusable--head.Choose the title prefix.
docs/CONTRIBUTING.mdstates the rule and Danger enforces it on every PR. Choosing between the four is the part that is not written down elsewhere:Prefix Use for Fix:bug fixes visible to users Improve:enhancements to existing user-facing functionality Add:new user-facing features or capabilities Infra:build system, CI, tooling, refactoring, and other non-player-visible changes Distinguishing the last two: user-visible behavior change is
Improve, everything internal isInfra, however large the diff.Write the title. Use the exact form
Prefix: Summary— capitalized prefix, colon, single space, then a summary whose first word is also capitalized. Keep the summary short and understandable to a non-technical reader; it becomes a line in the PTB changelog, which is why the casing is worth being consistent about even though Danger's check is case-insensitive and does not require the colon. Danger warns on overly long titles, so keep it brief.Write in American English, matching the rest of the project's user-facing text — "color" not "colour", "standardize" not "standardise".
Fix: Profiles named "." or ".." no longer delete every profile when removed Improve: OSC 8 hyperlink handling, and a setting to turn it off Add: Text-to-speech support for incoming game text Infra: Tidy up how CI installs LuaDependabot raises its own PRs as
Infrastructure: Bump ...; that is generated upstream and is not something to correct by hand.Draft the body. Read
.github/PULL_REQUEST_TEMPLATE.mdand fill in its headings — read it rather than reproducing it here, so this skill cannot drift from the real template. Note that passing--bodytoghbypasses the template file, which is why it has to be read and filled in explicitly.House style on top of the template: keep each section terse, 1-3 bullet points for the overview and a single sentence of motivation. Add a
**Test case:**line at the end giving brief steps to verify the change — not part of the template, but reviewers expect it. No fluff; about one screen in total.For AI-assisted work, end the body with the
Assisted-by: AGENT_NAME:MODEL_VERSIONtrailer fromdocs/CONTRIBUTING.md; a squash merge drops commit trailers, so the body is the copy that lasts.Settle draft versus ready for review. With a person in the conversation, show them the draft title and body and ask which to open, and wait for both answers. Unattended, open ready for review and report the title and body with the URL — draft only when the branch is knowingly unfinished.
gh pr ready <number>promotes a draft later, so draft is the reversible choice.Confirm the fork before pushing anything.
originis not guaranteed to be the user's fork, and pushing to the wrong remote is awkward to undo, so establish this before the push rather than after. Derive the head explicitly too — a checkout commonly has several remotes, including other people's forks, and a head inferred byghcan point at the wrong one.BRANCH=$(git branch --show-current) FORK_OWNER=$(printf '%s' "$(git remote get-url --push origin)" \ | sed -E 's#\.git$##; s#^[a-zA-Z+]+://##; s#^[^@/]+@##; s#^[^/:]+(:[0-9]+)?/##; s#^[^/:]+:##; s#/[^/]*$##')Use
--push: a remote can carry a separatepushurl, and it is the push URL the branch actually lands on, so the head must be derived from the same URLgit pushwill use.This handles the
https://,ssh://andgit@host:owner/repoforms, with or without an explicit port. Check the result before using it: if$FORK_OWNERis empty or still contains/,:or@, the URL was not in a form this understands — stop and report it rather than building a malformed--head.$FORK_OWNERmust not beMudlet— that is upstream, the mistake this step exists to catch. Matchinggh api user --jq .login, the accountgh pr createacts as, is confirmation enough unattended; otherwise show both values and ask before pushing.Publish the branch with
git push -u origin "$BRANCH". Do this every time, not only when the branch lacks an upstream — a branch that already tracksorigincan still hold local commits that have not been pushed, and those would be missing from the pull request.The push must succeed before continuing. If it fails, stop and report the error; do not open a pull request against a branch whose commits are not on the fork.
Open the PR against upstream, adding
--draftif that is what step 5 settled on:gh pr create --repo Mudlet/Mudlet --base development \ --head "${FORK_OWNER}:${BRANCH}" \ --title "Fix: <short non-technical title>" \ --body "$(cat <<'EOF' <the body from step 4> EOF )"A draft can be marked ready later with
gh pr ready <number>, so choosing draft is the reversible option.Report the result — the PR URL on success, the error output on failure. AI-assisted work is not done there: ask the human to build and manually test the branch, then to supply the name and email for the
Signed-off-bytrailer thatdocs/ai-instructions.mdrequires. Never fabricate one, and never imply the change is finished without it.
Notes
- Never force-push to a remote branch.