Skip to content
AI CraftsmanSUPERPOWERS
Blog
  • CI
  • DevEx
  • TDD

Zero Drift CI: Same Rules Everywhere, from Hook to Pipeline

Local hooks pass but CI fails? Never again. Multi-CI Zero Drift ensures identical validation at every stage.

Alexandre Mallet2 min read

You know the drill. You write code locally. Your editor says it's clean. You commit, push, and open a PR. Twenty minutes later, CI fails on a rule you've never seen enforced locally.

This gap between local validation and CI validation is drift, and it's one of the most common sources of developer frustration.

The Drift Problem

Drift happens when your local tooling and your CI pipeline diverge:

  • CI runs PHPStan level 9, but your local hook only runs level 6
  • CI checks architecture boundaries, but locally nobody runs that check
  • CI enforces coding standards your editor plugin ignores
  • A new rule was added to CI last week, but nobody updated the local config

The result: developers stop trusting local feedback. They push and wait. The feedback loop stretches from seconds to minutes. Velocity drops. Frustration rises.

One Config, Every Stage

AI Craftsman Superpowers solves this with a single source of truth: .craft-config.yml. The same rules file drives both your local hooks (Claude Code hooks that validate on every write) and your CI pipeline.

# .craft-config.yml: single source of truth
v: 4
stack: symfony
strictness: strict
rules:
  PHP003: block    # setters refused, not only reported
  TS002: ignore    # default exports allowed in this project

Locally, this config powers the quality gate on every file write. In CI, the exact same config and the same rules engine feed the pipeline, so a rule cannot mean one thing on your machine and another in the pipeline.

GitHub Actions Integration

Setting up CI is a single workflow file:

# .github/workflows/craftsman.yml, from ci/templates/craftsman-quality-gate.yml
name: Craftsman Quality Gate

on:
  pull_request:
  push:
    branches: [main]

permissions:
  contents: read
  pull-requests: write

jobs:
  quality:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          fetch-depth: 0

      - name: Run craftsman-ci quality gate
        env:
          GH_TOKEN: ${{ github.token }}
          GITHUB_PR_NUMBER: ${{ github.event.pull_request.number }}
          CRAFTSMAN_SCOPE: ${{ github.event_name == 'pull_request' && '--changed-only' || '' }}
        run: bash ci/craftsman-ci.sh ci --provider github $CRAFTSMAN_SCOPE

The --changed-only flag keeps CI fast: only files touched in the PR are validated. The --provider github option selects the GitHub adapter, which writes the findings as check annotations on the PR diff and posts a PR comment.

Beyond GitHub

The same pattern works across providers. The plugin ships with starter configs for GitLab CI, Bitbucket Pipelines, and Jenkins: each using the same .craft-config.yml as the source of truth. Switch providers without rewriting rules.

# GitLab CI, from ci/templates/.gitlab-ci.craftsman.yml
craftsman-quality-gate:
  stage: test
  image: python:3.12-slim
  variables:
    GIT_DEPTH: 0
  rules:
    - if: $CI_MERGE_REQUEST_IID
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
  script:
    - if [ -n "$CI_MERGE_REQUEST_IID" ]; then git fetch origin "+refs/heads/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME:refs/remotes/origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME"; SCOPE="--changed-only"; else SCOPE=""; fi
    - bash ci/craftsman-ci.sh ci --provider gitlab $SCOPE
  artifacts:
    reports:
      codequality: gl-code-quality-report.json
    when: always

The Feedback Loop

Zero drift means zero surprises:

  1. You write code → the pre-write hook judges the file before it reaches disk, using .craft-config.yml
  2. You push → CI validates using the same .craft-config.yml
  3. PR opens → violations appear as inline annotations, identical to what you saw locally

If it passes locally, it passes in CI. If it fails in CI, it would have failed locally. The feedback loop is tight, consistent, and trustworthy.

Developers who trust their local tooling commit with confidence. Developers who don't trust it push and pray. Zero drift turns prayers into guarantees.