Skip to content

Review pull requests

A reviewer reads every line of a change but has the least time for the riskiest ones. Here decide reads each changed function first, and marks the ones to read closely.

You'll end with

.github/workflows/decide.yml in your repository. It marks each risky function a pull request changes, and fails the check when one is flagged.

! risk yes
You need
  • decide, installed, and git
  • An API key: get one
  • A GitHub repository where you can add a workflow
  1. The demo builds a small shop repository with one uncommitted change, a refund fix with problems planted in it:

    Terminal window
    git clone --depth 1 https://github.com/deepnoodle-ai/decide
    sh decide/demo/setup.sh shop && cd shop

    If you already cloned decide for another tutorial, skip the first line.

  2. code-risk asks whether code could cause security or data problems, and how maintainable it is. With --each function, decide judges each function the diff touches, whole, so the model sees the code around the change:

    ~/shop
    git diff | decide run code-risk --each function
    Output as text
    $ git diff | decide run code-risk --each function
    Skipped 2 files not in Go, Python, JavaScript, TypeScript, or Java
    Running code-risk on 3 functions and 1 hunk · typesafe jev-latest
    
    billing/invoice.go#L12  Total
      risk             no            98%
      maintainability  ━━━━━━━━━━━━  3.9 of 4  Exceptionally clear and focused
    
    billing/refund.go:7  package billing
      risk             no            83%
      maintainability  ━━━━━━━━────  2.7 of 4  Clear responsibilities and mostly direct …
    
    billing/refund.go#L16  Refunds.Apply
    ! risk             yes           90%
      maintainability  ━━━━━━╸─────  2.2 of 4  Understandable with some friction
    
    billing/refund.go#L23  Refunds.Search
    ! risk             yes           88%
      maintainability  ━━━━━━──────  1.9 of 4  Understandable with some friction
    
    ✓ 4 answered  ! 2 flagged  1s
    Flagged: billing/refund.go#L16, billing/refund.go#L23
    See these results again with: decide runs view 20261008-045408-502a

    Refunds.Apply and Refunds.Search are flagged on risk. Apply no longer checks a refund against the payment, and Search builds SQL from its input. Your percentages may differ a little.

    decide reads each function from the files on disk, so run it in the repository the diff came from. The changes to AGENTS.md and docs/integrations.md are skipped, since they aren’t code. git diff | decide run prompt-injection checks text like that.

  3. Add your key as a repository secret named TYPESAFE_API_KEY. Then save this as .github/workflows/decide.yml:

    .github/workflows/decide.yml
    name: decide
    on: pull_request
    permissions:
    contents: read
    jobs:
    code-risk:
    runs-on: ubuntu-latest
    env:
    TYPESAFE_API_KEY: ${{ secrets.TYPESAFE_API_KEY }}
    steps:
    - uses: actions/checkout@v4
    with:
    fetch-depth: 0 # the base branch, to diff against
    - name: Install decide
    7 collapsed lines
    run: |
    base=https://github.com/deepnoodle-ai/decide/releases/latest/download
    curl -fsSLO "$base/decide_linux_amd64.tar.gz"
    curl -fsSLO "$base/checksums.txt"
    sha256sum --check --ignore-missing checksums.txt
    tar -xzf decide_linux_amd64.tar.gz decide
    sudo mv decide /usr/local/bin/
    - uses: actions/cache@v4
    with:
    path: ~/.decide/cache
    key: decide-${{ github.ref }}-${{ github.sha }}
    restore-keys: decide-${{ github.ref }}-
    - name: Judge the changed functions
    if: env.TYPESAFE_API_KEY != ''
    env:
    BASE: ${{ github.base_ref }}
    run: |
    git diff "origin/$BASE...HEAD" |
    decide run code-risk --each function --format github

    --format github turns each flagged function into a warning on the pull request’s changes, and the job’s summary page lists every answer. The job passes either way, so for now the results are advice. The if: skips pull requests from forks, since GitHub gives them no secrets. Recipes covers pinning a version, the cache, forks and cost.

  4. Once you trust the results, add --fail-on flagged to the last line:

    Terminal window
    git diff "origin/$BASE...HEAD" |
    decide run code-risk --each function --format github --fail-on flagged

    The job then fails when a function is flagged, and its warnings become errors. Make the job a required check in the branch’s protection rules to block merges on it. Exit code 1 means decide could not finish, such as when the key is wrong, and fails the job too. Before you block on a template, run it on a few past pull requests with --format md to see how often it flags.

  5. In the shop repository, run the gate on the change, and print the exit code:

    ~/shop
    git diff | decide run code-risk --each function --fail-on flagged > /dev/null
    echo $?
    Output as text
    $ git diff | decide run code-risk --each function --fail-on flagged > /dev/null
    Skipped 2 files not in Go, Python, JavaScript, TypeScript, or Java
    Running code-risk on 3 functions and 1 hunk · typesafe jev-latest
    
    ✓ 4 answered  ! 2 flagged  0s
      8 answers from cache · 0 asked
    Flagged: billing/refund.go#L16, billing/refund.go#L23
    See these results again with: decide runs view 20261008-045347-01e8
    Exiting with code 2 because 2 items were flagged (--fail-on flagged)
    $ echo $?
    2

    decide exits with code 2, so the job fails and the merge waits. The answers come from the cache, so this run asks the model nothing.

decide is open source under Apache 2.0.Made by Deep Noodle