open source · MIT license

Enforce module boundaries in Python.
Catch violations in CI.

Define allowed dependencies between modules in a governance.toml. Run it locally, in CI, or let an LLM tell you what to fix.

View on GitHub
terminal

Codebases rot from the inside

One "quick" import across a module boundary becomes ten. Suddenly everything depends on everything. Tests break for no reason. Refactors are impossible.

api auth core bill mail pay
β†’
presentation infrastructure domain api web auth mail core db

Three commands. That's it.

1

Generate

Scans your source code, detects modules, and maps every real import.

governance-ast --generate --source-root src/
2

Configure

Review the generated governance.toml. Adjust boundaries to match your intended architecture.

[[modules]]
name = "api"
cannot_depend_on = ["billing", "migrations"]
3

Enforce

Run locally or in CI. Violations fail the build. No more silent boundary erosion.

governance-ast

Five rules, zero ambiguity

πŸ”—
enforce_cannot_depend_on
Module imports from a forbidden dependency.
πŸ”„
no_cycles
Circular dependency detected. A imports B, B imports A.
πŸ“
enforce_layers
Lower architectural layer imports from a higher one.
πŸ“’
max_public_surface
Too many symbols exposed to other modules. Keep your API tight.
🧲
min_cohesion
Module imports more from outside than from itself. It might belong elsewhere.

Catches violations in your PR

Add one GitHub Action. Get violation reports as PR comments with LLM-powered fix suggestions.

❌ 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.

Reply /governance fix on the PR and the bot auto-updates your governance.toml with correct cannot_depend_on and commits to your branch.

Adopting on an existing codebase? Save a baseline and only fail on new violations:

governance-ast --save-baseline .governance-baseline.json
governance-ast --baseline .governance-baseline.json
- uses: actions/checkout@v4
- name: Governance
  uses: useparadigm/code-governance@main
  with:
    config: governance.toml
    diff: origin/main
    advise: true
  env:
    OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}

Don't just find violations β€” understand them

Pass --advise and get architectural recommendations powered by OpenAI or Anthropic.

$ governance-ast --advise
πŸ€– Architectural advice:
The api β†’ billing dependency suggests checkout logic is reaching into the billing module directly. Consider:

1. Extract charge_customer() into a shared interface in core
2. Or explicitly remove "billing" from api's cannot_depend_on β€” this is a legitimate dependency if api owns the checkout flow

The payments ↔ notifications cycle is more concerning. Break it with an event bus or move send_receipt into the payments module.
β—‹ OpenAI (gpt-4o)
β—‹ Anthropic (claude-sonnet)

vs tach & import-linter

tach and import-linter are the established tools. Here's an honest comparison.

code-governance tach import-linter
Setup --generate creates config from source 50-100 lines TOML with regex Manual contract definition
Monorepo support βœ“ scans source directly βœ“ scans source Must be importable
Diff mode βœ“ only check changed files βœ— βœ—
Baseline βœ“ accept existing, fail on new βœ— βœ—
CI comments βœ“ PR comments + fix suggestions Exit code only Exit code only
Auto-fix βœ“ /governance fix βœ— βœ—
LLM advice βœ“ architectural recommendations βœ— βœ—
Error guidance LLM explains why + suggests fix "cycle detected" β€” no context Import chain shown, no fix
Module metrics βœ“ cohesion, surface, symbol count βœ— βœ—
HTML report βœ“ dependency matrix viewer βœ— separate browser UI
Public interface enforcement βœ— βœ“ visibility controls βœ—
Transitive imports βœ“ transitive chains direct only βœ“ transitive chains
Speed (Django, 902 files) ~1.2s sub-second (Rust) ~0.1s
Package needs installing No β€” scans source directly No β€” scans source Yes β€” must be importable

Choose tach if you need public interface enforcement or visibility controls. Choose code-governance for transitive chain detection, CI integration, auto-fix, LLM advice, and zero-config setup.