Inwards: Reguły architektury dla Pythona, na tyle szybkie, że można je uruchamiać po każdej edycji agenta AI.¶
Deklarujesz warstwy w pyproject.toml. Gdy import wskazuje w złą stronę, inwards check podaje linię i mówi agentowi, jak to naprawić.
3from __future__ import annotations45from dataclasses import dataclass6from shop.infrastructure.in_memory_orders import InMemoryOrderRepository
$ uv run inwards check shop/domain/order.py
shop/domain/order.py:6:50: INW001 Layer "domain" imports "shop.infrastructure.in_memory_orders.InMemoryOrderRepository" from outer layer "infrastructure". Allowed direction: domain <- application <- infrastructure <- presentation <- bootstrap.
fix: Depend on an abstraction owned by "domain" instead of "shop.infrastructure.in_memory_orders.InMemoryOrderRepository".
1. Delete `from shop.infrastructure.in_memory_orders import InMemoryOrderRepository`. Do not move the import into a function or behind TYPE_CHECKING; Inwards checks those too.
2. Declare a typing.Protocol in `shop.domain` (for example `shop.domain.ports`) that describes only what this module needs from `InMemoryOrderRepository`.
3. Type this module against that Protocol and receive the implementation through a constructor or function parameter.
4. Make the class in "infrastructure" satisfy the Protocol, and wire it in the outermost layer (the composition root).
docs: https://sircypkowskyy.github.io/inwards/rules/INW001/
Found 1 violation in 1 file (63.7 ms).
Twoja architektura jako reguły¶
Warstwy trafiają do pyproject.toml, od najbardziej wewnętrznej. INW001 pilnuje kierunku; każda diagnostyka ma kroki naprawy.
[tool.inwards]
root = "."
layers = [
{ name = "domain", modules = ["shop.domain"] },
{ name = "application", modules = ["shop.application"] },
{ name = "infrastructure", modules = ["shop.infrastructure"] },
{ name = "presentation", modules = ["shop.presentation"] },
{ name = "bootstrap", modules = ["shop.bootstrap"] },
]
Wbudowane w pętlę agenta¶
Sprawdzenie po każdej edycji, Stop gate nad całą sesją (także edycje przez Bash), config guard na reguły i eskalacja do ciebie po escalate-after próbach.
Łapie to, co robią agenci¶
Zmyślone moduły, importy za TYPE_CHECKING, importy dynamiczne. Wyciszenie wymaga powodu (INW009); poluzowanie konfiguracji zostaje odrzucone.
$ uv run inwards check shop/domain/dodge.py --format concise
shop/domain/dodge.py:8:33: INW010 "shop.domain.pricing" is not a module of this project: "shop.domain" has no "pricing". fix: Check the name. The closest modules in "shop.domain": `shop.domain.order`.
shop/domain/dodge.py:11:54: INW001 Layer "domain" imports "shop.infrastructure.in_memory_orders.InMemoryOrderRepository" from outer layer "infrastructure". Allowed direction: domain <- application <- infrastructure <- presentation <- bootstrap. fix: Delete `from shop.infrastructure.in_memory_orders import InMemoryOrderRepository`. Do not move the import into a function or behind TYPE_CHECKING; Inwards checks those too.
shop/domain/dodge.py:15:12: INW011 Layer "domain" imports "shop.infrastructure.in_memory_orders" from outer layer "infrastructure" through a dynamic import (importlib.import_module). Allowed direction: domain <- application <- infrastructure <- presentation <- bootstrap. fix: Delete `importlib.import_module("shop.infrastructure.in_memory_orders")`. A dynamic import is still a dependency: building the module name at runtime or moving it to another loader hides it instead of removing it.
Found 3 violations in 1 file (109.4 ms).
Na tyle szybkie, by działać po każdej edycji¶
Sprawdzenie jednego pliku, które uruchamia hook, mieści się w budżecie 100 ms dla p95, nawet dla pliku z 4482 liniami.
| Plik | p95, ze 100 ms |
|---|---|
| saleor, jeden plik | 30 ms |
| Przykładowy pakiet ze scaffoldu | 39.5 ms |
| polar, plik z 4482 liniami | 90 ms |
inwards check <file> ze startem procesu, jeden wątek, 2026-09-26.Zimne pełne sprawdzenie, jeden rdzeń: 496 000 linii w 0,4 s, 848 000 linii saleora w 1,8 s. Przeoczenia prescanu: 0 w 6543 plikach.
Szybki start¶
-
Zainstaluj albo pobierz plik binarny.
-
Dodaj hooki Claude Code. Nowy projekt? Dodaj
--style clean --scaffold. -
Sprawdź projekt.
- Zacznij
- Instalacja i podłączenie agenta.
- Reguły
- Każdy kod i jego naprawa.
- Jak działa z agentami
- Hooki i Stop gate.
- Architektura i decyzje
- Widoki C4 i decyzje.
Pre-alpha. Najnowsze wydanie: 0.7.0 na PyPI, 2026-10-11. Reguły: INW000–INW021, FAPI001–FAPI003 i FAPI005–FAPI009.