Api Architecture Rules
ASecurityChoose and lay out the architecture of a Python web API (FastAPI) — domain modules, or hexagonal modules (domain model, ports and adapters) for a module with complex rules — and decide where each piece of code goes (router, schemas, service, domain model, repository, dependencies). Use when starting a Python API, deciding how to organise packages, splitting a growing codebase into modules, reviewing a project's structure, or when the user says "architecture", "project structure", "where shoul...
- 2 stars
- 0 votes
- 0 copies
- 0 views
- Added November 11, 2026
Works with
Security analysis
100/100Pro scans all 3 files and shows the line behind each finding
npx -y skills add JanSzewczyk/claude-plugins --skill api-architecture-rules --agent claude-codeAre you the author of Api Architecture Rules?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/janszewczyk-api-architecture-rules)---
name: api-architecture-rules
description: Choose and lay out the architecture of a Python web API (FastAPI) — domain modules, or hexagonal modules (domain model, ports and adapters) for a module with complex rules — and decide where each piece of code goes (router, schemas, service, domain model, repository, dependencies). Use when starting a Python API, deciding how to organise packages, splitting a growing codebase into modules, reviewing a project's structure, or when the user says "architecture", "project structure", "where should this code live", "modular monolith" or "hexagonal" for a Python service. NOT for writing endpoint code (use the python-developer agent) or documenting the API (see fastapi-rules).
allowed-tools: Read, Glob, Grep, Bash
argument-hint: "[project path, or a one-line description of the API]"
---
# API architecture (Python, FastAPI)
Decide how a Python API is structured and hand back a concrete layout. The default is a modular
monolith: one package per domain, layers inside, and more structure added to one module at a time
when a pain shows. The reasoning is in the guide; the rules below are what the code must follow.
Read the guide before recommending anything:
[references/guides/architecture--python--guides--api-structure.md](./references/guides/architecture--python--guides--api-structure.md)
holds the two layouts (domain modules and hexagonal modules), their costs and the signals to move a module to hexagonal.
## Workflow
1. **Look at what exists.** For a path, list the packages and read `main.py`, one router and one
service. Note the framework, the ORM, how tests reach the database and the endpoint count. For a
description only, ask for the domain's main areas and whether the rules are mostly CRUD.
2. **Place it.** Name the current layout and the pain, if any, using the signals in the guide's
Evolution section. No pain means no move.
3. **Recommend one step.** Pick the smallest change that removes the pain: a domain split, a service
extracted from a router, hexagonal layers in one module. Say what you would not do yet, and why.
4. **Show the layout.** Give the tree for the chosen layout and where the next three pieces of code
would go. State the import direction: routers know services, services know the domain, adapters
know the domain, never the reverse.
5. **Hand off.** Writing the code is the `python-developer` agent's job; give it the layout and the
module to start with. Do not edit the project yourself unless asked.
## Rules
The index below lists every rule; open the file when the task touches one.
<!-- BEGIN:knowledge -->
<!-- generated by knowledge.mjs from 13 note(s) (sha256 c1ad5be73004); edit the notes in knowledge/, then run build -->
| Impact | Rule | Applies to |
| --- | --- | --- |
| high | [Add structure to one module at a time, when it hurts](references/rules.md#add-structure-to-one-module-at-a-time-when-it-hurts) — Start with a service and models; add a port, a fake and a rich model only where a concrete pain shows. | any |
| high | [Keep a handler to parsing, one service call and error mapping](references/rules.md#keep-a-handler-to-parsing-one-service-call-and-error-mapping) — A handler translates HTTP and delegates; a service orchestrates one use case. | any |
| high | [Let imports point toward the domain, never away from it](references/rules.md#let-imports-point-toward-the-domain-never-away-from-it) — Handlers import services, services import the domain, adapters import the domain; the domain imports none of them. | any |
| high | [Put a rule about what is allowed in the domain, not in a handler or service](references/rules.md#put-a-rule-about-what-is-allowed-in-the-domain-not-in-a-handler-or-service) — Invariants live in domain objects, so a service does not turn models into bags of fields. | any |
| high | [Split the codebase by domain first and by layer inside each domain](references/rules.md#split-the-codebase-by-domain-first-and-by-layer-inside-each-domain) — Top-level packages are business areas such as orders and users; layers live inside them. | any |
| high | [Keep a FastAPI route to parsing, one service call and error mapping](references/rules.md#keep-a-fastapi-route-to-parsing-one-service-call-and-error-mapping) — The route calls one service function and maps its exceptions to status codes; no rules or queries. | python, fastapi |
| high | [Organize a FastAPI project as one package per domain](references/rules.md#organize-a-fastapi-project-as-one-package-per-domain) — src/<domain>/ holds router.py, schemas.py, models.py and service.py; main.py only includes routers. | python, fastapi |
| high | [Structure a Python API as domain modules, with hexagonal layers only where they pay](references/rules.md#structure-a-python-api-as-domain-modules-with-hexagonal-layers-only-where-they-pay) — Domain modules by default; hexagonal layers inside one module when its rules need testing without a database. | python, fastapi |
| medium | [Refer to another module's objects by id, not by its model](references/rules.md#refer-to-another-modules-objects-by-id-not-by-its-model) — Each module owns its model; across a boundary pass identifiers and translate the data. | any |
| medium | [Make a service depend on a repository Protocol and test its rules with a fake](references/rules.md#make-a-service-depend-on-a-repository-protocol-and-test-its-rules-with-a-fake) — A typing.Protocol in the domain, a SQLAlchemy adapter, and a dict-backed fake for rule tests. | python |
| medium | [Build adapters in dependency functions and inject them with Depends](references/rules.md#build-adapters-in-dependency-functions-and-inject-them-with-depends) — A domain's dependencies.py creates its repositories and services; the rest receives them as arguments. | python, fastapi |
| medium | [Hold another domain's id in a field instead of importing its model](references/rules.md#hold-another-domains-id-in-a-field-instead-of-importing-its-model) — orders stores customer_id; it asks the users service for the customer when it needs one. | python |
| medium | [Put a business rule in a method of the domain object](references/rules.md#put-a-business-rule-in-a-method-of-the-domain-object) — order.confirm() checks the invariant; the service loads the object, calls it and saves. | python |
<!-- END:knowledge -->
Files in this skill
- SKILL.md
- references/guides/architecture--python--guides--api-structure.md
- references/rules.md
Attribution
Related skills
View all in development →Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.