sybl 0.1.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 (139) hide show
  1. sybl-0.1.0/.cursor/rules/maintain-agents-md.mdc +34 -0
  2. sybl-0.1.0/.cursor/rules/no-coauthor-commits.mdc +9 -0
  3. sybl-0.1.0/.githooks/commit-msg +6 -0
  4. sybl-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +96 -0
  5. sybl-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +54 -0
  6. sybl-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +17 -0
  7. sybl-0.1.0/.github/workflows/ci.yml +49 -0
  8. sybl-0.1.0/.github/workflows/release.yml +25 -0
  9. sybl-0.1.0/.gitignore +17 -0
  10. sybl-0.1.0/.python-version +1 -0
  11. sybl-0.1.0/AGENTS.md +256 -0
  12. sybl-0.1.0/CHANGELOG.md +41 -0
  13. sybl-0.1.0/CODE_OF_CONDUCT.md +59 -0
  14. sybl-0.1.0/CONTRIBUTING.md +92 -0
  15. sybl-0.1.0/LICENSE +21 -0
  16. sybl-0.1.0/PKG-INFO +123 -0
  17. sybl-0.1.0/README.md +79 -0
  18. sybl-0.1.0/SECURITY.md +26 -0
  19. sybl-0.1.0/docs/DAEMON.md +45 -0
  20. sybl-0.1.0/docs/DEVELOPMENT.md +72 -0
  21. sybl-0.1.0/docs/POPUP-SPIKE.md +42 -0
  22. sybl-0.1.0/docs/RESEARCH-NOTES.md +184 -0
  23. sybl-0.1.0/docs/ROADMAP.md +261 -0
  24. sybl-0.1.0/docs/configuration.md +147 -0
  25. sybl-0.1.0/docs/getting-started.md +117 -0
  26. sybl-0.1.0/docs/permissions.md +61 -0
  27. sybl-0.1.0/docs/providers.md +110 -0
  28. sybl-0.1.0/main.py +6 -0
  29. sybl-0.1.0/pyproject.toml +83 -0
  30. sybl-0.1.0/sybl/__init__.py +3 -0
  31. sybl-0.1.0/sybl/__main__.py +5 -0
  32. sybl-0.1.0/sybl/audio/__init__.py +38 -0
  33. sybl-0.1.0/sybl/audio/debug.py +41 -0
  34. sybl-0.1.0/sybl/audio/devices.py +224 -0
  35. sybl-0.1.0/sybl/audio/errors.py +17 -0
  36. sybl-0.1.0/sybl/audio/metering.py +77 -0
  37. sybl-0.1.0/sybl/audio/resample.py +25 -0
  38. sybl-0.1.0/sybl/audio/session.py +289 -0
  39. sybl-0.1.0/sybl/audio/types.py +34 -0
  40. sybl-0.1.0/sybl/cli/__init__.py +56 -0
  41. sybl-0.1.0/sybl/cli/audio_cmd.py +147 -0
  42. sybl-0.1.0/sybl/cli/config_cmd.py +164 -0
  43. sybl-0.1.0/sybl/cli/doctor.py +534 -0
  44. sybl-0.1.0/sybl/cli/hotkey_cmd.py +72 -0
  45. sybl-0.1.0/sybl/cli/io.py +13 -0
  46. sybl-0.1.0/sybl/cli/meter.py +32 -0
  47. sybl-0.1.0/sybl/cli/start.py +70 -0
  48. sybl-0.1.0/sybl/cli/status.py +39 -0
  49. sybl-0.1.0/sybl/cli/stop.py +32 -0
  50. sybl-0.1.0/sybl/cli/transcribe_cmd.py +169 -0
  51. sybl-0.1.0/sybl/cli/tui.py +30 -0
  52. sybl-0.1.0/sybl/config/__init__.py +29 -0
  53. sybl-0.1.0/sybl/config/manager.py +101 -0
  54. sybl-0.1.0/sybl/config/models.py +107 -0
  55. sybl-0.1.0/sybl/config/paths.py +34 -0
  56. sybl-0.1.0/sybl/config/vocabulary.py +94 -0
  57. sybl-0.1.0/sybl/core/__init__.py +17 -0
  58. sybl-0.1.0/sybl/core/daemon.py +305 -0
  59. sybl-0.1.0/sybl/core/dictation.py +340 -0
  60. sybl-0.1.0/sybl/core/events.py +95 -0
  61. sybl-0.1.0/sybl/core/history.py +63 -0
  62. sybl-0.1.0/sybl/core/postprocess.py +124 -0
  63. sybl-0.1.0/sybl/core/state.py +70 -0
  64. sybl-0.1.0/sybl/core/transcribe.py +189 -0
  65. sybl-0.1.0/sybl/core/voice_commands.py +43 -0
  66. sybl-0.1.0/sybl/hotkeys/__init__.py +16 -0
  67. sybl-0.1.0/sybl/hotkeys/base.py +40 -0
  68. sybl-0.1.0/sybl/hotkeys/bindings.py +95 -0
  69. sybl-0.1.0/sybl/hotkeys/focus.py +45 -0
  70. sybl-0.1.0/sybl/hotkeys/pynput_backend.py +197 -0
  71. sybl-0.1.0/sybl/indicator/__init__.py +22 -0
  72. sybl-0.1.0/sybl/indicator/base.py +15 -0
  73. sybl-0.1.0/sybl/indicator/cursor_win.py +31 -0
  74. sybl-0.1.0/sybl/indicator/noop.py +17 -0
  75. sybl-0.1.0/sybl/indicator/tk_win.py +187 -0
  76. sybl-0.1.0/sybl/inject/__init__.py +9 -0
  77. sybl-0.1.0/sybl/inject/base.py +32 -0
  78. sybl-0.1.0/sybl/inject/clipboard_win.py +253 -0
  79. sybl-0.1.0/sybl/inject/focus_win.py +56 -0
  80. sybl-0.1.0/sybl/ipc/__init__.py +12 -0
  81. sybl-0.1.0/sybl/ipc/client.py +175 -0
  82. sybl-0.1.0/sybl/ipc/process.py +28 -0
  83. sybl-0.1.0/sybl/ipc/protocol.py +76 -0
  84. sybl-0.1.0/sybl/ipc/server.py +192 -0
  85. sybl-0.1.0/sybl/ipc/single_instance.py +66 -0
  86. sybl-0.1.0/sybl/logging/__init__.py +6 -0
  87. sybl-0.1.0/sybl/logging/ring_buffer.py +36 -0
  88. sybl-0.1.0/sybl/logging/setup.py +49 -0
  89. sybl-0.1.0/sybl/providers/__init__.py +41 -0
  90. sybl-0.1.0/sybl/providers/base.py +17 -0
  91. sybl-0.1.0/sybl/providers/capabilities.py +51 -0
  92. sybl-0.1.0/sybl/providers/deepgram.py +213 -0
  93. sybl-0.1.0/sybl/providers/errors.py +21 -0
  94. sybl-0.1.0/sybl/providers/groq.py +141 -0
  95. sybl-0.1.0/sybl/providers/manager.py +90 -0
  96. sybl-0.1.0/sybl/providers/pcm.py +21 -0
  97. sybl-0.1.0/sybl/providers/registry.py +49 -0
  98. sybl-0.1.0/sybl/providers/types.py +12 -0
  99. sybl-0.1.0/sybl/secrets/__init__.py +19 -0
  100. sybl-0.1.0/sybl/secrets/store.py +52 -0
  101. sybl-0.1.0/sybl/tui/__init__.py +5 -0
  102. sybl-0.1.0/sybl/tui/app.py +178 -0
  103. sybl-0.1.0/sybl/tui/client.py +69 -0
  104. sybl-0.1.0/sybl/tui/screens/__init__.py +0 -0
  105. sybl-0.1.0/sybl/tui/screens/dashboard.py +51 -0
  106. sybl-0.1.0/sybl/tui/screens/onboarding.py +55 -0
  107. sybl-0.1.0/sybl/tui/screens/settings.py +147 -0
  108. sybl-0.1.0/sybl/tui/widgets/__init__.py +0 -0
  109. sybl-0.1.0/sybl/tui/widgets/history_panel.py +44 -0
  110. sybl-0.1.0/sybl/tui/widgets/log_view.py +17 -0
  111. sybl-0.1.0/sybl/tui/widgets/status_bar.py +29 -0
  112. sybl-0.1.0/tests/conftest.py +17 -0
  113. sybl-0.1.0/tests/test_audio.py +329 -0
  114. sybl-0.1.0/tests/test_bindings.py +40 -0
  115. sybl-0.1.0/tests/test_cli.py +83 -0
  116. sybl-0.1.0/tests/test_cli_io.py +16 -0
  117. sybl-0.1.0/tests/test_config.py +96 -0
  118. sybl-0.1.0/tests/test_daemon_indicator.py +65 -0
  119. sybl-0.1.0/tests/test_deepgram.py +119 -0
  120. sybl-0.1.0/tests/test_dictation.py +310 -0
  121. sybl-0.1.0/tests/test_doctor.py +46 -0
  122. sybl-0.1.0/tests/test_history.py +37 -0
  123. sybl-0.1.0/tests/test_hotkeys.py +79 -0
  124. sybl-0.1.0/tests/test_indicator.py +49 -0
  125. sybl-0.1.0/tests/test_inject.py +98 -0
  126. sybl-0.1.0/tests/test_ipc_protocol.py +39 -0
  127. sybl-0.1.0/tests/test_ipc_server.py +42 -0
  128. sybl-0.1.0/tests/test_logging.py +38 -0
  129. sybl-0.1.0/tests/test_manager.py +76 -0
  130. sybl-0.1.0/tests/test_postprocess.py +75 -0
  131. sybl-0.1.0/tests/test_provider_vocabulary.py +27 -0
  132. sybl-0.1.0/tests/test_providers.py +135 -0
  133. sybl-0.1.0/tests/test_secrets.py +75 -0
  134. sybl-0.1.0/tests/test_single_instance.py +34 -0
  135. sybl-0.1.0/tests/test_transcribe.py +128 -0
  136. sybl-0.1.0/tests/test_tui_client.py +31 -0
  137. sybl-0.1.0/tests/test_vocabulary.py +39 -0
  138. sybl-0.1.0/tests/test_voice_commands.py +35 -0
  139. sybl-0.1.0/uv.lock +1069 -0
@@ -0,0 +1,34 @@
1
+ ---
2
+ description: Keep AGENTS.md as the living source of truth; read it first and update it whenever project reality changes.
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Maintain AGENTS.md
7
+
8
+ `AGENTS.md` at the repo root is the living source of truth for the sybl project
9
+ (mission, product spec, current state, architecture decisions, structure,
10
+ conventions).
11
+
12
+ ## At the start of a task
13
+ - Read `AGENTS.md` before planning or making changes so your work aligns with
14
+ the current mission, decisions, and conventions.
15
+
16
+ ## During / after a task — update `AGENTS.md` when you:
17
+ - Change the mission, scope, or product behavior → update the Mission / Product
18
+ Spec sections.
19
+ - Advance the project phase or status → update the Current State section and
20
+ `docs/ROADMAP.md`.
21
+ - Make or reverse a technical/architecture decision → append a row/note to the
22
+ Architecture & Tech Decisions log (append, don't erase history).
23
+ - Add, move, or remove top-level files/directories → update the Project
24
+ Structure section.
25
+ - Establish or change a convention → update the Conventions section.
26
+
27
+ ## Rules
28
+ 1. Bump the `Last updated` date at the top of `AGENTS.md` whenever you edit it.
29
+ 2. Append to the decision log rather than deleting prior decisions; if a
30
+ decision changes, add a new entry explaining the change.
31
+ 3. Keep `AGENTS.md` concise — it is a map. Put depth in `docs/`.
32
+ 4. If reality and `AGENTS.md` disagree, fix `AGENTS.md`.
33
+ 5. Before ending a turn that changed the project, verify `AGENTS.md` is still
34
+ accurate and update it if anything went stale.
@@ -0,0 +1,9 @@
1
+ # No agent co-author commit trailers
2
+
3
+ When creating git commits in this repository:
4
+
5
+ - **Never** add `Co-authored-by:` trailers (including `Co-authored-by: Cursor <cursoragent@cursor.com>`).
6
+ - **Never** add any Cursor, Copilot, or AI agent attribution to commit messages.
7
+ - Keep commit messages concise and focused on the change; author attribution is handled by git config only.
8
+
9
+ If staging changes for the user to commit, leave the message body free of co-author lines.
@@ -0,0 +1,6 @@
1
+ #!/bin/sh
2
+ # Reject Cursor agent co-author trailers. Enable with: git config core.hooksPath .githooks
3
+ if grep -qi 'Co-authored-by:.*Cursor' "$1"; then
4
+ echo "error: commit message must not include Co-authored-by: Cursor trailers" >&2
5
+ exit 1
6
+ fi
@@ -0,0 +1,96 @@
1
+ name: Bug report
2
+ description: Something isn't working as expected
3
+ title: "[Bug]: "
4
+ labels: ["bug"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Thanks for the report. Include `sybl doctor` output if you can.
10
+
11
+ - type: dropdown
12
+ id: os
13
+ attributes:
14
+ label: Operating system
15
+ options:
16
+ - Windows
17
+ - macOS
18
+ - Linux
19
+ - Other
20
+ validations:
21
+ required: true
22
+
23
+ - type: input
24
+ id: python
25
+ attributes:
26
+ label: Python version
27
+ placeholder: "3.12.x"
28
+ validations:
29
+ required: true
30
+
31
+ - type: input
32
+ id: sybl_version
33
+ attributes:
34
+ label: sybl version
35
+ placeholder: "0.1.0 or git commit"
36
+ validations:
37
+ required: true
38
+
39
+ - type: dropdown
40
+ id: provider
41
+ attributes:
42
+ label: STT provider
43
+ options:
44
+ - Groq
45
+ - Deepgram
46
+ - Other / none
47
+ - Not sure
48
+ validations:
49
+ required: true
50
+
51
+ - type: textarea
52
+ id: steps
53
+ attributes:
54
+ label: Steps to reproduce
55
+ placeholder: |
56
+ 1. sybl start
57
+ 2. Hold hotkey and speak
58
+ 3. ...
59
+ validations:
60
+ required: true
61
+
62
+ - type: textarea
63
+ id: expected
64
+ attributes:
65
+ label: Expected behavior
66
+ validations:
67
+ required: true
68
+
69
+ - type: textarea
70
+ id: actual
71
+ attributes:
72
+ label: Actual behavior
73
+ validations:
74
+ required: true
75
+
76
+ - type: textarea
77
+ id: doctor
78
+ attributes:
79
+ label: sybl doctor output
80
+ render: shell
81
+ placeholder: Paste output of `sybl doctor`
82
+
83
+ - type: textarea
84
+ id: logs
85
+ attributes:
86
+ label: Relevant logs
87
+ description: Redact API keys. Log file is under your sybl state directory.
88
+ render: shell
89
+
90
+ - type: checkboxes
91
+ id: terms
92
+ attributes:
93
+ label: Checklist
94
+ options:
95
+ - label: I searched existing issues before opening this
96
+ required: true
@@ -0,0 +1,54 @@
1
+ name: Feature request
2
+ description: Suggest an idea for sybl
3
+ title: "[Feature]: "
4
+ labels: ["enhancement"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Check [docs/ROADMAP.md](https://github.com/Rikhil-Nell/sybl/blob/main/docs/ROADMAP.md)
10
+ before filing — some items may already be planned.
11
+
12
+ - type: textarea
13
+ id: problem
14
+ attributes:
15
+ label: Problem or use case
16
+ description: What problem does this solve? Who benefits?
17
+ validations:
18
+ required: true
19
+
20
+ - type: textarea
21
+ id: solution
22
+ attributes:
23
+ label: Proposed solution
24
+ description: How would you like this to work?
25
+ validations:
26
+ required: true
27
+
28
+ - type: textarea
29
+ id: alternatives
30
+ attributes:
31
+ label: Alternatives considered
32
+ description: Other approaches you've thought about
33
+
34
+ - type: dropdown
35
+ id: platform
36
+ attributes:
37
+ label: Primary platform
38
+ options:
39
+ - Windows
40
+ - macOS
41
+ - Linux
42
+ - Cross-platform
43
+ validations:
44
+ required: true
45
+
46
+ - type: checkboxes
47
+ id: terms
48
+ attributes:
49
+ label: Checklist
50
+ options:
51
+ - label: This aligns with sybl's BYOK, local-first mission (no hosted backend)
52
+ required: true
53
+ - label: I searched existing issues before opening this
54
+ required: true
@@ -0,0 +1,17 @@
1
+ ## Summary
2
+
3
+ <!-- What changed and why? -->
4
+
5
+ ## Test plan
6
+
7
+ - [ ] `uv run ruff check sybl tests`
8
+ - [ ] `uv run pytest -m "not integration" -q`
9
+ - [ ] Updated [AGENTS.md](AGENTS.md) if behavior or architecture changed
10
+ - [ ] No secrets or API keys in the diff
11
+
12
+ ## Platform notes
13
+
14
+ <!-- If hotkeys, injection, or indicator code changed, describe manual Windows testing. -->
15
+
16
+ - [ ] Not applicable
17
+ - [ ] Tested manually on Windows
@@ -0,0 +1,49 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ lint-and-test:
11
+ runs-on: ${{ matrix.os }}
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ os: [windows-latest, ubuntu-latest]
16
+ python-version: ["3.12"]
17
+ env:
18
+ NO_COLOR: "1"
19
+ TERM: dumb
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+
23
+ - uses: astral-sh/setup-uv@v5
24
+ with:
25
+ python-version: ${{ matrix.python-version }}
26
+
27
+ - name: Install system dependencies (Linux)
28
+ if: runner.os == 'Linux'
29
+ run: sudo apt-get update && sudo apt-get install -y portaudio19-dev xvfb
30
+
31
+ - name: Install dependencies
32
+ run: uv sync
33
+
34
+ - name: Install Linux keyring backend
35
+ if: runner.os == 'Linux'
36
+ run: uv pip install keyrings.alt
37
+
38
+ - name: Lint
39
+ run: uv run ruff check sybl tests
40
+
41
+ - name: Unit tests (Linux)
42
+ if: runner.os == 'Linux'
43
+ env:
44
+ PYTHON_KEYRING_BACKEND: keyrings.alt.file.PlaintextKeyring
45
+ run: xvfb-run uv run pytest -m "not integration" -q --ignore=tests/test_inject.py
46
+
47
+ - name: Unit tests (Windows)
48
+ if: runner.os == 'Windows'
49
+ run: uv run pytest -m "not integration" -q
@@ -0,0 +1,25 @@
1
+ name: Release
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ id-token: write
9
+ contents: read
10
+
11
+ jobs:
12
+ pypi:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+
17
+ - uses: astral-sh/setup-uv@v5
18
+ with:
19
+ python-version: "3.12"
20
+
21
+ - name: Build package
22
+ run: uv build
23
+
24
+ - name: Publish to PyPI
25
+ uses: pypa/gh-action-pypi-publish@release/v1
sybl-0.1.0/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ # Tooling caches
13
+ .ruff_cache/
14
+ .pytest_cache/
15
+
16
+ # Logs
17
+ *.log
@@ -0,0 +1 @@
1
+ 3.12
sybl-0.1.0/AGENTS.md ADDED
@@ -0,0 +1,256 @@
1
+ # AGENTS.md
2
+
3
+ > Living source of truth for the sybl project. Read this first. Keep it current.
4
+ > Last updated: 2026-06-28 (rebrand to sybl — package, CLI, PyPI, and paths)
5
+
6
+ ---
7
+
8
+ ## 1. Mission
9
+
10
+ **sybl is an open-source, bring-your-own-key (BYOK) voice dictation tool.**
11
+
12
+ Put your cursor anywhere, hit a global shortcut, speak/ramble into a lightweight
13
+ popup, and sybl transcribes it fast and types it in for you — wherever you were
14
+ about to type. It is the open-source answer to closed tools like Wispr Flow.
15
+
16
+ The guiding principles:
17
+
18
+ - **BYOK, provider-agnostic.** Users plug in whatever speech-to-text (STT)
19
+ credits they already have — Deepgram, AssemblyAI, Gladia, Groq (Whisper
20
+ large-v3), etc. No vendor lock-in, no sybl-hosted backend, no subscription.
21
+ - **Local-first & private.** Audio goes straight from the user's machine to the
22
+ STT provider of their choice. sybl keeps no telemetry and stores nothing it
23
+ doesn't have to.
24
+ - **Fast & invisible.** Dictation should feel instant and stay out of the way.
25
+ - **TUI, daemon-based.** sybl runs as a background daemon. All of its UI is a
26
+ terminal UI (TUI): live logs, status, history, and config — nothing more.
27
+
28
+ ## 2. What sybl Does (Product Spec)
29
+
30
+ - **Global activation.** A system-wide shortcut works regardless of focused app.
31
+ - **Two interaction modes:**
32
+ - **Push-to-talk (PTT):** hold the shortcut, speak, release to finish.
33
+ - **Toggle / constant recording:** a double-press of the shortcut starts
34
+ continuous recording; press again to stop.
35
+ - **Popup capture surface.** When activated, a small on-screen pill appears near the
36
+ cursor so the user knows sybl is listening (Windows tkinter overlay MVP; see
37
+ `docs/POPUP-SPIKE.md`).
38
+ - **BYOK transcription.** Audio is streamed/sent to the user's selected provider
39
+ and transcribed quickly.
40
+ - **Text injection.** The transcript is inserted at the current cursor location
41
+ in whatever app had focus when activation happened.
42
+ - **TUI surface.** A Textual-based TUI shows live logs, current state, and a
43
+ scrollback history of recent transcriptions for reference.
44
+
45
+ ## 3. Current State
46
+
47
+ > Update this section every time the project's reality changes.
48
+
49
+ - **Phase:** Phase 10 complete — v0.1.0 public release on GitHub and PyPI; contributor
50
+ docs, CI (Windows + Ubuntu), issue/PR templates, and user docs hub shipped.
51
+ - **Code:** `sybl/audio/` implements `AudioCaptureSession` (sounddevice callback →
52
+ asyncio queue, 16 kHz mono int16, resampling, dBFS peak metering, debug WAV save).
53
+ `sybl/providers/` implements streaming-first STT interface, `ProviderCapabilities`,
54
+ `resolve_provider` session-start selection, `GroqProvider` (batch), and
55
+ `DeepgramProvider` (WebSocket streaming + REST batch via official SDK).
56
+ `sybl/hotkeys/` implements `HotkeyManager`, binding parser, Windows `pynput` PTT
57
+ backend, and focus capture at activation. `sybl/inject/` implements `TextInjector`,
58
+ Windows clipboard-paste injection with focus restore and clipboard restoration.
59
+ `sybl/core/` has `StateMachine`, `DictationController`, `SyblDaemon`, post-processing,
60
+ voice commands, `TranscriptHistory`, `EventBus`, and transcribe pipeline.
61
+ `sybl/config/vocabulary.py` stores STT hint terms. `sybl/ipc/` implements
62
+ NDJSON command/event TCP servers and client. `sybl/tui/` is a Textual app (logs,
63
+ status, history, settings, BYOK onboarding). `sybl/indicator/` implements
64
+ `CaptureIndicator` (NoOp + Windows tkinter overlay near cursor with RMS level bar).
65
+ CLI: `sybl start`, `sybl stop`, `sybl status`, `sybl tui`, `sybl config`,
66
+ `sybl config vocab`, `sybl doctor`, `sybl audio`, `sybl transcribe`, `sybl hotkey test`.
67
+ - **Stack pinned:** `typer`, `pydantic`, `platformdirs`, `keyring`, `tomli-w`,
68
+ `sounddevice`, `numpy`, `soundfile`, `soxr`, `groq`, `tenacity`, `deepgram-sdk`,
69
+ `pynput`, `textual`; dev: `ruff`, `pytest`, `pytest-asyncio`.
70
+ - **Primary platform:** Windows first (dev machine). Code stays cross-platform
71
+ behind interfaces, but the core loop is proven on Windows before expanding.
72
+ - **Open questions:** per-platform overlay beyond Windows; text-injection
73
+ edge cases (Wayland especially); how aggressive default post-processing should
74
+ be.
75
+
76
+ ## 4. Architecture & Tech Decisions
77
+
78
+ > A decision log. Append new decisions; don't silently rewrite history.
79
+
80
+ | Area | Decision | Rationale |
81
+ |------|----------|-----------|
82
+ | Language | Python 3.12 | Already scaffolded; first-class STT SDKs; great TUI ecosystem. |
83
+ | Packaging / env | `uv` + `pyproject.toml` | Already in place; fast, reproducible. |
84
+ | TUI framework | Textual (pinned) | Modern, async, rich rendering for logs/history; `sybl tui` attaches over IPC. |
85
+ | Audio capture | `sounddevice` + **callback → queue** pattern | PortAudio bindings, NumPy-friendly; callback pushes int16 PCM to an `asyncio.Queue`; never block or process in the callback. |
86
+ | Audio format | **16 kHz, mono, int16 PCM** | What most STT providers expect; resample in-pipeline if the device opens at 48 kHz. |
87
+ | Daemon concurrency | **`asyncio` event loop** + dedicated audio thread | Daemon/TUI/async providers run on asyncio; sounddevice callback thread only enqueues chunks. |
88
+ | Global hotkeys | `pynput` for **MVP**, behind `HotkeyManager` interface | Fast to ship on Windows; plan migration to a small **native helper** (e.g. Rust `global-hotkey`) if reliability stalls. Avoid the `keyboard` library (security/root issues). |
89
+ | STT providers | Pluggable, **streaming-first** interface | Core BYOK requirement; designing for streaming up front avoids rework when batch is the easy case. |
90
+ | Reference provider | **Deepgram** (streaming) as reference; **Groq Whisper** (batch) as early sanity check | Deepgram's streaming is fast/feature-rich and makes the cleanest reference; Groq gives the fastest first end-to-end signal as a degenerate batch case behind the same interface. |
91
+ | Groq integration | Official **`groq` SDK** + in-memory WAV upload via `asyncio.to_thread()` | OpenAI-compatible transcriptions endpoint; default model `whisper-large-v3-turbo`; PCM→WAV matches Groq's 16 kHz mono expectation. |
92
+ | Deepgram integration | Official **`deepgram-sdk`** — WebSocket `wss://api.deepgram.com/v1/listen` for streaming, REST `/v1/listen` for batch | Raw linear16 PCM at 16 kHz mono on websocket; `interim_results=true` for partials; `CloseStream` on end; default model `nova-3`. |
93
+ | Process model | Background daemon + TUI client over local IPC | Daemon listens for hotkeys always; TUI attaches on demand. |
94
+ | Daemon authority | Daemon is the **single source of truth** | Owns mic, providers, state machine, injection, config; TUI is a thin observe/command client. Config changes flow through the daemon so they persist and take effect immediately (no TUI/daemon drift). |
95
+ | IPC shape | Simple command/response + a separate log/event stream; ring buffer for logs & history | More maintainable than sharing complex objects across processes; predictable memory; clean TUI reconnects. |
96
+ | STT interface shape | **Async generators** yielding `TranscriptionResult` | `async def transcribe(audio: bytes \| AsyncIterable[bytes]) -> AsyncGenerator[TranscriptionResult, None]` with `text`, `is_final`, optional `confidence`. |
97
+ | STT errors/retries | Custom exception hierarchy + **`tenacity`** | Normalize `STTError`, `STTTimeoutError`, `STTRateLimitError`; retry only transient failures. |
98
+ | Provider selection | **`ProviderManager`** above providers | Registry + capability flags + config-driven fallback at **session start** (not mid-stream). |
99
+ | Config validation | **Pydantic** models | Schema validation and sane defaults for provider/device settings. |
100
+ | Text injection | **Clipboard set + simulated paste = primary**; synthetic keystrokes = labeled secondary/experimental | Paste is the most forgiving path in pure Python; restore prior clipboard after. Wispr-level reliability eventually needs **native injection** (Win `SendInput`, macOS `CGEvent`) — document limitations until then. |
101
+ | Hotkey escape hatch | If `pynput` reliability becomes a recurring problem, introduce a small **native component** (Rust `global-hotkey` or similar) rather than fighting Python libs | Commercial tools use native code per OS; pure Python won't match Wispr Flow on hotkeys/injection long-term. |
102
+ | Signal metering | **RMS level** for UI now; proper **VAD later** | RMS feeds the popup/TUI meter; `webrtcvad` or `silero-vad` when we need to avoid cutting off speech or trailing silence. |
103
+ | Core concerns | State machine + post-processing pipeline are **first-class from early on** | They sit at the center of UX and the core text path; easier to refine while surrounding plumbing is still simple. |
104
+ | Secrets | OS keyring via `sybl.secrets` | Keep API keys out of plaintext config; `sybl config set-key`. |
105
+ | CLI | Typer subcommands | `start`, `stop`, `status`, `tui`, `config`, `doctor`, `audio`, `transcribe`, `hotkey`. |
106
+ | Logging | File + console + ring buffer | `sybl.logging.setup_logging`; ring buffer for future TUI tail. |
107
+ | Phase 4 hotkeys | **PTT-first** via `pynput` behind `HotkeyManager`; focus captured at **activation press** | Reliability anchor before toggle mode; HWND stored for Phase 5 injection; Windows-only MVP. |
108
+ | Phase 5 injection | **Clipboard set + simulated Ctrl+V** via `SendInput` (ctypes); restore prior clipboard; focus restore with thread attach | Primary strategy on Windows; avoids pynput paste deadlock with hotkey listener; no new deps. |
109
+ | Phase 5.5 post-processing | **Rule-based pipeline** (`PostProcessConfig` + ordered passes) between STT and inject | Whitespace, filler trim, capitalize on by default; auto-punctuation off; Phase 9 expands without restructuring. |
110
+ | Phase 6 IPC | **TCP localhost NDJSON** — separate command + event ports; `daemon.json` + PID lock | Cross-platform; asyncio-native; TUI/CLI attach without shared memory. |
111
+ | Phase 7 TUI | **Textual dashboard** — logs, status, history, settings, BYOK onboarding | All config/key writes routed through daemon IPC; keyboard-driven MVP. |
112
+ | Phase 8 indicator | **Windows tkinter overlay** on dedicated thread; `CaptureIndicator` protocol + `NoOpIndicator` elsewhere | Stdlib, no new deps; cursor position via ctypes; show on LISTENING, RMS level bar; degrade to no-op if tk fails (`docs/POPUP-SPIKE.md`). |
113
+ | Phase 9 vocabulary | **STT hints only** — `vocabulary.toml` + Deepgram keyterms + Groq prompt at session start | Names/jargon at transcription source; no post-STT replacement map; term list reused by future LLM pass. |
114
+ | Phase 9 voice commands | **Final-transcript parsing** — `new line`, `period`, `comma` | No streaming/wake-word; Esc cancels before STT/inject; no scratch-that erase. |
115
+ | Phase 10 OSS | **MIT license**, PyPI + `pipx`/`uv tool` primary install, GitHub issue/PR templates, CI on Windows+Ubuntu | Hermes-style contributor surface without a separate docs site; `docs/` hub + README landing page. |
116
+ | Phase 10 PyPI | **`release.yml`** on GitHub Release → `uv build` → PyPI trusted publishing (OIDC) | No long-lived PyPI token in repo; maintainers configure pending publisher on PyPI. |
117
+ | Rebrand | **sybl** everywhere — Python package `sybl/`, CLI **`sybl`**, PyPI **`sybl`**, app id `sybl` | Prior names `navi` and `sybil`/`sybil-dictation` were taken or conflicted on PyPI; `sybl` is the canonical name. |
118
+
119
+ High-level component map:
120
+
121
+ ```
122
+ +-------------------+
123
+ global hotkey | Hotkey Listener |
124
+ ───────────────▶ (PTT / toggle) │
125
+ +---------+---------+
126
+ │ activate
127
+
128
+ +-----------+ +-------+-------+ +------------------+
129
+ | Audio |─────▶| Daemon Core |─────▶| STT Provider |
130
+ | Capture | PCM | (state machine)| audio| (BYOK, pluggable)|
131
+ +-----------+ +-------+-------+ +--------+---------+
132
+ │ transcript │ text
133
+ ▼ │
134
+ +--------+--------+◀─────────────+
135
+ | Text Injection |
136
+ | (cursor target) |
137
+ +-----------------+
138
+
139
+ +-----------------+------------------+
140
+ │ IPC (logs/state/history) │
141
+ +--------+--------+ +-----------+-----------+
142
+ | TUI Client | | Capture Indicator |
143
+ | (Textual app) | | (listening pill, Win) |
144
+ +-----------------+ +-----------------------+
145
+ ```
146
+
147
+ ## 5. Project Structure
148
+
149
+ > Keep this in sync with the real tree as it grows.
150
+
151
+ ```
152
+ sybl/
153
+ ├── AGENTS.md
154
+ ├── README.md
155
+ ├── LICENSE
156
+ ├── CONTRIBUTING.md
157
+ ├── CODE_OF_CONDUCT.md
158
+ ├── SECURITY.md
159
+ ├── CHANGELOG.md
160
+ ├── .github/
161
+ │ ├── ISSUE_TEMPLATE/
162
+ │ ├── PULL_REQUEST_TEMPLATE.md
163
+ │ └── workflows/ # ci.yml, release.yml
164
+ ├── .githooks/ # optional commit-msg hook (no Cursor co-author)
165
+ ├── docs/
166
+ │ ├── getting-started.md
167
+ │ ├── providers.md
168
+ │ ├── configuration.md
169
+ │ ├── permissions.md
170
+ │ ├── DEVELOPMENT.md
171
+ │ ├── DAEMON.md
172
+ │ ├── POPUP-SPIKE.md
173
+ │ ├── ROADMAP.md
174
+ │ └── RESEARCH-NOTES.md
175
+ ├── main.py # legacy redirect to CLI
176
+ ├── pyproject.toml
177
+ ├── tests/
178
+ │ ├── conftest.py
179
+ │ ├── test_audio.py
180
+ │ ├── test_bindings.py
181
+ │ ├── test_cli.py
182
+ │ ├── test_config.py
183
+ │ ├── test_deepgram.py
184
+ │ ├── test_dictation.py
185
+ │ ├── test_doctor.py
186
+ │ ├── test_daemon_indicator.py
187
+ │ ├── test_history.py
188
+ │ ├── test_hotkeys.py
189
+ │ ├── test_indicator.py
190
+ │ ├── test_inject.py
191
+ │ ├── test_ipc_protocol.py
192
+ │ ├── test_ipc_server.py
193
+ │ ├── test_logging.py
194
+ │ ├── test_manager.py
195
+ │ ├── test_postprocess.py
196
+ │ ├── test_providers.py
197
+ │ ├── test_secrets.py
198
+ │ ├── test_single_instance.py
199
+ │ ├── test_transcribe.py
200
+ │ ├── test_tui_client.py
201
+ │ ├── test_vocabulary.py
202
+ │ ├── test_voice_commands.py
203
+ │ └── test_provider_vocabulary.py
204
+ └── sybl/
205
+ ├── __init__.py
206
+ ├── __main__.py
207
+ ├── cli/ # start, stop, status, tui, config, doctor, audio, transcribe, hotkey
208
+ ├── config/ # Pydantic models, paths, ConfigManager, vocabulary store
209
+ ├── secrets/ # keyring wrapper
210
+ ├── logging/ # setup + RingBufferHandler
211
+ ├── ipc/ # NDJSON command/event servers + client
212
+ ├── audio/ # capture session, devices, resample, metering
213
+ ├── core/ # daemon, dictation, postprocess, voice commands, transcribe
214
+ ├── providers/ # STT interface, capabilities, manager, Groq, Deepgram
215
+ ├── hotkeys/ # HotkeyManager, bindings, pynput backend, focus capture
216
+ ├── inject/ # TextInjector, Windows clipboard-paste injection
217
+ ├── indicator/ # CaptureIndicator, NoOp, Windows tkinter overlay
218
+ └── tui/ # Textual client (dashboard, settings, onboarding)
219
+ ```
220
+
221
+ ## 6. Conventions
222
+
223
+ - **Python:** target 3.12, type hints everywhere, **`ruff`** for lint/format.
224
+ - **Async:** the daemon and TUI are async-first (Textual is async); keep the
225
+ audio/STT pipeline non-blocking.
226
+ - **Comments:** explain *why*, not *what*. No narration comments.
227
+ - **Secrets:** never commit API keys; never log them. Use the keyring.
228
+ - **Cross-platform:** Windows, macOS, and Linux are all in scope long-term, but
229
+ **Windows is the primary target** for the core loop first. Always isolate
230
+ platform-specific code (hotkeys, injection, popup) behind interfaces so other
231
+ platforms slot in later without touching the core.
232
+
233
+ ## 7. Self-Maintenance Protocol (READ THIS, AGENT)
234
+
235
+ `AGENTS.md` is the project's living memory. **You are responsible for keeping it
236
+ accurate.** After any meaningful change, update the relevant sections in the
237
+ same task — do not defer it.
238
+
239
+ Update `AGENTS.md` whenever you:
240
+
241
+ - Change the mission, scope, or product behavior → update §1/§2.
242
+ - Advance the project's phase or status → update §3 (and `docs/ROADMAP.md`).
243
+ - Make or reverse a technical/architecture decision → append to §4.
244
+ - Add, move, or remove top-level files/directories → update §5.
245
+ - Establish or change a convention → update §6.
246
+
247
+ Rules:
248
+
249
+ 1. **Bump `Last updated`** at the top whenever you edit this file.
250
+ 2. **Append, don't erase** decisions in §4 — if a decision changes, add a new
251
+ row/note explaining the change rather than deleting the old one.
252
+ 3. **Keep it concise.** This is a map, not a manual. Link out to `docs/` for
253
+ depth.
254
+ 4. **If reality and this file disagree, this file is wrong — fix it.**
255
+ 5. When you finish a unit of work, ask yourself: *"Did anything here go stale?"*
256
+ If yes, update it before ending your turn.
@@ -0,0 +1,41 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.0] - 2026-06-26
9
+
10
+ First public release. sybl is a BYOK voice dictation daemon with global
11
+ push-to-talk, STT provider plugins, clipboard-paste injection, and a Textual TUI.
12
+
13
+ ### Added
14
+
15
+ - CLI: `sybl start`, `sybl stop`, `sybl status`, `sybl tui`, `sybl config`, `sybl doctor`, `sybl audio`, `sybl transcribe`, `sybl hotkey`
16
+ - Config system (TOML + Pydantic) and OS keyring secret storage
17
+ - Audio capture pipeline (16 kHz mono PCM, resampling, RMS metering, debug WAV)
18
+ - STT providers: Groq Whisper (batch) and Deepgram (streaming + batch)
19
+ - Global PTT hotkeys on Windows (`pynput`) with focus capture at activation
20
+ - Clipboard-paste text injection on Windows with clipboard restore
21
+ - Rule-based post-processing pipeline (fillers, capitalization, punctuation cleanup)
22
+ - Daemon + TCP NDJSON IPC; Textual TUI (logs, status, history, settings, onboarding)
23
+ - Windows listening indicator (tkinter overlay pill near cursor)
24
+ - Custom vocabulary STT hints (`sybl config vocab`) for Deepgram keyterms and Groq prompt
25
+ - Voice commands in final transcripts: `new line`, `period`, `comma`
26
+ - Duplicate punctuation collapse in post-processing
27
+
28
+ ### Changed
29
+
30
+ - **Rebrand:** project renamed from Navi to **sybl** (`sybl` CLI, PyPI package `sybl`)
31
+ - Removed `scratch that` voice command; use **Esc** while holding the hotkey to cancel
32
+ before injection instead
33
+
34
+ ### Notes
35
+
36
+ - **Windows-first:** hotkeys, injection, and the listening indicator are proven on
37
+ Windows. macOS/Linux backends are stubs behind interfaces.
38
+ - Integration tests requiring a microphone or live API keys are marked `@integration`
39
+ and excluded from CI.
40
+
41
+ [0.1.0]: https://github.com/Rikhil-Nell/sybl/releases/tag/v0.1.0
@@ -0,0 +1,59 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our
6
+ community a harassment-free experience for everyone, regardless of age, body
7
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
8
+ identity and expression, level of experience, education, socio-economic status,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ We pledge to act and interact in ways that contribute to an open, welcoming,
13
+ diverse, inclusive, and healthy community.
14
+
15
+ ## Our Standards
16
+
17
+ Examples of behavior that contributes to a positive environment:
18
+
19
+ * Demonstrating empathy and kindness toward other people
20
+ * Being respectful of differing opinions, viewpoints, and experiences
21
+ * Giving and gracefully accepting constructive feedback
22
+ * Accepting responsibility and apologizing to those affected by our mistakes,
23
+ and learning from the experience
24
+ * Focusing on what is best not just for us as individuals, but for the overall
25
+ community
26
+
27
+ Examples of unacceptable behavior:
28
+
29
+ * The use of sexualized language or imagery, and sexual attention or advances of
30
+ any kind
31
+ * Trolling, insulting or derogatory comments, and personal or political attacks
32
+ * Public or private harassment
33
+ * Publishing others' private information, such as a physical or email address,
34
+ without their explicit permission
35
+ * Other conduct which could reasonably be considered inappropriate in a
36
+ professional setting
37
+
38
+ ## Enforcement Responsibilities
39
+
40
+ Community leaders are responsible for clarifying and enforcing our standards of
41
+ acceptable behavior and will take appropriate and fair corrective action in
42
+ response to any behavior that they deem inappropriate, threatening, offensive,
43
+ or harmful.
44
+
45
+ ## Scope
46
+
47
+ This Code of Conduct applies within all community spaces, and also applies when
48
+ an individual is officially representing the community in public spaces.
49
+
50
+ ## Enforcement
51
+
52
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
53
+ reported to the maintainers at **nrikhil@gmail.com**. All complaints will be
54
+ reviewed and investigated promptly and fairly.
55
+
56
+ ## Attribution
57
+
58
+ This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org),
59
+ version 2.1.