chad-code 1.0.4__tar.gz → 1.0.6__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 (106) hide show
  1. {chad_code-1.0.4/src/chad_code.egg-info → chad_code-1.0.6}/PKG-INFO +42 -14
  2. {chad_code-1.0.4 → chad_code-1.0.6}/README.md +38 -12
  3. {chad_code-1.0.4 → chad_code-1.0.6}/pyproject.toml +31 -2
  4. chad_code-1.0.6/src/chad/__init__.py +14 -0
  5. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/agent.py +175 -62
  6. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/base_engine.py +67 -7
  7. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/bench.py +2 -2
  8. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/cli.py +267 -130
  9. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/completion_engine.py +168 -15
  10. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/engine.py +61 -52
  11. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/guardrails.py +160 -72
  12. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/levers.py +132 -49
  13. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/mlx_fastpath.py +26 -7
  14. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/mlx_qsdpa.py +333 -32
  15. chad_code-1.0.6/src/chad/parakeet/LICENSE +201 -0
  16. chad_code-1.0.6/src/chad/parakeet/__init__.py +27 -0
  17. chad_code-1.0.6/src/chad/parakeet/alignment.py +287 -0
  18. chad_code-1.0.6/src/chad/parakeet/attention.py +640 -0
  19. chad_code-1.0.6/src/chad/parakeet/audio.py +183 -0
  20. chad_code-1.0.6/src/chad/parakeet/cache.py +156 -0
  21. chad_code-1.0.6/src/chad/parakeet/conformer.py +423 -0
  22. chad_code-1.0.6/src/chad/parakeet/ctc.py +34 -0
  23. chad_code-1.0.6/src/chad/parakeet/parakeet.py +1055 -0
  24. chad_code-1.0.6/src/chad/parakeet/rnnt.py +155 -0
  25. chad_code-1.0.6/src/chad/parakeet/tokenizer.py +3 -0
  26. chad_code-1.0.6/src/chad/parakeet/utils.py +112 -0
  27. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/prompt.py +40 -8
  28. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/prove.py +5 -5
  29. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/repomap.py +4 -4
  30. chad_code-1.0.6/src/chad/serve.py +814 -0
  31. chad_code-1.0.6/src/chad/speech.py +565 -0
  32. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/syntaxgate.py +18 -19
  33. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/toolcall_parse.py +4 -4
  34. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/tools.py +263 -17
  35. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/tui.py +298 -15
  36. {chad_code-1.0.4 → chad_code-1.0.6/src/chad_code.egg-info}/PKG-INFO +42 -14
  37. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad_code.egg-info/SOURCES.txt +18 -0
  38. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad_code.egg-info/requires.txt +4 -1
  39. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_agent.py +1 -1
  40. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_agent_e2e.py +88 -32
  41. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_agent_guards.py +79 -13
  42. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_cli.py +248 -3
  43. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_completion_engine.py +84 -2
  44. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_config.py +1 -1
  45. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_confirm_preview.py +1 -1
  46. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_done_audit.py +237 -104
  47. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_edit.py +6 -6
  48. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_edit_corruption.py +1 -1
  49. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_engine.py +5 -9
  50. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_engine_kvquant.py +0 -8
  51. chad_code-1.0.6/tests/test_engine_pld_hybrid.py +227 -0
  52. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_garble_invariant.py +1 -1
  53. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_gate.py +85 -9
  54. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_intent.py +4 -4
  55. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_lever_bite.py +104 -18
  56. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_mlx_fastpath.py +2 -0
  57. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_mlx_qsdpa.py +75 -0
  58. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_render.py +1 -1
  59. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_repomap.py +1 -1
  60. chad_code-1.0.6/tests/test_serve.py +815 -0
  61. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_session.py +1 -1
  62. chad_code-1.0.6/tests/test_speech.py +284 -0
  63. chad_code-1.0.6/tests/test_speech_tui.py +508 -0
  64. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_subagent.py +7 -5
  65. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_symbols.py +1 -1
  66. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_syntaxgate.py +4 -4
  67. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_toolcall_parse.py +2 -2
  68. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_tools.py +204 -17
  69. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_tui.py +51 -2
  70. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_validate.py +1 -1
  71. chad_code-1.0.4/src/chad/__init__.py +0 -7
  72. {chad_code-1.0.4 → chad_code-1.0.6}/LICENSE +0 -0
  73. {chad_code-1.0.4 → chad_code-1.0.6}/setup.cfg +0 -0
  74. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/atif.py +0 -0
  75. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/compaction.py +0 -0
  76. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/config.py +0 -0
  77. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/diag.py +0 -0
  78. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/ignore.py +0 -0
  79. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/lsp.py +0 -0
  80. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/mcp.py +0 -0
  81. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/mcp_oauth.py +0 -0
  82. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/profiles.py +0 -0
  83. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/render.py +0 -0
  84. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/session.py +0 -0
  85. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/skills.py +0 -0
  86. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/symbols.py +0 -0
  87. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad/validate.py +0 -0
  88. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad_code.egg-info/dependency_links.txt +0 -0
  89. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad_code.egg-info/entry_points.txt +0 -0
  90. {chad_code-1.0.4 → chad_code-1.0.6}/src/chad_code.egg-info/top_level.txt +0 -0
  91. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_atif.py +0 -0
  92. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_bench.py +0 -0
  93. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_compact_notice.py +0 -0
  94. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_compaction.py +0 -0
  95. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_drift_warn.py +0 -0
  96. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_feel_pack.py +0 -0
  97. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_ignore.py +0 -0
  98. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_levers.py +0 -0
  99. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_log_redaction.py +0 -0
  100. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_lsp.py +0 -0
  101. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_mcp.py +0 -0
  102. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_mcp_oauth.py +0 -0
  103. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_plan_review.py +0 -0
  104. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_prove.py +0 -0
  105. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_replace_lines.py +0 -0
  106. {chad_code-1.0.4 → chad_code-1.0.6}/tests/test_skills.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: chad-code
3
- Version: 1.0.4
3
+ Version: 1.0.6
4
4
  Summary: Local MLX-backed, Claude-Code-style coding agent (Apple Silicon, Ornith 35B/9B)
5
5
  License-Expression: MIT
6
6
  Project-URL: Repository, https://github.com/nathansutton/chad
@@ -21,7 +21,7 @@ Requires-Dist: mlx<0.33,>=0.32.0; sys_platform == "darwin"
21
21
  Requires-Dist: mlx-lm<0.32,>=0.31.3; sys_platform == "darwin"
22
22
  Requires-Dist: transformers<5.13,>=5.0
23
23
  Requires-Dist: jinja2>=3.1
24
- Requires-Dist: numpy<2,>=1.26
24
+ Requires-Dist: numpy<3,>=1.26
25
25
  Requires-Dist: huggingface-hub>=1.22.0
26
26
  Requires-Dist: jedi>=0.19.2
27
27
  Requires-Dist: prompt_toolkit>=3.0.43
@@ -33,6 +33,8 @@ Provides-Extra: highlight
33
33
  Requires-Dist: pygments>=2.17; extra == "highlight"
34
34
  Provides-Extra: lsp
35
35
  Requires-Dist: serena-agent>=1.5; extra == "lsp"
36
+ Provides-Extra: speech
37
+ Requires-Dist: sounddevice>=0.5; extra == "speech"
36
38
  Dynamic: license-file
37
39
 
38
40
  # chad — a local, MLX-backed coding agent
@@ -58,7 +60,7 @@ uvx chad-code # runs chad anywhere — the command is still `chad`
58
60
  uvx chad-code prove # 2-min offline smoke test: 4 tiny fix-it tasks, verified, timed 🗿
59
61
  ```
60
62
 
61
- First run picks the right Ornith model for your RAM (9B under 32 GB, 35B at 32 GB+), asks,
63
+ First run picks the right Ornith model for your RAM (9B under 24 GB, 35B at 24 GB+), asks,
62
64
  and downloads it once (~5 GB / ~13 GB, resumable) into the shared Hugging Face cache. While
63
65
  it downloads, `cd` into a project and think of a scoped first ask — *"fix the failing test
64
66
  in `tests/test_x.py`"* lands; *"improve my codebase"* flails.
@@ -81,10 +83,12 @@ instrument:
81
83
  | **Harness** | open-ended, anything you can imagine | plan. execute. nothing else. |
82
84
  | **When wrong** | reasons a way out | already shipped |
83
85
 
84
- ![chad fixing a failing test end to end — reason, read, edit, rerun pytest, all on a local 35B](docs/demo.gif)
86
+ ![chad fixing a failing test end to end — reason, read, edit, run pytest, confirm green, all on a local 35B](docs/demo.gif)
85
87
 
86
- > Real session, unedited (cold model load cut): a local 35B reasons through the failure,
87
- > edits the file, reruns the tests, confirms green.
88
+ > Real session, unedited (the silent prefill is cut): a local 35B finds the cent that
89
+ > floor division loses, fixes it, and verifies itself — then your own `pytest`, in your
90
+ > own shell. Recorded with `--yolo` so nothing pauses for a keypress; the default mode
91
+ > stops and asks before every edit and every command.
88
92
 
89
93
  ## Frontier scores, laptop cost
90
94
 
@@ -139,16 +143,20 @@ uv run chad -c # resume this directory's last conversation
139
143
  ```
140
144
 
141
145
  **The model.** chad picks one for you by RAM and downloads it once into the shared Hugging
142
- Face cache (`~/.cache/huggingface`, reused across every project). No picker, no flags —
143
- override with `CHAD_MODEL=<repo or local dir>` if you must.
146
+ Face cache (`~/.cache/huggingface`, reused across every project). Override with
147
+ `--model 9b` / `--model 35b`, or `--model <repo or local dir>` for anything else.
144
148
 
145
149
  | Your Mac | Model | Footprint |
146
150
  |---|---|---|
147
- | **≥ 32 GB** | [Ornith-1.0-35B `UD-Q2_K_XL`](https://huggingface.co/nathansutton/Ornith-1.0-35B-UD-Q2_K_XL-MLX) — 35B MoE, 2-bit experts | ~13 GB resident (~16 GB with KV) |
148
- | **16 / 18 / 24 GB** | [Ornith-1.0-9B `UD-Q4_K_XL`](https://huggingface.co/nathansutton/Ornith-1.0-9B-UD-Q4_K_XL-MLX) — 4-bit AWQ | ~5 GB |
149
-
150
- The 35B's working set needs headroom a 24 GB Mac doesn't have (it SIGKILLs mid-turn), so its
151
- floor is **32 GB**; 24 GB and below run the 9B. Quant names follow
151
+ | **≥ 24 GB** | [Ornith-1.0-35B `UD-Q2_K_XL`](https://huggingface.co/nathansutton/Ornith-1.0-35B-UD-Q2_K_XL-MLX) — 35B MoE, 2-bit experts | ~13 GB resident (~16 GB with KV) |
152
+ | **16 / 18 GB** | [Ornith-1.0-9B `UD-Q4_K_XL`](https://huggingface.co/nathansutton/Ornith-1.0-9B-UD-Q4_K_XL-MLX) — 4-bit AWQ | ~5 GB |
153
+
154
+ The 35B's floor used to be 32 GB — its working set SIGKILLed a 24 GB Mac mid-turn. The
155
+ fused attention kernel and the 8-bit-from-the-start KV cache it enables cut the per-token
156
+ cache cost enough to give that headroom back, and the compaction trigger now sizes itself
157
+ from the live Metal budget, so a tight box narrows its context window instead of dying.
158
+ 24 GB runs the 35B; 16/18 GB still get the 9B. If a 24 GB machine feels tight next to your
159
+ other apps, `--model 9b` puts it back. Quant names follow
152
160
  [Unsloth's dynamic-quant convention](https://docs.unsloth.ai/) (`UD-…`).
153
161
 
154
162
  **Upgrading** — depends on how you installed: `uv tool upgrade chad-code`; `uvx --refresh
@@ -167,7 +175,10 @@ it chad uses the tree-sitter fallback automatically.
167
175
  `uv run chad` launches a full-screen terminal UI (built on prompt_toolkit):
168
176
 
169
177
  - **shift-tab cycles permission modes** — `normal` (confirm each bash/write/edit) →
170
- `auto-accept edits` → `plan mode` (read-only: investigate + propose a numbered plan) → back.
178
+ `auto-accept edits` (edits land silently; **terminal commands still ask**) → `yolo`
179
+ (nothing asks) → `plan mode` (read-only: investigate + propose a numbered plan) → back.
180
+ - **the approval prompt shows what you're approving** — the full command on its own lines
181
+ above the input, not a clipped single line. Approving blind isn't approving.
171
182
  - **type-ahead message queue** — keep typing while the agent works; messages run in order.
172
183
  - **ctrl-c interrupts the running turn** without killing the session.
173
184
  - **live status line** — model, mode, context %, a state glyph + verb, elapsed seconds, and
@@ -177,6 +188,14 @@ it chad uses the tree-sitter fallback automatically.
177
188
  `/model`, `/mode`, `/help`, `/exit`. Same set in the `--repl` line interface.
178
189
  - **`@file` / `@dir` mentions** and **`!command` shell passthrough** — pull a file into
179
190
  context inline, or run a shell command without invoking the model.
191
+ - **voice mode, all local** — `/speech`, then ctrl-t to talk: Parakeet-on-MLX transcribes
192
+ into the input box for you to review before Enter sends it (esc discards a take);
193
+ replies are read aloud via macOS `say`. A pre-roll buffer means your first syllable
194
+ isn't clipped, and a personal word table (`~/.chad/speech_words.json`) teaches it your
195
+ identifiers — `{"pie test": "pytest"}`. Dictation cost is linear in take length, so a
196
+ long thought is fine; `/speech` off releases both the mic and the weights. Nothing
197
+ leaves the machine. Needs the `speech` extra (`uv sync --extra speech` — just a mic
198
+ library; no torch, no numba).
180
199
 
181
200
  **Usage.** `uv run chad --help` is the source of truth:
182
201
 
@@ -187,8 +206,17 @@ it chad uses the tree-sitter fallback automatically.
187
206
  | `--plan` | start in read-only plan mode (investigate + propose, edits blocked) |
188
207
  | `--yolo` | auto-approve bash/write/edit (skip confirm prompts) |
189
208
  | `--no-think` | skip Ornith's `<think>` blocks — faster on well-scoped work |
209
+ | `--model` | `35b`, `9b`, `auto`, or any HF repo id / local model dir |
190
210
  | `--repl` | plain line REPL instead of the TUI |
191
211
 
212
+ Plus three subcommands, each with its own `--help`:
213
+
214
+ | Command | What it does |
215
+ |---|---|
216
+ | `chad serve` | serve this Mac's model to a container or the LAN ([Configuration](docs/configuration.md#serving-the-local-model-to-a-container-chad-serve)) |
217
+ | `chad prove` | 2-minute offline smoke test: 4 tiny fix-it tasks, verified, timed |
218
+ | `chad levers` | print the harness lever registry as JSON (ablation driver) |
219
+
192
220
  A headless task (positional, or piped with no TTY) auto-approves mutating tools; the model
193
221
  runs greedy (temp 0). Every conversation is persisted under `~/.chad/sessions/`, and every
194
222
  resume forks a new branch rather than overwriting — details in
@@ -21,7 +21,7 @@ uvx chad-code # runs chad anywhere — the command is still `chad`
21
21
  uvx chad-code prove # 2-min offline smoke test: 4 tiny fix-it tasks, verified, timed 🗿
22
22
  ```
23
23
 
24
- First run picks the right Ornith model for your RAM (9B under 32 GB, 35B at 32 GB+), asks,
24
+ First run picks the right Ornith model for your RAM (9B under 24 GB, 35B at 24 GB+), asks,
25
25
  and downloads it once (~5 GB / ~13 GB, resumable) into the shared Hugging Face cache. While
26
26
  it downloads, `cd` into a project and think of a scoped first ask — *"fix the failing test
27
27
  in `tests/test_x.py`"* lands; *"improve my codebase"* flails.
@@ -44,10 +44,12 @@ instrument:
44
44
  | **Harness** | open-ended, anything you can imagine | plan. execute. nothing else. |
45
45
  | **When wrong** | reasons a way out | already shipped |
46
46
 
47
- ![chad fixing a failing test end to end — reason, read, edit, rerun pytest, all on a local 35B](docs/demo.gif)
47
+ ![chad fixing a failing test end to end — reason, read, edit, run pytest, confirm green, all on a local 35B](docs/demo.gif)
48
48
 
49
- > Real session, unedited (cold model load cut): a local 35B reasons through the failure,
50
- > edits the file, reruns the tests, confirms green.
49
+ > Real session, unedited (the silent prefill is cut): a local 35B finds the cent that
50
+ > floor division loses, fixes it, and verifies itself — then your own `pytest`, in your
51
+ > own shell. Recorded with `--yolo` so nothing pauses for a keypress; the default mode
52
+ > stops and asks before every edit and every command.
51
53
 
52
54
  ## Frontier scores, laptop cost
53
55
 
@@ -102,16 +104,20 @@ uv run chad -c # resume this directory's last conversation
102
104
  ```
103
105
 
104
106
  **The model.** chad picks one for you by RAM and downloads it once into the shared Hugging
105
- Face cache (`~/.cache/huggingface`, reused across every project). No picker, no flags —
106
- override with `CHAD_MODEL=<repo or local dir>` if you must.
107
+ Face cache (`~/.cache/huggingface`, reused across every project). Override with
108
+ `--model 9b` / `--model 35b`, or `--model <repo or local dir>` for anything else.
107
109
 
108
110
  | Your Mac | Model | Footprint |
109
111
  |---|---|---|
110
- | **≥ 32 GB** | [Ornith-1.0-35B `UD-Q2_K_XL`](https://huggingface.co/nathansutton/Ornith-1.0-35B-UD-Q2_K_XL-MLX) — 35B MoE, 2-bit experts | ~13 GB resident (~16 GB with KV) |
111
- | **16 / 18 / 24 GB** | [Ornith-1.0-9B `UD-Q4_K_XL`](https://huggingface.co/nathansutton/Ornith-1.0-9B-UD-Q4_K_XL-MLX) — 4-bit AWQ | ~5 GB |
112
-
113
- The 35B's working set needs headroom a 24 GB Mac doesn't have (it SIGKILLs mid-turn), so its
114
- floor is **32 GB**; 24 GB and below run the 9B. Quant names follow
112
+ | **≥ 24 GB** | [Ornith-1.0-35B `UD-Q2_K_XL`](https://huggingface.co/nathansutton/Ornith-1.0-35B-UD-Q2_K_XL-MLX) — 35B MoE, 2-bit experts | ~13 GB resident (~16 GB with KV) |
113
+ | **16 / 18 GB** | [Ornith-1.0-9B `UD-Q4_K_XL`](https://huggingface.co/nathansutton/Ornith-1.0-9B-UD-Q4_K_XL-MLX) — 4-bit AWQ | ~5 GB |
114
+
115
+ The 35B's floor used to be 32 GB — its working set SIGKILLed a 24 GB Mac mid-turn. The
116
+ fused attention kernel and the 8-bit-from-the-start KV cache it enables cut the per-token
117
+ cache cost enough to give that headroom back, and the compaction trigger now sizes itself
118
+ from the live Metal budget, so a tight box narrows its context window instead of dying.
119
+ 24 GB runs the 35B; 16/18 GB still get the 9B. If a 24 GB machine feels tight next to your
120
+ other apps, `--model 9b` puts it back. Quant names follow
115
121
  [Unsloth's dynamic-quant convention](https://docs.unsloth.ai/) (`UD-…`).
116
122
 
117
123
  **Upgrading** — depends on how you installed: `uv tool upgrade chad-code`; `uvx --refresh
@@ -130,7 +136,10 @@ it chad uses the tree-sitter fallback automatically.
130
136
  `uv run chad` launches a full-screen terminal UI (built on prompt_toolkit):
131
137
 
132
138
  - **shift-tab cycles permission modes** — `normal` (confirm each bash/write/edit) →
133
- `auto-accept edits` → `plan mode` (read-only: investigate + propose a numbered plan) → back.
139
+ `auto-accept edits` (edits land silently; **terminal commands still ask**) → `yolo`
140
+ (nothing asks) → `plan mode` (read-only: investigate + propose a numbered plan) → back.
141
+ - **the approval prompt shows what you're approving** — the full command on its own lines
142
+ above the input, not a clipped single line. Approving blind isn't approving.
134
143
  - **type-ahead message queue** — keep typing while the agent works; messages run in order.
135
144
  - **ctrl-c interrupts the running turn** without killing the session.
136
145
  - **live status line** — model, mode, context %, a state glyph + verb, elapsed seconds, and
@@ -140,6 +149,14 @@ it chad uses the tree-sitter fallback automatically.
140
149
  `/model`, `/mode`, `/help`, `/exit`. Same set in the `--repl` line interface.
141
150
  - **`@file` / `@dir` mentions** and **`!command` shell passthrough** — pull a file into
142
151
  context inline, or run a shell command without invoking the model.
152
+ - **voice mode, all local** — `/speech`, then ctrl-t to talk: Parakeet-on-MLX transcribes
153
+ into the input box for you to review before Enter sends it (esc discards a take);
154
+ replies are read aloud via macOS `say`. A pre-roll buffer means your first syllable
155
+ isn't clipped, and a personal word table (`~/.chad/speech_words.json`) teaches it your
156
+ identifiers — `{"pie test": "pytest"}`. Dictation cost is linear in take length, so a
157
+ long thought is fine; `/speech` off releases both the mic and the weights. Nothing
158
+ leaves the machine. Needs the `speech` extra (`uv sync --extra speech` — just a mic
159
+ library; no torch, no numba).
143
160
 
144
161
  **Usage.** `uv run chad --help` is the source of truth:
145
162
 
@@ -150,8 +167,17 @@ it chad uses the tree-sitter fallback automatically.
150
167
  | `--plan` | start in read-only plan mode (investigate + propose, edits blocked) |
151
168
  | `--yolo` | auto-approve bash/write/edit (skip confirm prompts) |
152
169
  | `--no-think` | skip Ornith's `<think>` blocks — faster on well-scoped work |
170
+ | `--model` | `35b`, `9b`, `auto`, or any HF repo id / local model dir |
153
171
  | `--repl` | plain line REPL instead of the TUI |
154
172
 
173
+ Plus three subcommands, each with its own `--help`:
174
+
175
+ | Command | What it does |
176
+ |---|---|
177
+ | `chad serve` | serve this Mac's model to a container or the LAN ([Configuration](docs/configuration.md#serving-the-local-model-to-a-container-chad-serve)) |
178
+ | `chad prove` | 2-minute offline smoke test: 4 tiny fix-it tasks, verified, timed |
179
+ | `chad levers` | print the harness lever registry as JSON (ablation driver) |
180
+
155
181
  A headless task (positional, or piped with no TTY) auto-approves mutating tools; the model
156
182
  runs greedy (temp 0). Every conversation is persisted under `~/.chad/sessions/`, and every
157
183
  resume forks a new branch rather than overwriting — details in
@@ -4,7 +4,7 @@
4
4
  # import name, and command name are independent. `uvx chad-code` runs the alias
5
5
  # script added under [project.scripts].
6
6
  name = "chad-code"
7
- version = "1.0.4"
7
+ version = "1.0.6"
8
8
  description = "Local MLX-backed, Claude-Code-style coding agent (Apple Silicon, Ornith 35B/9B)"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -49,7 +49,10 @@ dependencies = [
49
49
  # absent in a clean install (e.g. chad inside a Linux benchmark container), where its
50
50
  # absence crashes the first turn. Declare it directly.
51
51
  "jinja2>=3.1",
52
- "numpy>=1.26,<2",
52
+ # <3: the old <2 cap was 1.0.0-era caution, not a known break. numpy 2.4.6
53
+ # verified end-to-end (full gate + live Parakeet-on-MLX transcription +
54
+ # `chad prove` 4/4); staying open keeps 2.x-floored ASR deps adoptable.
55
+ "numpy>=1.26,<3",
53
56
  "huggingface-hub>=1.22.0", # first-run model download (cli.py/engine.py); imported directly, not just transitively
54
57
  "jedi>=0.19.2", # in-process symbolic code intelligence (read/search/edit)
55
58
  "prompt_toolkit>=3.0.43",
@@ -78,6 +81,16 @@ highlight = ["pygments>=2.17"]
78
81
  # heavyweight tree; absent, every caller falls back to the tree-sitter backend.
79
82
  # Install with `uv sync --extra lsp`.
80
83
  lsp = ["serena-agent>=1.5"]
84
+ # Voice mode (/speech in the TUI): push-to-talk dictation via chad's vendored
85
+ # Parakeet-on-MLX (src/chad/parakeet — the PyPI parakeet-mlx drags librosa's
86
+ # numba/scipy tree for one mel-filterbank call) + spoken replies via macOS
87
+ # `say`. All on-device, nothing leaves the machine. mlx/numpy/huggingface-hub
88
+ # are already core deps, so the extra adds only the mic (sounddevice/PortAudio).
89
+ # Optional and import-guarded in speech.py: absent, /speech prints the install
90
+ # hint and everything else is untouched. Install with `uv sync --extra speech`.
91
+ speech = [
92
+ "sounddevice>=0.5",
93
+ ]
81
94
 
82
95
  # The one entrypoint: `uv run chad`. (`chad-bench` reproduces docs/benchmarks.md.)
83
96
  # `chad-code` is an alias so `uvx chad-code` (which runs the console script matching
@@ -107,6 +120,10 @@ build-backend = "setuptools.build_meta"
107
120
  [tool.setuptools.packages.find]
108
121
  where = ["src"]
109
122
 
123
+ # The vendored Parakeet code is Apache-2.0; its license text must travel with
124
+ # the code, wheel included.
125
+ [tool.setuptools.package-data]
126
+ "chad.parakeet" = ["LICENSE"]
110
127
  [tool.pytest.ini_options]
111
128
  testpaths = ["tests"]
112
129
  # No "-q" here: CI/docs/agents all invoke `pytest -q` explicitly, and stacking the two
@@ -127,6 +144,12 @@ src = ["src", "tests"]
127
144
  select = ["F", "E9", "I"]
128
145
  ignore = ["E741"] # ambiguous var names (l/I) appear in existing math code
129
146
 
147
+ [tool.ruff.lint.per-file-ignores]
148
+ # Vendored upstream (see chad/parakeet/__init__.py), kept byte-close for
149
+ # future re-syncs — not held to chad's own lint standard. (F401: imports left
150
+ # in place for upstream fidelity after the transcribe(path) cut.)
151
+ "src/chad/parakeet/*" = ["F401", "F821", "F841", "E741"]
152
+
130
153
  [tool.mypy]
131
154
  python_version = "3.11"
132
155
  files = ["src/chad"]
@@ -142,6 +165,12 @@ disable_error_code = ["var-annotated"]
142
165
  # Tighten (disallow_untyped_defs, re-enable var-annotated, add B/UP/SIM in ruff) in a
143
166
  # follow-up once this baseline holds.
144
167
 
168
+ [[tool.mypy.overrides]]
169
+ # Vendored upstream inference code (see chad/parakeet/__init__.py) is not held
170
+ # to chad's gate so re-syncs stay a plain re-copy.
171
+ module = "chad.parakeet.*"
172
+ ignore_errors = true
173
+
145
174
  [[tool.mypy.overrides]]
146
175
  # mlx_fastpath patches mlx_lm classes that only exist on macOS: with mlx installed
147
176
  # (dev Macs, the macos CI jobs) its `type: ignore[method-assign]` comments are load-
@@ -0,0 +1,14 @@
1
+ """chad — a local MLX-backed, Claude-Code-style coding agent.
2
+
3
+ A flat collection of cooperating modules behind one console script (``chad``):
4
+ the inference engine, the tool layer, the agent loop, and the terminal UI.
5
+ """
6
+
7
+ __version__ = "1.0.6"
8
+
9
+ # chad sets no MLX_* runtime vars. MLX_METAL_FAST_SYNCH, MLX_MAX_OPS_PER_BUFFER
10
+ # and MLX_MAX_MB_PER_BUFFER were each measured end-to-end on the 35B and every
11
+ # setting was slower than mlx's own defaults (1-4% at both 8k and 32k), so the
12
+ # mechanism that used to apply them at package import is gone. Any future entry
13
+ # has to be set before mlx's backend initializes — package import is the last
14
+ # hook early enough, since chad imports mlx lazily inside functions.