Skip to main content

AST-based governance engine for enforcing module boundaries and architecture rules in Python and TypeScript codebases

Project description

code-governance

code-governance

Stop spaghetti imports. Enforce module boundaries in Python and TypeScript.

PyPI Tests License


Before / After

Without governance With governance
api/ imports from billing/, db/, auth/, utils/, migrations/... api/ has cannot_depend_on = ["billing", "migrations"] — forbidden imports blocked
One refactor breaks 14 files across 6 modules Boundaries are explicit, changes stay local
New dev: "Can I import this here?" "Uhh... maybe?" Config says yes or no. CI enforces it.

Setup

Option 1: With Claude Code (recommended)

Install the plugin — Claude handles everything interactively. Run each command separately — pasting them all at once will concatenate into a single broken URL:

/plugin marketplace add useparadigm/code-governance-plugin
/plugin install code-governance
/reload-plugins

Then run:

/governance-init

Without /reload-plugins, the new commands won't be registered yet and /governance-init will fail with Unknown command.

What happens:

  1. Claude installs code-governance in your project
  2. Scans your codebase — discovers modules, maps every import
  3. Shows you the dependency map: "I found 8 modules. api imports from db directly — should it?"
  4. You discuss architecture: which dependencies are intentional, which are spaghetti
  5. Claude creates governance.toml based on your answers
  6. Enables rules: no_cycles, enforce_cannot_depend_on, optionally enforce_layers
  7. If existing violations: "Want a baseline? I'll accept these and only fail on new ones."
  8. Sets up GitHub Actions — CI check on every PR + /governance fix command
  9. Done. Every PR is now gated on architecture rules.

After setup, two more commands available:

Command What it does
/governance-check Run checks, explain violations, fix them interactively
/governance-audit Architecture health review — metrics, hotspots, suggestions

Option 2: Manual

pip install code-governance

Quick scan — no config needed, instant results:

$ governance-ast --auto src/

Governance Report (python)
Modules: 8 | Files scanned: 47

Violations (1):
  [E] [no_cycles] Circular dependency: payments -> notifications -> payments

FAILED

Works on TypeScript too — language auto-detected from source:

$ governance-ast --auto src/

Governance Report (typescript)
Modules: 6 | Files scanned: 82
...

.ts, .tsx, .js, .jsx, .mts, .cts, .mjs, .cjs all supported. tsconfig.json path aliases (@/*, extends chains) are honored.

Full setup — generate config, review, enforce:

# Generate config: detect modules + seed cannot_depend_on by locking down
# every module pair that does not currently import from each other.
governance-ast --generate --source-root src/

# See the dependency map
governance-ast --discover

# Edit governance.toml — remove dependencies you don't want, add layers
# Then enforce:
governance-ast

Set up CI — add to .github/workflows/governance.yml:

- uses: actions/checkout@v4
- name: Governance
  uses: useparadigm/code-governance@main
  with:
    config: governance.toml
    diff: origin/main

See governance-fix workflow to enable the /governance fix PR command.

GitLab CI — add to .gitlab-ci.yml:

governance:
  image: python:3.12-slim
  variables:
    GIT_DEPTH: 0
  before_script:
    - pip install code-governance
  script:
    - governance-ast --config governance.toml --diff origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

See GitLab MR comments to post the report as an MR note.

What it catches

Rule Example
enforce_cannot_depend_on api imports billing but billing is in cannot_depend_on
no_cycles payments -> notifications -> payments
enforce_layers db (infrastructure) imports from api (presentation)
max_public_surface 80% of core's symbols used externally — too exposed
min_cohesion utils imports 90% from other modules — grab-bag module

What happens in CI

Every PR gets a governance comment:

❌ Governance — 1 violation, 1 new module

🔴 🔗 core: Forbidden dependency: 'core' imports 'db' (cannot_depend_on: ['db'])
  core/service.py:2

📦 New module exporters (exporters/) — not in governance.toml

Reply /governance fix to apply.

🤖 AI: The core→db import creates tight coupling. Extract shared
types into a common module, or remove "db" from core's cannot_depend_on.

New module detected? Reply /governance fix — bot adds it to config, commits to your branch.

Violation? Fix the import or update governance.toml. Use /governance-check in Claude Code for interactive help.

Pre-commit

repos:
  - repo: https://github.com/useparadigm/code-governance
    rev: main
    hooks:
      - id: governance-check
      - id: governance-diff

Adopting on legacy codebases

governance-ast --save-baseline .governance-baseline.json
governance-ast --baseline .governance-baseline.json

Accept existing violations. Only fail on new ones.

Transitive detection

governance-ast --transitive

Detects indirect violations through dependency chains. If api has cannot_depend_on = ["db"] and api → service → db, the transitive check catches it. Also works with layer enforcement. Enable permanently in config with transitive = true under [rules].

LLM advice

export OPENAI_API_KEY=sk-...   # or ANTHROPIC_API_KEY
governance-ast --advise

Analyzes violations and suggests: accept the dependency, restructure the code, or extract a shared module. Works with OpenAI and Anthropic.

HTML report

governance-ast --format html > report.html

Self-contained dependency matrix with module metrics. Drop any governance JSON into it.

Comparison

code-governance tach import-linter
Zero-config scan --auto — instant No No
Config generation --generate from source tach init (interactive TUI) Manual
LLM advice --advise — explains + suggests fix No No
CI comments PR comments with explanations No No
Auto-fix from PR /governance fix No No
AI agent plugin Claude Code plugin No No
Diff mode --diff HEAD No No
Baseline Accept existing, fail on new No No
Module metrics Cohesion, surface, symbols No No
HTML report Dependency matrix viewer tach show Browser UI
JSON output Yes Yes No
Scans source directly Yes Yes No — must be importable
Interface enforcement No Yes No
Transitive imports Full chain (--transitive) Direct only Full chain
Forbidden imports cannot_depend_on cannot_depend_on Forbidden contract
Visibility control No Yes No
Speed (Django) ~1.2s Sub-second (Rust) ~0.1s (grimp)
Config syntax Simple TOML lists TOML with regex INI or TOML
Maintenance Active Abandoned by original team Active, slow

Choose tach if you need interface enforcement or visibility control (note: unmaintained). Choose code-governance if you want transitive detection, AI-guided setup, CI integration, or zero-config scanning.


Governance fix workflow

Add to .github/workflows/governance-fix.yml:

name: Governance Fix

on:
  issue_comment:
    types: [created]

permissions:
  contents: write
  pull-requests: write

jobs:
  apply-fix:
    name: Apply config fix
    runs-on: ubuntu-latest
    if: |
      github.event.issue.pull_request &&
      contains(github.event.comment.body, '/governance fix')
    steps:
      - name: Acknowledge
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          gh api repos/${{ github.repository }}/issues/comments/${{ github.event.comment.id }}/reactions \
            -X POST -f content=eyes

      - uses: actions/checkout@v4

      - name: Checkout PR branch
        env:
          GH_TOKEN: ${{ github.token }}
        run: gh pr checkout ${{ github.event.issue.number }}

      - name: Find and apply fix
        id: fix
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          PAYLOAD=$(gh api repos/${{ github.repository }}/issues/${{ github.event.issue.number }}/comments \
            --jq '.[] | select(.body | contains("<!-- governance-fix:")) | .body' \
            | grep -oP '<!-- governance-fix:\K[A-Za-z0-9+/=]+' | tail -1)

          if [ -z "$PAYLOAD" ]; then
            gh api repos/${{ github.repository }}/issues/comments/${{ github.event.comment.id }}/reactions \
              -X POST -f content=confused
            exit 1
          fi

          DECODED=$(echo "$PAYLOAD" | base64 -d)
          CONFIG_PATH=$(echo "$DECODED" | python3 -c "import sys,json; print(json.load(sys.stdin)['config_path'])")
          echo "$DECODED" | python3 -c "import sys,json; print(json.load(sys.stdin)['updated_config'])" > "$CONFIG_PATH"

          pip install code-governance
          echo "Config updated"

          git config user.name "github-actions[bot]"
          git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
          git add "$CONFIG_PATH"
          git diff --cached --quiet && exit 0

          git commit -m "governance: add new modules to config"
          git push
          echo "sha=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT

      - name: Confirm
        if: steps.fix.outputs.sha
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          gh api repos/${{ github.repository }}/issues/comments/${{ github.event.comment.id }}/reactions \
            -X POST -f content='+1'
          gh pr comment ${{ github.event.issue.number }} \
            --body "✅ Config fix applied in \`${{ steps.fix.outputs.sha }}\`. Re-run checks to verify."

GitLab MR comments

Posts the governance report as a note on the merge request. Requires a Project Access Token with api scope, exposed as masked CI variable GOVERNANCE_GITLAB_TOKEN.

governance:
  image: python:3.12-slim
  variables:
    GIT_DEPTH: 0
  before_script:
    - pip install code-governance
    - apt-get update && apt-get install -y --no-install-recommends curl jq && rm -rf /var/lib/apt/lists/*
  script:
    - set +e
    - governance-ci-report --config governance.toml --json > report.json
    - set -e
    - PASSED=$(jq -r '.passed' report.json)
    - jq -r '.markdown' report.json | tee report.md
    - |
      if [ "$CI_PIPELINE_SOURCE" = "merge_request_event" ] && [ -n "$GOVERNANCE_GITLAB_TOKEN" ]; then
        BODY=$(jq -Rs . < report.md)
        curl -sf --request POST \
          --header "PRIVATE-TOKEN: $GOVERNANCE_GITLAB_TOKEN" \
          --header "Content-Type: application/json" \
          --data "{\"body\": $BODY}" \
          "$CI_API_V4_URL/projects/$CI_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID/notes"
      fi
    - test "$PASSED" = "true"
  artifacts:
    when: always
    paths: [report.json, report.md]
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

/governance fix is GitHub-only for now — GitLab equivalent would need a Note webhook listener.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

code_governance-0.4.0.tar.gz (235.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

code_governance-0.4.0-py3-none-any.whl (45.3 kB view details)

Uploaded Python 3

File details

Details for the file code_governance-0.4.0.tar.gz.

File metadata

  • Download URL: code_governance-0.4.0.tar.gz
  • Upload date:
  • Size: 235.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.0

File hashes

Hashes for code_governance-0.4.0.tar.gz
Algorithm Hash digest
SHA256 81ab00ae07e08dfe67d648d26e65aa210bdb3fc11684cdb0c1e505aa3d9bfc0e
MD5 17e0b63ee0631d47f22ea0ab28fca4e6
BLAKE2b-256 f72814efb7fc016fbe40b140713f52ddda3036af41d0f89d7f1bcadb35ddf76e

See more details on using hashes here.

File details

Details for the file code_governance-0.4.0-py3-none-any.whl.

File metadata

File hashes

Hashes for code_governance-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 78d1604ddcf2630adfa4b7599f467c80f3dbfcbb1177ab4f658de70151ad0273
MD5 0ce25ca51f71d983d4d132cb31a3f226
BLAKE2b-256 8deaf787e4251834b3344e7fa91ddbb7b7cce3d19539069b7d93df4c8b47d294

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page