Repository navigation
feat: the Kaiten Python SDK - #2
Merged
Merged
Conversation
Alex (Alexkuva)
force-pushed
the
feat/kaiten-python-sdk
branch
2 times, most recently
from
September 30, 2026 18:56
adf7e30 to
eedbc3c
Compare
A typed Python client for both Kaiten APIs, generated and tested against the contract of kaitencloud/kaiten@fa7f554f. - Core API: KaitenClient and AsyncKaitenClient over 98 of the contract's 107 operations. Of the nine left out, three are the console's rule-editor tooling and four a signed-in person's notification feed and preferences, which kaiten's own SDK coverage test exempts for the same reasons; the other two are OFREP flag evaluation, which belongs to OpenFeature. - Platform API: KaitenPlatformClient and AsyncKaitenPlatformClient over all 10 operations. - License versioning: a license is a version of a license family, moved through DRAFT, PUBLISHED and ARCHIVED by publish(), archive() and unarchive(); license_families resolves a family to the version it serves, or to a pinned one. - Models for every response and each of the 55 published webhook events, generated from openapi/ by scripts/generate_models.py: snake_case attributes, lenient about fields and enum values the API adds after a release, and to_dict() for the exact wire shape. kaitencloud.types.Scope lists every scope an organization token can carry. - One implementation, two clients: src/kaitencloud/_sync is generated from _async by scripts/unasync.py, so they cannot drift. Behaviours: - list() walks every page at the API's maximum page size, and raises PaginationError rather than return a list the API said was incomplete. - Retries cover only what is safe to repeat. A usage report is never retried: replayed after a lost response, it would be usage counted twice. - Errors are typed and keep the RFC 9457 problem -- code, detail, errorId -- with ThresholdExceededError for a report refused at the license's cap. - A credential of the wrong class is refused before anything is sent. - The API address is required, as base_url or KAITEN_BASE_URL: every deployment has its own, and the SDK never guesses where to send a token. - Flags are defined here and evaluated through OpenFeature. Kaiten speaks OFREP, so the README shows openfeature-provider-ofrep rather than a second client for the same endpoint. examples/playbook.py walks a deployment of your own from end to end, one resumable step at a time, and deletes what it created; examples/README.md explains how to run it. Tests: 744, none of which opens a socket. Every mapped operation is called on both clients against a fake API that answers the way the contract says, and every request body is validated against the operation's own JSON Schema, once with all arguments and once with only the required ones. The README's examples and links, and every file's license notice, are checked too. Licensed under Apache-2.0; contributions are certified under the Developer Certificate of Origin, which .github/workflows/dco.yml checks on every pull request with no third-party app (CONTRIBUTING.md, DCO.md, SECURITY.md, NOTICE). Signed-off-by: Alexandre Bergere <[email protected]>
Alex (Alexkuva)
force-pushed
the
feat/kaiten-python-sdk
branch
from
September 30, 2026 19:33
eedbc3c to
79c92bc
Compare
Kevin Gonnord (Lleios)
approved these changes
Sep 30, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The Kaiten Python SDK:
kaitencloud, a typed client for both Kaiten APIs, generated and testedagainst the contract of kaitencloud/kaiten@fa7f554f, its
mainof 2026-09-29.The README is the guide; this description is what to look at when reviewing.
Coverage
get-targeting-context,lint-targeting-rule,test-targeting-rule) are the console's rule-editor tooling and four (listNotifications,markNotificationsRead,get/putNotificationPreferences) a signed-in person's own feed and preferences, all of which kaiten's own SDK coverage test exempts for the same reasons; the other two are OFREP, see belowopenapi/coverage.yamlmaps every operation to the method that calls it. The tests fail when anoperation is left unwrapped, when a mapped method is missing, and when a client grows a public
method nothing maps.
Beyond the resources themselves: license versioning (
licenses.publish/archive/unarchive, andlicense_familiesto resolve a family to the version it serves), models for all55 webhook events, and
kaitencloud.types.Scope, generated from the scopes the contract publishes.Decisions worth a second opinion
kaitencloud, notkaiten.kaitenon PyPI is a third-party client forkaiten.ru, so it can never be ours.
docs/content/docs/sdks/python.mdxstill promisespip install kaitenand a draft API; it needs rewriting.POST /api/webhooksand friends areserved by
saas-apiand are outside the published contract, so nothing here could test themagainst it. Verifying deliveries is included.
update()mirrors the API'sPUT: it replaces. The docstrings say so field by field,including the two exceptions on instances, where an omitted slug or deployment zone is kept.
evaluateFlagandevaluateFlagsBulkare deliberately unwrapped: Kaiten implements OFREP so that anyOpenFeature SDK can read its flags through the generic provider, and a method here would be
a second, worse client for the same endpoint. The README and the playbook show
openfeature-provider-ofrepwith the same URL and token.base_urlorKAITEN_BASE_URL, and a clear error namingboth when neither is set: every deployment has its own address, and the SDK never guesses
where to send a token. go-sdk takes it as a required argument too.
repository is the first. LICENSE (the apache.org text, byte for byte), NOTICE, DCO.md,
CONTRIBUTING.md, SECURITY.md, a pull request template, and a DCO check the repository owns
(
.github/workflows/dco.yml, no third-party app); every Python file opens with# SPDX-License-Identifier: Apache-2.0, generated ones included, and a test keeps it so.For the repositories that follow: go-sdk's and cli's current LICENSE reword section 9, so take
the pack's.
How it stays true to the API
openapi/holds a snapshot of both contracts, copied bytask sync:openapifrom a kaitencheckout, with the commit recorded in
openapi/source.yaml.scripts/generate_models.py), and the sync client from theasync source (
scripts/unasync.py). CI fails if either is stale.validated against the operation's JSON Schema with readOnly properties removed — so a key too
many or a required key missing fails here rather than as a 422 in production.
The playbook
examples/playbook.pyis the part to try by hand. Thirteen steps walk a deployment end to end —catalog, license and a second version of it, customer, component, release, zone, metadata field,
instance — meter usage until the license refuses a report, evaluate a flag through OpenFeature,
mint and revoke a token, verify a webhook signature, then delete what the run made. Each step
prints the SDK call before it makes it;
examples/README.mdexplains how to run it.Resources are named after the run and recorded in
.kaiten-playbook.json, so runs never collide,--fromresumes where you stopped, andcleanup— never included by a bare run or by--from—deletes only what that file records.
tests/test_playbook.pyruns every step against the samecontract-backed fake as the rest of the suite, and
mypy --strictcoversexamples/, so theexample cannot rot.
Verification
(httpx 0.27, pydantic 2.11).
ruff,ruff format --check,mypy --strict, the generated-code checks, anduv build+twine check --strictall pass —task checkruns the lot. The wheel and thesdist both ship LICENSE and NOTICE.
svixlibrary and its published referencevector.
subprocess, against a server that answers with the contract's own samples, which checks the
script, not a deployment.
Before release
the whole organization), so commits made on github.com carry a sign-off too.
main'sdefault-branchruleset requires the checkslint,buildandtest, which theCI reports under exactly those names. After this merges, add
DCOwith GitHub Actions as itssource: the workflow runs as it is on
main(pull_request_target), so a pull requestcannot edit the check that judges it, and it starts with the first pull request after this
one. This one's commit is signed off already.
workflow's, under the same name.
git commit -s.offers it on public repositories only, so it comes with making this one public; until then,
reports go to [email protected], the other channel.
publishes it.
kaitencloudand apypienvironment on thisrepository; the release workflow then runs on a
v*tag.🤖 Generated with Claude Code · ✅ Tested and approved by Alex (@Alexkuva), maintainer