$npx -y skills add maksimzayats/specx --skill specx-diwire-compositionWire dependency injection for a specx Python service with diwire. Use when adding ioc/container.py, explicit dependency registrations for capabilities, repositories, gateways, UoW managers, clients, settings, or factories, Injected[...] constructor fields, FastAPI app facto
| 1 | # specx Diwire Composition |
| 2 | |
| 3 | Use this skill whenever object graphs, factories, controllers, adapters, or test |
| 4 | overrides need `diwire`. Read `references/diwire.md` before writing DI code. |
| 5 | |
| 6 | ## Rules |
| 7 | |
| 8 | - Application classes receive dependencies through constructor fields typed as |
| 9 | `Injected[DependencyType]`. |
| 10 | - Keep injection constructor-based. Do not hide dependency resolution in |
| 11 | application functions with `resolver_context.inject`. |
| 12 | - Capabilities are normal injectable collaborators. Register only capability |
| 13 | abstractions or existing instances that auto-wiring cannot infer. |
| 14 | - Only `ioc/`, top-level delivery `__main__.py`/factory/lifecycle modules, and |
| 15 | tests create or use `diwire.Container`. |
| 16 | - Do not inject `Container` except in `FastAPILifecycle`, where it is used only |
| 17 | to call `container.aclose()` during app shutdown. |
| 18 | - Do not inject `logging.Logger` or register loggers in the container. Runtime |
| 19 | logging is configured once by a top-level infrastructure configurator; classes |
| 20 | that log create local stdlib loggers. |
| 21 | - Do not call `container.resolve()` inside core use cases or services. |
| 22 | - Let `diwire` auto-wire concrete project classes. |
| 23 | - Let `diwire` auto-register `BaseRuntimeSettings` subclasses as root-scoped |
| 24 | singleton factories. Register a settings instance only for an intentional |
| 25 | test override or an explicitly prebuilt configuration object. |
| 26 | - Register only abstractions, external adapter bindings, gateway |
| 27 | implementations, factories, and instances that auto-wiring cannot infer. |
| 28 | Keep registration in private `_register_dependencies(...)` inside |
| 29 | `ioc/container.py`. |
| 30 | - Register the container instance itself with `provides=Container` only for the |
| 31 | FastAPI lifecycle shutdown dependency. |
| 32 | - Register concrete gateway implementations for their core `BaseGateway` ports. |
| 33 | - Register health readiness gateway implementations, such as |
| 34 | `SQLAlchemyReadinessCheckGateway`, for `ReadinessCheckGateway` when |
| 35 | `/readyz` needs infrastructure checks. |
| 36 | - Register unit-of-work managers for UoW abstractions. Persistence use cases |
| 37 | inject the manager and open the active UoW inside `execute(...)`; they do not |
| 38 | inject repositories, active UoWs, providers, SQLAlchemy sessions, engines, |
| 39 | session factories, or concrete infrastructure adapters directly. |
| 40 | - Unit tests receive a fresh native pytest `container` fixture built by the |
| 41 | project's real `get_container()`. Put project-wide test overrides in that |
| 42 | fixture and register scenario-specific overrides directly in the test before |
| 43 | resolving the target. |
| 44 | - Integration tests receive the transactional real-app `container` fixture. |
| 45 | They must use the real internal graph; do not mock internal use cases, |
| 46 | services, or capabilities. |
| 47 | - Use `container.resolve(...)` for normal synchronous graph construction, even |
| 48 | for targets with async methods; use `await container.aresolve(...)` only when |
| 49 | DI construction itself has async providers. |
| 50 | - One-off class-based test doubles live in the `test_*.py` module that uses |
| 51 | them. Reused unit-test doubles may live in mirrored |
| 52 | `tests/unit/core/<scope>/{capabilities,gateways,repositories}/fake_<source_module>.py` |
| 53 | modules. |
| 54 | - Inline `MagicMock` or `AsyncMock` in the test function when only one behavior |
| 55 | needs to change. |
| 56 | - Do not create DI-backed test factories, target harnesses, `harness.py`, |
| 57 | `tests/_support/fakes`, `tests/**/_fakes.py`, or fake modules outside |
| 58 | those mirrored unit port/capability packages. |
| 59 | - Keep tests on native pytest fixtures. Do not enable |
| 60 | `diwire.integrations.pytest_plugin`, and do not use `Injected[...]` |
| 61 | parameters in test functions. |
| 62 | - FastAPI async test helpers must enter `LifespanManager` and pass the yielded |
| 63 | manager's state-aware `manager.app` to the HTTPX2 `ASGITransport`. |
| 64 | |
| 65 | ## Code Style |
| 66 | |
| 67 | Use blank lines as logical separators in all code. Keep related statements |
| 68 | together, but separate independent setup, action, assertion, response, branch, |
| 69 | and transformation groups so long blocks stay readable. |
| 70 | |
| 71 | ## References |
| 72 | |
| 73 | - `references/diwire.md` - container code, registration examples, controller |
| 74 | composition, and test override patterns. |