Back to blog

Setting Up Automated Governance Checks on GitHub PRs

·9 min read·ExoProtocol Team
GitHub PR checksautomated code reviewPR governanceCI/CDExoProtocol setup

Setting Up Automated Governance Checks on GitHub PRs

This is a practical, step-by-step guide to adding automated governance checks to your GitHub pull requests. By the end, every PR in your repository will show a governance report with a pass/warn/fail verdict, drift scores, and commit-to-session attribution.

Total setup time: about 5 minutes for the basics, 15 minutes if you add feature manifests and requirement traceability.

What You'll Get

Before diving into setup, here's what the end result looks like. Every PR will show:

  • Verdict: pass (green), warn (yellow), or fail (red)
  • Commit coverage: how many commits are attributed to governed sessions
  • Per-session drift scores: how far each session deviated from its parameters
  • Scope violations: files changed outside the allowed scope
  • Boundary violations: changes to explicitly denied paths
  • Feature coverage: which features have tagged code in the PR
  • Requirement coverage: which requirements are implemented

The report appears as a GitHub check run, visible in the PR's checks tab. If you install the ExoProtocol GitHub App, it also posts an inline comment with the human-readable summary.

Prerequisites

You'll need:

  • A GitHub repository (public or private)
  • Python 3.10+ available in your CI environment
  • A terminal with access to your repo for the initial setup

Step 1: Install ExoProtocol

Install the CLI tool. This is the governance kernel that powers everything:

pip install exoprotocol

Verify the installation:

exo --version

You should see the current version number. ExoProtocol has no runtime dependencies beyond PyYAML, so installation is fast and lightweight.

Step 2: Initialize Governance

Navigate to your repository root and initialize the governance structure:

cd your-project
exo init

This creates the .exo/ directory with the initial governance structure:

.exo/
  constitution.yaml    # Governance rules and constraints
  config.yaml          # Configuration settings
  governance/          # Compiled governance state
  memory/              # Session mementos and history
  cache/               # Temporary session data

The constitution.yaml is where you define your governance rules. Open it and configure the basics:

# .exo/constitution.yaml
project:
  name: "your-project"
  description: "Brief description of your project"

governance:
  deny_patterns:
    - ".env"
    - ".env.*"
    - "*.key"
    - "*.pem"
    - "migrations/**"
    - ".github/workflows/**"
    - "infrastructure/**"

  defaults:
    max_files: 10
    drift_threshold: 0.7

The deny_patterns define files that AI agents must never modify. The defaults set baseline budgets for governed sessions. Adjust these to match your project's norms.

Step 3: Compile Governance

Compile the constitution into the governance lock file:

exo compile

This generates .exo/governance/lock.json - the compiled governance state that all checks reference. The lock file is deterministic: the same constitution always produces the same lock.

Commit the .exo/ directory to your repository:

git add .exo/
git commit -m "chore: initialize exoprotocol governance"

Step 4: Generate the CI Workflow

ExoProtocol can generate a GitHub Actions workflow that runs governance checks on every PR:

exo adapter-generate --target ci

This creates .github/workflows/exo-governance.yml:

# .github/workflows/exo-governance.yml
# Auto-generated by ExoProtocol - do not edit manually
name: ExoProtocol Governance

on:
  pull_request:
    branches: [main]

jobs:
  governance:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0  # Full history needed for commit analysis

      - uses: actions/setup-python@v5
        with:
          python-version: "3.11"

      - name: Install ExoProtocol
        run: pip install exoprotocol

      - name: Verify Governance Integrity
        run: exo verify

      - name: Run PR Governance Check
        run: |
          exo pr-check \
            --base ${{ github.event.pull_request.base.ref }} \
            --head ${{ github.event.pull_request.head.sha }} \
            --drift-threshold 0.7

      - name: Upload Governance Report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: governance-report
          path: .exo/reports/

You can customize the workflow by editing .exo/config.yaml before generating:

# .exo/config.yaml
ci:
  drift_threshold: 0.7
  python_version: "3.11"
  install_command: "pip install exoprotocol"

Commit the workflow file:

git add .github/workflows/exo-governance.yml
git commit -m "ci: add exoprotocol governance checks"

Step 5: Install the GitHub App (Optional)

The CI workflow gives you pass/fail verdicts on PRs. The ExoProtocol GitHub App adds richer integration:

  • Inline PR comments with human-readable governance reports
  • Check run annotations on specific files with violations
  • Team dashboard with aggregate drift metrics
  • One-click install, no workflow configuration needed

Visit the ExoProtocol website to install the GitHub App on your repository. The app runs exo pr-check in its own infrastructure, so it works even if you don't have the CI workflow set up.

The CI workflow and the GitHub App are complementary. The workflow gives you control (runs in your CI, your configuration). The app gives you convenience (richer UI, no workflow maintenance).

Step 6: Open a PR and See It Work

Now create a branch, make some changes, and open a pull request:

git checkout -b test-governance
# ... make some changes ...
git add -A
git commit -m "test: verify governance checks"
git push -u origin test-governance

Open a PR against main. Within a minute or two, you'll see the governance check appear in the PR's checks tab.

Reading the Governance Report

The report has several sections. Here's what each one means:

Verdict is the top-line result:

  • PASS (green): All commits are attributed to governed sessions. Drift scores are below the threshold. No boundary violations. The PR is clean.
  • WARN (yellow): Some drift detected or minor scope violations, but no hard failures. The reviewer should check the flagged areas but the PR isn't blocked.
  • FAIL (red): One or more hard failures - ungoverned commits, boundary violations, governance integrity drift, or verify failures. The PR needs investigation.

Commit Coverage shows how many commits in the PR are matched to governed sessions:

Commits: 5 total, 4 governed, 1 ungoverned

An ungoverned commit means someone pushed a change without starting a governed session. This is the most common cause of FAIL verdicts. It doesn't necessarily mean the code is bad - it means there's no governance data to verify it.

Per-Session Detail shows each governed session that contributed to the PR:

Session s-abc123 (AUTH-42):
  Drift Score: 0.18
  Files: 4/8 budget (50%)
  LOC: 120/300 budget (40%)
  Scope: All files within allowed paths
  Verdict: PASS

Low drift scores with no violations indicate well-governed work. High drift scores or scope violations indicate the agent exceeded its mandate.

Scope Violations list specific files that were changed outside the session's allowed scope:

Scope Violations:
  - src/utils/helpers.py (not in allowed paths)
  - config/database.yml (in denied paths - BOUNDARY VIOLATION)

Boundary violations (changes to denied paths) are more severe than regular scope violations.

Step 7: Advanced Configuration

Once the basics are working, you can add more governance layers.

Add a Feature Manifest

Create .exo/features.yaml to track which code belongs to which feature:

features:
  user-auth:
    status: active
    description: "User authentication and authorization"
    allow_agent_edit: true
  payment-processing:
    status: active
    description: "Stripe payment integration"
    allow_agent_edit: true
  legacy-billing:
    status: deprecated
    description: "Old billing system - do not extend"
    allow_agent_edit: false

Tag your code with @feature: annotations:

# @feature:user-auth
def login(email: str, password: str) -> AuthToken:
    ...
# @endfeature

Run the feature trace to check coverage:

exo trace

The PR governance check will automatically include feature coverage if a features.yaml exists.

Add a Requirement Registry

Create .exo/requirements.yaml to define what the system must do:

requirements:
  REQ-001:
    description: "Users must authenticate before accessing protected resources"
    status: active
    priority: high
    tags: [security, auth]
  REQ-002:
    description: "All API responses must include request-id header"
    status: active
    priority: medium
    tags: [api, observability]

Reference requirements in code with @req: annotations:

# @implements:REQ-001
@app.middleware("http")
async def auth_middleware(request, call_next):
    if not request.headers.get("Authorization"):
        return JSONResponse(status_code=401)
    ...

Check requirement coverage:

exo trace-reqs

Customize Drift Thresholds

Different projects have different tolerances. Adjust the drift threshold in your config:

# .exo/config.yaml
ci:
  drift_threshold: 0.5  # Stricter: flag drift above 50%

Or per-session:

exo session-finish --session-id <id> --drift-threshold 0.3

Lower thresholds catch more drift but generate more warnings. Start with 0.7 (lenient) and tighten as your team calibrates.

Generate Agent Configurations

Keep your agent config files in sync with governance:

# Generate all agent configs from governance state
exo adapter-generate --target claude    # CLAUDE.md
exo adapter-generate --target cursor    # .cursorrules
exo adapter-generate --target agents    # AGENTS.md

These files include deny patterns, budgets, and lifecycle commands derived from your governance configuration. Regenerate them whenever you update the constitution.

Run a Composite Drift Check

For a comprehensive health check of your entire governance setup, use the drift command:

$ exo drift

Governance Drift Report
========================
Overall: PASS

Governance Integrity: PASS
  Constitution hash matches lock

Adapter Freshness: WARN
  CLAUDE.md hash mismatch - regenerate with `exo adapter-generate`

Features: PASS
  12 features, 0 violations

Requirements: PASS
  8 requirements, 7 covered, 1 uncovered (warning)

Sessions: PASS
  No stale or orphaned sessions

This checks everything in one command: governance integrity, adapter freshness, feature traceability, requirement coverage, and session health. Run it locally before pushing, or add it to your CI workflow.

Troubleshooting

"No governed sessions found" on every PR:

This means commits aren't being matched to sessions. Make sure developers are running exo session-start before making changes and exo session-finish when done. The PR check matches commits to sessions by timestamp, so the session must be active when the commit is created.

"Governance integrity: FAIL":

This means the compiled governance lock doesn't match the current constitution. Run exo compile and commit the updated lock file.

CI workflow fails with "exo: command not found":

The Python setup step may not be adding pip-installed binaries to PATH. Add pip install exoprotocol to the install step and ensure the Python version matches what's in your config.

Drift scores seem too high:

Your budgets may be too tight for the type of work being done. Check the per-session detail to see which budget dimension is driving the drift, and adjust accordingly.

What's Next

With automated governance checks running on every PR, you've established a baseline of accountability for AI-generated code. From here, you can:

  • Tighten drift thresholds as your team calibrates
  • Add feature manifests for traceability across large codebases
  • Add requirements for compliance and audit trails
  • Use audit sessions for independent code review

Every PR, every commit, every session - governed, measured, and visible. That's the foundation of trustworthy AI-assisted development.

Get started now. Five minutes of setup saves hours of review debt on every PR that follows.

Learn more at exoprotocol.dev

Ready to govern your AI-written code?

Install ExoProtocol in 30 seconds. Your next PR will have a governance report.