sidekick-agent 0.1.1__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 (43) hide show
  1. sidekick_agent-0.1.1/.gitignore +15 -0
  2. sidekick_agent-0.1.1/LICENSE +21 -0
  3. sidekick_agent-0.1.1/PKG-INFO +250 -0
  4. sidekick_agent-0.1.1/README.md +188 -0
  5. sidekick_agent-0.1.1/docs/shot.py +43 -0
  6. sidekick_agent-0.1.1/docs/tui-chat.svg +184 -0
  7. sidekick_agent-0.1.1/docs/tui-complete.svg +184 -0
  8. sidekick_agent-0.1.1/packaging/README.md +62 -0
  9. sidekick_agent-0.1.1/pyproject.toml +82 -0
  10. sidekick_agent-0.1.1/src/sk/__init__.py +2 -0
  11. sidekick_agent-0.1.1/src/sk/__main__.py +4 -0
  12. sidekick_agent-0.1.1/src/sk/agent.py +649 -0
  13. sidekick_agent-0.1.1/src/sk/auth.py +78 -0
  14. sidekick_agent-0.1.1/src/sk/brief.py +80 -0
  15. sidekick_agent-0.1.1/src/sk/cli.py +1105 -0
  16. sidekick_agent-0.1.1/src/sk/clip.py +89 -0
  17. sidekick_agent-0.1.1/src/sk/config.py +156 -0
  18. sidekick_agent-0.1.1/src/sk/daemon.py +97 -0
  19. sidekick_agent-0.1.1/src/sk/router.py +39 -0
  20. sidekick_agent-0.1.1/src/sk/skills.py +179 -0
  21. sidekick_agent-0.1.1/src/sk/slash.py +287 -0
  22. sidekick_agent-0.1.1/src/sk/store.py +349 -0
  23. sidekick_agent-0.1.1/src/sk/tools.py +776 -0
  24. sidekick_agent-0.1.1/src/sk/tui.py +1036 -0
  25. sidekick_agent-0.1.1/src/sk/voice.py +288 -0
  26. sidekick_agent-0.1.1/tests/conftest.py +26 -0
  27. sidekick_agent-0.1.1/tests/test_auth.py +193 -0
  28. sidekick_agent-0.1.1/tests/test_brief.py +14 -0
  29. sidekick_agent-0.1.1/tests/test_clip.py +132 -0
  30. sidekick_agent-0.1.1/tests/test_daemon.py +32 -0
  31. sidekick_agent-0.1.1/tests/test_eval.py +371 -0
  32. sidekick_agent-0.1.1/tests/test_memory.py +42 -0
  33. sidekick_agent-0.1.1/tests/test_provider.py +110 -0
  34. sidekick_agent-0.1.1/tests/test_router.py +31 -0
  35. sidekick_agent-0.1.1/tests/test_sessions.py +90 -0
  36. sidekick_agent-0.1.1/tests/test_shell.py +31 -0
  37. sidekick_agent-0.1.1/tests/test_skills.py +62 -0
  38. sidekick_agent-0.1.1/tests/test_slash.py +80 -0
  39. sidekick_agent-0.1.1/tests/test_todos.py +31 -0
  40. sidekick_agent-0.1.1/tests/test_tools.py +137 -0
  41. sidekick_agent-0.1.1/tests/test_tui.py +863 -0
  42. sidekick_agent-0.1.1/tests/test_voice.py +310 -0
  43. sidekick_agent-0.1.1/tests/test_web.py +35 -0
@@ -0,0 +1,15 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.pyc
4
+ .pytest_cache/
5
+ *.db
6
+ .env
7
+ dist/
8
+ build/
9
+ *.egg-info/
10
+
11
+ # AUR builds (packaging/aur)
12
+ packaging/aur/pkg/
13
+ packaging/aur/src/
14
+ packaging/aur/*.tar.gz
15
+ packaging/aur/*.zst
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Irfanwani and Sidekick contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,250 @@
1
+ Metadata-Version: 2.5
2
+ Name: sidekick-agent
3
+ Version: 0.1.1
4
+ Summary: Local-first terminal companion agent (Ollama-powered)
5
+ Project-URL: Homepage, https://github.com/Faisal01011/sidekick
6
+ Project-URL: Repository, https://github.com/Faisal01011/sidekick
7
+ Project-URL: Issues, https://github.com/Faisal01011/sidekick/issues
8
+ Project-URL: Documentation, https://github.com/Faisal01011/sidekick/tree/main/README.md
9
+ Project-URL: Changelog, https://github.com/Faisal01011/sidekick/releases
10
+ Author-email: Irfanwani <irfanwani347@gmail.com>
11
+ License: MIT License
12
+
13
+ Copyright (c) 2026 Irfanwani and Sidekick contributors
14
+
15
+ Permission is hereby granted, free of charge, to any person obtaining a copy
16
+ of this software and associated documentation files (the "Software"), to deal
17
+ in the Software without restriction, including without limitation the rights
18
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19
+ copies of the Software, and to permit persons to whom the Software is
20
+ furnished to do so, subject to the following conditions:
21
+
22
+ The above copyright notice and this permission notice shall be included in all
23
+ copies or substantial portions of the Software.
24
+
25
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31
+ SOFTWARE.
32
+ License-File: LICENSE
33
+ Keywords: agent,cli,llm,local-first,ollama,terminal,tui,voice
34
+ Classifier: Development Status :: 3 - Alpha
35
+ Classifier: Environment :: Console
36
+ Classifier: Intended Audience :: Developers
37
+ Classifier: License :: OSI Approved :: MIT License
38
+ Classifier: Operating System :: MacOS
39
+ Classifier: Operating System :: POSIX :: Linux
40
+ Classifier: Programming Language :: Python :: 3
41
+ Classifier: Programming Language :: Python :: 3.12
42
+ Classifier: Programming Language :: Python :: 3.13
43
+ Classifier: Programming Language :: Python :: 3.14
44
+ Classifier: Topic :: System :: Shells
45
+ Classifier: Topic :: Terminals
46
+ Requires-Python: >=3.12
47
+ Requires-Dist: httpx>=0.27
48
+ Requires-Dist: openai>=1.0
49
+ Requires-Dist: python-dotenv>=1.0
50
+ Requires-Dist: rich>=13.0
51
+ Requires-Dist: textual>=8.0
52
+ Requires-Dist: typer>=0.12
53
+ Provides-Extra: dev
54
+ Requires-Dist: build>=1.2; extra == 'dev'
55
+ Requires-Dist: pytest>=8.0; extra == 'dev'
56
+ Requires-Dist: twine>=5.0; extra == 'dev'
57
+ Provides-Extra: test
58
+ Requires-Dist: pytest>=8.0; extra == 'test'
59
+ Provides-Extra: voice
60
+ Requires-Dist: faster-whisper; extra == 'voice'
61
+ Description-Content-Type: text/markdown
62
+
63
+ <div align="center">
64
+
65
+ # Sidekick
66
+
67
+ **A local-first terminal companion you can talk to — chat, voice, and 17 tools, on your hardware.**
68
+
69
+ [![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/)
70
+ [![Textual TUI](https://img.shields.io/badge/TUI-textual-green.svg)](https://textual.textualize.io/)
71
+ [![Ollama](https://img.shields.io/badge/LLM-ollama%20%2B%20any%20OpenAI--compatible-orange.svg)](https://ollama.com/)
72
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
73
+ [![Tests](https://img.shields.io/badge/tests-167%20passing-brightgreen.svg)](tests/)
74
+
75
+ *No cloud account required. No API bill by default. Your files, memory, and voice never leave your machine unless you hand it a key.*
76
+
77
+ </div>
78
+
79
+ ## See it
80
+
81
+ Slash autocomplete with fuzzy filtering, right in the prompt:
82
+
83
+ ![Slash autocomplete](docs/tui-complete.svg)
84
+
85
+ A grounded answer — real tools, real system data, streamed live:
86
+
87
+ ![Grounded answer](docs/tui-chat.svg)
88
+
89
+ *Screenshots are real SVG captures of the app running headless (`docs/shot.py`), not mockups.*
90
+
91
+ ```console
92
+ $ sk brief
93
+ ╭─ sidekick brief Sat 2026-09-19 11:58 ─╮
94
+ │ CPU: AMD Ryzen 7 4800H (16 threads) │
95
+ │ Mem: 7.2Gi · GPU: GTX 1650 4GB │
96
+ │ /dev/nvme0n1p8 133G 117G 8.5G 94% / │
97
+ ╰─────────────────────────────────────────╯
98
+ │ ! disk 94% full — clean ~/Downloads… │
99
+
100
+ $ sk run "what is the ideal llm i can run on my device"
101
+ • qwen3:4b (2.5 GB): fits comfortably in your 4096 MiB VRAM.
102
+ • llama3.2:3b (2.0 GB): another good option.
103
+
104
+ $ sk talk
105
+ [Enter] to record, [Enter] to stop. /quit exits.
106
+ heard> what files are in the sidekick repo
107
+ ```
108
+
109
+ ## Why sidekick
110
+
111
+ | | Sidekick | Typical cloud agent |
112
+ |---|---|---|
113
+ | Runs fully offline (Ollama) | ✅ | ❌ |
114
+ | Voice input, transcribed on your CPU | ✅ | ❌ |
115
+ | Copy/paste that works in-terminal | ✅ drag-select, `ctrl+y`, `/copy` | varies |
116
+ | Answers grounded in *your* system, not guessed | ✅ deterministic grounding | prompt-only |
117
+ | Skills you can read (`SKILL.md`, incl. superpowers) | ✅ | varies |
118
+ | 167-test suite incl. prompt-regression evals | ✅ | rare |
119
+
120
+ ## Quickstart
121
+
122
+ ```bash
123
+ uv tool install sidekick-agent[voice] # global `sk`, STT included
124
+ sk doctor # checks provider + model
125
+ sk tui # fullscreen chat — start here
126
+ ```
127
+
128
+ No clone, no build — installs straight from PyPI. Requires Python 3.12+.
129
+ Without `[voice]` you get everything except Talk/mic (installs on first use instead). Local path needs Ollama (`ollama serve`, pull `qwen2.5-coder:7b` for smarts or `llama3.2:3b` for speed).
130
+
131
+ ## Install
132
+
133
+ | Channel | Command |
134
+ |---|---|
135
+ | PyPI / uv | `uv tool install sidekick-agent[voice]` |
136
+ | PyPI / pipx | `pipx install sidekick-agent[voice]` |
137
+ | PyPI / pip | `pip install sidekick-agent[voice]` |
138
+ | AUR (Arch) | `yay -S python-sidekick-agent` |
139
+ | conda-forge | `conda install -c conda-forge sidekick-agent` *(feedstock lives in a separate repo)* |
140
+
141
+ The published name is **`sidekick-agent`** (the `sidekick` name is taken on
142
+ PyPI); the command stays `sk`. Version is a single source of truth in
143
+ `src/sk/__init__.py`. Publishing is automatic and credential-free: when a PR
144
+ is merged to `main` of the canonical repo
145
+ [`Faisal01011/sidekick`](https://github.com/Faisal01011/sidekick) with a bumped
146
+ `__version__`, GitHub Actions trusted-publishes to PyPI and opens a GitHub
147
+ Release (forks can never publish) — details in [`packaging/README.md`](packaging/README.md).
148
+
149
+ **From source (dev):**
150
+
151
+ ```bash
152
+ git clone https://github.com/Faisal01011/sidekick && cd sidekick
153
+ uv tool install -e ".[voice]" # editable dev install; STT included
154
+ sk doctor
155
+ ```
156
+
157
+ ## Chat
158
+
159
+ One input, two surfaces — REPL and fullscreen TUI share every command:
160
+
161
+ ```bash
162
+ sk chat # type /help once you're in
163
+ sk tui # same, fullscreen with streaming + themes
164
+ sk tui --model fast
165
+ ```
166
+
167
+ Type `/` and an autocomplete popup filters all 20+ commands — Enter completes, Tab too, Esc dismisses, ↑/↓ navigates. `F1` opens a generated cheatsheet (keys + commands, built from the same tables as the dispatcher, so it can't rot).
168
+
169
+ TUI keys: **Enter** sends · **ctrl+j**/**alt+enter** newline · **↑/↓** history · **ctrl+y** copies · **ctrl+t** push-to-talk · **ctrl+b/f** scroll · **F1** help. Answers stream live with role colors; the footer shows model · session · last-turn time/tokens.
170
+
171
+ ## Voice
172
+
173
+ ```bash
174
+ sk talk [-d SECS] [--stt-model base] [--device hw:2,0] # Enter records, Enter stops
175
+ sk mic-test # peak dB + silent/quiet/good verdict
176
+ ```
177
+
178
+ Capture via the OS-native recorder (arecord/ALSA on Linux, sox/ffmpeg on macOS), transcription via local faster-whisper int8, transcript lands editable in the prompt. In the TUI, `ctrl+t` (or the mic pill) does the same. Voice never leaves your machine; recordings are temp files, deleted after each take.
179
+
180
+ ## Providers (BYO key)
181
+
182
+ ```bash
183
+ sk connect # pick provider → paste key (hidden) → pick model → ping. Done.
184
+ ```
185
+
186
+ One guided flow: numbered provider list (local ones skip keys), live validation *before* anything saves, curated model list (TTS/image junk filtered, recommended pre-highlighted, Enter accepts), and a 5-token ping instead of a full agent turn. Advanced paths still work: `sk auth add/list/status/remove`, `sk model`, `sk setup` (connect + hook), `sk config --provider openai --api-key sk-...`, `/provider groq` inside chat.
187
+
188
+ Presets: `ollama|openai|groq|together|deepseek|openrouter|google|lmstudio|custom`. Any OpenAI-compatible endpoint works via `--provider custom --base-url https://... --api-key ...`. Preferred: `SIDEKICK_API_KEY` env (never touches disk); file keys are chmod 600 and masked in `--show`. Note: true Anthropic-native API isn't wrapped — reach Claude via OpenRouter.
189
+
190
+ ## Command reference
191
+
192
+ | Command | What |
193
+ |---|---|
194
+ | `sk chat [--continue]` / `sk tui [--continue]` | Interactive chat, fresh session each launch |
195
+ | `/sessions`, `/resume <n>`, `/sessions delete <n>` | List, switch, delete past sessions |
196
+ | `sk run "task" [--yes] [--model auto\|fast\|smart\|name]` | Single-shot agent run (auto-router picks the model) |
197
+ | `sk brief [-p PATH] [--smart]` | Morning digest: system + git + todos + memories, instant without LLM |
198
+ | `sk remember/recall/memories/forget` | Long-term memory (FTS5 search, auto-injected) |
199
+ | `sk todo add/list/done/clear` | Todos |
200
+ | `sk history` / `sk oops` | Shell log / explain last failure |
201
+ | `sk hook-install [--write]` | Bash/zsh logging hook |
202
+ | `sk skills` / `sk skills-install superpowers` / `sk daemon [--once]` | Skill packs (obra/superpowers) / background watcher |
203
+ | `sk doctor` / `sk models` / `sk config` / `sk version` | Health / models / settings / build |
204
+
205
+ Packs use the `SKILL.md` frontmatter format. The prompt carries a relevance-ranked index; the agent loads full instructions on demand via the `skill` tool. `fast`/`smart` resolve per provider (Ollama: llama3.2:3b/qwen2.5-coder:7b, Groq: gpt-oss-20b/120b).
206
+
207
+ ## Architecture
208
+
209
+ ```mermaid
210
+ flowchart TB
211
+ U([you]) --> CLI[sk chat / sk run]
212
+ U --> TUI[sk tui: autocomplete, streaming, mic pill]
213
+ U --> VOICE[sk talk: arecord + faster-whisper]
214
+ CLI --> SLASH[slash.py: /commands, no LLM]
215
+ TUI --> SLASH
216
+ VOICE --> AGENT
217
+ CLI --> AGENT[agent.py: stream → tools → synthesize]
218
+ TUI --> AGENT
219
+ AGENT --> GROUND[deterministic grounding: ~/paths, URLs,\nsysinfo — injected before the model sees the prompt]
220
+ AGENT --> TOOLS[tools.py: 17 tools, allowlists,\nhard-blocks, SSRF guard]
221
+ AGENT --> MEM[(store.py: history, memories FTS5,\ntodos, shell log)]
222
+ AGENT --> SKILLS[skills: relevance-ranked SKILL.md index]
223
+ ```
224
+
225
+ Design bets that paid off: **deterministic grounding beats prompt instructions** (small models ignore rules but can't argue with injected facts), **text-JSON fallback** (coders emit tools as text over the OpenAI endpoint), **FTS5 over vectors** (zero deps, instant, no embedding server on a 4GB box).
226
+
227
+ ## Safety
228
+
229
+ Reads auto-run. Writes, deletes, and general shell need approval (inline `[y/N]` in TUI, prompt in CLI), HOME/`/tmp` only, ≤100KB, never `~/.ssh`, `~/.gnupg`, `/etc`, `/usr`. `shell` hard-refuses `rm -rf /`, `mkfs`, `dd` to devices, fork bombs even with approval. `read_url`/`web_search` block localhost/private IPs. API keys chmod 600, masked in output.
230
+
231
+ ## Tests
232
+
233
+ ```bash
234
+ uv run --python 3.12 --with ".[test]" pytest tests -q # 167 passed: unit + regression + Textual pilot, no Ollama needed
235
+ ```
236
+
237
+ The eval harness (`tests/test_eval.py`) locks in every past quality bug as an offline regression test. A suite-wide fixture guarantees tests never touch your live `~/.sidekick/`.
238
+
239
+ ## Config
240
+
241
+ `~/.sidekick/config.toml` (`provider`, `model`, `base_url` override, `api_key`, …). Env overrides: `SIDEKICK_PROVIDER`, `SIDEKICK_MODEL`, `SIDEKICK_BASE_URL`, `SIDEKICK_API_KEY`. Data stays home: `history.db`, `skills/`, `nudges.log`, `input_history`, `tui-errors.log`.
242
+
243
+ ## Roadmap
244
+
245
+ - [x] Voice input (local STT) · [x] Skills (superpowers) · [x] Sessions · [x] Providers/BYOK · [x] Eval harness
246
+ - [ ] Spoken replies (offline TTS) · [ ] Native Anthropic provider · [ ] Daemon as a systemd service · [ ] `sk skills search`
247
+
248
+ ## License
249
+
250
+ MIT — do what you want, shout-outs appreciated.
@@ -0,0 +1,188 @@
1
+ <div align="center">
2
+
3
+ # Sidekick
4
+
5
+ **A local-first terminal companion you can talk to — chat, voice, and 17 tools, on your hardware.**
6
+
7
+ [![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/)
8
+ [![Textual TUI](https://img.shields.io/badge/TUI-textual-green.svg)](https://textual.textualize.io/)
9
+ [![Ollama](https://img.shields.io/badge/LLM-ollama%20%2B%20any%20OpenAI--compatible-orange.svg)](https://ollama.com/)
10
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
11
+ [![Tests](https://img.shields.io/badge/tests-167%20passing-brightgreen.svg)](tests/)
12
+
13
+ *No cloud account required. No API bill by default. Your files, memory, and voice never leave your machine unless you hand it a key.*
14
+
15
+ </div>
16
+
17
+ ## See it
18
+
19
+ Slash autocomplete with fuzzy filtering, right in the prompt:
20
+
21
+ ![Slash autocomplete](docs/tui-complete.svg)
22
+
23
+ A grounded answer — real tools, real system data, streamed live:
24
+
25
+ ![Grounded answer](docs/tui-chat.svg)
26
+
27
+ *Screenshots are real SVG captures of the app running headless (`docs/shot.py`), not mockups.*
28
+
29
+ ```console
30
+ $ sk brief
31
+ ╭─ sidekick brief Sat 2026-09-19 11:58 ─╮
32
+ │ CPU: AMD Ryzen 7 4800H (16 threads) │
33
+ │ Mem: 7.2Gi · GPU: GTX 1650 4GB │
34
+ │ /dev/nvme0n1p8 133G 117G 8.5G 94% / │
35
+ ╰─────────────────────────────────────────╯
36
+ │ ! disk 94% full — clean ~/Downloads… │
37
+
38
+ $ sk run "what is the ideal llm i can run on my device"
39
+ • qwen3:4b (2.5 GB): fits comfortably in your 4096 MiB VRAM.
40
+ • llama3.2:3b (2.0 GB): another good option.
41
+
42
+ $ sk talk
43
+ [Enter] to record, [Enter] to stop. /quit exits.
44
+ heard> what files are in the sidekick repo
45
+ ```
46
+
47
+ ## Why sidekick
48
+
49
+ | | Sidekick | Typical cloud agent |
50
+ |---|---|---|
51
+ | Runs fully offline (Ollama) | ✅ | ❌ |
52
+ | Voice input, transcribed on your CPU | ✅ | ❌ |
53
+ | Copy/paste that works in-terminal | ✅ drag-select, `ctrl+y`, `/copy` | varies |
54
+ | Answers grounded in *your* system, not guessed | ✅ deterministic grounding | prompt-only |
55
+ | Skills you can read (`SKILL.md`, incl. superpowers) | ✅ | varies |
56
+ | 167-test suite incl. prompt-regression evals | ✅ | rare |
57
+
58
+ ## Quickstart
59
+
60
+ ```bash
61
+ uv tool install sidekick-agent[voice] # global `sk`, STT included
62
+ sk doctor # checks provider + model
63
+ sk tui # fullscreen chat — start here
64
+ ```
65
+
66
+ No clone, no build — installs straight from PyPI. Requires Python 3.12+.
67
+ Without `[voice]` you get everything except Talk/mic (installs on first use instead). Local path needs Ollama (`ollama serve`, pull `qwen2.5-coder:7b` for smarts or `llama3.2:3b` for speed).
68
+
69
+ ## Install
70
+
71
+ | Channel | Command |
72
+ |---|---|
73
+ | PyPI / uv | `uv tool install sidekick-agent[voice]` |
74
+ | PyPI / pipx | `pipx install sidekick-agent[voice]` |
75
+ | PyPI / pip | `pip install sidekick-agent[voice]` |
76
+ | AUR (Arch) | `yay -S python-sidekick-agent` |
77
+ | conda-forge | `conda install -c conda-forge sidekick-agent` *(feedstock lives in a separate repo)* |
78
+
79
+ The published name is **`sidekick-agent`** (the `sidekick` name is taken on
80
+ PyPI); the command stays `sk`. Version is a single source of truth in
81
+ `src/sk/__init__.py`. Publishing is automatic and credential-free: when a PR
82
+ is merged to `main` of the canonical repo
83
+ [`Faisal01011/sidekick`](https://github.com/Faisal01011/sidekick) with a bumped
84
+ `__version__`, GitHub Actions trusted-publishes to PyPI and opens a GitHub
85
+ Release (forks can never publish) — details in [`packaging/README.md`](packaging/README.md).
86
+
87
+ **From source (dev):**
88
+
89
+ ```bash
90
+ git clone https://github.com/Faisal01011/sidekick && cd sidekick
91
+ uv tool install -e ".[voice]" # editable dev install; STT included
92
+ sk doctor
93
+ ```
94
+
95
+ ## Chat
96
+
97
+ One input, two surfaces — REPL and fullscreen TUI share every command:
98
+
99
+ ```bash
100
+ sk chat # type /help once you're in
101
+ sk tui # same, fullscreen with streaming + themes
102
+ sk tui --model fast
103
+ ```
104
+
105
+ Type `/` and an autocomplete popup filters all 20+ commands — Enter completes, Tab too, Esc dismisses, ↑/↓ navigates. `F1` opens a generated cheatsheet (keys + commands, built from the same tables as the dispatcher, so it can't rot).
106
+
107
+ TUI keys: **Enter** sends · **ctrl+j**/**alt+enter** newline · **↑/↓** history · **ctrl+y** copies · **ctrl+t** push-to-talk · **ctrl+b/f** scroll · **F1** help. Answers stream live with role colors; the footer shows model · session · last-turn time/tokens.
108
+
109
+ ## Voice
110
+
111
+ ```bash
112
+ sk talk [-d SECS] [--stt-model base] [--device hw:2,0] # Enter records, Enter stops
113
+ sk mic-test # peak dB + silent/quiet/good verdict
114
+ ```
115
+
116
+ Capture via the OS-native recorder (arecord/ALSA on Linux, sox/ffmpeg on macOS), transcription via local faster-whisper int8, transcript lands editable in the prompt. In the TUI, `ctrl+t` (or the mic pill) does the same. Voice never leaves your machine; recordings are temp files, deleted after each take.
117
+
118
+ ## Providers (BYO key)
119
+
120
+ ```bash
121
+ sk connect # pick provider → paste key (hidden) → pick model → ping. Done.
122
+ ```
123
+
124
+ One guided flow: numbered provider list (local ones skip keys), live validation *before* anything saves, curated model list (TTS/image junk filtered, recommended pre-highlighted, Enter accepts), and a 5-token ping instead of a full agent turn. Advanced paths still work: `sk auth add/list/status/remove`, `sk model`, `sk setup` (connect + hook), `sk config --provider openai --api-key sk-...`, `/provider groq` inside chat.
125
+
126
+ Presets: `ollama|openai|groq|together|deepseek|openrouter|google|lmstudio|custom`. Any OpenAI-compatible endpoint works via `--provider custom --base-url https://... --api-key ...`. Preferred: `SIDEKICK_API_KEY` env (never touches disk); file keys are chmod 600 and masked in `--show`. Note: true Anthropic-native API isn't wrapped — reach Claude via OpenRouter.
127
+
128
+ ## Command reference
129
+
130
+ | Command | What |
131
+ |---|---|
132
+ | `sk chat [--continue]` / `sk tui [--continue]` | Interactive chat, fresh session each launch |
133
+ | `/sessions`, `/resume <n>`, `/sessions delete <n>` | List, switch, delete past sessions |
134
+ | `sk run "task" [--yes] [--model auto\|fast\|smart\|name]` | Single-shot agent run (auto-router picks the model) |
135
+ | `sk brief [-p PATH] [--smart]` | Morning digest: system + git + todos + memories, instant without LLM |
136
+ | `sk remember/recall/memories/forget` | Long-term memory (FTS5 search, auto-injected) |
137
+ | `sk todo add/list/done/clear` | Todos |
138
+ | `sk history` / `sk oops` | Shell log / explain last failure |
139
+ | `sk hook-install [--write]` | Bash/zsh logging hook |
140
+ | `sk skills` / `sk skills-install superpowers` / `sk daemon [--once]` | Skill packs (obra/superpowers) / background watcher |
141
+ | `sk doctor` / `sk models` / `sk config` / `sk version` | Health / models / settings / build |
142
+
143
+ Packs use the `SKILL.md` frontmatter format. The prompt carries a relevance-ranked index; the agent loads full instructions on demand via the `skill` tool. `fast`/`smart` resolve per provider (Ollama: llama3.2:3b/qwen2.5-coder:7b, Groq: gpt-oss-20b/120b).
144
+
145
+ ## Architecture
146
+
147
+ ```mermaid
148
+ flowchart TB
149
+ U([you]) --> CLI[sk chat / sk run]
150
+ U --> TUI[sk tui: autocomplete, streaming, mic pill]
151
+ U --> VOICE[sk talk: arecord + faster-whisper]
152
+ CLI --> SLASH[slash.py: /commands, no LLM]
153
+ TUI --> SLASH
154
+ VOICE --> AGENT
155
+ CLI --> AGENT[agent.py: stream → tools → synthesize]
156
+ TUI --> AGENT
157
+ AGENT --> GROUND[deterministic grounding: ~/paths, URLs,\nsysinfo — injected before the model sees the prompt]
158
+ AGENT --> TOOLS[tools.py: 17 tools, allowlists,\nhard-blocks, SSRF guard]
159
+ AGENT --> MEM[(store.py: history, memories FTS5,\ntodos, shell log)]
160
+ AGENT --> SKILLS[skills: relevance-ranked SKILL.md index]
161
+ ```
162
+
163
+ Design bets that paid off: **deterministic grounding beats prompt instructions** (small models ignore rules but can't argue with injected facts), **text-JSON fallback** (coders emit tools as text over the OpenAI endpoint), **FTS5 over vectors** (zero deps, instant, no embedding server on a 4GB box).
164
+
165
+ ## Safety
166
+
167
+ Reads auto-run. Writes, deletes, and general shell need approval (inline `[y/N]` in TUI, prompt in CLI), HOME/`/tmp` only, ≤100KB, never `~/.ssh`, `~/.gnupg`, `/etc`, `/usr`. `shell` hard-refuses `rm -rf /`, `mkfs`, `dd` to devices, fork bombs even with approval. `read_url`/`web_search` block localhost/private IPs. API keys chmod 600, masked in output.
168
+
169
+ ## Tests
170
+
171
+ ```bash
172
+ uv run --python 3.12 --with ".[test]" pytest tests -q # 167 passed: unit + regression + Textual pilot, no Ollama needed
173
+ ```
174
+
175
+ The eval harness (`tests/test_eval.py`) locks in every past quality bug as an offline regression test. A suite-wide fixture guarantees tests never touch your live `~/.sidekick/`.
176
+
177
+ ## Config
178
+
179
+ `~/.sidekick/config.toml` (`provider`, `model`, `base_url` override, `api_key`, …). Env overrides: `SIDEKICK_PROVIDER`, `SIDEKICK_MODEL`, `SIDEKICK_BASE_URL`, `SIDEKICK_API_KEY`. Data stays home: `history.db`, `skills/`, `nudges.log`, `input_history`, `tui-errors.log`.
180
+
181
+ ## Roadmap
182
+
183
+ - [x] Voice input (local STT) · [x] Skills (superpowers) · [x] Sessions · [x] Providers/BYOK · [x] Eval harness
184
+ - [ ] Spoken replies (offline TTS) · [ ] Native Anthropic provider · [ ] Daemon as a systemd service · [ ] `sk skills search`
185
+
186
+ ## License
187
+
188
+ MIT — do what you want, shout-outs appreciated.
@@ -0,0 +1,43 @@
1
+ """Capture real TUI screenshots headless for the README. No LLM, no network."""
2
+
3
+ import asyncio
4
+
5
+ from sk.tui import SidekickTUI
6
+
7
+
8
+ async def main() -> None:
9
+ # 1. chat view with content + slash popup open
10
+ app = SidekickTUI()
11
+ async with app.run_test(size=(100, 30)) as pilot:
12
+ log = app.query_one("#chat-log")
13
+ log.write("sidekick online. Enter sends · ctrl+j newline · ↑ history · ctrl+t to talk.")
14
+ from sk.tui import _role
15
+
16
+ _role(log, "you", "what files are in ~/sidekick?")
17
+ _role(log, "tool", "○ tool: list_dir {'path': '~/sidekick'}")
18
+ _role(log, "sidekick", "")
19
+ log.write("**~/sidekick**: `pyproject.toml`, `src/sk/`, `tests/`, `README.md`")
20
+ area = app.query_one("#chat-input")
21
+ area.focus()
22
+ area.text = "/mo"
23
+ await pilot.pause()
24
+ await pilot.pause()
25
+ app.save_screenshot("docs/tui-complete.svg")
26
+ print("shot 1: complete popup")
27
+
28
+ # 2. rich conversation: tools + answer + stats line
29
+ area.text = ""
30
+ await pilot.pause()
31
+ from sk.tui import _role
32
+
33
+ _role(log, "you", "summarize disk usage in ~/")
34
+ _role(log, "tool", "○ tool: exec {'cmd': 'df -h'}")
35
+ _role(log, "sidekick", "")
36
+ log.write("/dev/nvme0n1p8 133G 117G 8.5G 94% /")
37
+ await pilot.pause()
38
+ await pilot.pause()
39
+ app.save_screenshot("docs/tui-chat.svg")
40
+ print("shot 2: conversation")
41
+
42
+
43
+ asyncio.run(main())