DEV Community

Avery Lin
Avery Lin

Posted on

Free Preflight Review in CI: Cut Paid Minutes with a Simple Gate

Short answer: a free preflight review step before your paid CI jobs can catch trivial failures—debug prints, missing tests, migration hazards—in seconds, so you spend metered container minutes only on changes that actually need them. This article gives you a runnable shell script, a GitHub Actions hook, and a triage table for adding that step without making a probabilistic model a merge blocker. Disclosure: This article was prepared as part of MonkeyCode's product outreach.

The Cost You’re Trying to Avoid

I see the same loop in many teams: a developer pushes a PR, waits seven minutes for a container build, then watches it fail on a debug print or a migration with no rollback path. The real cost is the loop, not the CI minutes.

Most CI gates treat every commit identically. If your team already practices continuous integration, you know that every push triggers the same expensive jobs. You pay the same container minutes for a two-line logging change as you do for a migration that touches half your tables. The first useful signal is often the diff itself.

git diff origin/main...HEAD --stat
Enter fullscreen mode Exit fullscreen mode

You might see:

 src/api/orders.ts      | 184 ++++++++++++++++++++++++++++++++-----
 src/db/migrations/0012 |  38 ++++++++++++
 src/utils/log.ts       |   2 +-
 3 files changed, 190 insertions(+), 34 deletions(-)
Enter fullscreen mode Exit fullscreen mode

The first two files deserve close attention; the third probably does not. A paid container test still pays for all three. One way to break that uniform cost is a preflight pass: before the expensive job starts, send the source diff to a model that returns a risk label, reasons, and a list of files to recheck. If your account has MonkeyCode's free model access and free server option, you can run that pass without adding another metered model call to your bill. The point is not to replace review or tests. It is to decide when a full run is worth it.

What the Preflight Reviewer Should Return

Keep the output small and machine-checkable. The script I propose expects this exact contract:

{
  "risk": "medium",
  "reasons": [
    "Migration 0012 adds a NOT NULL column without a default",
    "Orders handler now calls a new service but has no test"
  ],
  "files_to_recheck": [
    "src/db/migrations/0012",
    "src/api/orders.ts"
  ]
}
Enter fullscreen mode Exit fullscreen mode

The risk field is the only thing your automation should act on directly. reasons and files_to_recheck are for the human reviewer and for targeted test selection.

A Runnable Preflight Script and GitHub Actions Hook

The script below uses jq to build and parse JSON, and the workflow uses the standard GitHub Actions syntax. The /v1/chat/completions path assumes an OpenAI-compatible chat completions API; if your free server option uses a different path, change the URL in the curl call rather than adapting the rest of the script.

This script is a proposal you can adapt. It does not execute anything from the model output, and it fails open to medium when the model returns something invalid.

#!/usr/bin/env bash
set -euo pipefail

# Preflight reviewer: cheap triage before full CI.
# This is informational, not a security gate.
: "${MONKEYCODE_SERVER_URL:?Set MONKEYCODE_SERVER_URL}"
: "${MONKEYCODE_API_KEY:?Set MONKEYCODE_API_KEY}"
: "${MONKEYCODE_MODEL_ID:?Set MONKEYCODE_MODEL_ID to the free model ID in your account}"

DIFF="$(git diff origin/main...HEAD -- . ':(exclude)*.lock' ':(exclude)package-lock.json' ':(exclude)pnpm-lock.yaml' ':(exclude)yarn.lock')"

if [ -z "$DIFF" ]; then
  echo "No source diff to review."
  exit 0
fi

PROMPT='You are a preflight code reviewer. Return only JSON with exactly three keys: risk (low|medium|high), reasons (array of strings), files_to_recheck (array of strings). Focus on missing tests, migration risk, accidental debug code, and changes that touch shared code. Do not comment on formatting or style.'

PAYLOAD="$(jq -n --arg model "$MONKEYCODE_MODEL_ID" --arg prompt "$PROMPT" --arg diff "$DIFF" '{model: $model, temperature: 0.2, messages: [{role: "system", content: $prompt}, {role: "user", content: $diff}]}')"

curl -sS --connect-timeout 10 --max-time 120 -H "Authorization: Bearer $MONKEYCODE_API_KEY" -H "Content-Type: application/json" -d "$PAYLOAD" "$MONKEYCODE_SERVER_URL/v1/chat/completions" | jq -r '.choices[0].message.content // empty' > review.json

# Validate the JSON before anyone trusts it.
jq -e '.risk and (.risk | test("^(low|medium|high)$"))' review.json >/dev/null || { echo "Preflight output invalid; defaulting to medium"; jq -n '{risk: "medium", reasons: ["invalid reviewer output"], files_to_recheck: []}' > review.json; }

RISK="$(jq -r '.risk' review.json)"
echo "Preflight risk: $RISK"
jq -r '.reasons[]' review.json
Enter fullscreen mode Exit fullscreen mode

Set the three MONKEYCODE_* variables to the values from your account. Wire it as an informational GitHub Actions job. The job should not be a required status yet.

name: Preflight review
on:
  pull_request:

permissions:
  contents: read

jobs:
  preflight:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Run preflight reviewer
        env:
          MONKEYCODE_SERVER_URL: ${{ secrets.MONKEYCODE_SERVER_URL }}
          MONKEYCODE_API_KEY: ${{ secrets.MONKEYCODE_API_KEY }}
          MONKEYCODE_MODEL_ID: ${{ secrets.MONKEYCODE_MODEL_ID }}
        run: ./scripts/preflight_review.sh
      - name: Upload reviewer output
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: preflight-review
          path: review.json
Enter fullscreen mode Exit fullscreen mode

How to Act on the Output

Use a simple table so nobody has to remember the policy.

Risk Action Human input
low Let normal CI run; no extra gating. Optional sanity check.
medium Run targeted tests matching files_to_recheck before the full matrix. Reviewer adds a comment.
high Expand the CI matrix and block merge until a human confirms the risky file list. Required.

Do not auto-block on low or medium. Free model output is advisory, and a flaky or rate-limited endpoint should not become a merge blocker.

Limitations, Safety, and Where This Fits

This is a triage aid, not a reviewer. You still need your existing tests, linters, and human review.

Treat every PR as untrusted input. A diff can contain instructions aimed at the model, and the model can return plausible-looking file lists. The script deliberately does not execute files_to_recheck; it only prints them for a human or for targeted test selection.

The free model access and free server option may have rate limits, slower response, or availability constraints. Do not make this job a required merge check until you have observed it over multiple PRs and know how it behaves under load.

Check the data handling policy for the free server option before sending proprietary code. If your repo is regulated or security-sensitive, an external preflight pass may not be appropriate.

Very large diffs can exceed the model's context or make the reviewer slow. The script excludes lockfiles, but you may also want a local guard that skips the review when the diff is larger than a threshold you set.

Who should skip this approach: teams whose CI is already cheap and whose PR volume is low; repos that cannot send code to an external endpoint; large monorepos where a full diff is routinely too large; and anyone expecting deterministic output from a probabilistic system.

Start by wiring the script as an informational job on one low-traffic repository. After a week, compare the risk labels against what your full CI actually found. If the free preflight reviewer consistently flags the right files, you can use it to sequence targeted tests instead of paying for the whole matrix first. If it does not, you have lost nothing but a few GitHub Actions minutes. Wire it up this week—your pipeline budget will notice the difference.

Top comments (0)