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.2.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.2-py3-none-any.whl (38.3 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: chisel_checker-0.1.2.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.2.tar.gz
Algorithm Hash digest
SHA256 fefb9e3c16e4c6234c8b1d5f8e0539c8741d2c766d3c35de3dcdc6c896a6d3aa
MD5 56d3d9c10464e399eb250ddce07338ce
BLAKE2b-256 b66156a600dcf8a123b2315326b2fafbd7843cd46b392d67bab39c8d1610088c

See more details on using hashes here.

Provenance

The following attestation bundles were made for chisel_checker-0.1.2.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.2-py3-none-any.whl.

File metadata

  • Download URL: chisel_checker-0.1.2-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.2-py3-none-any.whl
Algorithm Hash digest
SHA256 2e1bad2d14c79c4adfc97d1e389349e80a642f44c2ba7e26915bfa0d3b7960b8
MD5 f6b417025d516ad7bb6930fd5f7a39b9
BLAKE2b-256 e5a675ce431b8fc87cf5834858cc7eb582c72ad7a70d80ae1f7fc1619072585b

See more details on using hashes here.

Provenance

The following attestation bundles were made for chisel_checker-0.1.2-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