Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

PR Workflow

The maintainer-side governance contract for PRs targeting master. Branch-protection settings, the DoR/DoD readiness contracts, and the failure-recovery protocol live here. Day-to-day reviewing lives in the Reviewer Playbook. The contributor-facing flow lives in How to contribute.

Governance goals

The workflow exists to keep five things true under high PR volume:

  1. Merge throughput is predictable.
  2. CI signal quality stays high, fast feedback, low false positives.
  3. Security review is explicit on risky surfaces.
  4. Changes are easy to reason about and easy to revert.
  5. Repository artifacts stay free of personal or sensitive data.

The control loop that delivers this is layered on purpose:

  • Intake classification: path/size/risk labels route the PR to the right depth.
  • Deterministic validation: the merge gate depends on reproducible checks, not subjective comments.
  • Risk-based review depth: high-risk consequences and security boundaries get deep review, while low-risk work stays fast.
  • Rollback-first merge contract: every merge path includes a concrete recovery story.

Automation handles path/scope labels, manual issue-dashboard planning reports, and CI gating. Risk, size, type, and contributor-tier labels are maintainer intake decisions unless a maintained workflow explicitly owns them. Final merge accountability stays with human maintainers and PR authors. A PR carrying either risk:high or domain:security requires deep review and two independent Core Team approvals; automated review does not count as a Core Team approval.

Project board contract

The Project board is an automated planning board, not the authoritative PR review queue.

Use the board for issue readiness, routing evidence, roadmap grouping, dependencies, blocker state, and stale-exemption reasons. Those signals move slowly enough that a board field or planning lane can stay useful.

The current automation is manual and report-only. project-dashboard-plan.yml runs on workflow_dispatch for a single issue number, reads the issue payload, and writes a step summary proposing the existing Project Status value that best matches the issue’s live labels and state. It does not write Project fields, edit issues, add labels, post comments, or run automatically on issue events.

A JSON summary of this planning split lives in project-board-contract.json. Treat it as the contract for the report-only planner and future board refresh automation, not as approval for automatic issue-event runs or active GitHub Project mutation yet. Live ProjectV2 writes need an approved field mapping, a project-scoped credential or app installation, and readback that compares planned status with live Project state before maintainers rely on it.

Do not mirror native PR review state into manual board lanes. GitHub PR state owns review decision, required checks, mergeability, conflicts, stale approvals, and merge readiness. If the board later displays derived PR routing such as DIRTY, BEHIND, or APPROVED, treat it as a dashboard view of GitHub state, not a separate source of truth.

This keeps the board useful without asking maintainers to update it after every push, review, or CI run.

Size and risk auto-labeling are separate workflow questions. #9345 may recalculate deterministic size labels on PR updates. Its risk classifier remains report-only until maintainers review the evidence and separately enable risk-label mutation. Risk automation must honor risk:manual until a maintainer removes that override. The issue-dashboard planner does not apply or recalculate PR risk, size, or type labels.

Issue routing evidence

Issue triage stays a shared maintainer responsibility. Accepted issues do not need a standing owner map before they can remain open, and CODEOWNERS does not make code owners responsible for every issue in a matching area.

Issues need contributor-visible routing evidence when a special state would otherwise hide them from routine review or stale sweeps: status:no-stale, active release/RFC/design tracker status, or a deferred maintainer decision. status:blocked keeps its simpler rule: record the unresolved blocker and revisit stale protection when the blocker clears.

Use these meanings consistently:

Routing signalMeansDoes not mean
AssigneeSomeone is actively implementing, investigating, or shepherding the immediate work.Permanent area ownership or passive responsibility for every related issue.
Routing evidenceA visible issue comment, body section, public field, board field, or linked tracker records the reason for special handling and the next decision surface.Automatic implementation ownership or permanent area ownership.
Tracker/RFC surfaceAn active release tracker, RFC, or design tracker can be the coordination surface while it remains current.Permanent stale protection after the tracker closes, drifts, or stops representing an active decision.
Project board fieldOptional planning signal for readiness, routing evidence, blocker state, or stale-exemption rationale when it is visible and maintained.A private stale-policy source or replacement for native PR review state.
Labels and CODEOWNERSDurable classification, likely area routing, and PR-review consultation hints.Ownership or stale protection by themselves.

CODEOWNERS is a PR-review routing mechanism. It can identify people to consult when an issue clearly touches a path, but it does not create issue ownership and should not be mirrored into stale policy as a private routing map.

Routing evidence is about the next decision, not delivery ownership. A routed issue should not sit in “owned” limbo; the next visible update should make one of these outcomes explicit: assign an active implementer, make the issue contributor-ready, route it to a tracker or milestone, record the blocker, schedule a concrete maintainer decision point, or close/defer it with rationale.

Scheduling an issue for maintainer triage is valid only when the issue records what decision is needed, where that decision will be tracked, and when it will be revisited. After that triage pass, replace the triage routing with an active implementer, contributor-ready scope, tracker or milestone route, blocked/deferred state, or closure rationale.

For protected issues, record both the stale-exemption reason and the next decision surface before adding or keeping status:no-stale. Useful visible evidence sources include:

  • an assignee doing active work plus an issue-visible note, body section, or tracker entry explaining why stale handling should not apply;
  • an issue comment, issue body section, or public issue field recording the stale-exemption reason and next decision surface;
  • a public Project field that is visible to normal issue readers and actively maintained;
  • a linked public tracker, milestone, RFC, or design issue that records why the issue stays open and when it should be revisited.

Active release trackers and active RFC or design trackers are durable coordination surfaces. When the issue title, body, labels, or milestone clearly identify an active tracker or RFC, the tracker itself supplies the stale-exemption reason and contributor-visible routing surface; it does not need repetitive per-issue comments. Revisit the exemption when the milestone closes, the tracker drifts from live release state, the RFC reaches a decision, is superseded, or closes, or the issue no longer represents an active project decision surface.

When a tracker marker label is needed, use type:tracker. It applies to issue-only parent coordination surfaces such as release trackers, roadmap or epic trackers, RFC/design trackers, implementation batch trackers, cleanup trackers, and audit trackers. Do not apply it to ordinary child issues, ordinary feature requests, bugs, PRs, or items merely linked from a tracker. type:tracker helps humans and automation find the parent surface; it does not replace the required stale-exemption reason, next decision surface, milestone, assignee, or close criteria. If the live label does not exist yet, do not substitute roadmap, type:roadmap, or another alias; create and migrate the canonical label through a separate exact label packet.

If none of those exists and the issue is not an active tracker or RFC, the issue can still stay open while triage continues, but it should not rely on status:no-stale as a permanent shield. Until the stale-exemption audit lands, missing reason or routing evidence is an audit finding and proposed correction, not an automatic stale-closure trigger.

Named milestone policy

Named milestones are finite delivery cohorts for bounded outcomes within capability domains, not permanent domain backlogs. For this policy, a named milestone is organized around an outcome rather than a numbered release; Parking Lot and Icebox are holding areas, not named milestones. Name each new milestone as Domain: Bounded Outcome. Prefer RPC Client: Authentication & Authorization over a broad reusable name such as Auth. A combined title occupies each domain it names.

Treat every open named milestone as active. Before opening another, maintainers must explicitly confirm that coordination and review capacity exists for the added cohort. Record why the cohort cannot wait and which current milestone is expected to close next. When capacity is exhausted, do not open another named milestone until one closes or the proposed work is consolidated into an existing cohort. Reassess capacity whenever maintainer availability or review load materially changes.

Keep at most one active named milestone per domain. An explicit maintainer exception may allow independent outcomes in the same domain to proceed in parallel when the decision records why the added coordination cost is justified.

Every named milestone needs an explicit scope and close criteria, though a due date is optional. Do not leave a paused cohort open: reroute its unfinished work and close the milestone. Before closing any named milestone, close or reroute every unfinished issue and add a closure note stating whether the outcome was completed, canceled, or superseded. Closed named milestones stay closed. Follow-on work can form a new named milestone only when enough coherent scope exists to define another finite outcome. Name that milestone for the outcome; do not create rolling v2, v2.1, or similar successors by default.

GitHub allows an issue or pull request to belong to only one milestone. Work required to complete a named cohort stays in that named milestone through completion, even when it ships in a numbered release. Record release inclusion in the release tracker and changelog. Use numbered release milestones for urgent bugs, maintenance, and other release-bound work outside a named cohort.

Once a named milestone is active, limit new intake to work required to finish its stated cohort: direct scope, blockers, dependencies, and regressions. Route other work by intent:

DestinationUse for
Current named milestoneWork required to complete the milestone’s defined cohort.
Numbered release milestoneUrgent bugs, maintenance, or other release-bound work outside a named cohort.
RFC or design issueWork whose design or governance direction is not settled.
Parking LotShort-term routing while maintainers decide the next concrete home.
IceboxValid future work for a domain with an active named milestone when it is outside the current cohort and is not scheduled soon.

PR lanes

PR lanes are routing expectations, not another required label family. Use them to decide how much review depth, sequencing, and maintainer attention a PR needs. CODEOWNERS, native GitHub review state, CI, labels, linked issues, and explicit relationship keywords still carry the actual routing data.

LaneCommon examplesExpected movement
A: maintenance fast laneDocs-only corrections, small tests that leave behavior unchanged, metadata/template fixes, narrow examples, CI/tooling fixes that preserve permissions and release behaviorLightest review; fast merge once CI, template, labels, and privacy checks are clean. Usually risk:low and size:XS or size:S.
B: narrow bug/fix laneSmall bug fixes with clear failing behavior, targeted provider/channel/tool fixes with focused validation, compatibility fixes that preserve behavior outside the reported pathNormal review by one subsystem-aware reviewer unless risk or ownership says otherwise. Merge when the linked issue is actually satisfied, validation is credible, and CI is green.
C: feature slice laneAdditive feature work, new provider/channel/tool support, new config surface, scoped user-visible behavior changesNormal review plus boundary-specific validation. Milestone fit matters, and the PR should say whether it implements, depends on, or is related to a tracker.
D: architecture, migration, and elevated-review laneConcrete trust, credential, compatibility, governance, release-authority, migration, lifecycle, persistence, permission, or toolchain-floor boundary; any PR carrying risk:high or domain:securityDeep review, evidence matched to the changed risk, and rollback and compatibility analysis. A PR carrying risk:high or domain:security also requires two independent Core Team approvals.
E: supersede, replacement, and overlap laneMultiple PRs solving the same issue, newer PRs replacing older ones, contributor work carried forward from another PR, old PR made obsolete by current masterCoordinate before deep review. Choose one canonical path when possible, use Supersedes #N only when accurate, and preserve attribution when work is materially carried forward.

Do not build a separate manual PR board for these lanes unless native GitHub state and CODEOWNERS stop answering the routing question. Check native GitHub merge state before normal lane review: DIRTY means resolve conflicts first; BEHIND alone is mergeability housekeeping, not an author-facing blocker.

Required repository settings

Branch protection on master:

  • Require status checks before merge.
  • Require check CI Required Gate.
  • Require pull request reviews before merge.
  • Require CODEOWNERS review for protected paths. .github/** (including .github/workflows/**) is owned by the maintainers listed in .github/CODEOWNERS, so workflow changes need an owning maintainer’s review.
  • Keep branch / ruleset bypass limited to org owners.
  • Dismiss stale approvals when new commits are pushed.
  • Restrict force-push.
  • All contributor PRs target master directly.

Definition of Ready (DoR)

Before requesting review, the PR has all of these:

  • PR template fully completed.
  • Scope boundary explicit (what changed / what did not).
  • Validation evidence attached, actual command output, not “CI will check.”
  • Security & privacy, compatibility, and (for risky paths) rollback fields completed.
  • Privacy and data-hygiene rules satisfied, neutral, project-scoped test wording. See Privacy.
  • Identity-like wording, where unavoidable, uses ZeroClaw / project-native labels.

Definition of Done (DoD)

Before merge:

  • CI Required Gate is green.
  • Required reviewers approved (including any CODEOWNERS paths); a PR carrying risk:high or domain:security has two independent Core Team approvals.
  • Risk labels match the actual diff and consequence rather than broad component location. See Labels.
  • Migration / compatibility impact is documented.
  • Rollback path is concrete and fast.

Maintainer merge checklist

Every merge:

  • Scope is focused and understandable.
  • CI gate is green.
  • Docs-quality checks are green when docs changed.
  • Security and privacy fields are complete; evidence is redacted / anonymized.
  • A PR carrying risk:high or domain:security has two independent Core Team approvals; automated review does not count.
  • Agent-workflow notes are sufficient for reproducibility (if AI-assisted).
  • Rollback plan is explicit.
  • Commit title follows Conventional Commits.

Squash-merge with full commit history preserved in the body. The squash-merge skill produces both the purple Merged badge and the conventional-commits formatted body, see Skills for invocation.

AI / Agent contribution policy

AI-assisted PRs are welcome. Review can also be agent-assisted.

Required:

  1. Clear PR summary with scope boundary.
  2. Explicit test / validation evidence.
  3. Security impact and rollback notes for risky changes.

Recommended:

  1. Brief tool / workflow notes when automation materially influenced the change.
  2. Optional prompt / plan snippets for reproducibility.

We do not require contributors to quantify AI-vs-human line ownership. The diff and the validation evidence carry the load.

For AI-heavy PRs, reviewers focus on:

  • Contract compatibility.
  • Security boundaries.
  • Error handling.
  • Performance and memory regressions.
  • Whether the author can answer questions about behavior and blast radius (intent comprehension).

Review SLA and queue discipline

  • First maintainer triage target: within 48 hours.
  • Blocked PRs get one actionable checklist comment, not a series of partial reviews.
  • status:no-stale is reserved for accepted or otherwise long-lived work with a recorded stale-exemption reason and contributor-visible routing evidence when the issue is not already protected by another stale exclusion. Active release trackers and active RFC or design trackers may use the tracker itself as that visible reason and routing surface while they remain active. Existing exemptions missing those facts are audit findings until the stale-exemption repair packet lands.

For stacked work, require explicit Depends on #... so review order is deterministic.

Apply that deterministic order operationally: prioritize and review a parent before its children; when a parent is not reviewable, defer deep child review unless a bounded independent slice benefits from early review; after the parent lands, refresh and revalidate the child. A parent becoming reviewable does not make previously collected child evidence current.

For a report-only snapshot of the live GitHub queues, run python3 scripts/github/pr_review_queue.py --queue all --older-than-days 7 --format table. The --queue values are near-ready, maintainer, second-core, author-action, stacked, mine, and all; --format accepts table, json, or links. near-ready narrows the maintainer lane to PRs whose GitHub search status is successful, so maintainers can start with candidates that may need less work before merge; it does not establish mergeability or approval sufficiency. all runs the shared lanes independently, so one PR can appear in more than one lane; add --author LOGIN to include the mine lane. GitHub search supplies the candidate lists. Only author-action reads timeline detail to estimate unanswered-request age, and only second-core reads reviews to find one Core approval on the current head. The command never writes queue state or mutates GitHub, and it reports missing or ambiguous detail as unknown. It is a work-selection aid, not merge-readiness evidence.

For replacements, require explicit Supersedes #.... See Superseding PRs for attribution and template rules.

The reviewer-side queue management, backlog pruning order, stale handling, label hygiene, is in Reviewer Playbook.

Security and stability rules

Review these paths attentively because they often contain boundary-relevant behavior:

  • crates/zeroclaw-runtime/ (including src/security/)
  • crates/zeroclaw-gateway/ (ingress, authentication, pairing)
  • crates/zeroclaw-tools/ (anything with execution capability)
  • .github/workflows/ and the release pipeline

Path location alone does not select risk:high. Classify the actual diff and consequence under Labels → Risk labels. A trust, credential, compatibility, governance, release-authority, or cross-cutting security boundary receives deep review when the PR carries risk:high or domain:security.

Filesystem access boundaries and network or authentication behavior inside these crates deserve particular attention even when the diff is small.

Minimum for risk:high or domain:security PRs: threat or risk statement, mitigation notes, rollback steps, and two independent Core Team approvals.

Recommended for risk:high or domain:security PRs: a focused test proving boundary behavior, plus one explicit failure-mode scenario with expected degradation.

For agent-assisted contributions that cross these boundaries, reviewers also verify the author can talk through runtime behavior and blast radius, not just paste validation output.

Failure recovery

If a merged PR causes regressions:

  1. Revert on master immediately.
  2. Open a follow-up issue with root-cause analysis.
  3. Re-introduce the fix only with regression tests covering the failure mode.

Prefer fast restoration of service quality over a delayed perfect fix.

What this page does NOT cover