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.
.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-
Get the demo
Section titled “Get the demo”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/decidesh decide/demo/setup.sh shop && cd shopIf you already cloned
decidefor another tutorial, skip the first line. -
Judge each changed function
Section titled “Judge each changed function”code-riskasks 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: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.ApplyandRefunds.Searchare flagged on risk.Applyno longer checks a refund against the payment, andSearchbuilds 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.mdanddocs/integrations.mdare skipped, since they aren’t code.git diff | decide run prompt-injectionchecks text like that. -
Run it on each pull request
Section titled “Run it on each pull request”Add your key as a repository secret named
TYPESAFE_API_KEY. Then save this as.github/workflows/decide.yml:.github/workflows/decide.yml name: decideon: pull_requestpermissions:contents: readjobs:code-risk:runs-on: ubuntu-latestenv:TYPESAFE_API_KEY: ${{ secrets.TYPESAFE_API_KEY }}steps:- uses: actions/checkout@v4with:fetch-depth: 0 # the base branch, to diff against- name: Install decide7 collapsed linesrun: |base=https://github.com/deepnoodle-ai/decide/releases/latest/downloadcurl -fsSLO "$base/decide_linux_amd64.tar.gz"curl -fsSLO "$base/checksums.txt"sha256sum --check --ignore-missing checksums.txttar -xzf decide_linux_amd64.tar.gz decidesudo mv decide /usr/local/bin/- uses: actions/cache@v4with:path: ~/.decide/cachekey: decide-${{ github.ref }}-${{ github.sha }}restore-keys: decide-${{ github.ref }}-- name: Judge the changed functionsif: env.TYPESAFE_API_KEY != ''env:BASE: ${{ github.base_ref }}run: |git diff "origin/$BASE...HEAD" |decide run code-risk --each function --format github--format githubturns 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. Theif:skips pull requests from forks, since GitHub gives them no secrets. Recipes covers pinning a version, the cache, forks and cost. -
Block a merge
Section titled “Block a merge”Once you trust the results, add
--fail-on flaggedto the last line:Terminal window git diff "origin/$BASE...HEAD" |decide run code-risk --each function --format github --fail-on flaggedThe 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 mdto see how often it flags. -
Check that it works
Section titled “Check that it works”In the shop repository, run the gate on the change, and print the exit code:
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.