Repo: sdk-python
Rendered from spec at76d46f3 (2026-10-25) · its source · Edit this page
Status: Accepted
The Python client for lemonfiber’s web API, with an asynchronous and a synchronous client over one generated contract. Python, Hippocratic 3.0.
Implements: the client half of the
web API contract, as a peer of
sdk-ts and sdk-php.
What this repo is
A library with no user interface and no server. It speaks the
web API and exposes it as typed calls, a typed
event stream, and typed errors. Its first consumer is
integration-home-assistant, and it is written so that a
script can use it too.
It is a peer of the other SDKs, not a translation of either (ADR-0013). An SDK that disagrees with the contract is wrong.
Two clients, one contract
| Client | Transport | Why |
|---|---|---|
| Asynchronous | aiohttp, with a session the caller may supply |
Home Assistant is asynchronous throughout and gives an integration its own session |
| Synchronous | urllib3 |
A script should not need an event loop to read a disk figure |
Both are built from the same generated shapes and the same written behaviour, and both are held to the same tests: each behaviour the async client has is asserted of the sync client too.
What is generated and what is written
The split is the same in every SDK (ADR-0014):
Generated into src/lemonfiber/_generated/, never edited by hand |
Response shapes, endpoint paths and parameters, action names, event names, the wire version |
| Written, once, in Python | The stream’s behaviour, the token’s placement, the pin, the error model’s wording |
Everything generated comes from the contract/web-api/ directory. A generator run that changes
anything committed fails CI.
What it owns
- The stream: heartbeat detection (
ARCH-R50), resumption, and marking values held across a reconnect gap as stale rather than current (ARCH-R51). - The token: a per-run token, a session or an integration key
(C10), supplied by the
caller, sent in
X-Lemonfiber-Token, never placed in a URL (ARCH-R52). - Loopback, or an address a pin vouches for: a non-loopback host is refused unless the
caller gave that stack’s certificate pin, and the pin is checked against the peer’s
certificate after the handshake and before any request is written (
ARCH-R60,ARCH-R99, ADR-0025). The async client usesaiohttp.Fingerprintand the sync clienturllib3’sassert_fingerprint. The pin is given when a client is built, and no argument or setting weakens verification. - The refusal on mismatch: a wire version it cannot speak names both versions and
returns nothing (
ARCH-R55).
What it must not own
- Rendering or presentation. Home Assistant draws entities, a script prints. Neither is this library’s business.
- Policy. It reports what the core said.
- State beyond the stream. No caching, no reconciliation.
Quality bar
The same standard as the other SDKs, in Python’s equivalents:
pyrightin strict mode with no suppressions, andruffwith its full rule set and the formatter enforced.pytestat 100% line and branch coverage, enforced as a gate.- Mutation testing with a minimum score, run in CI.
- Architecture tests that keep generated code generated and transports behind the client.
- A backward-compatibility check against the last commit a consumer pins, and a changelog.
- The organisation’s shared workflows: spec-check, DCO, commitlint, hygiene, security, attribution, workflow pins, Sonar and CodeQL.
Runtime dependencies are aiohttp and urllib3 and nothing else without a recorded reason.
The supported Python versions start at the oldest one Home Assistant’s current release
supports.
Publishing
Not published to a package registry. Consumers take it by commit:
integration-home-assistant vendors the generated client at a pinned commit, with a drift
check that fails when the pin is behind what the core serves.