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"
depends_on = ["core", "auth"]
3

Enforce

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

governance-ast

Five rules, zero ambiguity

πŸ”—
enforce_depends_on
Module imports something not in its allowed dependency list.
πŸ”„
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: Undeclared dependency: 'core' imports 'db' (allowed: [])
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 add "db" to core's depends_on.

Reply /governance fix on the PR and the bot auto-updates your governance.toml with correct depends_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 add "billing" to api's depends_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 import-linter

import-linter is the established tool for this. Here's an honest comparison.

code-governance import-linter
Setup --generate creates config from source Manual contract definition
Diff mode βœ“ only check changed files βœ—
Baseline βœ“ accept existing, fail on new βœ—
CI comments βœ“ PR comments + fix suggestions βœ—
Auto-fix βœ“ /governance fix βœ—
LLM advice βœ“ architectural recommendations βœ—
Module metrics βœ“ cohesion, surface, symbol count βœ—
HTML report βœ“ dependency matrix viewer separate browser UI
Transitive imports direct only βœ“ transitive chains
Forbidden contracts βœ— βœ“
Speed (Django, 902 files) ~1.2s ~0.1s
Package needs installing No β€” scans source directly Yes β€” must be importable

Choose import-linter if you need transitive import detection. Choose code-governance if you want CI integration, auto-fix, LLM advice, or zero-config setup.