Skip to content
GuidesDOCS

PR Review with Gather Step

gather-step pr-review builds a disposable review index for any two refs and returns a structured delta report covering every public surface changed across all affected repos. No code leaves the machine. The workspace’s normal .gather-step/ state is never modified.

Use pr-review before merging any branch that:

  • adds or removes an HTTP route, an exported symbol, or a payload contract
  • changes the shape of an event producer or consumer
  • modifies deployment config (Dockerfiles, Compose services, K8s manifests, env vars)
  • touches a shared package used by multiple repos

For smaller, self-contained changes with no cross-repo surface the report is still useful but usually short. The cost is the indexing time on the first run (30-90 seconds); cache hits complete in 1-2 seconds when a retained matching artifact exists.

Terminal window
gather-step pr-review --base main --head feat/my-change

The command resolves both refs to SHAs, expands the set of affected repos from the changed files, indexes the head branch into a disposable storage location, and prints the delta report.

Review a child repo with a parent workspace config

Section titled “Review a child repo with a parent workspace config”

When the Git branch belongs to a child repo but the gather-step.config.yaml lives at the parent workspace, run from the parent and point --workspace at the child repo while passing the parent config:

Terminal window
gather-step --workspace /path/to/workspace/web-client pr-review \
--base main \
--head feature/checkout-ui \
--config /path/to/workspace/gather-step.config.yaml

The review rewrites the matching repo entry inside the temporary worktree so the child repo indexes as .. The parent workspace’s .gather-step baseline remains the comparison source; no duplicate config is required inside the child repo.

Create a manifest that names each PR and its dependency order:

version: 0
id: checkout-refresh
title: Checkout refresh cross-repo set
prs:
- id: api-contract-42
repo: api-service
base: main
head: feature/checkout-contract
pr: 42
depends_on: []
- id: ui-hookup-108
repo: web-client
base: main
head: feature/checkout-ui
pr: 108
depends_on:
- api-contract-42

Then run:

Terminal window
gather-step --workspace /path/to/workspace pr-review \
--pr-set examples/pr-set/cross-repo-feature.yaml \
--parallelism 2

Entries with satisfied dependencies can run in parallel. If one entry fails, dependent entries are skipped and the final MultiPrDeltaReport still includes the completed PRs, failed/skipped entries, and cross-PR payload-contract drift.

You can also generate a draft manifest from GitHub search results:

Terminal window
gather-step --workspace /path/to/workspace pr-review init-set \
--query "checkout refresh is:open" \
--output checkout-refresh-pr-set.yaml

Or resolve and run immediately:

Terminal window
gather-step --workspace /path/to/workspace pr-review \
--from-gh "checkout refresh is:open" \
--set-id checkout-refresh \
--parallelism 2

--from-gh writes the resolved manifest under the review cache before running, so the exact PR set remains inspectable after the command completes.

Terminal window
gather-step pr-review --base main --head feat/my-change --format json

(--json is accepted as a deprecated alias for --format json.)

The JSON form emits a DeltaReport (schema_version: 1) suitable for piping into other tools or reading programmatically. It includes canonical evidence metadata computed from the typed delta surfaces at query time.

Terminal window
gather-step pr-review --base main --head feat/my-change --keep-cache --json

With --keep-cache, the review index survives after the report is returned. The suggested_followups field in the report contains ready-to-run commands pre-filled with --registry / --storage overrides that point at the kept review index. Run them as-is to query PR-branch state rather than the workspace baseline:

Terminal window
# example from suggested_followups:
gather-step pack createOrder --mode review \
--registry /path/to/review-registry.json \
--storage /path/to/review-graph.redb
Terminal window
gather-step pr-review --base main --head feat/my-change --severity strict
Value Behaviour
warn (default) Always returns the report; exits 0
strict Non-zero exit when removed_surface_risks contains high findings
pedantic Non-zero exit on any removed_surface_risks finding

Use strict or pedantic in CI to gate merges on risk findings.

The report is divided into sections. Each section is empty when nothing changed in that surface category.

Section What it shows
metadata Base/head SHAs, checkout mode, indexed repos, elapsed time, warnings
safety Review storage path, run ID, cleanup policy, cache key, config hash
changed_files Repo-relative paths changed in merge_base..head
evidence Canonical evidence rows with closed kind/source enums and structured citations
routes Added / removed / changed HTTP routes. Removed routes carry downstream impact summaries.
symbols Added / removed / changed exported symbols. Flags signature_changed and visibility_changed.
payload_contracts Field-level diffs: added, removed, type-changed, optional-required flips
ai_contracts Added / removed / changed AI structured-output contracts, keyed by source symbol: schema-field diffs plus AI-facet changes (provider, model, temperature, inference_kind, schema_format)
events Producer/consumer set diffs across Topic, Queue, Subject, Stream, and Event virtual nodes
decorators Permission, audit, and authorization decorator changes
contract_alignments Cross-repo clusters of related payload contracts with confidence scores
removed_surface_risks Removed routes / symbols / events with surviving consumers, classified high / medium / low
deployment Deployment-topology changes: Dockerfiles, Compose services, K8s manifests, env vars, secrets, config maps, brokers, databases, GitHub Actions deploy jobs
suggested_followups Ready-to-run gather-step pack and trace crud commands for the highest-impact deltas

removed_surface_risks contains the most actionable findings. Each entry has:

  • kindroute, symbol, or event for a removed surface; or one of the cross-repo mirror/guard kinds below
  • surface — the canonical name of the removed surface
  • severityhigh, medium, or low
  • reason — a human-readable explanation
  • detail — for mirror/guard kinds, names the mirror or guard surface (repo + file) and the specific value involved
  • surviving_consumers — graph nodes that still reference the removed surface

A high-severity removal means at least one consumer of the surface is in a different repo and has no apparent migration. These entries should be reviewed before merge.

In addition to removed surfaces, removed_surface_risks carries cross-repo mirror and guard completeness kinds — cases where a value is hand-mirrored across repos with no graph edge, so a change on one side would otherwise go unflagged:

  • value_mirror_incomplete — add-and-forget: a PR adds a new authoritative enum/union/const value that an established cross-repo mirror surface (e.g. an allowlist array or a frontend category map) does not yet mirror.
  • value_mirror — a PR changes or removes an authoritative value that an un-updated mirror still carries.
  • enum_guard_incomplete — a PR adds a new enum member, but an established switch/if guard that already handles other members of the same enum gains no case for the new value. Exempted when the guard has an explicit default: / case _:.

The deployment section shows changes to the infrastructure layer alongside code changes. Common cases to look for:

  • A new service appears in Compose or K8s without a corresponding routes or symbols delta — the service may be wired in deployment config but not yet indexed.
  • An env var is removed from a Dockerfile while env_var_consumers shows other services still reading it — potential misconfiguration.
  • A shared_infra entry (broker, database) appears or disappears — worth a cross-team check before merge.

Without --keep-cache, the review index is deleted when the report is returned.

With --keep-cache, use the clean subcommand to manage artifacts:

Terminal window
gather-step pr-review clean --dry-run # list every kept artifact for this workspace
gather-step pr-review clean --run-id <id> # delete one run by ID
gather-step pr-review clean --base main --head feat/my-change # delete by refs
gather-step pr-review clean --older-than 7d # prune artifacts older than 7 days
gather-step pr-review clean --all # wipe all review artifacts for this workspace

clean --older-than skips InProgress artifacts so it cannot race a running review. When a marker has last_accessed_at, pruning uses that timestamp so cache hits keep useful artifacts fresh; older markers fall back to created_at. --all removes everything including InProgress.

gather-step clean --include-review extends the workspace clean command to also wipe review artifacts. A full gather-step reindex automatically wipes review artifacts since their baseline is invalidated.

Any MCP-aware client can invoke the same review through the pr_review tool. Claude Code triggers it automatically when you ask:

“Review this PR using gather-step.”

“What does this branch change structurally?”

“Check the cross-repo impact of feat/my-change.”

The tool accepts the same parameters as the CLI (base, head, config, cache_root, keep_cache, severity, no_baseline_check, timeout_secs) and returns the same DeltaReport JSON. It works with any client that supports the stdio transport. See Connect an MCP Client for setup.

For coordinated sets, MCP clients can call pr_review_set with either a pr_set manifest path or a from_gh search query. It also exposes set_id, parallelism, allow_unknown_repos, config, cache_root, keep_cache, severity, no_baseline_check, and timeout_secs, and returns the same MultiPrDeltaReport JSON as the CLI PR-set modes.

Clients known to work with pr_review:

  • Claude Code (stdio MCP, any version with tool-call support)
  • Cursor (MCP stdio transport)
  • Any client following the stdio MCP protocol