Recipes

Review every pull request

Review every pull request by starting a run on github.pull_request.opened, asking Scout for a structured review, pausing for a human verdict, and posting a GitHub review comment.

This is the internal business operations use case Mobius should make easy to recognize. The agent does the first pass, the reviewer stays accountable, and the review lands back where the engineering team already works.

Use this when you want AI review without letting the agent speak for the team automatically. Scout drafts the review, Mobius asks a person, and only the approved path posts to GitHub.

What you'll build

  • An event trigger for pull requests in acme/api.
  • A run name with the repository and pull request number.
  • An agent review step.
  • One focused agent history per pull request.
  • A request_review interaction step.
  • A conditional child-loop step that posts the review only after approval.

Prerequisites

  • A connected GitHub integration for acme/api.
  • An agent named Scout (agt_scout).
  • At least one Mobius user who can receive the review interaction.

Build it

  1. In the app, open Build > Loops.
  2. Create a loop named Review every pull request.
  3. Add an Event trigger for github.pull_request.opened.
  4. Set Run name template to PR review · ${{ event.repository.full_name }} #${{ event.pull_request.number }}.
  5. Add an agent step named Review diff.
  6. Ask Scout to return verdict, risk, and body.
  7. Set the loop's History control to Pull request so another run for the same pull request can reuse earlier findings.
  8. Add an interaction step named Human review.
  9. Use request_review with any_of resolution.
  10. Add a child-loop step named Post review.
  11. Point it at a small post-github-review loop whose only step calls github.pull_request.create_review.
  12. Set the child-loop if: to steps.human-review.output == "post_comment".
  13. Create the loop as active.

You will end with two loops: the pull request review loop, and a small post-github-review child loop that owns the GitHub review action. The parent only starts the child when the interaction output is post_comment.

Finished spec

schema_version: "1"
name: review-every-pull-request
description: Review new pull requests and post a GitHub review comment.
concurrency: allow
run_name:
  template: "PR review · ${{ event.repository.full_name }} #${{ event.pull_request.number }}"
defaults:
  agent_session:
    scope: loop
    name: "github:${{ event.repository.full_name }}:pull:${{ event.pull_request.number }}"
    title: "${{ event.repository.full_name }} PR #${{ event.pull_request.number }}"
    visibility: project
triggers:
  - key: pr-opened
    name: Pull request opened
    kind: event
    enabled: true
    config:
      event_type: github.pull_request.opened
      source_id: github
      condition: event.repository.full_name == "acme/api"
steps:
  - id: scout-review
    name: Review diff
    kind: agent
    config:
      agent_id: agt_scout
      instructions: |
        Review the pull request. Return JSON with verdict, risk, and body.
        Keep body suitable for a GitHub pull request review.
  - id: human-review
    name: Human review
    kind: interaction
    config:
      protocol: request_review
      targets:
        - usr_platform_lead
      prompt: |
        Review Scout's pull request notes and choose whether to post them.
      resolution_policy: any_of
      spec:
        mode: select
        options:
          - value: post_comment
            label: Post comment
          - value: skip
            label: Skip
    timeout:
      duration: 4h
      on_timeout: fail
  - id: post-review-if-approved
    name: Post review if approved
    kind: loop
    if: "steps.human-review.output == \"post_comment\""
    config:
      loop_id: loop_3f8k2m9x4v7n5r6t
      inputs:
        repo_full_name: "${{ event.repository.full_name }}"
        pr_number: "${{ event.pull_request.number }}"
        review_event: COMMENT
        review_body: "${{ steps.scout-review.output.body }}"

The child loop is intentionally small:

schema_version: "1"
name: post-github-review
description: Post an approved GitHub pull request review.
concurrency: allow
inputs:
  repo_full_name:
    type: string
    required: true
  pr_number:
    type: integer
    required: true
  review_event:
    type: string
    required: true
  review_body:
    type: string
    required: true
triggers:
  - key: manual
    kind: manual
    enabled: true
steps:
  - id: post-review
    name: Post review
    kind: action
    config:
      action_name: github.pull_request.create_review
      parameters:
        repo_full_name: "${{ inputs.repo_full_name }}"
        pr_number: "${{ inputs.pr_number }}"
        event: "${{ inputs.review_event }}"
        body: "${{ inputs.review_body }}"

Today the conditional field lives on loop steps as a step-level if:, so the posting path is a child loop instead of a direct action step.

For a lighter experiment, stop before the child loop. Let Scout write review notes and ask a human whether the notes are useful. Add the posting path once the review quality is predictable.

Run it

Open a test pull request in acme/api. The run should suspend at the interaction until a target responds:

run.started
step.started          step=scout-review kind=agent
step.completed        step=scout-review
step.started          step=human-review kind=interaction
interaction.requested step=human-review
wait.opened           kind=interaction
step.suspended        step=human-review
run.suspended

After the response, the run resumes and posts the review:

interaction.responded
wait.resumed
step.completed        step=human-review
step.started          step=post-review-if-approved kind=loop
step.completed        step=post-review-if-approved
run.completed

If the human chooses skip, post-review-if-approved is marked skipped and the posting child loop never starts.

Variations

  • Replace the final review action with github.issue.create_comment if you want a normal PR comment instead of a review.
  • Switch History to Fresh run when every review should ignore findings from earlier runs on the same pull request.
  • Use queue if a shared review environment should not run two PR reviews at the same time.
  • Add github.pull_request.list_files as an action step before Scout if the trigger payload does not include enough diff context.

Next