Situation
A library whose autocompletion does not work is a library people copy examples from and guess at. Protocol-heavy interfaces and decorator-based tools are exactly the shapes that lose type information, so a @tool-decorated function or an agent.run() result can arrive as Any in an editor — and the typed-boundary rule stops being enforced at the one moment enforcing it is free.
Task
User or System Story
As a engineer writing agent code in an editor
I want the public API to carry full type information end to end, verified by a conformance suite
So that autocompletion, inline signatures and static errors work, and structured-output guarantees are enforced before the code ever runs
Scope
In scope
py.typed shipped in the wheel and re-export hygiene via __all__, so imports resolve to stable documented paths
@tool typed with ParamSpec and TypeVar so the decorated callable keeps its original signature and its generated schema type stays inferable
Agent[InputT, OutputT] generic so run() is inferred as the declared output model rather than a union or Any
Literal and TypedDict for task classes, config keys and provider names, so a typo is a static error not a runtime routing failure
- Overloads distinguishing streaming from non-streaming run, so each returns a precise type
- A typing conformance suite of assert-type cases run in CI under both
mypy --strict and pyright strict, across every supported Python version
- Deprecation shims annotated so editors surface the replacement, consistent with the documented deprecation policy
Out of scope
- Documentation content and tutorials, owned by the docs workstream
- Runtime validation behaviour, owned by the core and runtime epics
- Editor plugins or language-server extensions
Acceptance Criteria
Primary Scenario
Given a consumer project on mypy --strict defining a @tool that returns a Pydantic model and an Agent[TripRequest, TripPlan]
When the project is type-checked
Then agent.run(...) is inferred as TripPlan, the decorated tool retains its original parameter types, and passing a wrong argument type is reported at the call site rather than at runtime
Failure or Validation Scenario
Given a consumer passes an unknown task class or a mistyped config key
When the project is type-checked
Then type checking fails with a Literal mismatch listing the allowed values, instead of the mistake surfacing later inside provider routing
Edge Cases
from __future__ import annotations and postponed evaluation of annotations
Any leaking in through a third-party adapter without stubs, which must be contained at the adapter boundary
- Generic behaviour differences between supported Python versions
- Cases where
pyright strict and mypy --strict legitimately disagree and one must be declared authoritative
- Decorated tools with default, keyword-only or variadic parameters
Engineering Guardrails
Complete the applicable items before the story is closed.
Code Quality
Test-Driven Development
Automated Testing
Security and Access
Public API Obligations
Performance and Reliability
Observability
Documentation
Result
- Expected user or system outcome: A kit consumer gets working autocompletion, accurate inline signatures and static errors for wrong tool arguments or config keys.
- Expected business or operational outcome: The typed-boundary non-negotiable is enforced by the type checker in every consuming repository, catching a class of defects before any test runs.
- Success metric or validation method: Typing conformance suite green under both strict type checkers on all supported Python versions; no
Any in the public API surface per the typing coverage report
- Monitoring period, where applicable: Reviewed at the M5 milestone against typing coverage of the public API and consumer type-check adoption
Pull Request Evidence
The pull request should include:
Definition of Done
The story is complete when:
Exceptions
For any guardrail marked not applicable, record:
Guardrail:
Reason:
Alternative validation:
Residual risk:
Approved by:
Situation
A library whose autocompletion does not work is a library people copy examples from and guess at. Protocol-heavy interfaces and decorator-based tools are exactly the shapes that lose type information, so a
@tool-decorated function or anagent.run()result can arrive asAnyin an editor — and the typed-boundary rule stops being enforced at the one moment enforcing it is free.Task
User or System Story
As a engineer writing agent code in an editor
I want the public API to carry full type information end to end, verified by a conformance suite
So that autocompletion, inline signatures and static errors work, and structured-output guarantees are enforced before the code ever runs
Scope
In scope
py.typedshipped in the wheel and re-export hygiene via__all__, so imports resolve to stable documented paths@tooltyped withParamSpecandTypeVarso the decorated callable keeps its original signature and its generated schema type stays inferableAgent[InputT, OutputT]generic sorun()is inferred as the declared output model rather than a union orAnyLiteralandTypedDictfor task classes, config keys and provider names, so a typo is a static error not a runtime routing failuremypy --strictandpyrightstrict, across every supported Python versionOut of scope
Acceptance Criteria
Primary Scenario
Given a consumer project on
mypy --strictdefining a@toolthat returns a Pydantic model and anAgent[TripRequest, TripPlan]When the project is type-checked
Then
agent.run(...)is inferred asTripPlan, the decorated tool retains its original parameter types, and passing a wrong argument type is reported at the call site rather than at runtimeFailure or Validation Scenario
Given a consumer passes an unknown task class or a mistyped config key
When the project is type-checked
Then type checking fails with a
Literalmismatch listing the allowed values, instead of the mistake surfacing later inside provider routingEdge Cases
from __future__ import annotationsand postponed evaluation of annotationsAnyleaking in through a third-party adapter without stubs, which must be contained at the adapter boundarypyrightstrict andmypy --strictlegitimately disagree and one must be declared authoritativeEngineering Guardrails
Complete the applicable items before the story is closed.
Code Quality
Test-Driven Development
Automated Testing
Security and Access
Public API Obligations
mypy --strict.import-linterlayering contract still passes.Performance and Reliability
Observability
Documentation
Result
Anyin the public API surface per the typing coverage reportPull Request Evidence
The pull request should include:
Definition of Done
The story is complete when:
Exceptions
For any guardrail marked not applicable, record:
Guardrail:
Reason:
Alternative validation:
Residual risk:
Approved by: