Getting Started
Requirements
- Python 3.12+
- A project with
pyproject.toml
Installation
pip install pyarchrules
1. Initialise
Run from the directory that contains pyproject.toml:
pyarchrules init-project
This adds an empty [tool.pyarchrules] block to pyproject.toml. Service
definitions go under [tool.pyarchrules.services.<name>].
2. Add a service
A service is any directory you want to enforce rules on.
pyarchrules add-service backend src/backend
Appends to pyproject.toml:
[tool.pyarchrules.services.backend]
path = "src/backend"
3. Define rules
Edit pyproject.toml to add the rules you need:
[tool.pyarchrules.services.backend]
path = "src/backend"
tree = ["api", "domain", "infra"]
tree_mode = "strict"
dependencies = ["api -> domain", "domain -> infra", "* -> utils"]
See Configuration for the full list of options.
4. Run the check
pyarchrules check
Passing:
🔍 Checking 1 service(s)...
📦 backend src/backend
✨ All checks passed!
Checked 2 rule(s) across 1 service(s)
Failing:
❌ Validation failed!
Found 1 error(s):
❌ [backend] tree_structure
Missing required paths: ['domain']
Exit code 1 is returned on any error, 2 on a configuration problem
(missing pyproject.toml, malformed table, etc.). See
CLI Reference → Exit codes.
5. Inspect the resolved config
To see exactly which services and rules check will run — useful when
debugging a monorepo or a --config override:
pyarchrules show-config
Outputs a JSON document with every service, its declared keys, and the list of rules that will actually execute.
6. CI integration
- name: Architecture check
run: pyarchrules check
For machine-readable output (GitHub annotations, custom dashboards):
pyarchrules check --format json --quiet > arch.json
Python API
Rules can also be written in Python, typically inside pytest:
# tests/test_architecture.py
from pyarchrules import PyArchRules
def test_architecture():
rules = PyArchRules()
rules.for_service("backend") \
.tree_structure(["domain", "application", "infra"], mode="strict") \
.dependencies(["application -> domain", "infra -> domain"]) \
.no_circular_imports()
rules.validate()
If you don't want a [tool.pyarchrules] table at all, use from_services
for a TOML-free setup:
rules = PyArchRules.from_services({"backend": "src/backend"})
rules.for_service("backend").no_circular_imports().validate()
See Python DSL for all available rules.