pr-prepare · diff

git:20260801.d01533f to git:20260912.ccc9adf

49 added, 7 removed. Audit A to A.

---
name: pr-prepare
- description: Prepare or open a GitHub or Gitea pull request with an explicit AI-authorship disclosure, change classification, verification checklist, and optional Mermaid diagram. Use whenever the user asks to prepare, write, open, create, push, ship, or get changes ready for a PR or review. Unless the user explicitly asks for a draft-only result, create or reuse a dedicated branch, verify the change, commit scoped files, push the branch, and then create the PR with gh or tea.
+ description: Prepare or open a GitHub or Gitea pull request with an explicit AI-authorship disclosure, change classification, reproducible reviewer verification steps, and optional Mermaid diagram. Use whenever the user asks to prepare, write, open, create, push, ship, or get changes ready for a PR or review. Unless the user explicitly asks for a draft-only result, create or reuse a dedicated branch, verify the change, commit scoped files, push the branch, and then create the PR with gh or tea.
---
# Prepare and open a pull request
Produce a reviewable PR and, unless the user explicitly requests a draft-only result, carry it through the safe sequence:
```text
branch -> verify -> commit -> push -> create PR -> verify PR
```
Never skip forward after a failed step. Preserve unrelated user changes and never force-push.
## Select the operating mode
- **Execute mode (default)**: Run the complete sequence whenever the user invokes PR preparation, including creating or opening a PR. Do not ask for a final confirmation before creating the branch, committing, pushing, or opening the PR.
- **Draft-only mode**: Use only when the user explicitly asks for a draft-only result: a PR description, template, or read-only review. Read the change and output the PR body, but do not create a branch, stage, commit, push, or create/edit a PR.
## Workflow
### Step 1 - Inspect the repository
Gather the current state before making changes:
```bash
git status --short
git branch --show-current
git remote -v | sed -E 's#://[^/@]*@#://***@#g'
git config --get "branch.$(git branch --show-current).remote" || echo "no tracking remote configured"
git rev-parse --abbrev-ref --symbolic-full-name '@{upstream}' 2>/dev/null || echo "no upstream configured"
git log --oneline -20
```
A missing tracking remote or upstream is expected before the first push; treat both as informational, not as failures.
Remote URLs can carry credentials in their userinfo (for example `https://x-access-token:<token>@host/owner/repo.git`), so `git remote -v` is piped through `sed` to mask that segment before it reaches output or logs. Apply the same redaction to any other command that echoes a remote URL.
The mask replaces the userinfo of any scheme-qualified URL, whether or not it holds a secret — `ssh://git@host/owner/repo.git` becomes `ssh://***@host/owner/repo.git`, hiding a username that was never sensitive. That is deliberate: erring toward masking costs only a well-known username, while a narrower pattern risks missing a real token. URLs with no userinfo and scp-style `git@host:owner/repo.git` (which has no `://`) pass through untouched. Scheme, host, and path always survive, so provider detection below still has what it needs.
Determine the base branch from repository configuration or the remote default branch. If it is still unclear, ask the user; common values are `main` and `develop`.
In Execute mode, resolve a writable push remote instead of assuming it is named `origin`:
- Reuse the remote from an existing correct upstream.
- Otherwise select the repository's configured writable fork or push remote and verify it with `git remote get-url --push <push-remote> | sed -E 's#://[^/@]*@#://***@#g'`, which masks any credentials embedded in the push URL.
- If no writable remote is clear, ask the user before pushing.
Detect the hosting provider from the selected remote URL and record the matching CLI context:
- **GitHub**: Use `gh`. Verify authentication with `gh auth status`.
- **Gitea**: Use `tea`. Inspect `tea --version` and `tea pulls create --help`, verify that a matching login exists with `tea logins list`, and confirm repository access with a read-only `tea pulls list` query. Run that probe in the same context the PR will be created with — `--remote <gitea-remote>`, or the explicit `--login <gitea-login> --repo <base-owner>/<base-repo>` — as resolved below. Without those flags `tea` falls back to whatever it infers from the local repository, so the probe can pass against a fork or a different server while PR creation still fails against the intended base.
- If the hostname or provider is ambiguous, ask the user instead of choosing a CLI by guesswork.
For Gitea, resolve `<gitea-remote>` to the base/upstream repository that should receive the PR, then prefer `--remote <gitea-remote>` so `tea` discovers its login and repository. This may differ from the writable push remote in a fork workflow. If the mapping is unavailable or ambiguous, use `--login <gitea-login>` and `--repo <base-owner>/<base-repo>` explicitly. Never print or persist access tokens in the PR body or command output.
Stop before mutation when any of these conditions apply:
- The repository is in a merge, rebase, cherry-pick, or conflicted state.
- `HEAD` is detached.
- The base branch cannot be determined, or Execute mode cannot determine a writable push remote.
- The working tree mixes the requested change with unrelated edits that cannot be safely separated.
In Execute mode, stop before mutation if the selected provider CLI is unavailable or unauthenticated.
### Step 2 - Resolve issue references and branch name
Collect issue identifiers only from reliable context:
1. The user's request.
2. An explicit GitHub or Gitea issue URL, or a Jira browse URL.
3. A plan or task document that clearly identifies the work item.
Recognize:
- GitHub or Gitea issue numbers such as `#123`, `issue 123`, or `/issues/123`.
- Jira issue keys such as `GAIA-5375` or `/browse/GAIA-5375`.
Do not guess an issue from similar titles. Do not treat an ambiguous `#123` as an issue when it may be a PR number. If more than one repository-host issue or more than one Jira issue could be primary, ask the user which one to use.
Build the branch name as `<type>/<identifiers>-<slug>`:
```text
feat/add-consent-flow
feat/123-add-consent-flow
fix/GAIA-5375-handle-expired-token
feat/GAIA-5375-123-add-consent-flow
```
Use the repository's established prefix convention when one exists; otherwise use a concise type such as `feat`, `fix`, `docs`, `refactor`, `test`, `ci`, or `chore`. Preserve Jira keys in uppercase, strip `#` from GitHub or Gitea issue numbers, and keep the lowercase slug short. When both Jira and repository-host identifiers exist, put the Jira key first. Preserve identifiers before shortening an overly long slug.
Validate the result with `git check-ref-format --branch <branch>`.
### Step 3 - Create or confirm the head branch
In Draft-only mode, skip this step.
In Execute mode, ensure the work is on a dedicated head branch before staging or committing:
- If currently on the base branch, create the new branch with `git switch -c <branch>`; uncommitted changes move with it.
- If already on the dedicated branch for this work, reuse it so rerunning the skill is idempotent.
- If currently on another feature branch whose commits may not belong in this PR, ask whether the new branch should start from that `HEAD` or from the base branch. Do not silently include unrelated commits.
- Check local and remote names before creation. If the desired name belongs to different work, append a numeric suffix such as `-2`; never overwrite or delete it.
Record the base branch, head branch, push remote, and existing upstream for the push and PR commands.
### Step 4 - Read and classify the change
Inspect committed and uncommitted changes that would enter the PR:
```bash
git log <base>..HEAD --oneline
git diff <base>...HEAD --stat
git diff <base>...HEAD
git diff --stat
git diff
git diff --cached --stat
git diff --cached
```
For large diffs, read the stat and the important changed sections. Identify files, packages, services, public interfaces, and call relationships.
Classify the whole PR using the stricter applicable category:
- **Leaf**: Failure remains local, such as a report, isolated endpoint, UI component, or one-off script.
- **Core**: Other components depend on it, such as auth, payments, schemas, shared frameworks, public APIs, or orchestrators.
If the blast radius is unclear, ask: "If this code is buggy, how far would the failure spread?"
### Step 5 - Record AI authorship
Use the following default disclosure without asking the user for confirmation:
- **Tool / model**: the AI agent executing this workflow; use its reported model or tool name when available.
- **AI-authored files**: every task-related file included in the PR.
- **Human line-by-line reviewed**: `None — not yet reviewed by a human.`
Do not treat the lack of human review as a reason to stop. Make the disclosure conspicuous in the PR body and final handoff so the PR is opened for human review with an accurate record. If the user supplies more specific authorship or review information, use that instead.
### Step 6 - Verify before commit
Use repository instructions and existing scripts to run the relevant formatter, lint, tests, and build checks.
- In Execute mode, run the normal required commands and inspect the diff again after any formatter or generator changes files.
- In Draft-only mode, preserve the read-only guarantee: use only check or dry-run variants known not to modify tracked files. Do not run formatters, generators, fixers, or other potentially mutating commands; skip them and record `Not run` when no read-only variant exists or their behavior is uncertain.
Ask only about checklist items that cannot be established from repository evidence:
- [ ] A plan or written goal and scope exists.
- [ ] The PR is focused and reviewable; coordinate or split unusually large changes.
- [ ] Relevant tests pass locally.
- [ ] No secrets, API keys, credentials, or unrelated files are included.
- [ ] Plan boundaries, including `must not modify`, were respected.
- [ ] Auth, payment, permission, or external-interface changes received the necessary security review.
- [ ] Long-running or asynchronous behavior has appropriate stress or soak coverage.
Also run `git diff --check` and, after staging, `git diff --staged --check`.
- If a required check fails or cannot be verified, stop. In Execute mode, leave the local head branch intact, but do not commit, push, or create the PR.
+ In Execute mode, if a required check fails or cannot be verified, stop. Leave the local head branch intact, but do not commit, push, or create the PR. In Draft-only mode, continue preparing the body and report failed checks as `Failed` and skipped or unavailable checks as `Not run`, with reasons; do not claim the draft is verified or ready to merge.
+ Record the working directory, prerequisites, exact commands or actions, and observed results while verifying so Step 8 can turn them into reproducible reviewer instructions. Keep expected behavior separate from observed results; a proposed check is not evidence that it passed.
+
### Step 7 - Map the change
For a non-trivial change, add a Mermaid diagram derived from the actual diff:
| Change shape | Diagram |
| ------------------------------------ | ------------------------------ |
| Calls or handshakes over time | `sequenceDiagram` |
| Decisions, control flow, or pipeline | `flowchart TD` |
| Modules, packages, or services | `flowchart LR` with `subgraph` |
| Status or lifecycle transitions | `stateDiagram-v2` |
Keep the diagram honest and renderable:
- Map every changed node to a touched file, function, package, or service.
- Distinguish new or modified nodes with per-node `style` lines.
- Stay below roughly 15-20 nodes and prefer `TD` when `LR` would be too wide.
- Do not use `click` handlers or theme initialization directives.
- Omit the diagram for a one-line fix, copy change, or dependency bump.
### Step 8 - Prepare the PR body
- Match an existing repository PR template when present, including `.github/` templates for GitHub and `.gitea/` templates for Gitea. Otherwise fill this template without inventing evidence:
+ Match an existing repository PR template when present, including `.github/` templates for GitHub and `.gitea/` templates for Gitea. Put the verification details below in its equivalent testing section, or add a section if none exists. Otherwise fill this template without inventing evidence:
+ #### Write reproducible reviewer verification
+
+ The PR body must let a reviewer verify the intended behavior without needing the author's local state or this conversation. Scale detail to the change, but do not reduce verification to "tests pass" or "test manually."
+
+ - **Prerequisites and setup**: Identify the head branch to check out, or the exact PR head SHA when the intended changes are already committed, along with the working directory, relevant runtime/tool versions, dependencies, services, configuration, test data, and account roles. Before commit, use the resolved head branch; never substitute the base SHA or invent a revision. In Draft-only mode with uncommitted changes, state that the changes are local and not yet available from the branch. Give the actual setup/start commands and readiness signal where needed. Use safe sample data and environment-variable names, never credentials. Link maintained setup documentation for lengthy standard setup, but keep PR-specific instructions in the body.
+ - **Behavioral scenarios**: Derive acceptance conditions from the requested goal or issue and confirm them against the diff. Include the main changed flow and relevant failure, boundary, permission, or regression cases; omit unrelated cases. For a bug fix, describe the original trigger and corrected outcome. For a refactor, state which behavior should remain unchanged. For documentation or skill changes, provide a concrete inspection or representative usage scenario instead of inventing application commands.
+ - **Steps and expected results**: For each scenario, state the starting state and provide numbered actions with concrete inputs, commands, requests, or UI navigation. Pair each meaningful step with observable expected output or state, such as HTTP status/body, UI text, stored data, or job completion. For asynchronous flows, identify the completion signal and a supported timeout. Map scenarios to the changed flow or diagram when present so reviewers can compare implementation with intent.
+ - **Automated checks**: Include copyable repository-supported commands, where to run them, what behavior they cover, and how to recognize success. A test-suite command alone is insufficient when it does not explain the changed behavior being verified. Do not invent scripts, fixtures, endpoints, or outputs; mark missing information explicitly.
+ - **Execution evidence**: Label each automated check and behavioral scenario in the Verification section `Passed`, `Failed`, or `Not run`, and record actual results separately from expected results. For checks not run, explain the reason and what access or environment is needed. Reviewer-only checks do not count as completed verification or override Step 6's Execute-mode required-check gate.
+ - **Cleanup**: Include reset/cleanup steps when verification creates data or changes state. Describe side effects and use a disposable or non-production environment for mutating checks.
+
+ Before finalizing, walk through the instructions from a fresh reviewer's perspective: can they prepare the environment, follow each step, and decide whether the flow meets the stated acceptance conditions? Fill all placeholders with repository evidence, and omit inapplicable fields with a brief reason when needed.
+
```markdown
## Summary
<What changed, why, and the mechanism used>
## Related issues
- Jira: <[GAIA-5375](Jira URL), plain key, or N/A>
- GitHub/Gitea: <Closes #123, Related to #123, full cross-repository URL, or N/A>
## Architecture / flow
<Mermaid diagram; omit this section for trivial changes>
## AI authorship
- [ ] No AI was used
- [ ] AI was used
- **Tool / model**: <value>
- **AI-authored files**: <list>
- **Human line-by-line reviewed**: None — not yet reviewed by a human.
## Change classification
- [ ] Leaf change
- [ ] Core change
## Plan reference
<Link or concise goal and scope>
## Verification
- - **Automated**: <commands and results>
- - **Manual**: <steps and results>
- - **Not run**: <checks and reason>
+ ### Setup
+ - **Checkout target / working directory**: <head branch, or exact PR head SHA when already committed, and directory; disclose local-only changes in Draft-only mode>
+ - **Prerequisites**: <tools, services, configuration names, test data, account roles>
+ - **Prepare and start**: <exact commands/actions and readiness signal, or setup link plus PR-specific steps>
+
+ ### Automated checks
+
+ | Command (with working directory) | Behavior covered / expected success | Status | Observed result / reason not run |
+ | --- | --- | --- | --- |
+ | <copyable command> | <coverage and success signal> | <Passed / Failed / Not run> | <actual evidence or blocker> |
+
+ ### Behavioral scenarios
+
+ Repeat this block for each relevant scenario:
+
+ #### <Scenario name: main flow, regression, or relevant edge case>
+
+ - **Acceptance condition**: <intended behavior; related issue requirement or flow node where available>
+ - **Starting state**: <fixture, role, configuration, or other preconditions>
+
+ | Step | Action / command / input | Expected observable result |
+ | --- | --- | --- |
+ | 1 | <concrete action> | <observable output or state> |
+ | 2 | <next action> | <observable output or state> |
+
+ - **Execution status**: <Passed / Failed / Not run>
+ - **Observed result**: <actual evidence, or reason not run and required environment/access>
+ - **Cleanup**: <reset commands/actions, or N/A with reason>
+
## Security check
- [ ] No secrets in the diff
- [ ] External inputs are validated
- [ ] Permission checks are tested
- [ ] Errors do not leak internals
- [ ] N/A - no external or security-sensitive interface changed
## Risk and rollback
- **Risk**: <what could break>
- **Rollback**: <how to revert safely>
## Reviewer guide
- **Read carefully**: <high-risk files or functions>
- **Spot-check**: <lower-risk generated or mechanical changes>
```
Use `Closes #123` only when the selected GitHub or Gitea repository supports the closing keyword and the PR should close that issue in the same repository. Otherwise use `Related to #123` or a full URL. Jira keys do not use repository-host closing syntax; link them when the Jira base URL is known and use the plain key otherwise.
### Step 9 - Stage and commit
In Draft-only mode, skip this step.
First determine whether the intended change is already committed:
```bash
git log <base>..HEAD --oneline
git diff <base>...HEAD --stat
git status --short
```
- If `<base>..HEAD` already contains the complete intended change and no task-related uncommitted changes remain, inspect those commits, skip staging and commit creation, and continue to push.
- If task-related changes remain uncommitted, stage only those files. Never use `git add .` or `git add -A` in a dirty worktree.
- If there are neither intended commits nor task-related changes, stop because there is nothing to open as a PR.
When staging is needed, inspect exactly what will be committed:
```bash
git add <task-file-1> <task-file-2>
git diff --staged --stat
git diff --staged
git diff --staged --check
```
Stop if a non-empty staged diff contains unrelated changes, violates the announced scope, or fails verification. An empty staged diff is valid only when `<base>..HEAD` already contains the complete intended commits; otherwise stop.
Match recent repository commit style. Prefer a focused conventional commit when no stronger convention exists:
```text
<type>(<scope>): <imperative summary>
<important change bullets, if useful>
```
When staging was needed, create the commit directly because Execute mode already expresses the user's intent to commit and open the PR. Whether the commit was created now or already existed, verify the intended commit range and `git show --stat --oneline HEAD`, then report any intentionally unstaged user changes.
### Step 10 - Push the branch
Push only after the intended commit was created successfully or verified as already present.
- If the branch already has the correct upstream, preserve it and use `git push`.
- If the branch has no upstream, use the writable push remote resolved in Step 1.
- If the existing upstream is wrong or ambiguous, stop and ask before replacing it.
- On reruns, if the correct upstream already contains `HEAD`, skip the redundant push and continue to PR creation.
```bash
git push
git push -u <push-remote> <head-branch>
```
Use only the command that matches the branch state; do not run both.
Never force-push. If authentication, policy, hooks, or network errors prevent the push, stop and report the exact failure. Keep the local branch and commit for retry; do not create the PR.
### Step 11 - Create and verify the PR
Check whether the exact head and base branch pair already has a PR before creating one. If it does, return the existing PR instead of creating a duplicate; edit it only when the user asks.
Both lookups below request only the fields needed to identify a match. They deliberately omit `body`: it has no bearing on whether a PR exists for the pair, and pulling every candidate's full description into the transcript is wasted output. Fetch the body later, from the verification step, once a specific PR is known.
For GitHub, query existing PRs with `gh`:
```bash
gh pr list \
--repo <base-owner>/<base-repo> \
--head <head-branch> \
--base <base-branch> \
--state all \
--json number,state,url,title,baseRefName,headRefName,headRepositoryOwner
```
Pin every `gh` call in this step to the base repository with `--repo <base-owner>/<base-repo>`. Without it `gh` infers the repository from the local checkout's remotes, which in a fork clone resolves to the fork rather than the repository that should receive the PR — so the lookup can miss an existing upstream PR and the workflow creates a duplicate. This mirrors the `--remote`/`--repo` context the Gitea commands below already pin.
Pass `--head` a bare branch name. `gh pr list --head` does not support `<owner>:<branch>`, and it returns an empty list rather than an error when given one — which reads as "no existing PR" and causes a duplicate. When the head branch lives in a fork, or the same branch name could exist across forks, filter the returned `headRepositoryOwner.login` for the expected head owner instead of encoding the owner in `--head`.
For Gitea, query with `tea` and filter the JSON result for the exact head and base. Use the selected `--remote` context, or replace it with the resolved `--login` and optional `--repo` context:
```bash
tea pulls list \
--remote <gitea-remote> \
--state all \
--fields index,state,url,title,base,head \
--output json
```
Save the prepared body to a temporary file, then create the PR only after the push succeeds:
For GitHub:
```bash
gh pr create \
--repo <base-owner>/<base-repo> \
--base <base-branch> \
--head <head-branch> \
--title "<title>" \
--body-file <body-file>
```
When the GitHub head branch is in a fork, use `--head <head-owner>:<head-branch>`; `gh pr create --head` accepts that form to select a head repo owned by another user. It does not accept an organization as the owner, so for an org-owned fork run `gh` against that repository context instead. Unlike `gh pr list`, an explicit owner here is required for fork-based creation, not optional.
The two flags pin opposite ends and are both needed in a fork workflow: `--repo` fixes the repository the PR is opened against, `--head` fixes the repository the commits come from. `--repo` also keeps creation non-interactive — left to infer an ambiguous context, `gh` may prompt, which stalls an unattended run.
For Gitea, pass the body through `--description` because `tea pulls create` has no body-file option:
```bash
tea pulls create \
--remote <gitea-remote> \
--base <base-branch> \
--head <head-branch> \
--title "<title>" \
--description "$(cat <body-file>)"
```
When the Gitea head branch is in a fork, keep `--remote` pointed at the base/upstream repository and use `--head <head-owner>:<head-branch>`. When remote discovery is unsuitable, replace `--remote <gitea-remote>` with `--login <gitea-login> --repo <base-owner>/<base-repo>`.
Do not force issue identifiers into the title when repository conventions place them only in branch names or the body.
Verify the result with the same provider and context used to create it.
For GitHub, pass the PR number returned by creation or found by the exact head/base query:
```bash
gh pr view <pr-number> \
--repo <base-owner>/<base-repo> \
--json number,title,url,state,baseRefName,headRefName,body
```
A PR number is only unique within a repository, so `--repo` is what makes the number resolve against the intended one. Without it, a rerun from a fork clone can return a different repository's PR of the same number and report a false pass.
For Gitea, pass the PR index returned by creation or found by the exact head/base query:
```bash
tea pulls <pr-index> \
--remote <gitea-remote> \
--fields index,state,url,title,body,base,head \
--output json
```
Confirm that the PR is open against the intended base, uses the pushed head branch, and contains the expected issue links and body. A PR creation failure leaves the remote branch intact for retry.
## Failure and rerun behavior
- - A verification failure stops before commit.
+ - In Execute mode, a verification failure stops before commit; Draft-only mode records it and continues preparing the body.
- A commit failure stops before push.
- A push failure stops before PR creation.
- A PR creation failure does not delete or rewrite the pushed branch.
- A rerun reuses the correct branch, commit, upstream, or existing PR when already present instead of duplicating work.
- Never use destructive cleanup such as `git reset --hard`, branch deletion, or force-push as automatic recovery.
## Final handoff
Report:
- Operating mode used.
- Hosting provider and CLI context used.
- Base and head branches.
- GitHub/Gitea and Jira issue identifiers included or omitted.
- Commit SHA and title, if created.
- Push remote and upstream status, if pushed.
- PR number and URL, if created or already present.
- Verification commands and results.
- Remaining unstaged changes, failed checks, TODOs, and reviewer recommendation: one reviewer for leaf changes, two or more including the module owner for core changes.
## Quality rules
- Be specific about the bug, feature, mechanism, risk, and verification.
+ - Make reviewer verification reproducible: include setup, concrete steps, observable expected results, and honest execution status for the changed behavior, even when using a repository PR template.
- Match repository branch, commit, and PR conventions before applying defaults.
- Lead reviewers toward high-risk code and disclose AI authorship honestly.
- Reject architecture fiction: diagrams and claims must trace back to the actual diff.
- Flag unreviewed AI-authored core code, missing tests, leaked secrets, scope creep, and sprawling cross-module changes before any push.