Contributing, testing, and release checks
The published documentation is exactly the pages listed in mkdocs.yml. The
guide and the generated API reference are the authority on the public
interface. Planning notes and experiments (docs/superpowers/, .superpowers/,
spikes/) are git-ignored and are never versioned or published.
Locked setup
Kenkui supports CPython 3.11 through 3.13. Install uv, then use the committed lock as authority:
uv lock --check
uv sync --frozen --all-groups
Do not refresh uv.lock as a side effect of an unrelated change. When a
dependency update is intentional, explain the pin/lock change and rerun the full
matrix-relevant gates.
Deterministic default gates
uv run ruff format --check .
uv run ruff check .
uv run mypy
uv run pytest
uv run mkdocs build --strict
Mypy is strict. Pytest enables branch coverage and fails below 90%; default test
configuration excludes the native marker. Tests must not need network,
credentials, user caches, model assets, or gated terms. Add/update deterministic
tests with implementation changes and keep imports from the documented public
facade in public API examples/smoke tests.
The scripts in examples/ are part of the documentation and are held to the
same gates: ruff lints them and strict mypy type-checks them against the
public API, so an API change that breaks an example fails CI. Update the
matching example and guide section whenever public behavior changes.
Opt-in tiers
Further tiers need local resources and never run in ordinary CI:
- Real Pocket inference.
KENKUI_RUN_PROVISIONING_REAL=1 uv run pytest --no-cov tests/test_voice_provisioning_real.pydownloads real assets and renders a real M4B. - spaCy roster.
uv run --extra spacy python -m spacy download en_core_web_lg, thenuv run --extra spacy pytest --no-cov -m spacy. The offline roster module is omitted from default coverage because these tests need that pipeline. - Corpus.
KENKUI_RUN_CORPUS=1 uv run pytest --no-cov -m corpusruns property tests over a local EPUB library, found at~/Calibre Libraryor the directory named byKENKUI_CORPUS_LIBRARY.
Native FFmpeg tier
Install/check host ffmpeg and ffprobe first, then opt in explicitly:
KENKUI_RUN_NATIVE=1 uv run pytest --no-cov -m native tests/test_native_ffmpeg.py
This runs generated fake PCM through the production FFmpeg shell and independently probes/full-decodes the resulting M4B. It is native FFmpeg acceptance, not real Pocket inference.
Documentation
uv run mkdocs build --strict
Strict mode must be warning-free. A theme package may print its own upstream informational notice; do not suppress project warnings to hide broken links/nav.
Distribution checks
Build does not need network after the locked environment is present:
uv build
uv run twine check dist/*
uv run check-wheel-contents dist/*.whl
Inspect both archives before publishing. The sdist intentionally includes source,
documentation, examples, README, changelog, contribution guide, MkDocs config,
Apache-2.0 LICENSE/NOTICE, project metadata, and the lock; it excludes
tests. The wheel includes only the package/public code and typing marker
plus required distribution metadata/licenses. Neither archive may contain tests,
virtual environments, temporary/build/site/cache files, credentials, .env
files, auth tokens, model/voice assets, or generated evidence.
Install the built wheel (not the source tree) in a fresh compatible Python 3.11,
3.12, or 3.13 environment with dependencies, import only kenkui public names,
and exercise constructor/validation/EPUB inspection. An isolated installation
without provisioned model/voice assets must reject production writing with a
stable resource error. Real Pocket inference is a separate opt-in acceptance
check; it is not a runtime approval switch.
CI runs these checks, including the isolated wheel smoke, on every push. Never add Pocket secrets or assets merely to make CI green.
Releasing
Versions follow Semantic Versioning, and every
user-visible change gets a line under ## [Unreleased] in CHANGELOG.md in
the same pull request.
- Move the
Unreleasedentries under a new## [X.Y.Z] - YYYY-MM-DDheading, and update the comparison links at the bottom of the file. - Set
versioninpyproject.tomland__version__insrc/kenkui/__init__.py, then runuv lock.tests/test_package.pyasserts that the two agree. - Merge to
mainand wait for CI to pass. - Tag the merge commit and push the tag:
git tag -s vX.Y.Z -m "Kenkui X.Y.Z"
git push origin vX.Y.Z
The Release workflow checks that the tag matches the package version, builds
the sdist and wheel, publishes them to PyPI through trusted publishing (no API
token is stored anywhere), and creates a GitHub release whose notes are that
version's changelog section. The Docs workflow republishes the documentation
site on every push to main.
DCO and license
Contributions require a Developer Certificate of Origin 1.1 sign-off:
git commit --signoff
The trailer must use your real name and an email address you control. By contributing, you agree that your contribution is licensed under Apache-2.0. Model/voice materials are not accepted without separate provenance and rights review.