skills/stack/python-clean-architecture/SKILL.md
# Python Clean Architecture Patterns for writing clean, maintainable, and type-safe Python code. These are foundational rules that apply to every Python file in the codebase. --- ## Type Hints Everywhere Every public function, method, and class attribute MUST have type hints. No exceptions. ```python # YES def calculate_total(items: list[LineItem], tax_rate: Decimal) -> Decimal: ... # NO def calculate_total(items, tax_rate): ... ``` Use `from __future__ import annotations` at the
npx skillsauth add 33prime/rtg-forge skills/stack/python-clean-architectureInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Patterns for writing clean, maintainable, and type-safe Python code. These are foundational rules that apply to every Python file in the codebase.
Every public function, method, and class attribute MUST have type hints. No exceptions.
# YES
def calculate_total(items: list[LineItem], tax_rate: Decimal) -> Decimal:
...
# NO
def calculate_total(items, tax_rate):
...
Use from __future__ import annotations at the top of every file for modern annotation syntax.
str | None instead of Optional[str]list[str], dict[str, int], tuple[int, ...]TypeAlias for complex types: UserId: TypeAlias = UUIDProtocol for structural subtyping instead of ABC where possibleTypeVar for generic functions, not AnyAny is a code smell. If you reach for it, reconsider your design.Use structured data types instead of raw dictionaries.
# YES — Clear, typed, documented
@dataclass(frozen=True)
class InvoiceLineItem:
description: str
quantity: int
unit_price: Decimal
@property
def total(self) -> Decimal:
return self.unit_price * self.quantity
# NO — Opaque, untyped, fragile
item = {"description": "Widget", "qty": 5, "price": 10.99}
| Type | Use When |
|---|---|
| @dataclass | Internal domain objects, value objects, configs |
| pydantic.BaseModel | API boundaries, validation, serialization |
| TypedDict | Legacy dict interop, JSON schemas |
| NamedTuple | Immutable records, database rows |
| Raw dict | Never for domain objects. Only for truly dynamic/unknown structures. |
Business logic lives in service classes or modules, NOT in route handlers, CLI commands, or model methods.
class InvoiceService:
def __init__(self, repo: InvoiceRepository, notifier: NotificationService) -> None:
self._repo = repo
self._notifier = notifier
async def create_invoice(self, request: CreateInvoiceRequest) -> Invoice:
invoice = Invoice.from_request(request)
await self._repo.save(invoice)
await self._notifier.send_invoice_created(invoice)
return invoice
__init__ (constructor injection)Define a clear error hierarchy per domain. Never use bare Exception or generic ValueError for business errors.
class InvoiceError(Exception):
"""Base error for invoice domain."""
class InvoiceNotFoundError(InvoiceError):
def __init__(self, invoice_id: UUID) -> None:
self.invoice_id = invoice_id
super().__init__(f"Invoice {invoice_id} not found")
class InvoiceAlreadyPaidError(InvoiceError):
def __init__(self, invoice_id: UUID) -> None:
self.invoice_id = invoice_id
super().__init__(f"Invoice {invoice_id} is already paid")
except: or except Exception:Every function that returns a value must have an explicit return on every code path. Never rely on implicit None returns.
# YES
def find_user(user_id: UUID) -> User | None:
user = self._repo.get(user_id)
if user is None:
return None
return user
# NO — implicit None return
def find_user(user_id):
user = self._repo.get(user_id)
if user:
return user
Functions should do one thing. Target 5-20 lines. If a function exceeds 30 lines, it needs to be split.
Extract logical sections into private helper methods with descriptive names:
# Instead of one 60-line function:
async def process_order(self, order: Order) -> ProcessedOrder:
validated = self._validate_order(order)
priced = self._apply_pricing(validated)
await self._reserve_inventory(priced)
return await self._finalize_order(priced)
src/
domain/
models.py # Dataclasses, enums, value objects
errors.py # Domain exception hierarchy
types.py # Type aliases, protocols
services/
invoice_service.py # Business logic
repositories/
invoice_repo.py # Data access
api/
routes/ # HTTP handlers (thin)
dependencies.py # FastAPI Depends factories
# YES — Named constants
MAX_RETRY_ATTEMPTS = 3
DEFAULT_PAGE_SIZE = 50
INVOICE_DUE_DAYS = 30
# NO — Magic numbers
if retries > 3:
...
results = query.limit(50)
Use environment variables through a typed settings class (Pydantic BaseSettings), never through raw os.getenv() scattered across the codebase.
development
# Parallel Execution > This skill is under development. Workflow patterns for running independent tasks in parallel to improve performance and throughput. ## Topics to Cover - Identifying independent tasks suitable for parallel execution - `asyncio.gather()` with `return_exceptions=True` - `asyncio.TaskGroup` for structured concurrency (Python 3.11+) - Semaphores for bounded concurrency - `Promise.all()` and `Promise.allSettled()` in TypeScript - Handling partial failures (some tasks succeed
development
# Module Extraction > This skill is under development. Workflow for identifying and extracting reusable modules from existing codebases. Extract when a pattern is used in 3+ places and has stabilized. ## Topics to Cover - Identifying extraction candidates (rule of three) - Defining module boundaries and public interface - Dependency analysis: what does the module need? - Interface design: protocols, abstract base classes - Step-by-step extraction process - Testing strategy: tests before, dur
development
# Forge Orchestrate — Intelligent Build Orchestration You are a build planner, not a build executor. Your job is to look at a project, figure out what's left to build, decompose the work into parallel streams, assign the right intelligence level to each stream, estimate cost, and hand the user a set of terminal commands they can run. You plan. They execute. --- ## Stream Decomposition The unit of parallelism is a **stream** — a self-contained bundle of tasks that one Claude session handles e
development
# Code Review > This skill is under development. Workflow for conducting effective code reviews that catch real issues and improve code quality. ## Topics to Cover - Review priorities: correctness > design > performance > style - What to check in every review (checklist) - How to give constructive feedback - Automated checks that should run before human review - Review scope: how big is too big? - Patterns for reviewing database migrations - Patterns for reviewing API changes - When to reque