Integration · GitHub Actions 4 min read · May 2026

# GitHub Actions AI Governance

Pre-generation enforcement catches most violations before code is written. CI enforcement catches the rest — running Mneme's checks against every PR diff, blocking merges that violate architectural decisions.

By Theo Valmis · Published Apr 2026 · Updated May 2026

## Why CI enforcement matters

- Generation-time hooks cover interactive and agentic Claude Code sessions
- Code can also arrive from manual edits, other tools, or agents without hook coverage
- CI enforcement is the backstop — every commit checked regardless of how it was produced
- Positions governance at three layers: generation time → PR review → CI gate

## How it works

- `mneme check` validates a file or diff against the decision corpus in `.mneme/project_memory.json`
- Run against changed files in a PR to surface any architectural violations
- Exit code 2 = violation found → CI step fails → PR blocked
- Exit code 0 = no violations → CI step passes

## Example workflow

    # .github/workflows/mneme-governance.yml
    name: Architectural Governance

    on:
      pull_request:
        branches: [main]

    jobs:
      governance:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
          - uses: actions/setup-python@v5
            with:
              python-version: '3.11'
          - run: pip install mneme-hq
          - name: Check changed files
            run: |
              git diff --name-only origin/main...HEAD | \
                xargs -I{} mneme check {}

## Status

- CI enforcement gate is Phase 1 current focus — see the roadmap
- The `mneme check` command is available today via `pip install mneme-hq`
- The GitHub Actions workflow above is the reference integration pattern
- Managed GitHub Actions workflow artifact coming in Q3 2026

## Layered governance model

Layer 1: Generation-time enforcement via Claude Code hooks
Layer 2: PR review (human + AI)
Layer 3: CI gate via Mneme in GitHub Actions

## What the gate actually checks

The CI step runs `mneme check --mode strict` against the PR diff and the project's decision corpus. The check returns a structured verdict per touched file, with three possible outcomes:

- PASS — the diff respects the relevant decisions. Exit code 0, CI green.
- WARN — the diff introduces something the corpus flags as policy-bordering (an unapproved dependency, a scope-boundary edge case). Exit code 0 in default mode, surfaces a structured comment via the action's PR-comment step.
- FAIL — the diff violates a hard architectural decision. Exit code 2 in strict mode, fails the workflow, blocks the PR until resolved or explicitly overridden.

Override events are themselves tracked: an override is a decision record with a rationale, scope, and expiry, committed as part of the same PR. Weakening a constraint costs the same as introducing one — a structured edit reviewers can see, not a quiet bypass.

## FAQ

Should we run this on every PR or only on main?
Every PR. The point of CI enforcement is to surface violations at PR time when the cost of fixing is lowest. Running only on main means failures land after merge, which defeats the gating purpose. The check is fast (deterministic keyword scoring, no embedding model) so per-PR cost is negligible.
What if a PR needs to override a decision intentionally?
Add an override record to `project_memory.json` as part of the same PR — with rationale, scope, and expiry. The check picks it up automatically. The override is reviewable in the PR diff like any other change, so weakening a constraint is a visible decision rather than a silent merge.
How does this compare to running CodeRabbit or a custom linter in CI?
Different layers. Linters check syntax and style; CodeRabbit reviews PRs for correctness and security; Mneme enforces architectural decisions against the project's own decision corpus. They compose: the typical CI sequence is lint → mneme check → tests → CodeRabbit review. See the CodeRabbit comparison for the detail.

## Related reading

- the Claude Code hook
- the Cursor integration