Skip to main content

Opinionated architecture constraint checker

Project description

chisel

Opinionated architecture constraint checker for FastAPI backends. Designed to catch the patterns agents get wrong — use it as a pre-commit hook to block violations, or run it interactively to steer an agent while it's working.

It pairs with agent skills: the skill teaches the agent the right pattern, the checker enforces it deterministically. Run chisel explain <rule-id> to get fix guidance the agent can consume directly.

Installation

pip install chisel

Quick start

chisel check ./backend              # check a project
chisel rules                        # list all ~55 rules grouped by category
chisel explain structural:print-banned  # detailed fix guidance
chisel check . --json               # machine-readable output for agents
chisel check . --no-strict          # skip src-layout enforcement

Commands

Command Description
chisel check [path] Scan a project for architectural violations
chisel check . --json Output violations as structured JSON
chisel check . --strict/--no-strict Toggle src-layout and build-config enforcement
chisel rules List all rules, grouped by category
chisel rules --json Machine-readable rule listing
chisel explain <rule-id> Detailed description + fix guidance for a rule
chisel explain <category> All rules in a category (e.g. structural)

What gets checked

Category What it enforces
Import Boundaries Layer-based import restrictions — services can't import SQLAlchemy, routes can't import services, HTTPException only in error_handlers.py, concrete services only in factory.py
Structural Invariants No getattr/setattr, no % string formatting, no f-strings in logger calls, no print() in src/, @dataclass uses slots=True, AppFactory has zero logic, match/case only in error handlers
Complexity Controller method ≤30 LoC, route handler ≤20 LoC, factory cyclomatic complexity = 1, app.py ≤50 LoC
Concurrency asyncio.gather banned unconditionally — use asyncio.TaskGroup
Error Flow AppError subclasses never contain HTTP status codes; status codes decided only in error_handlers.py
Project Structure pyproject.toml only (no setup.py), env vars read at startup only via AppConfig, no .py files at project root
Test Structure Test files only under tests/unit/, tests/integration/, tests/e2e/; one assert per test; no mocking libraries; test names describe invariants; pytest.mark.skip needs a reason; no TestClient outside e2e

Exceptions

Create a chisel-exceptions.toml at your project root:

[[exceptions]]
files = ["src/legacy/*.py", "src/cli/main.py"]
rules = ["structural:print-banned"]
reason = "CLI requires stdout output"

* matches all rules. A category prefix like structural matches all rules in that category.

Inline suppression per line: # noqa: rule-id — reason.

Severity tiers

Tier Behaviour
ERROR Blocks commit, no override. Import boundary violations, asyncio.gather, getattr/setattr, f-string in logger, print() in src/.
WARNING Blocks commit, suppressible with a reason comment. Controller/route LoC thresholds, test coverage gaps.
INFO Logged, non-blocking.

How it works

models/         Pure data — Violation, Severity, FileInfo, ProjectInfo
services/       One service per rule category, self-describing via describe_rules()
repositories/   File discovery, import graph analysis (grimp)
controllers/    Orchestrates all services, filters exceptions, suppresses via noqa
factory.py      Zero-logic DI — wires all services into the controller
cli/main.py     Typer-based CLI — check, rules, explain
reporter.py     Coloured terminal output via rich

Adding a rule requires one new check method in a service + one describe_rules() entry. The CLI discovers it automatically.

Development

pip install -e ".[dev]"
pytest tests/ -q

The checker is self-validating: chisel check . --strict produces zero violations on its own source.

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

chisel_checker-0.1.1.tar.gz (47.4 kB view details)

Uploaded Source

Built Distribution

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

chisel_checker-0.1.1-py3-none-any.whl (38.3 kB view details)

Uploaded Python 3

File details

Details for the file chisel_checker-0.1.1.tar.gz.

File metadata

  • Download URL: chisel_checker-0.1.1.tar.gz
  • Upload date:
  • Size: 47.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for chisel_checker-0.1.1.tar.gz
Algorithm Hash digest
SHA256 d3818e9b5c6d105a59984b1983d52ece9097d0d71cb215bbdf65e8ebaa20d2f4
MD5 c8ad85c453b20a6dd8c952cd6bd16916
BLAKE2b-256 b54d86a2916059f67b14f803b6058aa324dca47900206f28398254802df999c5

See more details on using hashes here.

Provenance

The following attestation bundles were made for chisel_checker-0.1.1.tar.gz:

Publisher: ci.yml on ChidiRnweke/chisel

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chisel_checker-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: chisel_checker-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 38.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for chisel_checker-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 4d0fde3eff0607736fd7e9ff6390697d61ef27b5294301791e9f52e643a8a55c
MD5 4fe526ba25102f52ed34ef521262c3f0
BLAKE2b-256 8216361b43cd51bccc49699a0e6341c8c85d415a0451561688b4f72f2fa236b5

See more details on using hashes here.

Provenance

The following attestation bundles were made for chisel_checker-0.1.1-py3-none-any.whl:

Publisher: ci.yml on ChidiRnweke/chisel

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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