Community · CI Gate
Gate AI-code defects before they merge
The Shipmoor CI Gate runs the same deterministic scan in two places — as a pre-commit hook on your laptop and as a CI job on every pull request — and fails the build when a finding at or above your severity threshold is present. Phantom imports, hallucinated APIs, stub paths, and placeholder bodies stop at the gate instead of in review.
A coding agent finishes a task, writes a confident summary, and opens a pull request. The diff compiles and the tests it wrote pass — but it imports a module that doesn’t exist, calls an API the library never shipped, or leaves a handler body as a TODO that quietly returns None. These are AI-code-integrity defects: plausible-looking mistakes that survive type checks and land in review, where a human has to catch them by reading carefully.
The Shipmoor CI Gate stops them earlier. It runs one deterministic scan in two places — as a pre-commit hook on the developer’s machine and as a CI job on every pull request — and fails the build when a finding at or above your severity threshold is present. Scope it to the change so pre-existing debt never blocks, start in measurement-only mode to baseline before you enforce, and keep everything local: the scan runs on your runner, and no source is ever uploaded.
- Free — no login, no account
- pre-commit + any CI
- Runs on your runner · no source upload
- pre-commit
- GitHub Actions
- SARIF 2.1.0
- exit-code gate
- diff-scoped
- pinned CLI
- no source upload
$ shipmoor scan --diff origin/main...HEAD --fail-on high --no-color Scanning 7 changed files (origin/main...HEAD) HIGH phantom-import services/api/handlers/webhook.py:12 import stripe.webhooks_v2 — module does not existHIGH stub-path services/api/handlers/webhook.py:41 handler returns None — TODO body never implemented Gate: FAILED — 2 high findings introduced by this changeSARIF written to shipmoor.sarif · exit 1 The gate on a pull request: scan the introduced change, fail the job on a high-severity finding.
One scan, two gates
The gate is the same binary and the same rules wherever it runs. Pre-commit catches defects locally, before they ever reach the remote; CI is the backstop that can't be skipped. Nothing pre-existing has to block — scope the gate to the change.
- Agent writes code
- pre-commit (local)
- CI gate (pull request)
- Review & merge
Catch it on the laptop where it's a one-line fix, or at the pull request where it's still cheaper than a review round-trip. Either way the same finding can't make it to main.
Wire the gate into your workflow
Two integrations, one engine. Start with pre-commit for the fast local loop, then add the CI gate so nothing slips past a skipped hook.
Pre-commit hook
The official pre-commit repo installs the Shipmoor CLI for you and scans the staged change. Latest CLI by default; pin a version with args.
- Run pre-commit install once; the hook runs on every commit.
- Installs the latest Community CLI by default, cached per version.
- Same scan, same rules, same exit code as the CI gate.
repos:
- repo: https://github.com/shipmoor/shipmoor-pre-commit
rev: v0.1.0
hooks:
- id: shipmoor-scan
# optional: pin the CLI and the severity gate
args: [--shipmoor-version=0.3.0, --fail-on, high]
GitHub Actions — quickstart
A minimal pull-request gate: install the pinned CLI from the official installer, scan only what the change introduced, and fail on a high finding.
- fetch-depth: 0 so the diff base is available for diff-scoped scans.
- Pin SHIPMOOR_VERSION for reproducible builds; scan . for a full tree.
- Exit code is the gate — non-zero at or above --fail-on fails the job.
name: shipmoor
on:
pull_request:
permissions:
contents: read
jobs:
gate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # the diff needs history
- name: Install Shipmoor Community CLI (pinned)
env:
SHIPMOOR_VERSION: "0.3.0"
SHIPMOOR_NO_PATH_HINT: "1"
run: |
curl -fsSL https://dl.shipmoor.dev/install.sh | bash
echo "$HOME/.shipmoor/bin" >> "$GITHUB_PATH"
- name: Gate the change
run: |
shipmoor scan \
--diff "origin/${{ github.base_ref }}...HEAD" \
--fail-on high --no-color
GitHub Actions — full composite action
Drop this in as a local action for the complete setup: a pinned install, diff-scoped gating, a measurement-only baseline mode, and SARIF + Markdown reports uploaded as artifacts on every run. Call it with uses: ./.github/actions/shipmoor-gate.
- diff-base gates only findings the change introduced — pre-existing debt never blocks.
- soft-fail: true is the measurement-only baseline: it reports without failing.
- Always uploads SARIF 2.1.0 + a Markdown summary as artifacts, even on failure.
- Per-package config-file makes it monorepo-ready out of the box.
name: "Shipmoor Gate"
description: >
Runs the Shipmoor Community CLI against scan-path to catch AI-code-integrity
defects (phantom imports, hallucinated APIs, stub paths, placeholder bodies).
Installs the pinned CLI via the official installer, scans, and fails the
build when a finding at or above `fail-on` severity is present. Always
uploads SARIF 2.1.0 + a Markdown summary as artifacts. Set soft-fail: true
for the measurement-only baseline run.
inputs:
scan-path:
description: "Directory to scan (e.g. services/realtime-listing-processor)"
required: true
version:
description: "Pinned Shipmoor CLI version (SHIPMOOR_VERSION)"
required: false
default: "0.3.0"
fail-on:
description: "Severity gate: none | medium | high | critical"
required: false
default: "high"
config-file:
description: "Path to .shipmoor.yaml relative to scan-path"
required: false
default: ".shipmoor.yaml"
soft-fail:
description: "Report findings without failing the job (true/false)"
required: false
default: "false"
diff-base:
description: >
When set, gate only findings introduced relative to this git ref by
running `shipmoor scan --diff <diff-base>...HEAD` (honours
.shipmoor.yaml `diff.only_introduced`). Leave empty for a full-tree scan.
Typically the PR base SHA: pre-existing debt must not block.
required: false
default: ""
runs:
using: "composite"
steps:
- name: Install Shipmoor Community CLI (pinned)
shell: bash
env:
SHIPMOOR_VERSION: ${{ inputs.version }}
SHIPMOOR_NO_PATH_HINT: "1"
run: |
curl -fsSL https://dl.shipmoor.dev/install.sh | bash
echo "$HOME/.shipmoor/bin" >> "$GITHUB_PATH"
- name: Show Shipmoor version
shell: bash
run: shipmoor version
- name: Resolve artifact suffix
id: name
shell: bash
run: |
SAFE="$(echo "${{ inputs.scan-path }}" | tr '/ ' '--')"
echo "suffix=$SAFE" >> "$GITHUB_OUTPUT"
- name: Run Shipmoor scan
shell: bash
working-directory: ${{ inputs.scan-path }}
run: |
SARIF="$RUNNER_TEMP/shipmoor-${{ steps.name.outputs.suffix }}.sarif"
SUMMARY="$RUNNER_TEMP/shipmoor-${{ steps.name.outputs.suffix }}.md"
# In soft-fail (baseline) mode the gate never blocks, so scan with
# --fail-on none; otherwise honour the requested severity threshold.
if [ "${{ inputs.soft-fail }}" = "true" ]; then
FAIL_ON="none"
else
FAIL_ON="${{ inputs.fail-on }}"
fi
# Prefer the per-package config, fall back to the repo-root config,
# otherwise let Shipmoor auto-discover.
CONFIG_ARG=""
if [ -f "${{ inputs.config-file }}" ]; then
CONFIG_ARG="--config ${{ inputs.config-file }}"
elif [ -f "$GITHUB_WORKSPACE/.shipmoor.yaml" ]; then
CONFIG_ARG="--config $GITHUB_WORKSPACE/.shipmoor.yaml"
fi
# When a diff base is supplied, gate only findings introduced by the
# change (legacy debt must not block migrations). Empty => full scan.
DIFF_ARG=""
if [ -n "${{ inputs.diff-base }}" ]; then
DIFF_ARG="--diff ${{ inputs.diff-base }}...HEAD"
echo "Shipmoor diff scope: ${{ inputs.diff-base }}...HEAD"
else
echo "Shipmoor scope: full tree"
fi
EXIT=0
shipmoor scan . \
--sarif --output "$SARIF" \
--markdown-summary "$SUMMARY" \
--fail-on "$FAIL_ON" \
--no-color \
$DIFF_ARG \
$CONFIG_ARG || EXIT=$?
if [ "${{ inputs.soft-fail }}" = "true" ]; then
echo "soft-fail mode: shipmoor exit was ${EXIT}, not failing the job"
exit 0
fi
exit "${EXIT}"
- name: Upload Shipmoor report
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: shipmoor-report-${{ steps.name.outputs.suffix }}
path: |
${{ runner.temp }}/shipmoor-${{ steps.name.outputs.suffix }}.sarif
${{ runner.temp }}/shipmoor-${{ steps.name.outputs.suffix }}.md
if-no-files-found: warn
Tune the gate
Every behavior in the action maps to a flag on shipmoor scan — the same flags you run locally.
-
Gate only what the PR introduced
shipmoor scan --diff origin/main...HEAD --fail-on high -
Set the severity threshold
shipmoor scan --staged --fail-on high # none | medium | high | critical -
Measurement-only baseline (never blocks)
shipmoor scan . --fail-on none --sarif --output shipmoor.sarif -
Per-package config in a monorepo
shipmoor scan services/api --config services/api/.shipmoor.yaml -
Reproduce the exact CI gate locally
SHIPMOOR_VERSION=0.3.0 shipmoor scan --staged --fail-on high
Same binary, same rules, same exit code — whether it runs in pre-commit, in CI, or on your laptop.
The gate runs in your pipeline, not ours
The official installer drops a pinned binary onto your runner, the scan runs there, and the job's exit code is the gate. No source is uploaded, there is no Shipmoor cloud in the critical path, and the same deterministic engine that fails your build is the one you can run offline on your laptop. A red check you can reproduce in one command beats a verdict you have to trust.
Free in Community, deeper in IC
The CI Gate is a Community feature — the structural scan and the gate need no login. The paid IC tier adds the Claim Check: did the change actually do what the task asked?
- Community · free
CI Gate
Structural AI-code-integrity gate, everywhere your code moves.
- pre-commit hook + any CI (GitHub Actions, GitLab, Jenkins…)
- phantom imports, hallucinated APIs, stub paths, placeholders
- diff-scoped gating + SARIF 2.1.0 output
- no login, no account, no source upload
- Shipmoor IC
Claim Check in CI
Add an intent gate on top of the structural one.
- checks the change against the task it was given
- deterministic probes, optional BYO-Judge second opinion
- gates on falsifiable evidence only
- same local-first, no-source-upload guarantee
Put the gate in front of your next agent change
Install the free CLI, drop the pre-commit hook and the CI job in, and let the build fail on the defects agents introduce — before they reach review.
Get Shipmoor CLI
One installer. One shipmoor command. Free Community scans.
CI Gate FAQ FAQ
Pre-commit, CI, severity gates, and rolling it out without breaking every build.