pyproject.toml, and pytest. Covers project scaffolding, core abstractions with adapters, and verifying each module before proceeding to the next.
Invocation
What it produces
Src layout
src/packagename/ structure with py.typed marker, _types.py for shared types, core.py for framework-agnostic logic, and an adapters/ directory for framework-specific code.pyproject.toml
Hatchling build backend, optional dependency groups per integration, pytest configuration with
asyncio_mode = "auto", and Pyright type checking config.Explicit public API
__init__.py with __all__ listing only the names users need. Internal modules prefixed with _. Adapter __init__.py intentionally empty to prevent pulling in all framework deps.Pytest setup
One test file per source module,
conftest.py with shared fixtures, and a verification script to confirm the public API imports cleanly after pip install -e ".[dev]".Workflow
Scaffold the project
Create the src layout directory structure, write
pyproject.toml with [build-system], [project], and [project.optional-dependencies] sections, and add the py.typed PEP 561 marker file.Define the public API
Write
__init__.py with explicit imports and __all__. Only types and functions users need are exported. Internal modules use an underscore prefix (_internal.py) or live in a _private/ subdirectory.Implement core abstractions
Build protocols/ABCs, data classes, and shared types in
_types.py. These are the foundation all concrete implementations depend on.Use Protocol for duck-typed interfaces (not ABC) unless you need shared implementation. Every function parameter and return type must have a type annotation.Test core abstractions
Write pytest tests for all core types and protocols. Run
pytest and verify zero failures before proceeding to concrete modules.Implement concrete modules
Build one module at a time: proxy wrappers, provider clients, adapters. Use lazy imports for optional framework dependencies:
Test each module before the next
Write tests for the module just implemented. Run
pytest and verify zero failures before starting the next module.Install and verify
Run
pip install -e ".[dev]" and confirm the package imports correctly from a clean script:Self-review checklist
Before delivering, verify all of the following:- Project uses src layout:
src/packagename/notpackagename/at root pyproject.tomlexists with[build-system],[project], and[project.optional-dependencies]py.typedmarker file exists in the package directory__init__.pyhas explicit__all__listing only public names- Every public function and class has a type-hinted signature (all parameters and return type)
- Every module has a corresponding test file (
src/pkg/foo.py→tests/test_foo.py) pytest -vpasses with zero failurespip install -e ".[dev]"succeedspython -c "from packagename import ..."imports all public API names without error- No third-party imports in core modules that lack a corresponding optional dependency group
- Proxy/wrapper classes delegate unknown attributes via
__getattr__to the wrapped object
Golden rules
1. Src layout always
1. Src layout always
Every project uses
src/packagename/ structure. Never place the package at the repository root. This prevents accidental imports from the source directory instead of the installed package.2. Test before you proceed
2. Test before you proceed
Never implement module N+1 until module N has passing tests. Run
pytest after each module. This catches integration errors early instead of at the end.3. Explicit public API
3. Explicit public API
__init__.py must define __all__ and import only the names users need. Internal modules start with underscore (_internal.py) or live in a _private/ subdirectory. Never expose implementation details.4. Type hints on every signature
4. Type hints on every signature
Every function parameter and return type must have a type annotation. Use
Protocol for duck-typed interfaces, not ABC unless you need shared implementation.5. Optional dependencies in extras
5. Optional dependencies in extras
Third-party framework imports (langchain, chromadb, openai) must be in
[project.optional-dependencies] groups and imported lazily with try/except at usage point, not at module top level.6. Proxy delegates everything
6. Proxy delegates everything
Wrapper classes must implement
__getattr__ to forward unknown attribute access to the wrapped object. Never enumerate and re-implement every method — the proxy must work with future methods the wrapped library adds.