AGENT SKILL

pushing-commits-to-the-repo

Open and advance a PR — write current metadata, apply the bounded pre-push review gate and its exemptions, push, watch CI, and triage comments. Use whenever you open a PR or push a commit.

License 许可
MIT
最近更新
2026-11-12
Stars
★ 2.1w
Forks
3.1k

01 前言 Front Matter

name
pushing-commits-to-the-repo
description
Open and advance a PR — write current metadata, apply the bounded pre-push review gate and its exemptions, push, watch CI, and triage comments. Use whenever you open a PR or push a commit.

02 资源文件 3

03 SKILL.md 正文

pushing-commits-to-the-repo

Pushing starts a loop; it does not end the task. Work stops only when the current HEAD meets the merge bar below, every comment is triaged, and metadata is current. Apply the prose-only documentation exception when that exception covers the whole PR.

Lifecycle: implement → targeted verification → commit → pre-push gate → push → CI → required reviews → metadata → handback → watch until merge or close. Apply the exceptions below at each gate.

Model tiers

Choose by the session's model family, not by the harness.

Family Strong Light
Claude latest Opus latest Haiku
GPT latest Sol latest Luna
Other session's model session's model

Start sessions that drive a PR on the strong tier. Use the light tier for the metadata check and, when your environment provides it, local /review-branch runs. Use the light tier for pre-push review until hosted review has commented on two earlier pushes. Then use the strong tier for pre-push review. Pass the model explicitly when the dispatch accepts one. Set the light model's effort from the PR's complexity.

Merge bar

Who merges says who merges a PR that meets this bar.

Size label Needs
S CI green, PR Review Checks passed, and a clean douwebot approval. An obviously trivial S PR needs CI green and PR Review Checks passed only.
M, L, XL CI green, PR Review Checks passed, and a clean douwebot approval.

Judge an S PR trivial only for string fixes or a clearly positive one-file docs update. State that judgment in the PR body. Until a size label exists, do not claim the trivial-S exception. Clean means douwebot APPROVE on the current head, with no douwebot comments on that head. Address every douwebot comment, including non-blocking comments. After addressing comments, obtain a clean approval on the resulting head. Resolve every review thread.

Douwebot posts as github-actions[bot] through the trusted PR Bots publisher. Verify its successful run and <!-- douwebot:review run=<id> head=<sha> engine=<claude|opencode|opencode-deepinfra> --> receipt. Legacy receipts omit engine. CI Review can use the same bot account but carries a separate gh-aw receipt; it cannot satisfy this bar. Associate inline comments with the head= in their parent review's receipt, or with the comment's original_commit_id when the parent has none, because GitHub can move both a review's and a comment's commit_id after a push. A clean, maintainer-authorized douwebot:review-agent-config approval satisfies the same requirement for protected paths. A human approval does not substitute for douwebot.

PR Review Gates enforces M/L/XL against the recomputed size and exactly one matching label. Size S remains a manual judgment; review enforcement skips merge groups after admission. On M, L and XL, the Gate: clean douwebot approval status reads failure until douwebot approves the head. Its description Requires a marked, successful douwebot approval on the current head. means douwebot has not approved this head. If douwebot already reviewed the head, triage its findings in step 4; otherwise trigger douwebot as step 3 of the loop says. Do not debug that failure as a CI failure.

PR Review Checks passed means its commit status reads success on the current head. .github/workflows/AGENTS.md and publish_pr_review_checks.py define the workflow and its verdict. A maintainer can pass a head despite its findings by applying pr-review-checks:accepted. That label covers only the current head; a push removes it. Never apply pr-review-checks:accepted yourself. PR Review Checks posts as github-actions[bot] with its own <!-- pr-review-checks run=… head=… --> receipt. Its comments are not douwebot comments.

Who merges

Adding a PR to the merge queue counts as merging it. A maintainer with merge rights (Douwe, Aditya, Mike or David) merges at the merge bar. Merge a PR yourself only in these two cases.

A flake fix. Once its head meets the merge bar, add it to the merge queue yourself. Enqueue it after the final metadata check. Flake fixes defines a flake fix.

A re-enqueue. Re-enqueue a PR the merge queue removed when all of these hold:

  • A maintainer enqueued it, or you enqueued it as a flake fix.
  • The removal's reason is failed_checks.
  • No maintainer asked to hold the PR since that enqueue.
  • Since that enqueue, the PR changed only by merging main without conflicts, or by commits that meet the Flake fixes conditions other than the size label. Outside the flake-fixed test module and its cassettes and snapshots, git diff main...<enqueued-head> equals git diff main...HEAD, with main freshly fetched. If you cannot establish the head at enqueue, hand the PR to a maintainer.
  • You pushed every commit since that enqueue.
  • Its current head meets the merge bar again.

In every other case, hand the PR to a maintainer. For a removed PR, comment that it is ready to re-enqueue once its current head meets the merge bar again.

Merge-queue removals

A merge-queue removal posts no comment and leaves the PR open. Detect it as a new removed_from_merge_queue event in gh api --paginate repos/pydantic/pydantic-ai/issues/<number>/timeline while the PR is still open; a merge logs the same event. Diagnose the failed jobs of the PR's newest merge_group run (head_branch gh-readonly-queue/main/pr-<number>-<sha>) as step 2 of "After you push — the loop" requires. After diagnosing, post a PR comment that names each failed job and its cause, with evidence: your fix commit, a known flake, or a failure already on main. Who merges says whether you re-enqueue it.

Flake claims

Claim a flake through its GitHub issue before you fix it, so that two agents never fix the same flake.

  1. Search the open issues for the failing test: gh issue list -R pydantic/pydantic-ai --state open --search '<test name> in:title'. Also search the closed flake issues: gh issue list -R pydantic/pydantic-ai --state closed --label flake --search '<test name> in:title'. If a closed issue's fix PR has merged to main, merge main into your branch instead of fixing the flake again.
  2. If no open issue names the test, file one. Title it Flaky <test node id>, label it flake, and link the failing CI run in the body.
  3. Cite the issue as evidence that the failure is a known flake.
  4. A claim is a comment on the issue that says you are fixing the flake and names your branch. Agents often share one GitHub account, so a claim is yours only when it names your branch.
  5. A claim expires one hour after it is posted, unless an open fix PR closes the issue. List the PRs that close the issue with gh issue view <issue> --json closedByPullRequestsReferences, then read each one's state with gh pr view <number> --json state. If an unexpired claim names another branch, do not fix the flake.
  6. A plain assignment with no claim comment is a maintainer's own claim. It does not expire. Leave that flake to them.
  7. To claim an unclaimed issue, or one whose claim expired, post your claim comment. Also assign yourself when you can, as a visible marker. Claim the issue before you write the fix. Open the fix PR within one hour of the claim.
  8. The fix PR closes the issue: put Closes #<issue> in its body.

A flake that this PR's diff introduced needs no issue. Fix it in this PR.

Flake fixes

A flake fix removes the source of nondeterminism that makes a test fail intermittently, so it passes deterministically. The trivial-S exception does not apply: require a clean douwebot approval. All of these must hold:

  • The PR body links a CI run where the test failed.
  • Unless this PR's own diff introduced the flake, the PR body closes the flake's issue, and you claimed that issue before you wrote the fix, as Flake claims says.
  • The PR body names the root cause and a reproduction that fails without the fix and passes with it. Force the failure, for example with a pytest-randomly seed, a forced ordering or a frozen clock. Or run the test repeatedly, and report its failure count without the fix and zero failures in at least as many runs with it.
  • Every changed file is the failing test's module, or a cassette or snapshot of it.
  • The PR is labeled size: S or size: M.
  • The diff removes no test.
  • The diff adds no skip, skipif, xfail, flaky or rerun marker.
  • The diff deletes no assertion.
  • The diff loosens no assertion: no wider tolerance, longer timeout or weaker matcher. Replacing a short readiness wait with the module's READINESS_WAIT_TIMEOUT, as agent_docs/concurrency.md recommends, is not a longer timeout.
  • The diff adds no real wait or in-test retry. A sleep or a polling loop is a real wait; waiting on an Event is not.

If any condition fails, hand the PR to a maintainer.

When you open the PR

Carry maintainer ownership onto the PR

For immediate maintainer work, assign the PR to the same human maintainer. Use gh pr create --assignee <maintainer-login> or gh pr edit <number> --add-assignee <maintainer-login>. Recover the owner from existing context or the linked issue's maintainer assignee and pydanty:skip label.

Write the title and body

Follow the title and template rules in the root AGENTS.md.

Put every closing issue reference at the start of the body, immediately after any required attribution line. These references are the first non-attribution content; use one Closes #<issue> line per issue the PR will close. Put related but non-closing issues in the explanation instead.

Keep visible body content within 40 lines. Exclude template lines and collapsed <details> contents from the count. For a feature or behavior change, use this order:

  1. Why we make these changes — State the problem and decision in a few sentences. Link the issue.
  2. New public surface — List each new maintained symbol. Write none when there is none.
  3. User-visible behavior — Show the smallest before-and-after example. Replace it with a call-path diff when the changed call chain explains the behavior; do not include both.
  4. Verification — Link the exact proving tests from the PR's Files changed tab so links survive later pushes. Put a minimal runnable playground in <details> only when it helps reviewers reproduce the behavior.
  5. What changes for existing users — State the effect in one sentence. Nothing is valid.

Use one collapsed <details> section per goal only when the PR has multiple independent goals. For a trivial PR, use the issue link, a short summary, and the test plan.

User-visible call-path diff

Use one fenced diff tree from the public entry point to the changed observable result.

  • Format each node as path/file.py :: Class.method() or path/file.py :: function().
  • Indent each callee beneath its caller with └─. Preserve enough unchanged nodes to show each edge.
  • Collapse irrelevant intermediate calls as … unchanged machinery ….
  • Include arguments only when they explain the change.
  • Include results only on relevant leaves.
  • Keep the shared caller prefix unmarked. Mark only diverging nodes, relevant arguments, or results.
  • Target 12 content lines inside the fence. Never exceed 20; collapse secondary branches instead.

Publish PR decisions

When .claude/skills/branch-context/pr-decisions.md has at least one entry, include them near the end of the body, before the checklist. Skip the section entirely when the log is empty or absent — /initialize-worktree and /adopt-pr own creating it, not this step:

<details>
<summary>PR decisions</summary>

<dated decision entries>
</details>

Do not copy the decisions template's instructions into the PR body. The section is public. Leave out confidential or privileged reasoning. Keep session ids: a later agent uses them to find the session that made the decision.

Keep labels current with the title and body

For prose-only documentation, handle title, body, and labels directly. Otherwise, assign updates to the same subagent. Reconcile labels whenever the title or body changes.

Run .agents/skills/pushing-commits-to-the-repo/label-catalog. Read the printed file directly for prose-only documentation; otherwise give it to the subagent. The checked-in catalog supplies clones and worktrees without label-read requests. Run the helper with --refresh after creating, renaming, or updating repository labels. Commit refreshed catalog changes. The helper uses at most two requests and verifies completeness before replacing the catalog. Never fetch labels individually or pass raw label API responses.

Keep the category label aligned with the PR's purpose: bug, feature, docs, chore or dependency. A refactor also carries refactor, alongside chore. A PR labelled test-suite or github-actions takes chore, never bug; .github/workflows/package-label.yml fails it otherwise. Add existing topic labels for every subject materially covered by the final title, body, and diff. Ignore incidental references, checklist text, and verification boilerplate when choosing topics. Remove topic labels only when the final scope no longer supports those labels. Preserve size, priority, review, and automation labels. Do not create or rename labels unless the user requests that change or approves a cluster name under PR clusters. Apply label additions and removals in a batch with the title/body update. Verify the resulting metadata.

Apply exactly one package label: pkg:core, pkg:harness, pkg:clai2, pkg:evals, pkg:graph or pkg:clai. Use the catalog descriptions to choose. Tests and docs count toward the package they cover. Use pkg:core for repository infrastructure. For changes spanning packages, choose the package whose users the change serves.

Labelling needs triage permission on the repo (Pydantic team members and their agents). If it fails, quote the actual error rather than concluding you lack permission. Size labels are applied automatically — don't set them.

PR clusters

Your PR is in a cluster when it shares a theme with at least two other open PRs. Merged PRs do not count. A PR in a cluster keeps its label and prefix after the other PRs merge. Never delete a cluster: label, even after its work stream ends. Deleting it strips the label from every merged PR and erases the record. Bug fixes count when they share the theme, such as caching bugs or privilege-escalation bugs. Unrelated bug fixes do not form a cluster.

Label every PR in a cluster cluster:<name>, and start its title with [<name>] . Name the cluster with one lowercase word, or two lowercase words joined by a hyphen: cache, voice-authority. Never apply the label without the prefix, or the prefix without the label. If creating or applying the label fails, apply neither. Tell the person driving you the cluster name and the error. After the prefix, the title follows the root AGENTS.md convention.

A cluster: label marks a time-bound work stream. It adds to the PR's topic labels and never replaces them. It is not an area: label. An area: label such as area:ui-adapters marks a permanent ownership area.

Detect clusters yourself. The people driving agents rarely name them, and a subagent does not know your sibling PRs. You usually notice a cluster because you started after another agent's work on the same theme, or because you coordinate with sibling PRs. When your PR is in a cluster:

  1. If another PR in the cluster carries a cluster: label, apply that label and its prefix to your PR, and stop.
  2. Otherwise, propose a cluster name to the person driving you. Do not hold the PR for the answer.
  3. Once that person approves the name, create the label with a one-line description of the theme.
  4. Apply the label and the prefix to your PR.
  5. Tell the agents driving the other PRs in the cluster to apply both to their PRs. If you cannot reach one, tell the person driving you which PRs still lack them.

David (dsfaccini) asked for this convention. The prefix makes a cluster easy to spot in PR lists. Release notes list PR titles, and a prefix catches the eye more than title text does. Release-note readers then notice what the team is focusing on. Raise objections to the convention with David instead of dropping the prefix.

Prose-only documentation

Prose-only documentation changes only natural-language text, including docstring prose and descriptive instruction wording. Substantive changes to instruction or review policy do not qualify. Executable code, code examples/snippets, configuration, schemas, CI logic, and machine-consumed data changes do not qualify.

Skip pre-push-review, all local reviewers, the second-opinion choice, and the final metadata-subagent review. Handle metadata directly. Keep CI checks and triage comments already posted before handoff. Apply the merge bar, including its trivial-S exception, to required hosted reviews.

Leave automatic configured CI and hosted review workflows unchanged; they may run independently. Do not edit workflows or triggers to implement this exception. Once the merge bar is met and posted comments are triaged, hand the PR diff to the maintainer driving you, or another maintainer, to inspect and merge.

Mechanical text/data refreshes

A small mechanical text/data refresh changes no code, runtime behavior, CI logic, or substantive instruction or review policy. A catalog-row refresh is one example.

For this case, skip local pre-push-review and any additional substantive review dispatch. Do not ask for a second-opinion choice. Automatic configured CI and hosted reviews still run.

Review scope

The first substantive pre-push review assesses the full branch against its merge base. Follow-up reviews normally assess changes since the last reviewed tree, plus affected callers and invariants. Check that prior findings were fixed and the changes introduce no regressions. Widen the scope for a substantive redesign, relevant upstream interaction, or an explicit review request. Do not restart a full-branch review automatically after a small correction. The reviewer may widen the supplied scope when the changed content requires broader context.

A verdict belongs to reviewed content. Record the reviewed commit and tree IDs with the review's scope. Committing an unchanged reviewed tree preserves that verdict even when HEAD changes. Material changes require the appropriate scoped review unless an exemption or exhausted budget applies.

Fresh reviewer context contract

Local review guarantees context independence, not hosted-grade hostile-content isolation. Hosted reviewers own that separate boundary. Every fresh reviewer here runs under the same context contract:

  • Capture three immutable commits: policy-base-sha is the fetched current target-branch tip whose instructions are authoritative; merge-base-sha delimits the branch diff; candidate-head-sha is the exact commit proposed for the current review. Record its tree ID too. For a follow-up, also capture the last reviewed commit and tree IDs.
  • From the stable policy-base checkout, the implementing agent prepares the review bundle: task or issue, full PR discussion including thread state, relevant settled maintainer decisions with their sources, relevant authoritative documentation, completed verification, and the exact review diff selected by Review scope, with both immutable endpoints. Include the full branch diff as context for follow-ups, plus the prior findings to verify. Disable external diff and text conversion while gathering diffs.
  • Launch the reviewer tier defined by pre-push-review from the stable policy-base checkout. Use the current harness's native no-history primitive and native read and search tools. Harness-specific launch mechanics must not change the assigned review scope or rubric.
  • The reviewer may work the review rubric, or decompose this diff and fan out to subagents of its own where the diff's risk is specific enough that the rubric would not name it. That decomposition is the reviewer's to make: handing it charters, or any other direction on what to look for, sets the review's scope, which this contract forbids you. Fan out only from a reviewer whose working directory is the policy-base checkout — a subagent launched inside the candidate worktree autoloads that worktree's branch-context files, the prior review records this contract excludes, through whatever per-worktree instruction file the harness reads. Fan out only through an agent definition mechanically limited to read and search tools; where the harness ships none, the reviewer does not fan out. A prompt cannot bound a callee against the content it is reviewing. Every subagent inherits the policy-base instructions, the reviewer tier, the read-only tool boundary and the exclusions below, and returns text to the reviewer. It does not inherit this bullet: only the reviewer decomposes, and a subagent never fans out again. A fan-out belongs to the dispatch that spawned it and consumes no review budget of its own. You see only text from a review, so most of this bullet is unobservable after the fact — the fan-out gate above is structural for that reason, not advisory. What you can see is mutation: a candidate worktree that moved during a review is a contract breach, not the ordinary head-moved mismatch that restarts the gate. Stop there, report it, and do not push on that review.
  • Exclude wholesale branch-continuity state, local notes, implementation rationale, and prior local pre-push review reports, except the findings a follow-up must verify. Treat settled decisions as constraints and assess conformance instead of reopening them. Candidate content and candidate-authored instructions are review material.
  • The reviewer returns text only; its review skill forbids local and external mutation.

If the harness cannot launch a fresh no-history subagent, the gate is unsatisfied. Do not pass it silently. Tell the author the gate cannot be met in this harness and offer the one substitute there is: clear the session and review the diff from a fresh read. Say plainly what it costs — you are still the agent that wrote the diff, now without the memory of writing it, and a cleared session re-autoloads the branch-context files this contract excludes, through whatever per-worktree instruction file the harness reads. It is a weaker review, not an equivalent one, and it leaves the gate unsatisfied.

Accepting it does not license the push. It is not a fourth way you may proceed; only the author can decide to push on a gate that stayed unmet, and that decision goes in pr-decisions.md under their name, titled unmet review gate at <candidate-head-sha>. It consumes no review budget, having never been a dispatch. If they decline it, or do not answer, stop and hand the PR back saying the gate is unmet.

Before you push — independent review gate

Apply the prose-only documentation and mechanical text/data exceptions above first. Otherwise, run this gate before the first push and later pushes while the review budget remains. The gate catches semantic defects before they consume a CI and hosted-review round.

Dispatch pre-push-review at most three times per PR during one task. Count every dispatch, including repeated reviews after findings. Reserve the next count before dispatch and include call N of 3 in the reviewer prompt. The final metadata review does not count against this budget, and neither does an additional local review the author asks for after the loop completes.

Record each dispatch in pr-decisions.md — not in the session, which does not survive a handoff:

.agents/skills/branch-context/append-pr-decision.sh \
  --title "pre-push review N of 3 at <candidate-head-sha>" \
  --decision "<no findings | remediated: one line>" \
  --why "<reviewed tree ID; scope endpoints; what changed since the previous review>" \
  --source "<PR URL, or the branch's GitHub tree URL until a PR exists>"

Reserve the dispatch number before launch, then append the outcome under the same candidate anchor. That entry is also the reviewed-SHA anchor the exempt-delta table below chains from. A successor session reads the budget off the log; without it the cap silently resets.

  1. Commit the exact state you intend to push. Leave nothing staged, unstaged, or uncommitted unless the user's instructions override this.

  2. Fetch the declared target branch. Capture and validate the full policy-base and candidate HEAD SHAs, compute the merge-base SHA, and verify the candidate worktree is clean. Materialize the policy-base checkout the contract above refers to — it does not exist until you make it:

    POLICY_BASE_DIR="$(mktemp -d)/policy-base"
    git worktree add --detach "$POLICY_BASE_DIR" "$POLICY_BASE_SHA"
    # ... run the gate ...
    git worktree remove --force "$POLICY_BASE_DIR"
    

    Put it outside the candidate worktree. A path inside it dirties the tree the clean check below is about to inspect. Materialize it for every review, including one that only needs to read instructions: whether the reviewer may decompose the diff turns on it, so skipping it would let your launch choice decide the review's scope, which the contract forbids you.

  3. Select the review scope above. Prepare the review bundle under the context contract.

  4. Launch the fresh subagent under the context contract above. Require actionable findings or current at <full-candidate-head-sha>.

  5. Triage every finding. Remediate valid findings, rerun affected verification, and commit. Dismiss invalid findings only with concrete evidence. If a finding exposes a real design choice, API trade-off, or behavioral default, pause the push and give the maintainer the options, trade-offs, evidence, and a recommendation; record the resulting decision. A remediation changes the candidate content. Reapply this gate, including its scope and exemptions, only while the budget remains. After a maintainer decision changes the acceptance criteria, dispatch a different fresh subagent when the budget remains. An evidence-backed dismissal on unchanged reviewed content does not require another pass. Escalate persistent disagreement.

Stop after a review returns no findings. After the third review, remediate its findings and run the relevant local checks. Do not dispatch a fourth review. Continue with the push, CI, and hosted review. Budget exhaustion is one of four ways a pushed SHA can go un-reviewed; the others are an evidence-backed dismissal on unchanged reviewed content, above, an exempt delta from the table below, and a push the author authorized over a gate that could not be met, recorded under their name. The first three you may decide. The fourth only they may. Nothing else.

Immediately before pushing, verify the worktree is clean and its tree equals the recorded reviewed tree. A different commit with the same tree keeps the verdict; record the new commit alongside the reviewed anchor. After third-review remediation, verify HEAD equals the locally checked remediation commit instead. Any other mismatch restarts the gate while the budget remains, unless the delta is exempt below.

When a later push does not need another review

Classify the actual delta, regardless of whether CI or a reviewer triggered the change. Routine CI repairs may skip repeated review only under the checks below. Changes to runtime, API, compatibility, design choices, or assumptions require review within the remaining budget. Keep targeted verification and configured CI and hosted reviews for exempt deltas.

Compute that delta from the last reviewed SHA, never from the last pushed one, and record which reviewed SHA the exemption chains from beside the budget count. Otherwise consecutive exempt pushes drift arbitrarily far from anything a reviewer read, each hop defensible on its own.

Exempt delta since the reviewed SHA Check
Missing coverage, test-harness repairs, or fixture/snapshot corrections to established intended behavior inspect the full diff: test code/data only; cite the established expectation and run affected tests; a snapshot must not bless a newly observed regression
Output of the repo's own tooling (make format, lint autofix) run that tooling on the reviewed SHA in a scratch checkout; its tree equals HEAD's
Comments or docstrings only, no docs/** page no non-comment line appears in git diff <reviewed>..HEAD
Target-branch merge with no conflict resolution git diff main...<reviewed-head> equals git diff main...HEAD, with main freshly fetched
Commit or revert to a tree that was already reviewed git rev-parse HEAD^{tree} equals a recorded reviewed tree
Lockfile-only dependency bump only lock and manifest paths changed

Anything not named above re-reviews. Size is never the test: a one-line production fix is the shape a wrong fix hides in, which is why the root AGENTS.md requires reproducing the defect first. Four deltas that look exempt and are not — a cassette re-record whose request body changed (a wire-contract change wearing a test path), a conflict resolution inside an otherwise-exempt merge, a snapshot accepting a newly observed regression, and any change to public API including a rename. Applying a review finding follows the same delta classification; an exact suggested edit is not itself an exemption.

To claim an exemption the table does not name, write down the rubric rung the delta could touch and why it cannot, in pr-decisions.md.

Never use the implementing agent as the reviewer. The one exception is the substitute the contract names for a harness that cannot launch a fresh no-history subagent at all — the author accepts it, and it leaves this gate unsatisfied. Never treat this gate as test execution.

Never force-push an open PR branch. Push follow-up commits so previous reviews remain valid; maintainers can squash them when merging.

Attempt the push. If it fails, read the real error. Do not infer a restriction from metadata.

After you push — the loop

These gates catch different failures; none replaces another:

  • Independent pre-push review catches semantic and design defects before they consume a CI or hosted-review round.
  • CI runs the repository-wide type check, test, and coverage gates.
  • Hosted reviewers inspect the pushed diff with different models, instructions, and context.

For prose-only documentation, follow the exception above for local review and metadata.

Capture the PR head SHA after the push. Every post-push gate below must prove it covered that SHA; if the head changes, capture the new SHA and restart the loop.

  1. Synchronize PR metadata. Update the title, summary, verification, and collapsed PR-decisions section for the pushed commit. Compare the dated decision entries in the body with the local log; the local log is authoritative.

  2. Watch CI to a terminal state. Require the CI workflow to succeed for the captured SHA. Its success certifies every job it contains, coverage included. Do not inspect individual jobs or their logs to reconfirm a success. Don't idle. If it fails, diagnose: fix if the failure is yours; if it's a known flake or pre-existing on main, say so with evidence. When a flake fails your CI, fix it in this PR if this PR caused it. For any other flake, find or file its issue as Flake claims says. Fix that flake in this PR only if you hold its claim, this PR is labeled size: S or size: M, and the fix stays within the root AGENTS.md scope rule. Otherwise, if the issue's claim belongs to another branch or a maintainer, cite the issue as the flake's evidence and leave the fix to them. In every other case, ask the person driving you whether to start a separate worktree and task to fix it. Recommend yes.

  3. Meet the merge bar on the captured SHA.

    • PR Review Checks: required for every PR. It starts on every push without a label, so watch it while CI runs. Its verdict is a commit status on the PR head, not a check run: the CI run and commits/<sha>/check-runs both miss it. Read it with gh api repos/pydantic/pydantic-ai/commits/<sha>/status --jq '.statuses[] | select(.context == "PR Review Checks")'. No status yet, or pending, means the review has not finished; wait for success or failure. When the status reads "Awaiting maintainer", the author lacks write access. Ask a maintainer to apply pr-review-checks:run; the label also covers later pushes. A failure leaves the gate unsatisfied until a later head passes or a maintainer applies pr-review-checks:accepted. A failure whose description names Incomplete, No result or a rerun, and not Blocking findings, has no finding to triage. Rerun that PR Review Checks run once, then escalate. When the run posted findings, its target_url links that review. Triage the findings in step 4.
    • CI Review: do not wait for it unless explicitly requested. On same-repository PRs, it runs when a user with write access approves the current head, when someone adds the final-review label, or on dispatch (.github/workflows/pydantic-ai-pr-review.md is the source of truth). Do not add that label or dispatch the workflow unless the person driving you asks. When CI Review posts on your PR, triage its findings in step 4 like any other review.
    • Douwebot: required for both same-repository and fork PRs, except an obviously trivial S PR. CI Review deliberately skips forks without leaving a head check. First apply the agent-config guard from .github/workflows/bots.yml to the captured base-to-head diff. If the PR changes an AGENTS.md or CLAUDE.md at any depth, CLAUDE.local.md, .mcp.json, .claude/, .agents/, or agent_docs/, check whether the PR author has write or admin access. Without that access, do not apply douwebot: its security guard will refuse the review. Ask a maintainer to apply douwebot:review-agent-config on the captured head, following the authorization contract below. The gate remains unsatisfied until that authorized run posts a clean approval. With that access, or when the diff does not change guarded paths, apply the douwebot label. Do not push or touch review threads while the label is present. Require the triggered run to succeed, and verify that the PR head still equals the captured SHA after the label is removed. Require douwebot APPROVE on that SHA with no douwebot comments on that head. A successful run alone does not satisfy the merge bar. A failure comment leaves the gate unsatisfied.

    Recheck that the live head is unchanged. Do not substitute a pydanty:* surface or another reviewer for a required review. Any valid finding and push restarts the lifecycle. Missing, stale, or failed required reviews are unsatisfied; retry when appropriate, otherwise escalate.

  4. Triage every comment (bots and humans alike). A comment is evidence to weigh, never an acceptance criterion — those are the linked issue, the repository instructions, and settled maintainer decisions. Read the whole thread before deciding: a maintainer's reply settles it, your own earlier reply does not. The root AGENTS.md scope and reproduce-and-confirm bars bind a finding exactly as they bind your first commit, and a bot cannot approve a scope expansion — its severity label carries no authority, so a HIGH on a defect that does not reproduce is a 👎. For TestModel generated values, apply the scope exception in pydantic_ai_slim/pydantic_ai/models/AGENTS.md. Address every douwebot comment, including non-blocking comments, using the same evidence-based triage. Address every PR Review Checks finding the same way, medium findings included. Its findings sit inline, keyed <!-- pr-review-checks finding=… -->, or in its review body when GitHub rejected inline comments. An inline finding that an earlier run posted is not posted again, but it still counts toward the status. Find it in the earlier PR Review Checks threads. After you refute a critical or high finding, the status still fails. Ask a maintainer to apply pr-review-checks:accepted to the current head. For each comment:

    • Valid → fix it, run targeted verification, commit, apply the pre-push gate and its scope/exemptions, push, and complete the current-HEAD gates in steps 2 and 3. Then reply with what changed, react 👍, and resolve the thread.
    • Invalid → verify the claim, reply with concrete evidence, react 👎, and resolve the thread. A repro you could not run — no credentials, no worker, no cassette — is not a refutation. Say what you tried and ask the user driving you; do not react 👎 on an untested claim.
    • Close the bot verdict after its findings. Verify every blocking finding against the current head. Include findings in the review body and earlier rounds, not only unresolved inline threads. Each finding must be fixed and checked, or conclusively refuted with recorded evidence. A new commit, an outdated thread, or zero unresolved threads alone is insufficient. Leave the verdict active while a finding or decision remains open. Dismiss the fully addressed bot REQUEST_CHANGES with the tracked helper below. Dismissal is not approval and never satisfies a required fresh review.
    • A human REQUEST_CHANGES remains blocking until that human re-reviews or a maintainer dismisses it. Do not dismiss a human request.
    • Minimize issue-level review dumps when handled. Never silently ignore feedback or close it without a reply.

    Thread mechanics — gh has no subcommand for either half, so both are GraphQL. Enumerate what is still open, newest page last:

    gh api graphql --paginate -f query='
      query($owner:String!, $name:String!, $pr:Int!, $endCursor:String) {
        repository(owner:$owner, name:$name) { pullRequest(number:$pr) {
          reviewThreads(first:100, after:$endCursor) {
            pageInfo { hasNextPage endCursor }
            nodes { id isResolved isOutdated path
                    comments(first:100) { nodes { databaseId author { login } body url } } } } } } }
      ' -F owner=pydantic -F name=pydantic-ai -F pr="$PR_NUMBER" \
      --jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved | not)'
    

    Read the whole comments list of a thread before deciding — the first comment is the finding, the rest may already settle it. Reply on a thread with gh api repos/pydantic/pydantic-ai/pulls/$PR_NUMBER/comments/<databaseId>/replies -F body=@<file> — -F reads the file, -f would post the literal string @<file>. Pass the text through a file so contributor-quoted $(...) and backticks are never expanded by your shell. Then resolve the thread by its node id:

    gh api graphql -f query='
      mutation($id:ID!) { resolveReviewThread(input:{threadId:$id}) { thread { isResolved } } }
      ' -F id="$THREAD_ID"
    

    Resolving is not the same as agreeing: resolve a thread you answered with evidence too. Leave one open only while a person still owes a response.

    After verifying every blocker in a bot verdict, prepare a dismissal reason file. Use the attribution required by your active repository or harness instructions for the first line. Explain each fix or refutation and link the commits or evidence. Pass the explicit review ID and full verified head to the tracked helper:

    bash .agents/skills/pushing-commits-to-the-repo/dismiss-addressed-bot-review \
      pydantic/pydantic-ai "$PR_NUMBER" "$REVIEW_ID" "$VERIFIED_HEAD" "$REASON_FILE" \
      --all-blockers-addressed
    

    The final flag attests that you assessed every blocker, including review-body findings. The helper rejects human verdicts, unresolved threads involving that bot, and changed or closed heads. Multiple workflows share a bot account; identify the review by its body and originating run. Read the resulting PR review state; another active request may still block review eligibility. If dismissal fails, report the actual error and leave that close-out item pending.

  5. Escalate real trade-offs, don't guess. If a comment needs a maintainer decision (a design choice, an API trade-off, a behavioral default), leave a comment containing: the background, your reasoning, the decision that needs making, the trade-offs (pros/cons of each option), and your recommendation. Then poll every 30 minutes for a reply and continue when it lands.

  6. Stop when steps 2 through 4 have each reached an accepted terminal state on the current HEAD, with any documented skip classified explicitly. Their results are the evidence; do not re-read a state an earlier step already established. When the HEAD changes, capture the new SHA and repeat the loop.

When the loop completes — choose an additional review surface

Skip this choice for prose-only documentation, mechanical text/data refreshes defined above, and flake fixes.

The required reviews are not on this menu. Step 3 applies the merge bar to both same-repository and fork PRs. CI Review starts on a write-access approval of the head, a final-review label, or a dispatch. Green CI alone never starts CI Review.

What this section chooses is a second opinion on top of the required reviews, and the choice belongs to the person whose PR it is, not to you.

Report the diff first: its size label, how many files it changes, and where the change lands on the review rubric — public API, then concepts and behavior, documentation, tests, code quality. Then recommend one from those three facts and ask. Lean toward none when the change cannot move a rung the required review has already covered: a dependency bump, a formatting pass, a test closing a coverage gap. Lean toward a surface when it moves public API, concepts and behavior, or user-facing docs — where a reviewer catches things like an example built on an outdated model. Small diffs are cheap to review, so take one when the call is close.

Surface Choose it when
pydanty:review-branch The diff reaches widely and you want findings fixed rather than only reported. It runs a fixed reviewer roster and pushes remediation commits to the branch. It waits on green CI.
pydanty:review-lite The diff is narrow or unusual enough that a fixed roster would look past it. It writes review charters for this diff, dispatches one reviewer per charter, and adjudicates before posting. It reports and never remediates, and it has no CI precondition.
douwebot One last high-judgment pass. Inline findings and a formal verdict, one review per label application. Unless the trivial-S exception applied, this is a second application of the reviewer that already gated the PR, against the diff as it now stands.
local No hosted surface fits, or you want a read before the PR moves again. Dispatch pre-push-review under the context contract above and triage its findings like any other.
none No second opinion. The merge bar still gates the PR.

If the author does not answer, stop and hand the PR back naming the surface still pending. Do not pick one yourself to keep moving.

Triggering a hosted surface

The pydanty:* labels are defined outside this repository; what follows is their contract as the maintainers run them, not something this repo can show you.

  • Apply the label last, not early. None of them re-runs on a later push, so a deep review of a still-moving PR reports on a diff that no longer exists.
  • How: gh pr edit <number> --add-label <name>, after confirming the name against the checked-in label catalog. This needs triage permission on the repo. If it fails, quote the actual error rather than skipping the step on an assumed lack of permission.
  • The label tells you nothing about the outcome. Every surface consumes its own trigger label — pydanty on pickup, before it has reviewed anything; douwebot from an always() step that also runs when the job was cancelled. A failed douwebot run comments saying so and invites a re-apply. A completed douwebot review posts a formal APPROVE or REQUEST_CHANGES verdict; its inline findings are attached to that verdict review. An incomplete run or a moved head may have no verdict. A head that already has douwebot findings is not reviewed again: the run comments with a link to the earlier review instead. Read the run conclusion and the captured-head reviews, as step 3 requires.
  • Wait for a pydanty run. It adds pydanty:is-working when it starts. Poll every 15 minutes for up to 2 hours 30 minutes. Never push to the branch and never touch a thread while pydanty:is-working is set. pydanty:review-branch reports either a review, pydanty:reviewed on a clean pass, or pydanty:rb-pending — which means it deferred on red or conflicted CI and will retry on its own, so fix CI rather than re-applying. pydanty:review-lite posts a review and sets neither label. If nothing has landed at 2 hours 30 minutes, stop and hand the PR back saying the run has not reported.
  • A pydanty remediation commit is a new HEAD. Fast-forward before acting on the verdict, or you will read a head behind the PR. Then treat it as the loop preamble requires of any head change: capture the new SHA and restart the loop against it. Classify the remediation delta under the pre-push gate above.
  • Known douwebot refusal: the job fails without reviewing if the PR touches an AGENTS.md or CLAUDE.md at any depth, CLAUDE.local.md, .mcp.json, or anything under .claude/, .agents/ or agent_docs/ — a security guard against a PR editing the reviewer's own instructions. The guard is skipped for an author with write or admin access on the repo. Don't apply the label to a PR the guard covers; the red check is the guard working.
  • When a maintainer explicitly requests review of those protected paths, apply douwebot:review-agent-config. It authorizes one review only when its first labeled event came from a User with current write or admin permission and the PR still has the event head. Do not treat label presence as approval for an ordinary douwebot trigger or a later head. If the run fails or is canceled, remove and reapply the label; rerunning the old event is denied.
  • Afterwards, re-enter the loop. A hosted surface posts comments that need the same triage as any other.

Before handing the PR back

For prose-only documentation, check the title, body, and labels directly against this skill, root AGENTS.md, and the PR template. Correct metadata directly, then hand the PR diff to a maintainer after the merge bar and comment triage are complete. Skip the subagent steps below.

For other diffs, run this final metadata check after CI, any required hosted review, and comments have settled. Any author-selected additional review must also have settled.

  1. Capture the current title, body, and labels. Dispatch a fresh subagent under the context contract above. The metadata subagent has not worked on the PR and never decomposes the diff. Run the subagent on the light tier from Model tiers. Set effort from the PR's complexity. The check compares text against written rules.

  2. Give it the PR URL, linked issue, current base...HEAD diff, final test status, captured metadata, complete catalog, and the local dated PR decisions. Exclude prior local review reports; permit the decisions log only to check its public mirror.

  3. Ask it to check only the title, body, and labels against this skill, the root AGENTS.md, and the PR template.

  4. Require either current or exact corrections: title or body text changes and label additions/removals.

    • Require each correction to cite the rule it enforces.
    • Require each correction to quote the title, body text, or label that breaks the rule. When the rule requires a missing element, require the correction to name that element instead.
  5. Verify each correction. Keep a correction only when a rule in this skill, the root AGENTS.md, or the PR template says what the correction claims and the current title, body, or labels break that rule. When that rule is not the one the correction cites, cite it on the kept correction. When you find a violation that no correction names, verify it the same way and add it as a kept correction.

  6. Edit the title, body, and labels once. Use the kept corrections, and write your own changes where they fall short. The edit is done when all three hold:

    • The edited title, body, and labels follow every rule a kept correction cites.
    • The edited title, body, and labels break no rule that the current ones follow.
    • The edit applies no subagent text that no kept correction covers.

    Committed changes restart the post-push loop; GitHub metadata-only changes do not.

  7. Verify the live title, body, and labels match the checked metadata. After metadata corrections, wait for the corresponding edited-event checks and triage feedback. Require workflow-defined accepted terminal outcomes; earlier checks on the same HEAD do not cover the edit. Hand the PR back after these gates settle.

After handback — watch until merge or close

Keep watching the PR after you hand it back, until it merges or closes. Poll the PR's state, timeline, comments and reviews every 30 minutes. The merge queue can remove the PR after handback, and new reviews can still land. Handle a merge-queue removal as Merge-queue removals requires, then keep watching. Triage each new comment or review through step 4 of After you push — the loop. A push changes the head, so restart that loop on the new head.

This section exempts a non-interactive run that exits when it hands back. A pydanty run and a hosted review workflow are examples. If an interactive session ends before the PR merges or closes, its last report states that nothing watches the PR.

04 同仓库更多 Skills

pydantic
pydantic/pydantic-ai

migrating-agno-to-pydantic-ai

Migrate Python Agno applications to Pydantic AI and, only when needed, Pydantic AI Harness. Use when source code imports `agno` or relies on Agno agents, teams, workflows, sessions, memory, knowledge, tools, hooks, guardrails, approvals, skills, streaming, or AgentOS.

★ 2.1w
pydantic
pydantic/pydantic-ai

reviewer

Review changes.

★ 2.1w
pydantic
pydantic/pydantic-ai

pydantic-ai-harness

Extend Pydantic AI agents with capabilities from pydantic-ai-harness -- the Coder coding agent, file and shell tools in local or sandboxed workspaces (Modal, E2B, Render, Sprites, Daytona, boxd, smolvm, BoxLite), Code Mode, sub-agents and planning, memory and skills, context compaction, guardrails and spend limits, web research and browsers, hosted SaaS integrations, step persistence, and background agents on Render Workflows. Use when the user mentions pydantic-ai-harness or pydantic_ai_harness, imports a harness capability such as Coder, CodeMode, FileSystem, Shell, SubAgents, Memory, or ToolGuardrail, or wants a Pydantic AI agent that edits files, runs commands or agent-written Python, delegates, remembers, manages long context, stays within limits, or runs model and tool operations as chained Render task runs.

资料检索与研究Skill与智能体开发
★ 2.1w
pydantic
pydantic/pydantic-ai

migrating-deep-agents-to-pydantic-ai-harness

Migrate Python LangChain Deep Agents applications to Pydantic AI and Pydantic AI Harness. Use when the source uses the upstream `deepagents` package or demonstrably reproduces its middleware, backends, skills, memory, subagents, or sandbox contracts. Use `migrating-langchain-to-pydantic-ai` for plain LangChain, LangGraph, or LCEL migrations and `pydantic-ai-harness` for greenfield Harness usage.

★ 2.1w
pydantic
pydantic/pydantic-ai

migrating-vercel-ai-sdk-and-eve-to-pydantic-ai

Migrate TypeScript Vercel AI SDK or Eve applications to Python with Pydantic AI and, only when needed, Pydantic AI Harness. Use when source code imports `ai`, `@ai-sdk/*`, or `eve`, or relies on `generateText`, `streamText`, `ToolLoopAgent`, `useChat`, Eve agents, tools, skills, subagents, approvals, sessions, channels, schedules, or sandboxes.

★ 2.1w
pydantic
pydantic/pydantic-ai

migrating-pi-to-pydantic-ai

Migrate TypeScript Pi coding-agent applications, extensions, or packages to Python with Pydantic AI and Pydantic AI Harness. Use when source code imports `@earendil-works/pi-*`, calls `createAgentSession`, registers Pi extensions, or relies on Pi tools, hooks, skills, sessions, compaction, providers, TUI, RPC, or packages.

★ 2.1w