- 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
rules:
php:
final-classes: error
strict-types: error
no-setters: error
private-constructor: warning
typescript:
no-any: error
readonly-default: error
named-exports: error
architecture:
dependency-direction: error
no-domain-imports-infra: errorLocally, 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
name: Craftsman Quality Gate
on:
pull_request:
branches: [main]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: composer install --no-interaction
- name: Run Craftsman validation
run: |
npx ai-craftsman-superpowers validate \
--config .craft-config.yml \
--changed-files-only \
--ci
env:
CI: true
- name: Architecture boundary check
run: |
npx ai-craftsman-superpowers architecture \
--config .craft-config.yml \
--strictThe --changed-files-only flag keeps CI fast: only files touched in the PR are validated. The --ci flag outputs machine-readable results that integrate with GitHub's check annotations, so violations appear directly on the PR diff.
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 example
craftsman:
stage: test
script:
- npx ai-craftsman-superpowers validate --config .craft-config.yml --ci
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"The Feedback Loop
Zero drift means zero surprises:
- You write code → hook validates in under 3 seconds using
.craft-config.yml - You push → CI validates using the same
.craft-config.yml - 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.