readio 0.2.2__tar.gz → 0.2.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. {readio-0.2.2 → readio-0.2.3}/.github/workflows/codecov.yml +1 -2
  2. readio-0.2.3/.github/workflows/python-publish.yml +49 -0
  3. {readio-0.2.2 → readio-0.2.3}/.github/workflows/tests.yml +25 -6
  4. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/events/events.jsonl +5 -0
  5. readio-0.2.3/.ledger/releaseledger/data/ledgers/main/releases/v0.2.3/entries/entry-0001.md +29 -0
  6. readio-0.2.3/.ledger/releaseledger/data/ledgers/main/releases/v0.2.3/entries/entry-0002.md +27 -0
  7. readio-0.2.3/.ledger/releaseledger/data/ledgers/main/releases/v0.2.3/entries/entry-0003.md +27 -0
  8. readio-0.2.3/.ledger/releaseledger/data/ledgers/main/releases/v0.2.3/entries/entry-0004.md +30 -0
  9. readio-0.2.3/.ledger/releaseledger/data/ledgers/main/releases/v0.2.3/release.md +27 -0
  10. {readio-0.2.2/readio.egg-info → readio-0.2.3}/PKG-INFO +39 -7
  11. {readio-0.2.2 → readio-0.2.3}/README.md +36 -4
  12. {readio-0.2.2 → readio-0.2.3}/docs/changelog.md +20 -1
  13. {readio-0.2.2 → readio-0.2.3}/docs/index.md +23 -4
  14. {readio-0.2.2 → readio-0.2.3}/llm-guides/README.md +2 -2
  15. {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/audio-drama.md +2 -2
  16. {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/debate-pro-con.md +2 -2
  17. {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/document-summary.md +2 -2
  18. {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/dramatic-story.md +2 -2
  19. {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/educational-explainer.md +2 -2
  20. {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/funny-story.md +2 -2
  21. {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/general-narration.md +2 -2
  22. {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/guided-meditation.md +2 -2
  23. {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/kids-story.md +2 -2
  24. {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/language-learning.md +2 -2
  25. {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/news-briefing.md +2 -2
  26. {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/podcast-interview.md +2 -2
  27. {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/podcast-roundtable.md +2 -2
  28. {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/podcast-solo.md +2 -2
  29. {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/quiz-trivia.md +2 -2
  30. {readio-0.2.2 → readio-0.2.3}/pyproject.toml +2 -2
  31. {readio-0.2.2 → readio-0.2.3}/readio/audio.py +17 -0
  32. {readio-0.2.2 → readio-0.2.3}/readio/cli.py +131 -14
  33. {readio-0.2.2 → readio-0.2.3}/readio/config.py +57 -0
  34. {readio-0.2.2 → readio-0.2.3}/readio/formats.py +3 -0
  35. readio-0.2.3/readio/logging_config.py +50 -0
  36. {readio-0.2.2 → readio-0.2.3}/readio/models.py +27 -6
  37. {readio-0.2.2 → readio-0.2.3}/readio/plan.py +208 -10
  38. {readio-0.2.2 → readio-0.2.3}/readio/reader.py +66 -11
  39. {readio-0.2.2 → readio-0.2.3}/readio/spotify.py +5 -0
  40. {readio-0.2.2 → readio-0.2.3}/readio/spotify_cli.py +8 -0
  41. {readio-0.2.2 → readio-0.2.3}/readio/ssmd.py +33 -0
  42. {readio-0.2.2 → readio-0.2.3}/readio/synthesis.py +47 -1
  43. {readio-0.2.2 → readio-0.2.3/readio.egg-info}/PKG-INFO +39 -7
  44. {readio-0.2.2 → readio-0.2.3}/readio.egg-info/SOURCES.txt +9 -1
  45. {readio-0.2.2 → readio-0.2.3}/readio.egg-info/requires.txt +2 -2
  46. {readio-0.2.2 → readio-0.2.3}/readio.egg-info/scm_file_list.json +9 -1
  47. readio-0.2.3/readio.egg-info/scm_version.json +8 -0
  48. {readio-0.2.2 → readio-0.2.3}/skill/readio/SKILL.md +4 -2
  49. {readio-0.2.2 → readio-0.2.3}/skill/readio/references/cli.md +16 -2
  50. {readio-0.2.2 → readio-0.2.3}/skill/readio/references/troubleshooting.md +18 -3
  51. {readio-0.2.2 → readio-0.2.3}/tests/test_config.py +8 -1
  52. {readio-0.2.2 → readio-0.2.3}/tests/test_llm_guides.py +2 -2
  53. readio-0.2.3/tests/test_logging_cli.py +136 -0
  54. {readio-0.2.2 → readio-0.2.3}/tests/test_manifest.py +28 -0
  55. readio-0.2.3/tests/test_packaging_metadata.py +30 -0
  56. {readio-0.2.2 → readio-0.2.3}/tests/test_plan.py +2 -1
  57. {readio-0.2.2 → readio-0.2.3}/tests/test_pykokoro_09_contract.py +11 -7
  58. {readio-0.2.2 → readio-0.2.3}/tests/test_pykokoro_09_regressions.py +5 -5
  59. readio-0.2.3/tests/test_pykokoro_09_support.py +231 -0
  60. {readio-0.2.2 → readio-0.2.3}/tests/test_reader_synthesis.py +24 -0
  61. {readio-0.2.2 → readio-0.2.3}/tests/test_synthesis.py +1 -1
  62. readio-0.2.2/.github/workflows/python-publish.yml +0 -30
  63. readio-0.2.2/CHANGELOG.md +0 -18
  64. readio-0.2.2/readio.egg-info/scm_version.json +0 -8
  65. {readio-0.2.2 → readio-0.2.3}/.codecrate.toml +0 -0
  66. {readio-0.2.2 → readio-0.2.3}/.github/workflows/pre-commit.yml +0 -0
  67. {readio-0.2.2 → readio-0.2.3}/.gitignore +0 -0
  68. {readio-0.2.2 → readio-0.2.3}/.ledger/documentledger/.ledger-project.toml +0 -0
  69. {readio-0.2.2 → readio-0.2.3}/.ledger/documentledger/config.toml +0 -0
  70. {readio-0.2.2 → readio-0.2.3}/.ledger/documentledger/data/.ledger-project.toml +0 -0
  71. {readio-0.2.2 → readio-0.2.3}/.ledger/documentledger/data/docs/docs-changelog-md-77f023b9.yaml +0 -0
  72. {readio-0.2.2 → readio-0.2.3}/.ledger/documentledger/data/docs/docs-index-md-b4d68dc8.yaml +0 -0
  73. {readio-0.2.2 → readio-0.2.3}/.ledger/documentledger/data/docs/readme-md-b3356305.yaml +0 -0
  74. {readio-0.2.2 → readio-0.2.3}/.ledger/documentledger/data/scan.yaml +0 -0
  75. {readio-0.2.2 → readio-0.2.3}/.ledger/documentledger/data/source-index.json +0 -0
  76. {readio-0.2.2 → readio-0.2.3}/.ledger/documentledger/data/storage.yaml +0 -0
  77. {readio-0.2.2 → readio-0.2.3}/.ledger/ledger.toml +0 -0
  78. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/.ledger-project.toml +0 -0
  79. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/config.toml +0 -0
  80. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/.ledger-project.toml +0 -0
  81. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.0/audit/commit-audit.yaml +0 -0
  82. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.0/entries/entry-0001.md +0 -0
  83. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.0/entries/entry-0002.md +0 -0
  84. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.0/entries/entry-0003.md +0 -0
  85. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.0/entries/entry-0004.md +0 -0
  86. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.0/entries/entry-0005.md +0 -0
  87. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.0/release.md +0 -0
  88. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.1/audit/commit-audit.yaml +0 -0
  89. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.1/entries/entry-0001.md +0 -0
  90. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.1/release.md +0 -0
  91. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.2/audit/commit-audit.yaml +0 -0
  92. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.2/entries/entry-0001.md +0 -0
  93. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.2/entries/entry-0002.md +0 -0
  94. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.2/entries/entry-0003.md +0 -0
  95. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.2/entries/entry-0004.md +0 -0
  96. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.2/release.md +0 -0
  97. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.3/audit/commit-audit.yaml +0 -0
  98. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.3/entries/entry-0001.md +0 -0
  99. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.3/entries/entry-0002.md +0 -0
  100. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.3/release.md +0 -0
  101. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.0/audit/commit-audit.yaml +0 -0
  102. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.0/entries/entry-0001.md +0 -0
  103. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.0/entries/entry-0002.md +0 -0
  104. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.0/entries/entry-0003.md +0 -0
  105. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.0/entries/entry-0004.md +0 -0
  106. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.0/entries/entry-0005.md +0 -0
  107. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.0/entries/entry-0006.md +0 -0
  108. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.0/release.md +0 -0
  109. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.1/audit/commit-audit.yaml +0 -0
  110. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.1/entries/entry-0001.md +0 -0
  111. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.1/release.md +0 -0
  112. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.2/audit/commit-audit.yaml +0 -0
  113. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.2/entries/entry-0001.md +0 -0
  114. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.2/entries/entry-0002.md +0 -0
  115. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.2/entries/entry-0003.md +0 -0
  116. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.2/entries/entry-0004.md +0 -0
  117. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.2/entries/entry-0005.md +0 -0
  118. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.2/entries/entry-0006.md +0 -0
  119. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.2/entries/entry-0007.md +0 -0
  120. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.2/release.md +0 -0
  121. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/work/v0.2.0/audit-decisions.yaml +0 -0
  122. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/work/v0.2.0/audit.yaml +0 -0
  123. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/work/v0.2.0/entries.yaml +0 -0
  124. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/work/v0.2.0/evidence/4ecf165.patch +0 -0
  125. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/work/v0.2.0/evidence/manifest.json +0 -0
  126. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/work/v0.2.0/range.json +0 -0
  127. {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/write.lock +0 -0
  128. {readio-0.2.2 → readio-0.2.3}/.ledger/taskledger/.ledger-project.toml +0 -0
  129. {readio-0.2.2 → readio-0.2.3}/.ledger/taskledger/config.toml +0 -0
  130. {readio-0.2.2 → readio-0.2.3}/.pre-commit-config.yaml +0 -0
  131. {readio-0.2.2 → readio-0.2.3}/LICENSE +0 -0
  132. {readio-0.2.2 → readio-0.2.3}/docs/conf.py +0 -0
  133. {readio-0.2.2 → readio-0.2.3}/docs/make.py +0 -0
  134. {readio-0.2.2 → readio-0.2.3}/docs/requirements.txt +0 -0
  135. {readio-0.2.2 → readio-0.2.3}/examples/README.md +0 -0
  136. {readio-0.2.2 → readio-0.2.3}/examples/readio-podcast.ssmd +0 -0
  137. {readio-0.2.2 → readio-0.2.3}/examples/readio-prosody.ssmd +0 -0
  138. {readio-0.2.2 → readio-0.2.3}/readio/__init__.py +0 -0
  139. {readio-0.2.2 → readio-0.2.3}/readio/__main__.py +0 -0
  140. {readio-0.2.2 → readio-0.2.3}/readio/document.py +0 -0
  141. {readio-0.2.2 → readio-0.2.3}/readio/errors.py +0 -0
  142. {readio-0.2.2 → readio-0.2.3}/readio/ingest.py +0 -0
  143. {readio-0.2.2 → readio-0.2.3}/readio/jsonutil.py +0 -0
  144. {readio-0.2.2 → readio-0.2.3}/readio/manifest.py +0 -0
  145. {readio-0.2.2 → readio-0.2.3}/readio/markdown.py +0 -0
  146. {readio-0.2.2 → readio-0.2.3}/readio/paths.py +0 -0
  147. {readio-0.2.2 → readio-0.2.3}/readio/progress.py +0 -0
  148. {readio-0.2.2 → readio-0.2.3}/readio/resources/__init__.py +0 -0
  149. {readio-0.2.2 → readio-0.2.3}/readio/resources/templates/__init__.py +0 -0
  150. {readio-0.2.2 → readio-0.2.3}/readio/resources/templates/briefing.ssmd +0 -0
  151. {readio-0.2.2 → readio-0.2.3}/readio/resources/templates/dialogue.ssmd +0 -0
  152. {readio-0.2.2 → readio-0.2.3}/readio/resources/templates/podcast.ssmd +0 -0
  153. {readio-0.2.2 → readio-0.2.3}/readio/ssmd_authoring.py +0 -0
  154. {readio-0.2.2 → readio-0.2.3}/readio/templates.py +0 -0
  155. {readio-0.2.2 → readio-0.2.3}/readio/text.py +0 -0
  156. {readio-0.2.2 → readio-0.2.3}/readio/wave.py +0 -0
  157. {readio-0.2.2 → readio-0.2.3}/readio.egg-info/dependency_links.txt +0 -0
  158. {readio-0.2.2 → readio-0.2.3}/readio.egg-info/entry_points.txt +0 -0
  159. {readio-0.2.2 → readio-0.2.3}/readio.egg-info/top_level.txt +0 -0
  160. {readio-0.2.2 → readio-0.2.3}/setup.cfg +0 -0
  161. {readio-0.2.2 → readio-0.2.3}/skill/readio/references/input-formats.md +0 -0
  162. {readio-0.2.2 → readio-0.2.3}/skill/readio/references/spotify.md +0 -0
  163. {readio-0.2.2 → readio-0.2.3}/skill/readio/references/ssmd.md +0 -0
  164. {readio-0.2.2 → readio-0.2.3}/tests/conftest.py +0 -0
  165. {readio-0.2.2 → readio-0.2.3}/tests/fixtures/architecture-review.ssmd +0 -0
  166. {readio-0.2.2 → readio-0.2.3}/tests/fixtures/markdown/all-elements.md +0 -0
  167. {readio-0.2.2 → readio-0.2.3}/tests/fixtures/markdown/all-elements.txt +0 -0
  168. {readio-0.2.2 → readio-0.2.3}/tests/test_audio.py +0 -0
  169. {readio-0.2.2 → readio-0.2.3}/tests/test_audio_formats.py +0 -0
  170. {readio-0.2.2 → readio-0.2.3}/tests/test_chapters.py +0 -0
  171. {readio-0.2.2 → readio-0.2.3}/tests/test_cli.py +0 -0
  172. {readio-0.2.2 → readio-0.2.3}/tests/test_defaults_cli.py +0 -0
  173. {readio-0.2.2 → readio-0.2.3}/tests/test_doctor.py +0 -0
  174. {readio-0.2.2 → readio-0.2.3}/tests/test_document.py +0 -0
  175. {readio-0.2.2 → readio-0.2.3}/tests/test_examples.py +0 -0
  176. {readio-0.2.2 → readio-0.2.3}/tests/test_ffmpeg_sink.py +0 -0
  177. {readio-0.2.2 → readio-0.2.3}/tests/test_ingest.py +0 -0
  178. {readio-0.2.2 → readio-0.2.3}/tests/test_language_defaults_config.py +0 -0
  179. {readio-0.2.2 → readio-0.2.3}/tests/test_markdown.py +0 -0
  180. {readio-0.2.2 → readio-0.2.3}/tests/test_model_source_preference.py +0 -0
  181. {readio-0.2.2 → readio-0.2.3}/tests/test_models_cli.py +0 -0
  182. {readio-0.2.2 → readio-0.2.3}/tests/test_package_resources.py +0 -0
  183. {readio-0.2.2 → readio-0.2.3}/tests/test_paths.py +0 -0
  184. {readio-0.2.2 → readio-0.2.3}/tests/test_plan_cli.py +0 -0
  185. {readio-0.2.2 → readio-0.2.3}/tests/test_plan_no_tts_load.py +0 -0
  186. {readio-0.2.2 → readio-0.2.3}/tests/test_plan_validation.py +0 -0
  187. {readio-0.2.2 → readio-0.2.3}/tests/test_progress.py +0 -0
  188. {readio-0.2.2 → readio-0.2.3}/tests/test_reader_markdown.py +0 -0
  189. {readio-0.2.2 → readio-0.2.3}/tests/test_reader_selection.py +0 -0
  190. {readio-0.2.2 → readio-0.2.3}/tests/test_reader_ssmd.py +0 -0
  191. {readio-0.2.2 → readio-0.2.3}/tests/test_render_from_plan.py +0 -0
  192. {readio-0.2.2 → readio-0.2.3}/tests/test_render_manifest_cli.py +0 -0
  193. {readio-0.2.2 → readio-0.2.3}/tests/test_skill_integrity.py +0 -0
  194. {readio-0.2.2 → readio-0.2.3}/tests/test_spotify.py +0 -0
  195. {readio-0.2.2 → readio-0.2.3}/tests/test_spotify_cli.py +0 -0
  196. {readio-0.2.2 → readio-0.2.3}/tests/test_spotify_lifecycle.py +0 -0
  197. {readio-0.2.2 → readio-0.2.3}/tests/test_ssmd_cli.py +0 -0
  198. {readio-0.2.2 → readio-0.2.3}/tests/test_ssmd_integration.py +0 -0
  199. {readio-0.2.2 → readio-0.2.3}/tests/test_ssmd_model_roster.py +0 -0
  200. {readio-0.2.2 → readio-0.2.3}/tests/test_ssmd_preflight.py +0 -0
  201. {readio-0.2.2 → readio-0.2.3}/tests/test_ssmd_single_source.py +0 -0
  202. {readio-0.2.2 → readio-0.2.3}/tests/test_template_validate.py +0 -0
  203. {readio-0.2.2 → readio-0.2.3}/tests/test_templates.py +0 -0
  204. {readio-0.2.2 → readio-0.2.3}/tests/test_text.py +0 -0
  205. {readio-0.2.2 → readio-0.2.3}/tests/test_voice_resolution_workflow.py +0 -0
  206. {readio-0.2.2 → readio-0.2.3}/tests/test_voices_cli.py +0 -0
  207. {readio-0.2.2 → readio-0.2.3}/tests/test_wave.py +0 -0
@@ -16,8 +16,7 @@ jobs:
16
16
  cache: pip
17
17
  - name: Install Readio runtime dependencies
18
18
  run: |
19
- python -m pip install "ssmd @ git+https://github.com/buchwandler/ssmd.git@631aa5a03ba2b2fcb364272843f88a8738d36484"
20
- python -m pip install "pykokoro[playback] @ git+https://github.com/buchwandler/pykokoro.git@07fdd07f4cccff7ab58bbe1f5c801bebe8b41a85"
19
+ python -m pip install "pykokoro[playback]==0.9.4"
21
20
  - name: Install project and coverage tools
22
21
  run: |
23
22
  python -m pip install --upgrade pip
@@ -0,0 +1,49 @@
1
+ # Build and publish Readio when a GitHub Release is published.
2
+
3
+ name: Upload Python Package
4
+
5
+ on:
6
+ release:
7
+ types: [published]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ deploy:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - name: Check out release
17
+ uses: actions/checkout@v4
18
+ - name: Set up Python
19
+ uses: actions/setup-python@v5
20
+ with:
21
+ python-version: "3.13"
22
+ - name: Install build tooling
23
+ run: python -m pip install --upgrade pip build twine
24
+ - name: Build package
25
+ run: python -m build
26
+ - name: Validate artifact metadata
27
+ run: python -m twine check dist/*
28
+ - name: Validate release version
29
+ env:
30
+ RELEASE_TAG: ${{ github.event.release.tag_name }}
31
+ run: |
32
+ python - <<'PY'
33
+ import os
34
+ from pathlib import Path
35
+ from packaging.utils import parse_wheel_filename
36
+
37
+ expected = os.environ["RELEASE_TAG"].removeprefix("v")
38
+ wheels = list(Path("dist").glob("*.whl"))
39
+ assert len(wheels) == 1, f"expected one wheel, found {len(wheels)}"
40
+ _, version, _, _ = parse_wheel_filename(wheels[0].name)
41
+ assert str(version) == expected, (
42
+ f"wheel version {version} does not match release tag {expected}"
43
+ )
44
+ PY
45
+ - name: Publish package to PyPI
46
+ uses: pypa/gh-action-pypi-publish@v1.14.1
47
+ with:
48
+ password: ${{ secrets.PYPI_API_TOKEN }}
49
+ attestations: false
@@ -25,8 +25,7 @@ jobs:
25
25
  cache: pip
26
26
  - name: Install Readio runtime dependencies
27
27
  run: |
28
- python -m pip install "ssmd @ git+https://github.com/buchwandler/ssmd.git@631aa5a03ba2b2fcb364272843f88a8738d36484"
29
- python -m pip install "pykokoro[playback] @ git+https://github.com/buchwandler/pykokoro.git@07fdd07f4cccff7ab58bbe1f5c801bebe8b41a85"
28
+ python -m pip install "pykokoro[playback]==0.9.4"
30
29
  - name: Install project and test tools
31
30
  run: |
32
31
  python -m pip install --upgrade pip
@@ -34,6 +33,27 @@ jobs:
34
33
  - name: Run test suite
35
34
  run: python -m pytest -q
36
35
 
36
+
37
+ minimum-compatibility:
38
+ name: Minimum PyKokoro compatibility (Ubuntu, Python 3.10)
39
+ runs-on: ubuntu-latest
40
+ steps:
41
+ - uses: actions/checkout@v4
42
+ - name: Install PortAudio
43
+ run: sudo apt-get update && sudo apt-get install --yes portaudio19-dev
44
+ - name: Set up Python
45
+ uses: actions/setup-python@v5
46
+ with:
47
+ python-version: "3.10"
48
+ cache: pip
49
+ - name: Install minimum PyKokoro runtime
50
+ run: python -m pip install "pykokoro[playback]==0.9.4"
51
+ - name: Install project and test tools
52
+ run: |
53
+ python -m pip install --upgrade pip
54
+ python -m pip install -e ".[dev]"
55
+ - name: Run minimum-version test suite
56
+ run: python -m pytest -q
37
57
  quality:
38
58
  name: Static quality checks
39
59
  runs-on: ubuntu-latest
@@ -48,8 +68,7 @@ jobs:
48
68
  cache: pip
49
69
  - name: Install Readio runtime dependencies
50
70
  run: |
51
- python -m pip install "ssmd @ git+https://github.com/buchwandler/ssmd.git@631aa5a03ba2b2fcb364272843f88a8738d36484"
52
- python -m pip install "pykokoro[playback] @ git+https://github.com/buchwandler/pykokoro.git@07fdd07f4cccff7ab58bbe1f5c801bebe8b41a85"
71
+ python -m pip install "pykokoro[playback]==0.9.4"
53
72
  - name: Install development tools
54
73
  run: python -m pip install -e ".[dev]"
55
74
  - name: Ruff lint
@@ -81,9 +100,9 @@ jobs:
81
100
  shell: bash
82
101
  run: |
83
102
  python -m venv "${RUNNER_TEMP}/readio-wheel-smoke"
84
- "${RUNNER_TEMP}/readio-wheel-smoke/bin/python" -m pip install "ssmd @ git+https://github.com/buchwandler/ssmd.git@631aa5a03ba2b2fcb364272843f88a8738d36484"
85
- "${RUNNER_TEMP}/readio-wheel-smoke/bin/python" -m pip install "pykokoro[playback] @ git+https://github.com/buchwandler/pykokoro.git@07fdd07f4cccff7ab58bbe1f5c801bebe8b41a85"
103
+ "${RUNNER_TEMP}/readio-wheel-smoke/bin/python" -m pip install "pykokoro[playback]==0.9.4"
86
104
  "${RUNNER_TEMP}/readio-wheel-smoke/bin/python" -m pip install dist/*.whl
105
+ "${RUNNER_TEMP}/readio-wheel-smoke/bin/python" -m pip check
87
106
  cd "${RUNNER_TEMP}"
88
107
  "${RUNNER_TEMP}/readio-wheel-smoke/bin/python" - <<'PY'
89
108
  import importlib.metadata
@@ -55,3 +55,8 @@
55
55
  {"data":{"kind":"quality","status":"accepted"},"entry_id":"entry-0005","event":"entry.added","event_id":"event-0055","record_revisions":{"entry:v0.2.2/entry-0005":1,"release:v0.2.2":9},"release_version":"v0.2.2","schema_version":2}
56
56
  {"data":{"kind":"quality","status":"accepted"},"entry_id":"entry-0006","event":"entry.added","event_id":"event-0056","record_revisions":{"entry:v0.2.2/entry-0006":1,"release:v0.2.2":10},"release_version":"v0.2.2","schema_version":2}
57
57
  {"data":{"kind":"internal","status":"accepted"},"entry_id":"entry-0007","event":"entry.added","event_id":"event-0057","record_revisions":{"entry:v0.2.2/entry-0007":1,"release:v0.2.2":11},"release_version":"v0.2.2","schema_version":2}
58
+ {"data":{"status":"planned"},"event":"release.created","event_id":"event-0058","record_revisions":{"release:v0.2.3":1},"release_version":"v0.2.3","schema_version":2}
59
+ {"data":{"kind":"changed","status":"accepted"},"entry_id":"entry-0001","event":"entry.added","event_id":"event-0059","record_revisions":{"entry:v0.2.3/entry-0001":1,"release:v0.2.3":2},"release_version":"v0.2.3","schema_version":2}
60
+ {"data":{"kind":"quality","status":"accepted"},"entry_id":"entry-0002","event":"entry.added","event_id":"event-0060","record_revisions":{"entry:v0.2.3/entry-0002":1,"release:v0.2.3":3},"release_version":"v0.2.3","schema_version":2}
61
+ {"data":{"kind":"changed","status":"accepted"},"entry_id":"entry-0003","event":"entry.added","event_id":"event-0061","record_revisions":{"entry:v0.2.3/entry-0003":1,"release:v0.2.3":4},"release_version":"v0.2.3","schema_version":2}
62
+ {"data":{"kind":"docs","status":"accepted"},"entry_id":"entry-0004","event":"entry.added","event_id":"event-0062","record_revisions":{"entry:v0.2.3/entry-0004":1,"release:v0.2.3":5},"release_version":"v0.2.3","schema_version":2}
@@ -0,0 +1,29 @@
1
+ ---
2
+ schema_version: 2
3
+ object_type: release_entry
4
+ versioning:
5
+ schema_version: 1
6
+ revision: 1
7
+ entry_id: entry-0001
8
+ release_version: v0.2.3
9
+ kind: changed
10
+ summary:
11
+ Aligned Readio dependency metadata and CI with released PyKokoro 0.9.4 and
12
+ SSMD 0.8.7+
13
+ status: accepted
14
+ audience: null
15
+ scopes: []
16
+ source_refs:
17
+ - tl:task-0019
18
+ paths:
19
+ - pyproject.toml
20
+ - .github/workflows/tests.yml
21
+ - .github/workflows/codecov.yml
22
+ issues: []
23
+ prs: []
24
+ sources: []
25
+ contributors: []
26
+ breaking: false
27
+ internal: false
28
+ order: 1
29
+ ---
@@ -0,0 +1,27 @@
1
+ ---
2
+ schema_version: 2
3
+ object_type: release_entry
4
+ versioning:
5
+ schema_version: 1
6
+ revision: 1
7
+ entry_id: entry-0002
8
+ release_version: v0.2.3
9
+ kind: quality
10
+ summary: Added bounded PyKokoro compatibility and package metadata regression coverage
11
+ status: accepted
12
+ audience: null
13
+ scopes: []
14
+ source_refs: []
15
+ paths:
16
+ - tests/test_pykokoro_09_contract.py
17
+ - tests/test_pykokoro_09_support.py
18
+ - tests/test_packaging_metadata.py
19
+ issues: []
20
+ prs: []
21
+ sources:
22
+ - tl:task-0019
23
+ contributors: []
24
+ breaking: false
25
+ internal: false
26
+ order: 2
27
+ ---
@@ -0,0 +1,27 @@
1
+ ---
2
+ schema_version: 2
3
+ object_type: release_entry
4
+ versioning:
5
+ schema_version: 1
6
+ revision: 1
7
+ entry_id: entry-0003
8
+ release_version: v0.2.3
9
+ kind: changed
10
+ summary:
11
+ Hardened package publishing with artifact checks and release-tag version
12
+ validation
13
+ status: accepted
14
+ audience: null
15
+ scopes: []
16
+ source_refs: []
17
+ paths:
18
+ - .github/workflows/python-publish.yml
19
+ issues: []
20
+ prs: []
21
+ sources:
22
+ - tl:task-0019
23
+ contributors: []
24
+ breaking: false
25
+ internal: false
26
+ order: 3
27
+ ---
@@ -0,0 +1,30 @@
1
+ ---
2
+ schema_version: 2
3
+ object_type: release_entry
4
+ versioning:
5
+ schema_version: 1
6
+ revision: 1
7
+ entry_id: entry-0004
8
+ release_version: v0.2.3
9
+ kind: docs
10
+ summary:
11
+ Documented the PyKokoro support floor, 0.9.4 tested target, and supported
12
+ SSMD API
13
+ status: accepted
14
+ audience: null
15
+ scopes: []
16
+ source_refs: []
17
+ paths:
18
+ - README.md
19
+ - docs/index.md
20
+ - skill/readio/SKILL.md
21
+ - llm-guides
22
+ issues: []
23
+ prs: []
24
+ sources:
25
+ - tl:task-0019
26
+ contributors: []
27
+ breaking: false
28
+ internal: false
29
+ order: 4
30
+ ---
@@ -0,0 +1,27 @@
1
+ ---
2
+ schema_version: 2
3
+ object_type: release
4
+ versioning:
5
+ schema_version: 1
6
+ revision: 5
7
+ version: v0.2.3
8
+ status: planned
9
+ history_state: curated
10
+ title: Readio v0.2.3
11
+ released_at: null
12
+ previous_version: v0.2.2
13
+ cancel_reason: null
14
+ superseded_by: null
15
+ changelog_file: null
16
+ boundary_ref: null
17
+ source_refs: []
18
+ source_count: null
19
+ entry_count: 4
20
+ artifact_count: 0
21
+ git_base_ref: null
22
+ git_base_sha: null
23
+ git_head_ref: null
24
+ git_head_sha: null
25
+ git_range: null
26
+ git_commit_count: null
27
+ ---
@@ -1,19 +1,19 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: readio
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Read text aloud in the terminal with streaming TTS and an Agent Skill for LLM invocation
5
5
  License: Apache-2.0
6
6
  Requires-Python: >=3.10
7
7
  Description-Content-Type: text/markdown
8
8
  License-File: LICENSE
9
- Requires-Dist: pykokoro[playback]<0.10,>=0.9.1
9
+ Requires-Dist: pykokoro[playback]<0.10,>=0.9.2
10
10
  Requires-Dist: platformdirs>=4.0
11
11
  Requires-Dist: soundfile>=0.12
12
12
  Requires-Dist: tomli>=2.0; python_version < "3.11"
13
13
  Requires-Dist: typing_extensions>=4.0
14
14
  Requires-Dist: tomli-w>=1.0
15
15
  Requires-Dist: PyYAML>=6.0
16
- Requires-Dist: ssmd<0.9,>=0.8.6
16
+ Requires-Dist: ssmd<0.9,>=0.8.7
17
17
  Requires-Dist: markdown-it-py<5.0,>=3.0
18
18
  Requires-Dist: mdit-py-plugins<1.0,>=0.4
19
19
  Provides-Extra: cpu
@@ -95,7 +95,8 @@ The configuration contains reader settings, SSMD defaults, provider-specific voi
95
95
 
96
96
  ### Model discovery and language defaults
97
97
 
98
- PyKokoro 0.9.x is the runtime contract and owns the model, language, voice, quality, frontend, and named-lexicon catalog. Discovery is metadata-only and does not download model weights:
98
+ PyKokoro >=0.9.2,<0.10 is the runtime contract and owns the model, language, voice, quality, frontend, and named-lexicon catalog. Discovery is metadata-only and does not download model weights:
99
+ Readio v0.2.3 is tested against PyKokoro 0.9.4.
99
100
 
100
101
  ```bash
101
102
  readio models list --language de --offline
@@ -116,11 +117,30 @@ readio defaults show de-at --json
116
117
  readio render --lang de --file notes.md
117
118
  ```
118
119
 
119
- When a model is selected, Readio fills its normalized source, default voice, and preferred quality, then validates language compatibility, voice roster, quality, named lexicons, and experimental frontend permission before saving. `--no-lexicons` clears an inherited explicit selection. Repeat `--lexicon` to preserve ordered layered lookup.
120
+ When a model is selected, Readio fills its normalized source, default voice, and preferred quality, then validates language compatibility, voice roster, quality, named lexicons, and experimental frontend permission before saving. `--no-lexicons` selects explicit provider-only pronunciation (`lexicons=[]`); `--auto-lexicons` returns to PyKokoro language defaults (`lexicons=null`). Repeat `--lexicon` to preserve ordered layered lookup.
120
121
 
121
- Direct `speak`, `render`, and `spotify publish` options (`--model`, `--model-source`, `--quality`, repeatable `--lexicon`, `--no-lexicons`, and `--allow-experimental`) override persisted defaults. Use `--json` for automation; JSON preserves unknown lexicon capability as `null` rather than an empty list.
122
+ Direct `speak`, `render`, and `spotify publish` options (`--model`, `--model-source`, `--quality`, repeatable `--lexicon`, `--no-lexicons`, `--auto-lexicons`, `--g2p-fallback`, `--lexicon-data-policy`, `--language-detection`, and repeatable `--detect-language`) override persisted defaults. Use `--json` for automation; JSON preserves `null` versus `[]` for lexicon selection.
122
123
  `--model-source github|huggingface` selects the same distribution for discovery, validation, and runtime construction. Voices are model-scoped: the legacy global `reader.voice` is retained only for unchanged default-reader use; `--lang de` without a voice leaves PyKokoro free to choose the German model default.
123
124
 
125
+ Named lexicons use PyKokoro selectors, not backend asset IDs:
126
+
127
+ ```text
128
+ crane = named selection token
129
+ de-de:crane = language-qualified Lexphon asset resolved downstream
130
+ de-crane = separate acoustic model ID
131
+ ```
132
+
133
+ For reproducible German synthesis:
134
+
135
+ ```bash
136
+ readio models show de-thorsten
137
+ readio defaults set de --model de-thorsten --lexicon crane --g2p-fallback espeak --lexicon-data-policy auto
138
+ readio plan --file article.md --lang de --json
139
+ readio render --file article.md --lang de --model de-thorsten --no-lexicons --g2p-fallback espeak --format mp3
140
+ ```
141
+
142
+ The plan also records optional PyKokoro language detection. SSMD documents may use `language_detection: {mode: auto, languages: [de, en]}`; this routes pronunciation fragments while retaining the selected acoustic language.
143
+
124
144
  ## Templates
125
145
 
126
146
  Built-in templates are copied into the user template directory during initialization. They are user-owned and are not overwritten by normal initialization or package upgrades.
@@ -265,13 +285,25 @@ readio --json spotify status spotify:episode:abc --wait
265
285
  ```
266
286
 
267
287
  Progress includes the current phase, completed units, elapsed time, approximate ETA for bounded renders, generated audio duration, and finalization. Live renders show cumulative units without a percentage or ETA. `--json` keeps stdout to one result object; automatic progress is disabled in JSON mode, while explicit `--progress` remains stderr-only.
288
+
289
+ ## Verbose diagnostics
290
+
291
+ Use the global repeatable verbosity option for live operational diagnostics:
292
+
293
+ ```bash
294
+ readio -v speak "Hello"
295
+ readio -vv render episode.ssmd -o episode.mp3
296
+ readio speak "literal --verbose" --
297
+ ```
298
+
299
+ `-v` shows timestamped lifecycle records at INFO level. `-vv` enables DEBUG-level Readio and PyKokoro details; additional repetitions are clamped to DEBUG. Verbose records always go to stderr, so ordinary output and `--json` results remain on stdout and stay machine-parseable. `--progress` is a separate user-facing progress control. When verbose mode and progress are combined, progress uses line-oriented stderr records instead of in-place terminal rewriting. Logs can contain paths and model or voice identifiers, so review them before sharing and never treat verbose mode as permission to expose document text, audio, or credentials.
268
300
  When `-o` is supplied, its `.wav`, `.mp3`, `.m4a`, or `.ogg` suffix selects the encoder. Use `--format` when the output path is omitted or to select the automatic filename suffix. An explicit format and suffix must agree. Extensionless output paths receive the selected suffix, and unsupported suffixes fail before synthesis. Automatic names use the configured output directory and never overwrite an existing file. Explicit output remains atomic and requires `--force` for replacement.
269
301
 
270
302
  M4A output requires an `ffmpeg` executable on `PATH`. WAV uses PCM16, while MP3 and OGG use the installed SoundFile/libsndfile codecs.
271
303
 
272
304
  ## SSMD consumption and authoring checks
273
305
 
274
- For `.ssmd` inputs, Readio parses the document through SSMD 0.8.6 and passes a PyKokoro 0.9 `SSMDRenderConfig` containing only missing Readio role defaults. Document `voice_bindings` remain authoritative, invocation `--voice-bind` values override configured provider roles, and concrete targets must belong to the active model roster. Normal `speak`, `render`, and `spotify` commands do not invoke `ssmd create`, rewrite the source, or require generic round-trip validation.
306
+ For `.ssmd` inputs, Readio parses the document through the supported SSMD 0.8.x API and passes a PyKokoro 0.9 `SSMDRenderConfig` containing only missing Readio role defaults. Document `voice_bindings` remain authoritative, invocation `--voice-bind` values override configured provider roles, and concrete targets must belong to the active model roster. Normal `speak`, `render`, and `spotify` commands do not invoke `ssmd create`, rewrite the source, or require generic round-trip validation.
275
307
 
276
308
  Inspect a document before rendering:
277
309
 
@@ -68,7 +68,8 @@ The configuration contains reader settings, SSMD defaults, provider-specific voi
68
68
 
69
69
  ### Model discovery and language defaults
70
70
 
71
- PyKokoro 0.9.x is the runtime contract and owns the model, language, voice, quality, frontend, and named-lexicon catalog. Discovery is metadata-only and does not download model weights:
71
+ PyKokoro >=0.9.2,<0.10 is the runtime contract and owns the model, language, voice, quality, frontend, and named-lexicon catalog. Discovery is metadata-only and does not download model weights:
72
+ Readio v0.2.3 is tested against PyKokoro 0.9.4.
72
73
 
73
74
  ```bash
74
75
  readio models list --language de --offline
@@ -89,11 +90,30 @@ readio defaults show de-at --json
89
90
  readio render --lang de --file notes.md
90
91
  ```
91
92
 
92
- When a model is selected, Readio fills its normalized source, default voice, and preferred quality, then validates language compatibility, voice roster, quality, named lexicons, and experimental frontend permission before saving. `--no-lexicons` clears an inherited explicit selection. Repeat `--lexicon` to preserve ordered layered lookup.
93
+ When a model is selected, Readio fills its normalized source, default voice, and preferred quality, then validates language compatibility, voice roster, quality, named lexicons, and experimental frontend permission before saving. `--no-lexicons` selects explicit provider-only pronunciation (`lexicons=[]`); `--auto-lexicons` returns to PyKokoro language defaults (`lexicons=null`). Repeat `--lexicon` to preserve ordered layered lookup.
93
94
 
94
- Direct `speak`, `render`, and `spotify publish` options (`--model`, `--model-source`, `--quality`, repeatable `--lexicon`, `--no-lexicons`, and `--allow-experimental`) override persisted defaults. Use `--json` for automation; JSON preserves unknown lexicon capability as `null` rather than an empty list.
95
+ Direct `speak`, `render`, and `spotify publish` options (`--model`, `--model-source`, `--quality`, repeatable `--lexicon`, `--no-lexicons`, `--auto-lexicons`, `--g2p-fallback`, `--lexicon-data-policy`, `--language-detection`, and repeatable `--detect-language`) override persisted defaults. Use `--json` for automation; JSON preserves `null` versus `[]` for lexicon selection.
95
96
  `--model-source github|huggingface` selects the same distribution for discovery, validation, and runtime construction. Voices are model-scoped: the legacy global `reader.voice` is retained only for unchanged default-reader use; `--lang de` without a voice leaves PyKokoro free to choose the German model default.
96
97
 
98
+ Named lexicons use PyKokoro selectors, not backend asset IDs:
99
+
100
+ ```text
101
+ crane = named selection token
102
+ de-de:crane = language-qualified Lexphon asset resolved downstream
103
+ de-crane = separate acoustic model ID
104
+ ```
105
+
106
+ For reproducible German synthesis:
107
+
108
+ ```bash
109
+ readio models show de-thorsten
110
+ readio defaults set de --model de-thorsten --lexicon crane --g2p-fallback espeak --lexicon-data-policy auto
111
+ readio plan --file article.md --lang de --json
112
+ readio render --file article.md --lang de --model de-thorsten --no-lexicons --g2p-fallback espeak --format mp3
113
+ ```
114
+
115
+ The plan also records optional PyKokoro language detection. SSMD documents may use `language_detection: {mode: auto, languages: [de, en]}`; this routes pronunciation fragments while retaining the selected acoustic language.
116
+
97
117
  ## Templates
98
118
 
99
119
  Built-in templates are copied into the user template directory during initialization. They are user-owned and are not overwritten by normal initialization or package upgrades.
@@ -238,13 +258,25 @@ readio --json spotify status spotify:episode:abc --wait
238
258
  ```
239
259
 
240
260
  Progress includes the current phase, completed units, elapsed time, approximate ETA for bounded renders, generated audio duration, and finalization. Live renders show cumulative units without a percentage or ETA. `--json` keeps stdout to one result object; automatic progress is disabled in JSON mode, while explicit `--progress` remains stderr-only.
261
+
262
+ ## Verbose diagnostics
263
+
264
+ Use the global repeatable verbosity option for live operational diagnostics:
265
+
266
+ ```bash
267
+ readio -v speak "Hello"
268
+ readio -vv render episode.ssmd -o episode.mp3
269
+ readio speak "literal --verbose" --
270
+ ```
271
+
272
+ `-v` shows timestamped lifecycle records at INFO level. `-vv` enables DEBUG-level Readio and PyKokoro details; additional repetitions are clamped to DEBUG. Verbose records always go to stderr, so ordinary output and `--json` results remain on stdout and stay machine-parseable. `--progress` is a separate user-facing progress control. When verbose mode and progress are combined, progress uses line-oriented stderr records instead of in-place terminal rewriting. Logs can contain paths and model or voice identifiers, so review them before sharing and never treat verbose mode as permission to expose document text, audio, or credentials.
241
273
  When `-o` is supplied, its `.wav`, `.mp3`, `.m4a`, or `.ogg` suffix selects the encoder. Use `--format` when the output path is omitted or to select the automatic filename suffix. An explicit format and suffix must agree. Extensionless output paths receive the selected suffix, and unsupported suffixes fail before synthesis. Automatic names use the configured output directory and never overwrite an existing file. Explicit output remains atomic and requires `--force` for replacement.
242
274
 
243
275
  M4A output requires an `ffmpeg` executable on `PATH`. WAV uses PCM16, while MP3 and OGG use the installed SoundFile/libsndfile codecs.
244
276
 
245
277
  ## SSMD consumption and authoring checks
246
278
 
247
- For `.ssmd` inputs, Readio parses the document through SSMD 0.8.6 and passes a PyKokoro 0.9 `SSMDRenderConfig` containing only missing Readio role defaults. Document `voice_bindings` remain authoritative, invocation `--voice-bind` values override configured provider roles, and concrete targets must belong to the active model roster. Normal `speak`, `render`, and `spotify` commands do not invoke `ssmd create`, rewrite the source, or require generic round-trip validation.
279
+ For `.ssmd` inputs, Readio parses the document through the supported SSMD 0.8.x API and passes a PyKokoro 0.9 `SSMDRenderConfig` containing only missing Readio role defaults. Document `voice_bindings` remain authoritative, invocation `--voice-bind` values override configured provider roles, and concrete targets must belong to the active model roster. Normal `speak`, `render`, and `spotify` commands do not invoke `ssmd create`, rewrite the source, or require generic round-trip validation.
248
280
 
249
281
  Inspect a document before rendering:
250
282
 
@@ -1,6 +1,23 @@
1
1
  # Changelog
2
2
 
3
- ## Unreleased
3
+ > **Generated by releaseledger.** Manual edits may be overwritten. Update releaseledger entries and rebuild this file instead.
4
+
5
+ ## [v0.2.3] - 2026-09-11
6
+
7
+ ### Changed
8
+
9
+ - Aligned Readio dependency metadata and CI with released PyKokoro 0.9.4 and SSMD 0.8.7+
10
+ - Hardened package publishing with artifact checks and release-tag version validation
11
+
12
+ ### Documentation
13
+
14
+ - Documented the PyKokoro support floor, 0.9.4 tested target, and supported SSMD API
15
+
16
+ ### Quality
17
+
18
+ - Added bounded PyKokoro compatibility and package metadata regression coverage
19
+
20
+ <!-- generated by releaseledger -->
4
21
 
5
22
  ## [v0.2.2] - 2026-09-05
6
23
 
@@ -85,3 +102,5 @@
85
102
  - Added cross-platform CI, pre-commit, coverage, package publishing checks, and a podcast example
86
103
 
87
104
  <!-- generated by releaseledger -->
105
+
106
+ <!-- releaseledger:generated-file -->
@@ -80,12 +80,19 @@ Synthesis options are available on all three commands:
80
80
  ```text
81
81
  --voice VOICE PyKokoro voice ID
82
82
  --lang LANGUAGE language code, such as en-us
83
+ --lexicon NAME named PyKokoro lexicon; repeat for ordered layers
84
+ --no-lexicons explicit provider-only pronunciation
85
+ --auto-lexicons restore automatic language-default lexicons
86
+ --g2p-fallback MODE none, espeak, or goruut
87
+ --lexicon-data-policy POLICY auto or installed-only
88
+ --language-detection MODE off or auto
89
+ --detect-language LANG repeatable pronunciation-routing language
83
90
  --speed NUMBER speech speed multiplier
84
91
  --pause-mode MODE tts, manual, or auto
85
92
  --unit UNIT sentence or paragraph
86
93
  ```
87
94
 
88
- Runtime discovery and per-language defaults are separate from legacy provider role configuration. Readio 0.2.0 requires the PyKokoro 0.9.x public discovery contract:
95
+ Runtime discovery and per-language defaults are separate from legacy provider role configuration. Readio v0.2.x uses the PyKokoro >=0.9.2,<0.10 public discovery and tokenizer contract. Readio v0.2.3 is tested with PyKokoro 0.9.4:
89
96
 
90
97
  ```bash
91
98
  readio models list --language de --offline
@@ -98,7 +105,7 @@ readio defaults show de-at --json
98
105
  readio render --lang de --file notes.md
99
106
  ```
100
107
 
101
- `models` reads PyKokoro's lightweight registry and supports `--offline`, `--refresh`, `--status`, and `--json`; it never loads model weights. `--refresh` updates metadata only and cannot be combined with `--offline`. Offline synthesis still needs cached model and voice assets. `defaults` stores validated user policy in schema 2. Exact locale profiles override base-language profiles, and `--no-lexicons` explicitly clears inherited lexicons. Repeated named lexicons retain their order for layered lookup.
108
+ `models` reads PyKokoro's lightweight registry and supports `--offline`, `--refresh`, `--status`, and `--json`; it never loads model weights. `--refresh` updates metadata only and cannot be combined with `--offline`. Offline synthesis still needs cached model and voice assets. `--lexicon crane` selects a named lexicon; `de-de:crane` is the downstream Lexphon asset ID, while `de-crane` is an acoustic model ID.
102
109
  `--model-source github|huggingface` drives both discovery and runtime selection. Voices are model-scoped. The legacy global `reader.voice` applies only to unchanged default-reader use; a language override such as `--lang de` leaves voice selection to the active PyKokoro model unless explicitly set. SSMD preflight uses that same resolved model roster.
103
110
 
104
111
  ## Synthesis planning
@@ -117,6 +124,8 @@ Keep the layers separate:
117
124
  - **Planning** (`readio plan`, `render --dry-run`) resolves one concrete request — model, source, quality, voice, lexicons, SSMD cast with per-reference bindings, output format/backend/path — and records a decision (winning source) for every effective value. Generated output paths are allocated once by the plan and reused by the render.
118
125
  - **Render result** executes the plan; a plan that fails validation (for example `model_language_incompatible`, `model_runtime_unavailable`, `ssmd_unresolved_voice`, `encoder_unavailable`) is printed with its diagnostics and no TTS model is loaded.
119
126
 
127
+ Plans preserve the tokenizer tri-state: `lexicons: null` means PyKokoro language defaults, `lexicons: []` means no static lexicon layers, and a non-empty list means ordered named layers. Fallback and lexicon data policy are also carried unchanged into `TokenizerConfig`; SSMD `language_detection` hints are resolved into the plan before execution.
128
+
120
129
  Planning is deterministic: `--resolve-voices` is rejected during `plan`/`--dry-run` in favor of `--voice-bind ROLE=VOICE_ID` or persisted roles, and `plan` supports `--force` to mirror render output requests.
121
130
 
122
131
  ## Durable render manifests
@@ -143,6 +152,16 @@ readio render --file notes.md -o notes.mp3 --json --progress
143
152
 
144
153
  Bounded renders show phases, completed/total units, percentage, elapsed time, approximate ETA, generated audio duration, and finalization. Live rendering shows elapsed time, cumulative units, and audio duration but no invented percentage or ETA.
145
154
 
155
+ ## Verbose diagnostics
156
+
157
+ Use `-v` for timestamped INFO lifecycle records and `-vv` for DEBUG details from Readio and PyKokoro:
158
+
159
+ ```bash
160
+ readio -v speak "Hello"
161
+ readio -vv render episode.ssmd -o episode.mp3
162
+ ```
163
+
164
+ The option is global and may appear before or after a command. Logs are written only to stderr. Human results and JSON remain on stdout, so `readio -v doctor --json` still emits valid JSON. `--progress` and `--no-progress` remain independent; verbose mode makes progress line-oriented on a TTY. Review paths, model names, and voice identifiers before sharing diagnostics. Complete document text, raw audio, Spotify credentials, and authorization responses are not logged.
146
165
  Playback-only options are `--queue-size` and `--device`. Audio rendering is streamed to an atomic output file through a bounded audio path rather than accumulated as one in-memory waveform.
147
166
 
148
167
  ## Configuration
@@ -162,8 +181,8 @@ readio config validate
162
181
  - `[ssmd]`: the selected `voice_provider` and SSMD validation behavior.
163
182
  - `[paths]`: user template, ingest, and audio output directories.
164
183
  - `[voices.<provider>]`: concrete voice IDs and logical role mappings.
165
-
166
- - `[languages.<locale>]`: validated model, source, quality, voice, ordered lexicons, and experimental opt-in defaults.
184
+ - `[languages.<locale>]`: validated model, source, quality, voice, ordered lexicons, `g2p_fallback`, and `lexicon_data_policy` defaults.
185
+ - `[reader]`: optional `language_detection` mode and ordered `detect_languages` routing hints.
167
186
  Set values with dotted keys. Aliases `voice`, `lang`, and `speed` target the corresponding reader settings:
168
187
 
169
188
  ```bash
@@ -56,8 +56,8 @@ When file creation is unavailable, the guide instructs the LLM to return the com
56
56
  The guides target the conservative authoring subset used by:
57
57
 
58
58
  - Readio 0.2.x
59
- - SSMD >=0.8.6,<0.9
60
- - PyKokoro 0.9.x
59
+ - SSMD >=0.8.7,<0.9
60
+ - PyKokoro >=0.9.2,<0.10 (Readio v0.2.3 tested with 0.9.4)
61
61
 
62
62
  This is a compatibility target, not a claim that the authoring environment ran validation. A generated file should be checked on the destination system before rendering.
63
63
 
@@ -42,8 +42,8 @@ If downloadable file or artifact creation is unavailable:
42
42
  Generate conservative SSMD for this compatibility target:
43
43
 
44
44
  - Readio 0.2.x
45
- - SSMD >=0.8.6,<0.9
46
- - PyKokoro 0.9.x
45
+ - SSMD >=0.8.7,<0.9
46
+ - PyKokoro >=0.9.2,<0.10 (Readio v0.2.3 tested with 0.9.4)
47
47
 
48
48
  These are authoring instructions, not a requirement to install or execute the runtime. They must work without Python, a Readio installation, the Readio Agent Skill, local SSMD tooling, or local model discovery. The generated file can be checked and rendered later on a Readio-capable system.
49
49
 
@@ -42,8 +42,8 @@ If downloadable file or artifact creation is unavailable:
42
42
  Generate conservative SSMD for this compatibility target:
43
43
 
44
44
  - Readio 0.2.x
45
- - SSMD >=0.8.6,<0.9
46
- - PyKokoro 0.9.x
45
+ - SSMD >=0.8.7,<0.9
46
+ - PyKokoro >=0.9.2,<0.10 (Readio v0.2.3 tested with 0.9.4)
47
47
 
48
48
  These are authoring instructions, not a requirement to install or execute the runtime. They must work without Python, a Readio installation, the Readio Agent Skill, local SSMD tooling, or local model discovery. The generated file can be checked and rendered later on a Readio-capable system.
49
49
 
@@ -42,8 +42,8 @@ If downloadable file or artifact creation is unavailable:
42
42
  Generate conservative SSMD for this compatibility target:
43
43
 
44
44
  - Readio 0.2.x
45
- - SSMD >=0.8.6,<0.9
46
- - PyKokoro 0.9.x
45
+ - SSMD >=0.8.7,<0.9
46
+ - PyKokoro >=0.9.2,<0.10 (Readio v0.2.3 tested with 0.9.4)
47
47
 
48
48
  These are authoring instructions, not a requirement to install or execute the runtime. They must work without Python, a Readio installation, the Readio Agent Skill, local SSMD tooling, or local model discovery. The generated file can be checked and rendered later on a Readio-capable system.
49
49
 
@@ -42,8 +42,8 @@ If downloadable file or artifact creation is unavailable:
42
42
  Generate conservative SSMD for this compatibility target:
43
43
 
44
44
  - Readio 0.2.x
45
- - SSMD >=0.8.6,<0.9
46
- - PyKokoro 0.9.x
45
+ - SSMD >=0.8.7,<0.9
46
+ - PyKokoro >=0.9.2,<0.10 (Readio v0.2.3 tested with 0.9.4)
47
47
 
48
48
  These are authoring instructions, not a requirement to install or execute the runtime. They must work without Python, a Readio installation, the Readio Agent Skill, local SSMD tooling, or local model discovery. The generated file can be checked and rendered later on a Readio-capable system.
49
49
 
@@ -42,8 +42,8 @@ If downloadable file or artifact creation is unavailable:
42
42
  Generate conservative SSMD for this compatibility target:
43
43
 
44
44
  - Readio 0.2.x
45
- - SSMD >=0.8.6,<0.9
46
- - PyKokoro 0.9.x
45
+ - SSMD >=0.8.7,<0.9
46
+ - PyKokoro >=0.9.2,<0.10 (Readio v0.2.3 tested with 0.9.4)
47
47
 
48
48
  These are authoring instructions, not a requirement to install or execute the runtime. They must work without Python, a Readio installation, the Readio Agent Skill, local SSMD tooling, or local model discovery. The generated file can be checked and rendered later on a Readio-capable system.
49
49
 
@@ -42,8 +42,8 @@ If downloadable file or artifact creation is unavailable:
42
42
  Generate conservative SSMD for this compatibility target:
43
43
 
44
44
  - Readio 0.2.x
45
- - SSMD >=0.8.6,<0.9
46
- - PyKokoro 0.9.x
45
+ - SSMD >=0.8.7,<0.9
46
+ - PyKokoro >=0.9.2,<0.10 (Readio v0.2.3 tested with 0.9.4)
47
47
 
48
48
  These are authoring instructions, not a requirement to install or execute the runtime. They must work without Python, a Readio installation, the Readio Agent Skill, local SSMD tooling, or local model discovery. The generated file can be checked and rendered later on a Readio-capable system.
49
49
 
@@ -42,8 +42,8 @@ If downloadable file or artifact creation is unavailable:
42
42
  Generate conservative SSMD for this compatibility target:
43
43
 
44
44
  - Readio 0.2.x
45
- - SSMD >=0.8.6,<0.9
46
- - PyKokoro 0.9.x
45
+ - SSMD >=0.8.7,<0.9
46
+ - PyKokoro >=0.9.2,<0.10 (Readio v0.2.3 tested with 0.9.4)
47
47
 
48
48
  These are authoring instructions, not a requirement to install or execute the runtime. They must work without Python, a Readio installation, the Readio Agent Skill, local SSMD tooling, or local model discovery. The generated file can be checked and rendered later on a Readio-capable system.
49
49