PR Revise Workflow Design¶
| Layer | Document |
|---|---|
| Platform | Multi-Branch Loops Design |
| Caller shell | Loop Caller Reusable Design (branch / PR-head) |
| Spec | Issue Autofix and PR Revise Full Design |
| Boundaries | Entity Caller Responsibility Separation |
| Invariants | Loop Engineering Design |
Artifacts: on-loop-github-pr-revise.yaml · skill github-pr-revise · detect_pr_revise.sh · ci-loop-caller.yaml
Purpose¶
Single intake for PR revision from human feedback: conversation or review comments containing default @loop (caller mention overrides) + repository_dispatch / workflow_dispatch → branch / PR-head caller.
Detect skips bots and comments without the mention token. Default landing: git_landing_pull_request=push_head (stacked via open_pr).
Supported use cases¶
issue_commenton a PR conversation containing the configured mention (dogfood:@loop)pull_request_review_comment(inline review) with the mention tokenrepository_dispatch(loop-github-pr-revise) orworkflow_dispatchwith explicitfeedbackandpr_number
Out of scope¶
- Issue triage (axis 1 — see Issue Triage Workflow Design)
- Issue→PR autofix (axis 2 — see Issue Autofix Workflow Design)
- L3 auto-merge on stacked fix PRs
- Mention-less triggers (any human comment starts revise)
- Bot-authored comments and acting without the mention token on webhooks
- Auto-resolving review threads (human resolve only)
- Copilot Coding Agent as the maker (LE Agent via
ci-loop-agentonly) - Comment gather / one-session batching improvements (
#683) - Last-run-only discard of earlier fixes on the PR head
- Force-push or
cancel-in-progressto recover merge conflicts (fail closed onpush_head)
Skill execution boundaries: github-pr-revise SKILL.md (USE FOR / DO NOT USE FOR).
Caller inputs¶
Keys are passed in on-loop-github-pr-revise.yaml via with: on ci-loop-caller.yaml. Shared semantics: Loop Caller Inputs Reference.
| Input / JSON key | Description | Dogfood value |
|---|---|---|
ack_trigger_comment |
Post eyes reaction on trigger comment via ack-trigger |
true |
agent_maker_instructions |
Apply human feedback; address full result.comments array |
Inline in caller workflow |
agent_maker_max_turns |
Max maker turns per attempt | 100 |
agent_maker_model |
Maker model ID | claude-sonnet-5 |
agent_maker_effort |
Maker reasoning effort. Only engines with an effort flag (claude) consume it | medium |
agent_maker_skill_name |
Skill package | github-pr-revise |
agent_loop_max_attempts |
Max Agent→Verify cycles | 3 |
agent_checker_instructions |
APPROVE/REJECT rubric (mention gate, full comment batch) | Inline in caller workflow |
agent_checker_max_turns |
Max checker turns | 100 |
agent_checker_model |
Checker model ID | claude-opus-5 |
agent_checker_effort |
Checker reasoning effort. Only engines with an effort flag (claude) consume it | medium |
agent_checker_skill_name |
Checker skill | loop-verifier |
allowlist |
File edit allowlist (empty = skill default) | "" |
branch_match |
Fallback integration watch (scoped PR mode drops integration targets) | main |
branch_state |
.loop/* persistence branch |
main |
budget_max_runs_per_day |
Daily run cap | 10 |
budget_max_tokens_per_day |
Daily token cap | 1000000 |
delivery |
Platform delivery after APPROVE | open_pr |
denylist |
Denylist globs | "" |
detect_script |
Domain detect script | .agents/skills/github-pr-revise/scripts/detect_pr_revise.sh |
engine |
AI engine | claude |
environment |
GitHub Environment for env-scoped secrets | default |
git_landing_pull_request |
PR-head landing (push_head default; open_pr stacked) |
push_head |
level |
Autonomy (L2) |
L2 |
loop_name |
Loop identifier | github-pr-revise |
may_edit |
Agent worktree edit gate | true |
no_changes_verdict |
Verdict when no file diff | REJECT |
pr_enabled |
Watch open PR heads (required for PR revise) | true |
pr_exclude |
PR exclusion tokens | fork,label:no-loop |
scoped_pr_number |
Fetch only this PR; drops integration watch | From webhook / dispatch / inputs.pr_number |
write_target |
Agent artifact type | fix |
Domain detect environment (detect_domain_env_json)¶
detect_domain_env_json: ${{ format('{{"PR_NUMBER":"{0}","PR_MENTION":"{1}"}}', github.event.pull_request.number || github.event.issue.number || github.event.client_payload.pr_number || inputs.pr_number || '', inputs.mention || '@loop') }}
| JSON key / env var | Description | Dogfood value |
|---|---|---|
PR_NUMBER |
Target PR number | From event / dispatch / workflow_dispatch input |
PR_MENTION |
Mention token required on comment webhooks | @loop (override via workflow_dispatch.inputs.mention) |
scoped_pr_number scopes loop-detect to the webhook PR so comment events do not scan main. See Loop Caller Inputs Reference — Scope.
Caller shape¶
on-loop-github-pr-revise.yaml
loop → uses ci-loop-caller.yaml
detect → detect_pr_revise.sh
ack-trigger (optional) → eyes reaction on trigger comment
execute → ci-loop-agent (may_edit=true)
finalize → push_head (default) or open_pr
issue_comment jobs run only when github.event.issue.pull_request is set.
Trigger UX (ACK + thread reply)¶
After detect proceeds on a comment webhook:
| Stage | Behavior |
|---|---|
| Start ACK | eyes reaction on each gathered result.comments[].comment_id (fallback: trigger comment.id) via ack-trigger when ack_trigger_comment |
| Done reply | Inline review: threaded REST reply; conversation comment: follow-up PR comment (loop-notify-pr) |
| Marker | Run-level loop-notify-pr marker comment unchanged |
| Resolve | Human only — no auto-resolve |
Detect JSON includes result.comment_id, result.event_name, inline review fields, and result.comments (batched open @mention feedback). See Detect result.
Concurrency and push_head landing¶
Same-PR revise runs serialize; earlier product fixes must remain on the PR head.
| Rule | Behavior |
|---|---|
| Concurrency group | loop-github-pr-revise-<pr_number> on on-loop-github-pr-revise.yaml |
cancel-in-progress |
false — do not kill in-flight revise work |
queue |
max — queued mentions wait; one worker per PR at a time |
push_head landing |
loop-finalize push_target.sh checks out latest to.branch, merges the agent branch with --no-ff, pushes without force |
| Conflict | Merge or non-fast-forward push fails the finalize step (fail closed; no tip overwrite) |
open_pr finalize is unchanged. Prefer keeping lost-commit prevention on the shared push / push_head path rather than force-push or cancel-newest policies.
Detect result¶
detect_pr_revise.sh emits result facts consumed via file-backed detect JSON / loop-detect prompt:
| Field | Source | Notes |
|---|---|---|
pr_number |
PR / issue / dispatch payload | Required to proceed |
mention |
PR_MENTION (default @loop) |
Mention gate on comment webhooks |
comment_body |
Trigger comment.body or dispatch feedback |
Backward-compatible scalar for the webhook that started the run |
comment_id |
Trigger comment.id |
JSON number when present |
event_name |
GITHUB_EVENT_NAME |
When set on webhook path |
path |
Trigger comment.path |
Set for pull_request_review_comment; empty for issue_comment |
line |
Trigger comment.line or comment.original_line |
JSON number when present |
start_line |
Trigger comment.start_line or comment.original_start_line |
JSON number when present (multi-line comments) |
subject_type |
Trigger comment.subject_type |
line / file when present |
side |
Trigger comment.side |
LEFT / RIGHT when present |
diff_hunk |
Trigger comment.diff_hunk |
Inline hunk text when present |
in_reply_to_id |
Trigger comment.in_reply_to_id |
JSON number when present |
comments |
Gathered open human @mention comments |
Array of {comment_id, body, path, line, start_line, side, diff_hunk, in_reply_to_id, source, actor, subject_type} |
actor |
comment user or sender login | Informational |
Comment batching¶
On issue_comment / pull_request_review_comment when GITHUB_REPOSITORY and a token are available, detect lists PR conversation and review comments, keeps human maintainer comments that contain the mention token, and drops comments that already have an eyes reaction (claimed by a prior run). The maker and checker must address the full comments array. When gather runs and the array is empty, detect skips so queued follow-up runs do not push a false success. Without gather prerequisites, detect falls back to a one-element comments array from the trigger fields. Dispatch paths keep a single synthetic entry from explicit feedback.
Hydration reads trigger fields from GITHUB_EVENT_PATH when the corresponding PR_* env vars are unset. PR_COMMENTS_JSON may pre-supply the array (tests / callers).