← All posts
BLOG · CI/CD

Adding a drift gate to CI: block incoherent AI code before merge

June 12, 2026 · 7 min read

AI code review in CI usually means a bot that reads a diff and leaves comments. A drift gate does something different. It scores how well your codebase still agrees with itself, and it fails the build when a pull request makes that worse. This guide shows you how to add one to GitHub Actions with VibeDrift, so coherence becomes a merge requirement instead of a hope.

The setup is small. The YAML is the main event, and the whole thing runs on your machine and in your runner. Your code never leaves either one. Here is why a gate matters, how to wire it up, and how to pick a threshold you can live with.

Why a CI gate for AI drift?

Drift is what builds up when AI writes code across separate sessions. Each session starts with no memory of the last one, so it makes reasonable but different choices. A new handler skips the auth check every other handler has. A service reaches for raw SQL where the rest use a repository. A response comes back in a shape nothing else returns. Each change compiles, passes tests, and passes the linter. The codebase quietly stops agreeing with itself. (We covered this problem in your AI codebase is drifting.)

The trouble with drift is that it is silent. There is no failing test, no red squiggle, no stack trace. It builds up a little at a time, until one day you are reading your own handlers and something feels off but you cannot grep for it. A CI gate fixes the silence. It turns a vague worry into a clear pass or fail signal on every pull request, where it is cheapest to act on.

Pull requestVibeDrift scanScore >= threshold?Merge / Block
The drift gate runs on every pull request and blocks the merge when the score drops below your threshold.
A gate makes coherence a merge requirement, not a hope you revisit during a cleanup sprint that never comes.

The GitHub Action, in full

Here is the entire workflow. Drop it in .github/workflows/vibedrift.yml and you have a drift gate on every pull request:

name: VibeDrift
on: [pull_request]
jobs:
  drift-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npx @vibedrift/cli . --json --fail-on-score 70
        env:
          VIBEDRIFT_TOKEN: ${{ secrets.VIBEDRIFT_TOKEN }}

That is the whole integration. No action to publish, no Docker image to maintain, no global install. The CLI runs through npx, so the runner pulls it on demand and throws it away when the job ends. The rest of this post just explains what that one line does.

What each piece does

The workflow is short on purpose, but every piece earns its place:

The JSON output

With --json, the CLI returns the same result it always computes, just in a structured form: the Vibe Drift Score from 0 to 100, the letter grade, and the findings. Each finding names the main pattern, the files that break from it, and the fix. The score is the number --fail-on-score checks against. The findings tell the author what to change. Log the payload in the step so a failed gate links straight to the files that drifted, not just a bare non-zero exit.

The token secret

Add VIBEDRIFT_TOKEN under your repository's Settings → Secrets and variables → Actions, then reference it with ${{ secrets.VIBEDRIFT_TOKEN }}. The local CLI is free, open source, and needs nothing to run on your machine. The token is for the authenticated CI path. Keep it in secrets so it never lands in a log or the workflow file.

How do I pick a starting threshold?

The 70 in the example is a placeholder, not a recommendation. The right threshold is one your repo can pass today, so the gate blocks regressions instead of blocking every PR on day one. To find it, run the scan locally first:

npx @vibedrift/cli .

That runs in about two seconds, never leaves your machine, and is free and unlimited. It gives you your current score. Set --fail-on-score at or just below that number and commit the workflow. Now the gate matches your reality. It passes on the code you already have and only fires when a change drags coherence backward.

Setting the threshold above your current score turns the gate into a wall. Every PR fails, the team learns to ignore or bypass the check, and the gate becomes noise. Start where you are, then climb.

Ratcheting the threshold up over time

A static gate stops new drift. A ratcheting gate pays down the old drift too. Once the gate is green, treat the threshold as something you raise on purpose:

  1. Land a few PRs that fix what the scan found: the files that drifted, the competing patterns, the leftover scaffolding.
  2. Re-run the scan locally to confirm the score went up.
  3. Bump --fail-on-score a few points, up to the new floor, and commit that change.
  4. Repeat. The gate can only go up, so coherence can only improve.

Small, frequent bumps beat one big jump. Each step is a PR the team can pass, and the threshold becomes a clear record of the codebase getting more coherent over time, not less.

Prevent first, gate as backstop

A CI gate catches drift at the last safe moment, when the code is already written and under review. That helps, but it is cheaper to never write the drift in the first place. That is what the Vibe Drift Score and the VibeDrift MCP server are for. The server gives your coding agent local tools to check the codebase's own conventions before it writes, so the agent follows them instead of inventing new ones. Add it with one line:

claude mcp add vibedrift -- npx -y @vibedrift/cli mcp

Run both. The MCP server prevents drift as you go. The CI gate is the backstop for whatever an agent, or a human, slips through anyway. The two work together. Prevention keeps the score high so the gate rarely fires, and the gate makes sure that when prevention misses, the drift does not merge. Both are free, local, and open source, so there is no reason to pick one.

Ship the gate

Run the scan once to find your score, paste the workflow above into .github/workflows/vibedrift.yml, set --fail-on-score to where you are today, and add the token to your repository secrets. From the next pull request on, incoherent AI code has to clear the gate before it merges.

npx @vibedrift/cli .

For per-client MCP setup and the full flag reference, see the guide, and pricing if you want deep scans on top of the free, unlimited local checks.

Frequently asked questions

What is a drift gate in CI?

A drift gate is a CI step that scores how coherent your codebase is and fails the build if the score drops below a threshold. With VibeDrift you run npx @vibedrift/cli . --json --fail-on-score 70 on every pull request; if the Vibe Drift Score falls under 70, the check fails and the merge is blocked until the drift is addressed.

How do I add VibeDrift to GitHub Actions?

Add a workflow that runs on pull_request, checks out the repo, and runs npx @vibedrift/cli . --json --fail-on-score 70 with your VIBEDRIFT_TOKEN passed in as an environment variable from repository secrets. No global install is needed because the CLI runs through npx.

What threshold should I pick for --fail-on-score?

Start at or just below your current Vibe Drift Score so the gate passes on day one and only blocks regressions. Run the scan locally first to see where you stand, set the threshold there, then ratchet it up a few points at a time as you pay down drift.

Do I still need the MCP server if I have a CI gate?

They do different jobs. The MCP server prevents drift in the loop by letting your agent consult the codebase before it writes. The CI gate is the backstop that catches whatever slips through. Prevention plus a gate is stronger than either alone, and both are free and local.


Local scans and the MCP tools are free and open source, forever. The free tier includes 1 deep scan a month; Pro is $15/mo for 12, and you can top up 5 more for $10 on any plan. Credits never expire.

Website · MCP guide · npm