vocalize-cli 0.11.0__tar.gz → 0.13.0__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 (235) hide show
  1. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/CHANGELOG.md +172 -0
  2. vocalize_cli-0.11.0/README.md → vocalize_cli-0.13.0/PKG-INFO +174 -60
  3. vocalize_cli-0.11.0/PKG-INFO → vocalize_cli-0.13.0/README.md +138 -96
  4. vocalize_cli-0.13.0/docs/app.md +205 -0
  5. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/dictation.md +66 -16
  6. vocalize_cli-0.13.0/docs/installation.md +211 -0
  7. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/choreography.md +110 -0
  8. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/decisions.md +509 -0
  9. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/design.md +355 -0
  10. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/plan.md +331 -0
  11. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/review-0.12.0.md +142 -0
  12. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/review-0.13.0.md +252 -0
  13. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/review-plan-2026-09-06.md +41 -0
  14. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-1-local-first-defaults/project-plan.md +76 -0
  15. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-1-local-first-defaults/report.md +16 -0
  16. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-1-local-first-defaults/task-report.md +30 -0
  17. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-1-local-first-defaults/validate-exit.sh +134 -0
  18. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-10-release-0-13-0/project-plan.md +50 -0
  19. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-10-release-0-13-0/validate-exit.sh +124 -0
  20. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-11-cue-hold-paste/project-plan.md +52 -0
  21. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-11-cue-hold-paste/validate-exit.sh +125 -0
  22. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-11b-playback-pause/project-plan.md +54 -0
  23. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-11b-playback-pause/validate-exit.sh +128 -0
  24. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-12-release-0-13-1/project-plan.md +47 -0
  25. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-12-release-0-13-1/validate-exit.sh +122 -0
  26. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-13-spikes/project-plan.md +45 -0
  27. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-13-spikes/validate-exit.sh +114 -0
  28. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-14-local-llm/project-plan.md +50 -0
  29. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-14-local-llm/validate-exit.sh +124 -0
  30. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-15-notes/project-plan.md +48 -0
  31. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-15-notes/validate-exit.sh +111 -0
  32. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-15b-recording-pause/project-plan.md +57 -0
  33. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-15b-recording-pause/validate-exit.sh +131 -0
  34. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-16-release-0-14-0/project-plan.md +50 -0
  35. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-16-release-0-14-0/validate-exit.sh +124 -0
  36. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-17-optional-spikes/project-plan.md +44 -0
  37. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-17-optional-spikes/validate-exit.sh +118 -0
  38. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-2-stt-decoding/project-plan.md +49 -0
  39. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-2-stt-decoding/report.md +16 -0
  40. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-2-stt-decoding/task-report.md +35 -0
  41. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-2-stt-decoding/validate-exit.sh +113 -0
  42. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-3-llm-and-enums/project-plan.md +55 -0
  43. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-3-llm-and-enums/report.md +20 -0
  44. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-3-llm-and-enums/task-report.md +36 -0
  45. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-3-llm-and-enums/validate-exit.sh +152 -0
  46. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-4-keychain/project-plan.md +80 -0
  47. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-4-keychain/report.md +16 -0
  48. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-4-keychain/task-report.md +34 -0
  49. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-4-keychain/validate-exit.sh +134 -0
  50. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-5-keys-tab/project-plan.md +47 -0
  51. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-5-keys-tab/report.md +24 -0
  52. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-5-keys-tab/task-report.md +31 -0
  53. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-5-keys-tab/validate-exit.sh +118 -0
  54. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-6-release-0-12-0/project-plan.md +50 -0
  55. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-6-release-0-12-0/report.md +31 -0
  56. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-6-release-0-12-0/validate-exit.sh +124 -0
  57. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-7-hotkey-spike-and-builder/project-plan.md +45 -0
  58. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-7-hotkey-spike-and-builder/report.md +17 -0
  59. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-7-hotkey-spike-and-builder/task-report.md +31 -0
  60. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-7-hotkey-spike-and-builder/validate-exit.sh +113 -0
  61. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-8a-app-swift/project-plan.md +44 -0
  62. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-8a-app-swift/report.md +19 -0
  63. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-8a-app-swift/task-report.md +30 -0
  64. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-8a-app-swift/validate-exit.sh +124 -0
  65. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-8b-app-python/project-plan.md +49 -0
  66. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-8b-app-python/report.md +20 -0
  67. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-8b-app-python/task-report.md +36 -0
  68. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-8b-app-python/validate-exit.sh +119 -0
  69. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-9-doctor-integrate-setup/project-plan.md +48 -0
  70. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-9-doctor-integrate-setup/report.md +21 -0
  71. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-9-doctor-integrate-setup/task-report.md +29 -0
  72. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/run-9-doctor-integrate-setup/validate-exit.sh +121 -0
  73. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/spike-notes.md +47 -0
  74. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/split-assessment.md +57 -0
  75. vocalize_cli-0.13.0/docs/plans/2026-09-app-roadmap/verification.md +216 -0
  76. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-10-release-0-11-0/report.md +8 -1
  77. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/provider-credentials.md +72 -0
  78. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/roadmap.md +2 -1
  79. vocalize_cli-0.13.0/hooks/install_quick_action.py +13 -0
  80. vocalize_cli-0.13.0/hooks/speak_options.py +13 -0
  81. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/pyproject.toml +2 -2
  82. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/conftest.py +76 -0
  83. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/portal_page_harness.js +222 -2
  84. vocalize_cli-0.13.0/tests/test_app_build.py +242 -0
  85. vocalize_cli-0.13.0/tests/test_app_cli.py +777 -0
  86. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_auth.py +206 -1
  87. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_chain.py +39 -0
  88. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_cli.py +380 -6
  89. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_config.py +281 -7
  90. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_dictate.py +206 -114
  91. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_http.py +19 -0
  92. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_install_quick_action.py +70 -30
  93. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_listen_check.py +3 -2
  94. vocalize_cli-0.13.0/tests/test_llm.py +491 -0
  95. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_local_install.py +31 -8
  96. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_portal.py +440 -3
  97. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_portal_assets.py +30 -6
  98. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_readiness.py +396 -0
  99. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_recorder_build.py +1 -37
  100. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_speak_options.py +14 -1
  101. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_whisper_manifest.py +22 -5
  102. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_whisper_worker.py +73 -2
  103. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_wizard.py +44 -2
  104. vocalize_cli-0.13.0/uv.lock +1571 -0
  105. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/__init__.py +2 -2
  106. vocalize_cli-0.13.0/vocalize/app.py +406 -0
  107. vocalize_cli-0.13.0/vocalize/assets/claude/speak/SKILL.md +168 -0
  108. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/assets/portal.html +9 -0
  109. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/assets/portal.js +265 -29
  110. {vocalize_cli-0.11.0/hooks → vocalize_cli-0.13.0/vocalize/assets}/quick_actions/Speak Latest Plan.workflow/Contents/Resources/document.wflow +1 -1
  111. {vocalize_cli-0.11.0/hooks → vocalize_cli-0.13.0/vocalize/assets}/quick_actions/Speak with Vocalize.workflow/Contents/Resources/document.wflow +2 -2
  112. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/auth.py +184 -8
  113. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/chain.py +21 -1
  114. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/cli.py +327 -31
  115. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/config.py +299 -10
  116. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/dictate.py +71 -79
  117. vocalize_cli-0.13.0/vocalize/integrate.py +264 -0
  118. vocalize_cli-0.13.0/vocalize/llm.py +315 -0
  119. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/local/install.py +172 -52
  120. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/local/whisper_manifest.py +11 -2
  121. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/local/whisper_worker.py +39 -2
  122. vocalize_cli-0.13.0/vocalize/menubar/Info.plist.in +47 -0
  123. vocalize_cli-0.13.0/vocalize/menubar/VocalizeApp.swift +1560 -0
  124. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/portal.py +160 -11
  125. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/providers/_http.py +9 -0
  126. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/providers/kokoro.py +2 -1
  127. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/readiness.py +232 -3
  128. {vocalize_cli-0.11.0/hooks → vocalize_cli-0.13.0/vocalize}/speak_options.py +4 -1
  129. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/wizard.py +9 -1
  130. vocalize_cli-0.11.0/docs/installation.md +0 -483
  131. vocalize_cli-0.11.0/hooks/install_quick_action.py +0 -136
  132. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/.env.example +0 -0
  133. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/.github/workflows/ci.yml +0 -0
  134. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/.gitignore +0 -0
  135. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/LICENSE +0 -0
  136. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/next-features-analysis.md +0 -0
  137. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/choreography.md +0 -0
  138. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/decisions.md +0 -0
  139. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/design.md +0 -0
  140. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/plan.md +0 -0
  141. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/review-0.10.0.md +0 -0
  142. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/review-0.11.0.md +0 -0
  143. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-1-status/project-plan.md +0 -0
  144. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-1-status/report.md +0 -0
  145. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-1-status/validate-exit.sh +0 -0
  146. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-10-release-0-11-0/project-plan.md +0 -0
  147. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-10-release-0-11-0/validate-exit.sh +0 -0
  148. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-2-stt-runtime/project-plan.md +0 -0
  149. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-2-stt-runtime/report.md +0 -0
  150. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-2-stt-runtime/validate-exit.sh +0 -0
  151. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-3-recorder/project-plan.md +0 -0
  152. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-3-recorder/report.md +0 -0
  153. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-3-recorder/validate-exit.sh +0 -0
  154. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-4-dictation/project-plan.md +0 -0
  155. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-4-dictation/report.md +0 -0
  156. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-4-dictation/validate-exit.sh +0 -0
  157. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-5-resume/project-plan.md +0 -0
  158. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-5-resume/report.md +0 -0
  159. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-5-resume/validate-exit.sh +0 -0
  160. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-6-release-0-10-0/project-plan.md +0 -0
  161. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-6-release-0-10-0/report.md +0 -0
  162. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-6-release-0-10-0/validate-exit.sh +0 -0
  163. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-7-portal-read/project-plan.md +0 -0
  164. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-7-portal-read/report.md +0 -0
  165. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-7-portal-read/review-findings.md +0 -0
  166. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-7-portal-read/validate-exit.sh +0 -0
  167. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-8-portal-write/project-plan.md +0 -0
  168. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-8-portal-write/report.md +0 -0
  169. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-8-portal-write/validate-exit.sh +0 -0
  170. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-9-portal-page/project-plan.md +0 -0
  171. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-9-portal-page/report.md +0 -0
  172. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-9-portal-page/review-findings.md +0 -0
  173. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/run-9-portal-page/validate-exit.sh +0 -0
  174. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/spike-2026-09-01.md +0 -0
  175. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/split-assessment.md +0 -0
  176. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/plans/2026-09-next-features/verification.md +0 -0
  177. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/research/2026-09-01-config-portal-design.md +0 -0
  178. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/research/2026-09-01-dictation-design.md +0 -0
  179. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/research/2026-09-01-voicebox-findings.md +0 -0
  180. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/docs/research/2026-09-04-app-roadmap-analysis.md +0 -0
  181. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/hooks/claude_stop_hook.py +0 -0
  182. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/hooks/install_hook.py +0 -0
  183. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/hooks/speak_url_gate.py +0 -0
  184. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_audio.py +0 -0
  185. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_cache.py +0 -0
  186. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_claude_stop_hook.py +0 -0
  187. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_clipboard.py +0 -0
  188. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_cue_assets.py +0 -0
  189. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_elevenlabs_provider.py +0 -0
  190. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_exceptions.py +0 -0
  191. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_google_provider.py +0 -0
  192. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_install_hook.py +0 -0
  193. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_kokoro_manifest.py +0 -0
  194. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_kokoro_provider.py +0 -0
  195. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_kokoro_worker.py +0 -0
  196. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_ledger.py +0 -0
  197. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_openai_provider.py +0 -0
  198. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_polly_provider.py +0 -0
  199. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_preprocess.py +0 -0
  200. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_providers_registry.py +0 -0
  201. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_say_provider.py +0 -0
  202. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_speak_url_gate.py +0 -0
  203. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_tts.py +0 -0
  204. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/tests/test_uv_path.py +0 -0
  205. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/__main__.py +0 -0
  206. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/assets/cues/README.md +0 -0
  207. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/assets/cues/ready.wav +0 -0
  208. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/assets/cues/start.wav +0 -0
  209. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/assets/cues/stopped.wav +0 -0
  210. {vocalize_cli-0.11.0/hooks → vocalize_cli-0.13.0/vocalize/assets}/quick_actions/Dictate with Vocalize.workflow/Contents/Info.plist +0 -0
  211. {vocalize_cli-0.11.0/hooks → vocalize_cli-0.13.0/vocalize/assets}/quick_actions/Dictate with Vocalize.workflow/Contents/Resources/document.wflow +0 -0
  212. {vocalize_cli-0.11.0/hooks → vocalize_cli-0.13.0/vocalize/assets}/quick_actions/Speak Latest Plan.workflow/Contents/Info.plist +0 -0
  213. {vocalize_cli-0.11.0/hooks → vocalize_cli-0.13.0/vocalize/assets}/quick_actions/Speak with Vocalize.workflow/Contents/Info.plist +0 -0
  214. {vocalize_cli-0.11.0/hooks → vocalize_cli-0.13.0/vocalize/assets}/quick_actions/Stop Vocalize.workflow/Contents/Info.plist +0 -0
  215. {vocalize_cli-0.11.0/hooks → vocalize_cli-0.13.0/vocalize/assets}/quick_actions/Stop Vocalize.workflow/Contents/Resources/document.wflow +0 -0
  216. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/audio.py +0 -0
  217. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/cache.py +0 -0
  218. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/clipboard.py +0 -0
  219. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/exceptions.py +0 -0
  220. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/interrupted.py +0 -0
  221. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/ledger.py +0 -0
  222. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/local/__init__.py +0 -0
  223. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/local/kokoro_manifest.py +0 -0
  224. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/local/kokoro_worker.py +0 -0
  225. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/preprocess.py +0 -0
  226. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/providers/__init__.py +0 -0
  227. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/providers/elevenlabs.py +0 -0
  228. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/providers/google.py +0 -0
  229. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/providers/openai.py +0 -0
  230. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/providers/polly.py +0 -0
  231. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/providers/say.py +0 -0
  232. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/recorder/Info.plist.in +0 -0
  233. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/recorder/Recorder.entitlements +0 -0
  234. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/recorder/VocalizeRecorder.swift +0 -0
  235. {vocalize_cli-0.11.0 → vocalize_cli-0.13.0}/vocalize/tts.py +0 -0
@@ -3,6 +3,178 @@
3
3
  All notable changes to this project are documented here. Format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
5
 
6
+ ## Unreleased
7
+
8
+ Nothing yet.
9
+
10
+ ## 0.13.0 - 2026-09-08
11
+
12
+ ### Added
13
+
14
+ - **The `[app]` config table** for the menu-bar app that arrives in 0.13.0:
15
+ `dictate`, `speak` and `stop` chords (`ctrl+alt+cmd+d`, `+s`, `+x` by
16
+ default; tokens joined by `+`, modifiers ctrl/alt/cmd/shift with their
17
+ long-form aliases, a key of a–z, 0–9 or f1–f12, ctrl or cmd required,
18
+ `""` disables) and `dictate_mode` (`toggle`; `hold` parses and resolves
19
+ to toggle with one warning until 0.13.1). The wizard renders it and
20
+ `vocalize settings` prints `app.<key>=…` in one canonical spelling.
21
+ - **`vocalize app install / uninstall / status [--json] / restart`** —
22
+ a menu-bar app (`Vocalize.app`) that owns the dictation, speak and stop
23
+ hotkeys system-wide, as a LaunchAgent, so a hotkey works from any app
24
+ with no Services menu and no per-app shortcut assignment. `install`
25
+ builds the bundle, warns about a running Hammerspoon or a Services
26
+ shortcut assigned to the "Dictate with Vocalize" Quick Action, resets
27
+ the Accessibility grant
28
+ only on a rebuild, and loads the LaunchAgent; `status` reports what's
29
+ built, whether the agent is loaded, and the app's own hotkey and
30
+ Accessibility state; `restart` kicks the running app without touching
31
+ the LaunchAgent; `uninstall` removes everything `install` put down
32
+ and leaves the Accessibility entry in System Settings alone. See
33
+ [docs/app.md](docs/app.md).
34
+ - **`dictate.session` gains a `state` and a per-dictation `nonce`.**
35
+ `state` moves through `starting` → `recording` → `transcribing` as a
36
+ dictation runs, so anything reading the session file (the app included)
37
+ knows which stage it's watching, not just that one is in progress.
38
+ `nonce` ties one dictation's session to its eventual `dictate.copied`
39
+ write. Unknown keys in the file are still ignored.
40
+ - **`vocalize doctor [--json]`** — every readiness row plus the toolchain
41
+ and environment checks `status` doesn't cover: `cli path`, `uv`,
42
+ `swiftc`, `claude` on PATH, the running console script's shebang
43
+ (brew rot), a Hammerspoon or old Quick Action conflict, `vocalize
44
+ --version` cold-start time, app bundle state with its repair command,
45
+ and the notes folder's size on disk. Exits 1 only on a failing row;
46
+ warn rows print but don't fail a script.
47
+ - **`vocalize integrate claude [--yes]`** — one command in place of the
48
+ hand-rolled `/speak` skill and the standalone Quick Action installer.
49
+ Checks `vocalize`, `claude`, `node`, and `python3` on PATH, installs
50
+ `~/.claude/skills/speak/SKILL.md` from the package (kept unless
51
+ `--yes`), installs the four Quick Actions into `~/Library/Services`,
52
+ and prints the GUI-only hotkey and Accessibility steps. The Quick
53
+ Action installer and its `.workflow` bundles moved into the package
54
+ (`vocalize/assets/quick_actions/`); `hooks/install_quick_action.py` is
55
+ now a thin wrapper around it. The baked `claude` path is the stable
56
+ symlink, not `.resolve()`'s version-pinned Caskroom target, so a
57
+ `brew upgrade claude-code` no longer silently breaks the summary
58
+ picker.
59
+ - **The Setup tab** in `vocalize portal` — a nine-step checklist
60
+ (toolchain, both bundles, login item, chords, model download,
61
+ microphone, `/speak` and Quick Actions, Accessibility, self-test)
62
+ built from the readiness rows the sidebar shows; its first step points at
63
+ `vocalize doctor`. Its install
64
+ buttons drive the existing `/api/local/install` routes, now including
65
+ target `app`. See [docs/app.md](docs/app.md#the-setup-tab).
66
+
67
+ ### Changed
68
+
69
+ - **The recorder is built by a general bundle builder.** `build_bundle(BundleSpec)`
70
+ replaces the recorder-only code path; `build_recorder` is the recorder's
71
+ door onto it and its build is unchanged byte for byte (a golden test pins
72
+ the `swiftc` and `codesign` argv, because any drift is a new ad-hoc
73
+ signature and a microphone re-grant). `vocalize local uninstall --stt`
74
+ now removes only the recorder bundle and its stamp, never the whole
75
+ `~/.cache/vocalize/bin`.
76
+ - **`vocalize clip` exits 3, not 1, when it refuses a credential-shaped
77
+ clipboard.** A script that already treats exit 1 as "something went
78
+ wrong, try again" can now tell that refusal apart from a real failure.
79
+
80
+ ## 0.12.0 - 2026-09-07
81
+
82
+ ### Changed
83
+
84
+ - **The default chain is now `kokoro`, then `say`.** A config with no
85
+ `chain` used to try ElevenLabs first; it now tries the on-device voice
86
+ first and falls back to macOS `say`. When `say` speaks because the Kokoro
87
+ model was never installed, the fallback line says so once and names the
88
+ fix: `vocalize local install`. Users who never set a chain hear `say`
89
+ after upgrading until they run that install; anyone with an explicit
90
+ `chain` sees no change. `vocalize usage`, `vocalize status` and the portal
91
+ now list the local providers first.
92
+ - **Dictation decodes with beam search.** whisper.cpp ran with its greedy
93
+ decoder, which merged words on fast speech ("toget" for "to get",
94
+ [#4](https://github.com/matthager12-collab/vocalize/issues/4)). The worker
95
+ now uses beam search with five beams, whisper.cpp's own default for that
96
+ strategy. `[stt] beam_size` (1–8) is the escape hatch: `1` restores the
97
+ greedy decoder if a take is slow to land on your machine. Honest result:
98
+ on the owner's own voice both decoders still produced "themerge" for
99
+ "the merge", so beam search improves decoding but does not close #4;
100
+ that issue stays open. The cost was measured on a 43 s synthetic clip
101
+ and recorded in `docs/plans/2026-09-app-roadmap/spike-notes.md`.
102
+
103
+ - **The default dictation model is now `large-v3-turbo-q5_0`.** On the
104
+ owner's own voice it was the first model to keep "the merge" as two
105
+ words ([#4](https://github.com/matthager12-collab/vocalize/issues/4));
106
+ beam search alone did not. It is no slower than `small.en` on an M4 and
107
+ uses about 90 MB more. **Upgrade note:** if your `[stt]` table sets no
108
+ `model`, dictation looks for the new default — run
109
+ `vocalize local install --stt` once (547 MB), or set
110
+ `model = "small.en"` to keep the lighter model.
111
+ - **`[stt] cleanup` names where the cleanup pass runs.** It was `true` or
112
+ `false`; it is now `off`, `claude-cli`, `anthropic` or `local` (`local`
113
+ is accepted today and honoured from 0.14.0). Older `true` / `false`
114
+ values keep working. The pass lives in a new `vocalize/llm.py`, one seam
115
+ for every language-model call, and the default prompt now also drops
116
+ restatements, false starts and filler
117
+ ([#3](https://github.com/matthager12-collab/vocalize/issues/3)); say
118
+ "verbatim" as the first word of a take, pass `--verbatim`, or set
119
+ `[stt] verbatim = true` to keep every word.
120
+ - **Every cloud send is visible.** One stderr line, `vocalize: sent to
121
+ <backend>`, prints immediately before text leaves the machine and never
122
+ otherwise; the clipboard notification for a cleaned take says "cleaned
123
+ up by Claude — sent off this Mac".
124
+ - **`claude -p` sessions are tighter.** The cleanup pass and the plan-
125
+ speaking hook now pass `--strict-mcp-config`, run from the system
126
+ temporary directory, and the cleanup pass excludes your own hooks,
127
+ skills and `CLAUDE.md` (`--setting-sources ""`) and strips any stored
128
+ Anthropic key from the child's environment.
129
+ - **Provider settings are type-checked** (issue
130
+ [#5](https://github.com/matthager12-collab/vocalize/issues/5)): a
131
+ `voice`, `model`, `engine`, `language`, `region` or `profile` that is not
132
+ a short printable string is refused with a message naming the file and
133
+ the key, in the CLI and the portal alike.
134
+ - **Sentences no longer run together with the turbo models.** Their
135
+ segments arrive without a leading space and the worker joined them with
136
+ nothing ("working.I want"); segments are now joined with one space.
137
+
138
+ ### Fixed
139
+
140
+ - **A stored key is readable from every Python on the Mac.** macOS pins a
141
+ keychain item to the binary that created it, so a key stored from the
142
+ terminal could be invisible, or behind an "Allow" dialog, when Claude
143
+ Code's shell or an upgraded vocalize asked for it. Keys are now written
144
+ and read through Apple's own `security` tool (secret on stdin, never on a
145
+ command line), which is the same accessing application whatever spawned
146
+ it; the item also records the date the key was last validated, shown by
147
+ `vocalize auth status`. An older item is replaced in place on the next
148
+ `vocalize auth login`.
149
+
150
+ ### Added
151
+
152
+ - **An Anthropic key slot, and a Keys tab that can test and remove.**
153
+ `vocalize auth login --provider anthropic` stores the key the `anthropic`
154
+ cleanup backend uses, under its own keychain item; `auth status`,
155
+ `auth logout` and `vocalize usage` know the slot too. It is a key, not a
156
+ voice: the chain does not accept it. On the portal's Keys tab every slot
157
+ (the three voice providers and Anthropic) gets **Test without storing**,
158
+ which checks a key and keeps nothing, and **Remove stored key**, which
159
+ reads the keychain back before it says the key is gone; each card shows
160
+ when its key was last checked. The key field is `autocomplete=
161
+ "new-password"`, the value Safari and Chrome honour on a password field.
162
+ The Local tab gained a select for the cleanup backend.
163
+
164
+ - **An Anthropic API backend for the cleanup pass** (`[stt] cleanup =
165
+ "anthropic"`): one Messages API call with a key from `ANTHROPIC_API_KEY`
166
+ or the keychain slot `anthropic-api-key`, under a monthly character
167
+ budget (`[providers.anthropic] monthly_chars`, 2,000,000 when unset)
168
+ counted in the usage ledger. The key is stored from the CLI or the
169
+ portal's Keys tab, as described above.
170
+ - **A `[notes]` config table** (`folder`, `template`, `summarizer`,
171
+ `keep_audio`, `model`) is parsed, validated and preserved by every writer
172
+ of the config file. `vocalize notes` itself arrives in 0.14.0.
173
+ - **`large-v3-turbo-q8_0`** joins the dictation models: the same turbo model
174
+ as `q5_0` with 8-bit weights (834 MB on disk), for machines with 16 GB or
175
+ more. `vocalize local install --stt --model large-v3-turbo-q8_0`. Pinned
176
+ from a completed download like the other three.
177
+
6
178
  ## 0.11.0 - 2026-09-05
7
179
 
8
180
  ### Added
@@ -1,11 +1,48 @@
1
+ Metadata-Version: 2.5
2
+ Name: vocalize-cli
3
+ Version: 0.13.0
4
+ Summary: A local-first CLI that turns text, markdown, or piped stdin into speech: the on-device Kokoro voice by default, cloud voices optional, with markdown-table-aware preprocessing and Claude Code hooks.
5
+ Project-URL: Homepage, https://github.com/matthager12-collab/vocalize
6
+ Project-URL: Repository, https://github.com/matthager12-collab/vocalize
7
+ Author: Mat
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Keywords: claude-code,cli,elevenlabs,kokoro,local,markdown,text-to-speech
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
20
+ Requires-Python: >=3.10
21
+ Requires-Dist: click>=8.1
22
+ Requires-Dist: elevenlabs>=2.0
23
+ Requires-Dist: keyring>=25
24
+ Requires-Dist: tomli>=2.0; python_version < '3.11'
25
+ Provides-Extra: dev
26
+ Requires-Dist: build; extra == 'dev'
27
+ Requires-Dist: pytest-cov>=4.0; extra == 'dev'
28
+ Requires-Dist: pytest>=7.0; extra == 'dev'
29
+ Requires-Dist: ruff; extra == 'dev'
30
+ Requires-Dist: twine; extra == 'dev'
31
+ Provides-Extra: dotenv
32
+ Requires-Dist: python-dotenv>=1.0; extra == 'dotenv'
33
+ Provides-Extra: polly
34
+ Requires-Dist: boto3>=1.34; extra == 'polly'
35
+ Description-Content-Type: text/markdown
36
+
1
37
  # vocalize
2
38
 
3
39
  [![CI](https://github.com/matthager12-collab/vocalize/actions/workflows/ci.yml/badge.svg)](https://github.com/matthager12-collab/vocalize/actions/workflows/ci.yml)
4
40
 
5
41
  A command-line tool that turns text, markdown files, or piped stdin into
6
- natural-sounding speech using the [ElevenLabs](https://elevenlabs.io) API —
7
- plus a hook that wires it directly into [Claude Code](https://claude.com/claude-code),
8
- so Claude's responses get read aloud automatically in your terminal or IDE.
42
+ natural-sounding speech on your own machine by default, with cloud voices as
43
+ an option — plus a hook that wires it directly into
44
+ [Claude Code](https://claude.com/claude-code), so Claude's responses get read
45
+ aloud in your terminal or IDE.
9
46
 
10
47
  ## Quickstart
11
48
 
@@ -14,17 +51,19 @@ pipx install vocalize-cli
14
51
  ```
15
52
 
16
53
  ```bash
17
- vocalize config
54
+ vocalize local install
18
55
  ```
19
56
 
20
- Walks you through your API key, a voice, and a speed, and saves it all.
57
+ Downloads the on-device Kokoro voice once (about 350 MB; needs
58
+ [`uv`](https://docs.astral.sh/uv/)). Skip it and `vocalize` speaks through
59
+ macOS `say` until you come back to it — the fallback line tells you so.
21
60
 
22
61
  ```bash
23
62
  vocalize speak "hello"
24
63
  ```
25
64
 
26
- To set up just the key, skip the wizard and run `vocalize auth login` — it
27
- stores the key in your OS keychain.
65
+ Prefer a cloud voice? See [Providers and fallback](#providers-and-fallback):
66
+ `vocalize config` walks you through a key, a voice and a speed.
28
67
 
29
68
  ## Why this exists
30
69
 
@@ -62,33 +101,8 @@ cd vocalize
62
101
  pip install -e .
63
102
  ```
64
103
 
65
- Get a free ElevenLabs API key at
66
- [elevenlabs.io/app/settings/api-keys](https://elevenlabs.io/app/settings/api-keys)
67
- (free tier: 10,000 characters/month, API access included, no commercial
68
- license). Then, recommended, store it in your OS keychain:
69
-
70
- ```bash
71
- vocalize auth login
72
- ```
73
-
74
- This prompts for the key (input hidden), validates it against the
75
- ElevenLabs API, and stores it via your OS's own keychain (macOS Keychain,
76
- Windows Credential Locker, Linux Secret Service) — no plaintext file to
77
- manage. Piping it in from a secret manager works too:
78
-
79
- ```bash
80
- op read op://vault/elevenlabs/key | vocalize auth login --stdin
81
- ```
82
-
83
- An environment variable or `.env` file work as well, and take priority over
84
- the keychain if both are set:
85
-
86
- ```bash
87
- export ELEVENLABS_API_KEY=your-key-here
88
- ```
89
-
90
- or copy `.env.example` to `.env` and fill it in (requires the optional
91
- `python-dotenv` extra: `pip install -e ".[dotenv]"`).
104
+ Cloud voices need an API key; storing one is covered under
105
+ [Providers and fallback](#providers-and-fallback).
92
106
 
93
107
  ## Usage
94
108
 
@@ -206,7 +220,8 @@ back to `~/.config/vocalize/config.toml`. Flat keys, no sections:
206
220
  ```toml
207
221
  chain = ["elevenlabs", "google", "say"]
208
222
 
209
- # Flat keys = ElevenLabs, unchanged since before there was a chain.
223
+ # Flat keys are the original cloud voice's settings, unchanged since
224
+ # before there was a chain; see Providers and fallback.
210
225
  voice = "21m00Tcm4TlvDq8ikWAM"
211
226
  model = "eleven_flash_v2_5"
212
227
  speed = 0.95
@@ -278,8 +293,10 @@ Five tabs:
278
293
  - **Chain** — reorder providers, or add and remove one.
279
294
  - **Providers** — each provider's voice, model, speed, and monthly budget,
280
295
  with a live preview of the voice you're looking at.
281
- - **Keys** — store or check an API key; the field is masked and never
282
- offers to autocomplete.
296
+ - **Keys** — store, test or remove an API key for each provider and for
297
+ Anthropic (the dictation cleanup backend, not a voice); the field is
298
+ masked and never offers to autocomplete, a stored key is never shown
299
+ again, and each card says when the key was last checked.
283
300
  - **Usage** — this month's spend and quota per provider.
284
301
  - **Local** — install or update the on-device Kokoro and whisper models,
285
302
  with progress.
@@ -358,6 +375,41 @@ For the click-by-click setup of each provider — where to go, what to click,
358
375
  the one command that stores the credential, the one command that proves it
359
376
  works — see [docs/provider-credentials.md](docs/provider-credentials.md).
360
377
 
378
+ ### Storing a cloud API key
379
+
380
+ For ElevenLabs, get a free API key at
381
+ [elevenlabs.io/app/settings/api-keys](https://elevenlabs.io/app/settings/api-keys)
382
+ (free tier: 10,000 characters/month, API access included, no commercial
383
+ license). Then, recommended, store it in your OS keychain:
384
+
385
+ ```bash
386
+ vocalize auth login
387
+ ```
388
+
389
+ This prompts for the key (input hidden), validates it against the
390
+ ElevenLabs API, and stores it via your OS's own keychain (macOS Keychain,
391
+ Windows Credential Locker, Linux Secret Service) — no plaintext file to
392
+ manage. On macOS the item is written and read through Apple's own
393
+ `security` tool, so the same key is readable from every Python and app
394
+ that runs vocalize — your terminal, Claude Code's shell, the portal —
395
+ with no keychain dialog, and `vocalize auth status` shows the date it was
396
+ last validated. Piping it in from a secret manager works too:
397
+
398
+ ```bash
399
+ op read op://vault/elevenlabs/key | vocalize auth login --stdin
400
+ ```
401
+
402
+ An environment variable or `.env` file work as well, and take priority over
403
+ the keychain if both are set:
404
+
405
+ ```bash
406
+ export ELEVENLABS_API_KEY=your-key-here
407
+ ```
408
+
409
+ or copy `.env.example` to `.env` and fill it in (requires the optional
410
+ `python-dotenv` extra: `pip install -e ".[dotenv]"`).
411
+
412
+
361
413
  ## Budgets and the usage ledger
362
414
 
363
415
  Cloud providers don't stop at their free tier — they bill past it. vocalize
@@ -421,7 +473,8 @@ Use it for one read with `--provider kokoro`, or add it to your chain in
421
473
  Long text streams: it's broken into ~400-character pieces, and playback
422
474
  starts after the first one is ready — roughly 20–25 seconds of speech —
423
475
  instead of waiting for the whole thing to render. Measured on this Mac
424
- (M3): about 5x faster than real time, peaking around 870 MB of RAM while
476
+ (M3): about 5x faster than real time, peaking around 760 MB of RAM (measured
477
+ on an M4 on 2026-09-07; the M3 spike saw 870 MB) while
425
478
  rendering. `vocalize stop`, run from any terminal, halts a Kokoro read
426
479
  mid-sentence the same as any other provider.
427
480
 
@@ -443,7 +496,7 @@ vocalize local install --stt
443
496
  A separate opt-in from Kokoro's `vocalize local install` — nothing here is
444
497
  downloaded or built until you run this. It:
445
498
 
446
- 1. Downloads one whisper.cpp model (`small.en` by default, ~465 MB) from a
499
+ 1. Downloads one whisper.cpp model (`large-v3-turbo-q5_0` by default, ~547 MB) from a
447
500
  pinned Hugging Face revision, verified against a pinned sha256 before
448
501
  it's kept.
449
502
  2. Compiles and ad-hoc signs a small Swift recorder bundle, **Vocalize
@@ -460,13 +513,24 @@ more accurate) or `--model base.en` (~141 MB, fastest, least accurate).
460
513
  ### The hotkey
461
514
 
462
515
  ```bash
463
- python3 hooks/install_quick_action.py
516
+ vocalize app install
517
+ ```
518
+
519
+ installs and starts **Vocalize.app**, a menu-bar app that owns the
520
+ dictation hotkey (and speak/stop) system-wide, no Services menu or
521
+ per-app shortcut assignment needed — see [docs/app.md](docs/app.md) for
522
+ install, uninstall, status and restart. `vocalize dictate` is the same
523
+ command from a terminal, if you'd rather trigger it that way.
524
+
525
+ Prefer a Quick Action instead? That still works:
526
+
527
+ ```bash
528
+ vocalize integrate claude
464
529
  ```
465
530
 
466
531
  then assign a shortcut under **System Settings › Keyboard › Keyboard
467
532
  Shortcuts › Services › Text › "Dictate with Vocalize"** — ⌃⌥⌘D is free by
468
- default and a sensible pick. `vocalize dictate` is the same command from a
469
- terminal, if you'd rather trigger it that way.
533
+ default and a sensible pick.
470
534
 
471
535
  ### How a dictation works
472
536
 
@@ -517,10 +581,12 @@ overrides `[stt] max_seconds` for one invocation.
517
581
 
518
582
  ```toml
519
583
  [stt]
520
- model = "small.en" # base.en | small.en | large-v3-turbo-q5_0
521
- language = "en" # a whisper.cpp language code
584
+ model = "large-v3-turbo-q5_0" # base.en | small.en | large-v3-turbo-q5_0 | large-v3-turbo-q8_0
585
+ language = "en" # a whisper.cpp language code ("auto" to detect)
522
586
  input_device = "" # "" = system default; else an exact name from --list-devices
523
- cleanup = false # send the transcript (never audio) to Claude first
587
+ cleanup = "off" # off | local | claude-cli | anthropic — what tidies the transcript (never audio)
588
+ verbatim = false # true keeps every word even when cleanup is on
589
+ beam_size = 5 # 1-8 whisper.cpp beams; 1 is the greedy decoder
524
590
  max_seconds = 120 # 1-600; the recorder self-stops here, dictate backstops it
525
591
  sounds = true # the Tink/Pop/Glass feedback sounds
526
592
  cues = "sounds" # "sounds" | "words" | "both" — speak "Start."/"Stopped."/"Ready." instead
@@ -528,10 +594,12 @@ cues = "sounds" # "sounds" | "words" | "both" — speak "Start."/"Stopped
528
594
 
529
595
  | Key | Allowed values | Default |
530
596
  |---|---|---|
531
- | `model` | `base.en`, `small.en`, `large-v3-turbo-q5_0` | `small.en` |
597
+ | `model` | `base.en`, `small.en`, `large-v3-turbo-q5_0`, `large-v3-turbo-q8_0` | `large-v3-turbo-q5_0` |
532
598
  | `language` | a whisper.cpp language code (`en`, `es`, `fr`, …); an `.en` model must stay `en` | `en` |
533
599
  | `input_device` | `""` (system default) or an exact name from `vocalize listen --list-devices`; ≤ 128 characters, printable, can't start with `-` | `""` |
534
- | `cleanup` | `true` / `false` | `false` |
600
+ | `cleanup` | `off`, `local` (0.13), `claude-cli`, `anthropic`; an old `true`/`false` reads as `claude-cli`/`off` | `off` |
601
+ | `verbatim` | `true` / `false` — keep every word even when cleanup is on | `false` |
602
+ | `beam_size` | integer, 1–8 | `5` |
535
603
  | `paste` | reserved — not implemented in 0.10.0 | `false` |
536
604
  | `max_seconds` | integer, 1–600 | `120` |
537
605
  | `sounds` | `true` / `false` | `true` |
@@ -552,6 +620,37 @@ set it:
552
620
  input_device = "MacBook Pro Microphone"
553
621
  ```
554
622
 
623
+ ### Configuration: the `[app]` table
624
+
625
+ The chords the menu-bar app owns, system-wide. A change needs
626
+ `vocalize app restart` before the app picks it up.
627
+
628
+ ```toml
629
+ [app]
630
+ dictate = "ctrl+alt+cmd+d" # start/stop dictation
631
+ dictate_mode = "toggle" # toggle | hold ("hold" arrives in 0.13.1)
632
+ speak = "ctrl+alt+cmd+s" # speak the selection
633
+ stop = "ctrl+alt+cmd+x" # stop whatever is playing
634
+ ```
635
+
636
+ | Key | Allowed values | Default |
637
+ |---|---|---|
638
+ | `dictate` | a chord, or `""` to disable | `ctrl+alt+cmd+d` |
639
+ | `dictate_mode` | `toggle`, `hold` | `toggle` |
640
+ | `speak` | a chord, or `""` to disable | `ctrl+alt+cmd+s` |
641
+ | `stop` | a chord, or `""` to disable | `ctrl+alt+cmd+x` |
642
+
643
+ **Chord grammar:** tokens joined by `+`. Modifiers are `ctrl`, `alt`,
644
+ `cmd`, `shift` (long spellings `control`, `option`, `command` also work);
645
+ the key is one of `a`-`z`, `0`-`9`, `f1`-`f12`. A chord must include
646
+ `ctrl` or `cmd` — macOS refuses to register the rest. The three chords
647
+ must differ from each other, and `""` disables one.
648
+
649
+ A bad chord is a `ConfigError` naming the key, the value and the legal
650
+ keys — and, like any bad config value, it stops the command you ran, so
651
+ fix it before anything else works. `vocalize settings` prints the four
652
+ `app.*` values in their canonical spelling.
653
+
555
654
  ### `vocalize status`
556
655
 
557
656
  ```bash
@@ -574,6 +673,17 @@ get four permanent red rows for a feature nobody asked for):
574
673
  providers and dictation both — is `ok`, 1 otherwise, so it composes with
575
674
  `&&` in a script.
576
675
 
676
+ ### `vocalize doctor`
677
+
678
+ Everything `status` checks plus the machine itself: the CLI's own path and
679
+ start-up time, `uv`, `swiftc`, `claude`, the console script's interpreter,
680
+ Hammerspoon, the app bundle and the notes folder. Every row regardless of the
681
+ chain, exit 1 when any row fails. `--json` for scripts.
682
+
683
+ ```bash
684
+ vocalize doctor
685
+ ```
686
+
577
687
  ### Continuing an interrupted read
578
688
 
579
689
  Starting a dictation stops any read in progress, but doesn't throw the rest
@@ -647,15 +757,16 @@ Four Services let you use vocalize from any app without a terminal:
647
757
  Install all four:
648
758
 
649
759
  ```bash
650
- python3 hooks/install_quick_action.py
760
+ vocalize integrate claude
651
761
  ```
652
762
 
653
- This copies the bundles from `hooks/quick_actions/` into
654
- `~/Library/Services/` with this machine's absolute `vocalize`, `claude`,
655
- and helper paths baked in, then refreshes the Services registry. Run it
656
- from a normal terminal — its PATH is what gets captured. To trigger the
657
- actions from the keyboard, assign shortcuts under System Settings →
658
- Keyboard → Keyboard Shortcuts → Services (Stop Vocalize is worth a
763
+ This installs the `/speak` skill plus the four Quick Action bundles into
764
+ `~/Library/Services/`, with this machine's `vocalize`, `claude`, and
765
+ helper paths baked in (the stable symlinks, not their resolved targets —
766
+ survives a `brew upgrade claude-code`), then refreshes the Services
767
+ registry. Run it from a normal terminal — its PATH is what gets captured.
768
+ To trigger the actions from the keyboard, assign shortcuts under System
769
+ Settings → Keyboard → Keyboard Shortcuts → Services (Stop Vocalize is worth a
659
770
  shortcut of its own so you can silence a read from anywhere).
660
771
 
661
772
  Some Electron apps (Claude Code desktop among them) don't expose the
@@ -867,9 +978,10 @@ model.
867
978
  there. Use `--no-play` and open the saved file with whatever's on hand.
868
979
  - **The disk cache under `~/.cache/vocalize` grows unbounded.** It's
869
980
  content-addressed (keyed by a hash of text, voice, model, format, and
870
- speed),
871
- so it's always safe to delete some or all of it — nothing will break,
872
- you'll just re-pay for a re-synthesized clip.
981
+ speed), so it's always safe to delete — except `bin/`, which holds
982
+ Vocalize Recorder and is tied to your microphone grant; deleting that
983
+ forces a rebuild and a re-grant. Delete anything else and nothing will
984
+ break, you'll just re-pay for a re-synthesized clip.
873
985
  - **`--api-key` on the command line is visible to other local processes**
874
986
  (anything that can run `ps`). Prefer `vocalize auth login`, the
875
987
  `ELEVENLABS_API_KEY` environment variable, or a `.env` file instead.
@@ -908,9 +1020,11 @@ model.
908
1020
  re-approve it in System Settings › Privacy & Security › Microphone. An
909
1021
  install that doesn't change the source never re-signs, so this isn't
910
1022
  every upgrade — only ones that touch the recorder.
911
- - **`small.en` mishears jargon.** The default model does fine on ordinary
912
- speech but can mangle project-specific words (`pyproject`, a function
913
- name) — pick `large-v3-turbo-q5_0` for better accuracy, or turn on
1023
+ - **The smaller models mishear jargon.** `large-v3-turbo-q5_0` is the
1024
+ default because it was the first model to keep "the merge" as two words
1025
+ on the owner's own voice; `small.en` (465 MB) is the lighter choice for a
1026
+ slow Mac but can mangle project-specific words (`pyproject`, a function
1027
+ name) — stay on the default for accuracy, or turn on
914
1028
  `[stt] cleanup` so Claude fixes obvious transcription noise before it
915
1029
  reaches your clipboard (it still can't guess a word it never heard
916
1030
  correctly).