shipper pr review
shipper pr review
Section titled “shipper pr review”Usage: shipper pr review [options] [target]
Review packaged work after check repair opportunities; stop stalled remediation
Arguments
Section titled “Arguments”| Argument | Required | Description | Choices |
|---|---|---|---|
| [target] | no | PR number/URL, or Shipper issue ID when pull requests are disabled | - |
| Long | Short | Value | Default | Description | Choices |
|---|---|---|---|---|---|
| —mode | - | default | execution mode: headless, interactive, or default | headless, interactive, default | |
| —agent | - | - | agent to use: claude, codex, copilot, grok, or opencode | claude, codex, copilot, grok, opencode | |
| —model | - | - | model to use for the agent CLI | - | |
| —reasoning-effort | - | - | reasoning effort to pass to the agent CLI | - | |
| —disable-mcp | - | - | - | disable MCP server loading for this run | - |
| —enable-mcp | - | - | - | enable MCP server loading for this run | - |
Examples
Section titled “Examples”Review pull request 42.
shipper pr review 42Review the recorded change for local issue S#177 when the repository has pullRequests: 'none'.
shipper pr review S#177Required-check failures
Section titled “Required-check failures”New automatic check stops apply only to independently acquired hosted checks. Hosted-check external obstruction and unchanged-revision stalled remediation enter Failed over Rework while retaining useful fixes, package/branch/PR identity, answers, evidence and delivery debt. Obstruction requires concrete evidence, cause, external remedy and final-HEAD applicability after same-pass fixes; red status, main-branch match or missing tools alone are insufficient. The mechanical backstop requires a completed current V4 check-only review with retained answers and identical fresh failures on unchanged HEAD after refresh/rerun/flake opportunities. Nits are neutral; changed/passed/new/material/pending/unavailable evidence and request-changes bodies veto it. Sandbox limitations remain ordinary investigation. A skipped review consumes no allowance and each stop counts once toward terminal safety. No report, answer, resolution or retry waives required checks or permits red ship/merge. Remedy/restart alone stays Failed. Preserving shipper reset S#123 --to rework and eligible shipper recover S#123 renew allowance on unchanged HEAD, preserve unpublished work and history, and require fresh normal verification. Existing eligibility, locks, closure holds and confirmation rules apply. Missing/divergent retained refs refuse retry. Read current or historical diagnosis, local procedures and pending delivery with issue view/get-issue, including roundless failures. Local verification uses existing prose summaries and relevant comments, without a structured local evidence report. Every attempted non-permission local failure, including apparently unrelated or pre-existing failures, requires an anchored 🔴 must-fix: comment on the most relevant changed line and REQUEST_CHANGES, then ordinary Rework fixes or prose replies. Permission-denied and unattempted checks are limitations, never passes or waivers; all previously required checks stay required. Local-only workflows have no local-evidence automatic stop; the ordinary review-round cap still applies. Historical local observations and failure records remain readable without migration. Outstanding historical local findings receive ordinary prose replies and never authorize a new automatic stop. Upgrade alone does not clear findings, renew allowance, or recover Failed. Publication and hook diagnostics and required hook execution remain unchanged.
Review acquisition
Section titled “Review acquisition”The resolved pullRequests policy selects where review inputs come from. When pull requests are
enabled, Shipper acquires the pull request metadata, changed-file list, and diff from GitHub.
When pullRequests: 'none', Shipper instead reads the recorded local change for the selected
Shipper issue and resolves its base branch locally. The diff uses three-dot semantics, comparing
the pinned change revision with its merge base against the current base branch. Base-only changes
made after the feature branch diverged are therefore not included. The recorded source branch tip
must still equal the pinned accepted revision.
Local acquisition fails rather than falling back to GitHub when the recorded change or local base
is missing or stale. Restore or configure the recorded base when base resolution fails. If the
source branch is absent, has moved from the pinned revision, or has no merge base, restore that
exact branch tip. Otherwise, return the issue to shipper:rework and rerun shipper implement
to re-deliver the change without changing its route.
Confirmed merge conflicts
Section titled “Confirmed merge conflicts”When GitHub reports mergeable: CONFLICTING, hosted review pre-flight returns the issue directly
to Rework to update the branch and resolve conflicts. It skips the normal review window and reviewer,
uses no review round, and does not renew the review allowance. The branch, pull request, and prior
review history are preserved. Direct review stops at Rework; Ship and Auto-ship continue through
the existing Rework implementation flow.
The conflict check takes precedence over pending rerun readiness. Missing checks on a conflicting
pull request do not establish CI success or authorize review. UNKNOWN or null mergeability is
not a confirmed conflict; ordinary missing-check behavior is unchanged. Without a confirmed
conflict, pending or unverified reruns still prevent reviewer launch.
CI status in review inputs
Section titled “CI status in review inputs”With a pull request and hosted checks, Shipper acquires the check rollup for the same revision the
review diff describes and writes it to ci-status.json alongside the other review inputs.
This happens inside a bounded revision transaction before any reviewer worktree or agent exists.
Checks mode waits for pending checks and unrecognized reported outcomes, honors its configured minimum review window, and at its
configured maximum proceeds with the latest readable rollup, marking unrecognized outcomes unavailable with their names and raw values. Three consecutive exhausted
check reads stop before reviewer launch and leave the issue at PR Open. Timer mode waits until the
pull request reaches the configured age. Foreground pr review and ship runs narrate and
perform these waits before the reviewer starts; background Auto-ship parks and later redispatches a
fresh issue run instead.
Every failed check produces exactly one diagnostic record. A record always carries the check name, its outcome, and either a run link or an explicit statement that no link is available. Where deeper evidence is unavailable, the record states the reason: the check is not a hosted Actions job, the failing job could not be matched inside its run, evidence exists but retrieval failed or was refused, or CI reported no step with a failing conclusion. The last of those is a finding about what CI reported and is never presented as a retrieval failure. Records also carry the failed step names, the failing test names exactly as the check’s own failure annotations reported them, and an advisory cross-branch line stating how often the same job failed recently on other branches, including how many of those failures were on the default branch.
Full log bodies are deliberately not delivered to review: records that carry a log member always
have status omitted-for-review; the other record shapes carry no log member at all. No
ci-log-*.txt file is written. When every check passes, the file carries a one-line status saying
so instead, so the absence of CI content never has to be interpreted. A check that has not concluded
produces no failed-check record.
When no hosted check appears during the check grace period, ci-status.json explicitly records
that CI is unavailable and review continues. A local-only review has no pull request, creates no CI
artifact, performs no GitHub wait, rerun, thread, external-comment, or parking operation, and starts
immediately.
Revision-pinned feedback and flake deferral
Section titled “Revision-pinned feedback and flake deferral”PR review pre-flight acquires the diff, metadata, check rollup, every unresolved GitHub review
thread with its full all-author conversation, external advisory comments, and the exact held review
round pinned by current review/rework history. The optional review-round.json retains its prior
findings, replies, and handled state. Local-only review can receive the same pinned held-round file
without any GitHub-only input.
Shipper verifies the pull-request base and head again after acquisition. Any movement during the wait, failed-check rerun, feedback collection, or immediately before durable flake recording discards the complete attempt and restarts against the new revision, up to three attempts. Exhaustion leaves the issue retryably at PR Open and launches no reviewer.
When initial checks fail and fewer than two prior deferrals exist for this issue and pull request, Shipper reruns each failed Actions run at the exact pinned head. It records a flake deferral only when every requested result is durably captured and the refreshed whole check rollup is settled and green. Version-compatible durable batch evidence records each request, original allowance, and verified attempt-specific job outcomes. Failed, pending, unavailable, incomplete, or moved-head evidence consumes no allowance. Two deferrals are allowed for the lifetime of the issue and pull request across revisions; a qualifying deferral invokes no reviewer and performs no workflow transition.
Failed-check rerun completion gate
Section titled “Failed-check rerun completion gate”Requested reruns have an independent clock measured from each request, so prior ordinary CI waiting consumes none of it. Timer-based review uses 60 minutes. Checks mode uses a 60-minute minimum even with a shorter configured maximum, honors longer maxima, and is unbounded when an explicit checks policy omits its maximum. Retries retain each original deadline and observe the same-revision request without starting another rerun merely because time expired.
No reviewer launches while any tracked rerun is pending or unverifiable, including mixed
pending/failed batches. Manual review and Ship wait, then return at finite expiry with PR Open and
run links/retry guidance. Auto-ship parks within the allowance, then defers the issue for the current
pass without an agent run and continues other issues. Retry with shipper pr review S#42,
shipper ship S#42, or a later Auto-ship run. For ambiguous dispatch without an observable newer
attempt, inspect Actions and request the rerun there if necessary before retrying Shipper.
Once all tracked reruns complete with known outcomes at the current head, confirmed failures become must-fix findings and reach Rework even if the reviewer approves or the aggregate rollup is absent, stale, green, contradictory, or unreadable. If no rerun starts but a current failure is confirmed, review still runs with that failure. Uncertainty alone causes neither a green deferral nor Rework. Successful all-green reruns link exactly once to the two-deferral lifetime cap. A changed head is reassessed without old-head success or failure; base-only movement retains request identity. Ordinary first-run pending-check deadline behavior and local-only review remain unchanged.
Sandboxed review environment
Section titled “Sandboxed review environment”Sandboxed review temporary storage is sandboxed-only and applies on macOS, Linux, and WSL2. A
sandboxed Codex reviewer receives a fresh unique real /tmp/shipper-cx-<24 lowercase hex>
directory (on macOS, /private/tmp/shipper-cx-<24 lowercase hex> after canonicalization). Shipper
applies that Shipper-managed path to TMPDIR, TMP, and TEMP after the inherited environment
and all worktreeEnv values. There is no setting, flag, or opt-out, and Shipper does not mutate
process.env or the operator’s shell. Sandboxed Claude reviews use Claude’s native per-session
temporary storage and receive no Shipper temporary-directory preparation or override. Unsandboxed
runs and other agents retain their existing temporary environment.
Shipper deletes current and abandoned sandboxed Codex directories only when exact ownership is
proven. Matching path, owner, device, and inode is insufficient because a successor directory may
reuse them. For abandoned reclamation, both the Shipper process and Codex child must also be proven
dead. When exact ownership cannot be proven, Shipper preserves the candidate, warns with its
specific location, and continues the requested stage with fresh isolated storage. Preparation
failure that makes isolated storage unsafe prevents launch with a standalone temporary-storage
error. Cleanup failures warn with the affected location and do not change the stage result or fall
back to shared or uncertain storage. Shipper does not add --add-dir /tmp or promise
exact-directory confinement; Codex may independently permit other system temporary directories.
Sandboxed Claude reviews explicitly allow read-only gh api --method GET, gh issue view,
gh pr view, and gh repo view commands with no interactive ask rule. Publishing, pushing,
and the existing GitHub and version-control mutation set remain denied and out of bounds.
If a verification command is refused specifically because of a sandbox or temporary-directory
permission denial, the review names the command and exact denial as an environment limitation in
### Verification; it does not turn that denial into a finding, requested change, or rejection.
Other failures remain actionable, and only a passing rerun on the identical commit proves a flake.
Review delivery
Section titled “Review delivery”After Shipper validates the agent result and every inline diff location, it keeps the review internally as one held review round. The agent’s intended disposition is recorded verbatim. Each round is a versioned, write-once record keyed by local issue and review round. It contains the reviewed acquisition revision, overall feedback and intended disposition, optional pull request number, stable finding IDs, every inline path, line, side, and multiline range, and structured path/addition/deletion metadata for diff files omitted because of size. Earlier rounds remain unchanged when later rounds are retained.
Successful reviewer execution is separate from the workflow gate. Shipper derives acceptance from
the completed disposition, canonical finding severities, and revision-pinned checks. A
REQUEST_CHANGES disposition, any 🔴 must-fix: finding, or any known failed hosted check
rejects. Each failed check becomes its own locationless must-fix finding with available failed-step
and failing-test evidence. Pending or unavailable hosted checks and deliberately absent local-only
checks are neutral unless another cause rejects.
Accepted reviews retain their complete round and advance directly to Ready. Rejected reviews retain
and pin the new round and return every route to Rework without changing package, branch, or
association identity. Older active findings for the same package are superseded without deleting
history. Within the current allowance, the first five completed reviews may reject into Rework;
a sixth rejection enters durable Failed over Rework, and recovery restarts the allowance while
preserving the retained pin and all history. A sixth approval may advance under existing rules. Legacy shipper:pr-reviewed records
are treated as PR Open and enter normal review.
The stage output and issue summary name the held round and state that Shipper keeps it internally.
Retrieve a round with shipper issue view <issue> --review-round <round-id> or MCP
shipper_get_review_round.
Exit Codes
Section titled “Exit Codes”| Code | When |
|---|---|
| 0 | The stage completes successfully or returns a reject verdict. |
| 1 | Preflight, validation, GitHub, agent, or fail verdict handling fails. |
| 79 | Clean GitHub-outage waiting is exhausted. The issue retains its stage and remains eligible in a later run. |
| 82 | An attended TTY agent session actually starts but ends without complete valid artifacts. The issue retains its entry stage as a neutral operator cancellation. |
Constraints
Section titled “Constraints”- Rework is the recommended preserving reset from PR Open, Ready, or Rework, and from a failed issue without a stage. It requires an open linked PR under GitHub PR policy or a reachable pinned local change under no-PR policy. Legacy reviewed labels normalize to PR Open for this check. All routes retain their route; early stages do not qualify merely because they hold a package. Missing, closed, merged, or unverifiable evidence refuses the reset without changes; inspect or repair the association with
shipper issue reconcile --repair, or recover the local package first. Rework preserves the package, association, branches, worktrees, route and review history, and clears failure. Repeat Rework resets are real operations. Next, Ship, and auto-ship dispatch Rework to implementation, which freezes one situation for the run: a current held-round pin selects review rework; otherwise a newer roundless merge-conflict entry selects merge rework; every other case is a roundless continuation of the retained packaged change with no correction delta, new reset instruction, accepted plan, or accepted design. Review rework consumes the pinned round, outstanding local findings, and supplied unresolved external threads, requires one nonblank fix or reasoned won’t-fix disposition per target, and durably delivers successful replies with configured best-effort resolution. An unreadable pin or dispositions still missing after one correction fail without advancing. Merge rework requires no review replies. Every situation reuses the preserved branch and open pull request without editing its metadata. Every successful explicit packaged preserving reset and eligible active packaged-change recovery restarts the five-round review allowance, including repeated Rework resets, unchanged revisions, and exhausted allowances. Package identity, full review history, findings, dispositions, and Rework context are preserved; renewal resolves no findings and grants no approval. Eligibility, destinations, and independent retry limits are unchanged. Count completed approved, addressed, superseded, and zero-finding reviews since the latest established renewal in append order; attempts without a completed review consume nothing. The first five completed reviews may reject into Rework; a sixth rejection enters durable Failed over Rework and retains its round, while a sixth approval may advance under existing approval rules. Automatic transitions and rejections, ordinary retries, restart/resume, grooming recovery, superseded-branch restoration, refused actions, and cancellation do not renew. Renewal belongs to the local logical commit even when projection repair is pending; repair grants no second renewal. A committed pending action reports its operation ID and says not to repeat it: store access finishes the existing operation. Recovery usesRecovery committed; local recovery pendingfor this outcome. For pre-release retained packages, affirmative historical preserving reset or packaged-recovery evidence, including recorded Reworkoperator-resethistory, establishes the latest renewal. Without such evidence the existing full count remains. Upgrade alone leaves Failed intact. Current-allowance progress can be 0 of 5 or 6 of 5; historical round numbers and order never change and may exceed six. Replacement package identities start independently. - —disable-mcp and —enable-mcp are mutually exclusive
- After an attended TTY agent session actually starts, Shipper validates its artifacts once. Complete valid artifacts finish normally even after a nonzero agent exit; missing, partial, or invalid artifacts cancel with exit
82. Cancellation retains the entry stage with null repository-safety impact, runs no correction or agent retry, creates no failed or recovery state, and requires no recovery action. Saved headless groom questions remain resumable. Committed workflow-branch HEAD is reused with continuation context on a later invocation while uncommitted work is removed during teardown. Compound next, ship, and automatic grooming runs start no later stage or issue after cancellation. This terminal outcome is distinct from the resumable exit-75pause. Non-interactive runs retain their bounded output correction, retry, failure, and recovery behavior.