chad-code 0.1.0__tar.gz → 1.0.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 (104) hide show
  1. chad_code-1.0.0/PKG-INFO +223 -0
  2. chad_code-1.0.0/README.md +186 -0
  3. {chad_code-0.1.0 → chad_code-1.0.0}/pyproject.toml +33 -11
  4. {chad_code-0.1.0 → chad_code-1.0.0}/src/chad/__init__.py +1 -1
  5. chad_code-1.0.0/src/chad/agent.py +1934 -0
  6. chad_code-1.0.0/src/chad/atif.py +243 -0
  7. chad_code-1.0.0/src/chad/base_engine.py +163 -0
  8. {chad_code-0.1.0 → chad_code-1.0.0}/src/chad/bench.py +11 -2
  9. {chad_code-0.1.0 → chad_code-1.0.0}/src/chad/cli.py +326 -74
  10. chad_code-1.0.0/src/chad/compaction.py +289 -0
  11. chad_code-1.0.0/src/chad/completion_engine.py +396 -0
  12. {chad_code-0.1.0 → chad_code-1.0.0}/src/chad/config.py +3 -3
  13. {chad_code-0.1.0 → chad_code-1.0.0}/src/chad/engine.py +554 -51
  14. chad_code-1.0.0/src/chad/guardrails.py +1201 -0
  15. chad_code-1.0.0/src/chad/levers.py +352 -0
  16. {chad_code-0.1.0 → chad_code-1.0.0}/src/chad/mcp.py +4 -4
  17. {chad_code-0.1.0 → chad_code-1.0.0}/src/chad/mcp_oauth.py +8 -8
  18. chad_code-1.0.0/src/chad/mlx_fastpath.py +370 -0
  19. chad_code-1.0.0/src/chad/mlx_qsdpa.py +481 -0
  20. chad_code-1.0.0/src/chad/profiles.py +81 -0
  21. {chad_code-0.1.0 → chad_code-1.0.0}/src/chad/prompt.py +60 -15
  22. chad_code-1.0.0/src/chad/prove.py +370 -0
  23. {chad_code-0.1.0 → chad_code-1.0.0}/src/chad/render.py +6 -5
  24. {chad_code-0.1.0 → chad_code-1.0.0}/src/chad/repomap.py +14 -2
  25. {chad_code-0.1.0 → chad_code-1.0.0}/src/chad/session.py +1 -1
  26. {chad_code-0.1.0 → chad_code-1.0.0}/src/chad/skills.py +7 -0
  27. {chad_code-0.1.0 → chad_code-1.0.0}/src/chad/symbols.py +13 -1
  28. chad_code-1.0.0/src/chad/syntaxgate.py +603 -0
  29. chad_code-1.0.0/src/chad/toolcall_parse.py +201 -0
  30. chad_code-1.0.0/src/chad/tools.py +1916 -0
  31. {chad_code-0.1.0 → chad_code-1.0.0}/src/chad/tui.py +86 -23
  32. {chad_code-0.1.0 → chad_code-1.0.0}/src/chad/validate.py +11 -0
  33. chad_code-1.0.0/src/chad_code.egg-info/PKG-INFO +223 -0
  34. {chad_code-0.1.0 → chad_code-1.0.0}/src/chad_code.egg-info/SOURCES.txt +22 -2
  35. {chad_code-0.1.0 → chad_code-1.0.0}/src/chad_code.egg-info/requires.txt +8 -5
  36. {chad_code-0.1.0 → chad_code-1.0.0}/tests/test_agent.py +1 -1
  37. chad_code-1.0.0/tests/test_agent_e2e.py +796 -0
  38. chad_code-1.0.0/tests/test_agent_guards.py +1004 -0
  39. chad_code-1.0.0/tests/test_atif.py +198 -0
  40. chad_code-1.0.0/tests/test_bench.py +48 -0
  41. {chad_code-0.1.0 → chad_code-1.0.0}/tests/test_cli.py +107 -10
  42. chad_code-1.0.0/tests/test_compact_notice.py +195 -0
  43. chad_code-1.0.0/tests/test_compaction.py +346 -0
  44. chad_code-1.0.0/tests/test_completion_engine.py +369 -0
  45. {chad_code-0.1.0 → chad_code-1.0.0}/tests/test_config.py +2 -2
  46. chad_code-1.0.0/tests/test_done_audit.py +408 -0
  47. chad_code-1.0.0/tests/test_drift_warn.py +127 -0
  48. chad_code-1.0.0/tests/test_edit.py +247 -0
  49. chad_code-1.0.0/tests/test_edit_corruption.py +154 -0
  50. {chad_code-0.1.0 → chad_code-1.0.0}/tests/test_engine.py +567 -14
  51. chad_code-1.0.0/tests/test_engine_kvquant.py +188 -0
  52. {chad_code-0.1.0 → chad_code-1.0.0}/tests/test_feel_pack.py +1 -1
  53. {chad_code-0.1.0 → chad_code-1.0.0}/tests/test_gate.py +2 -2
  54. {chad_code-0.1.0 → chad_code-1.0.0}/tests/test_ignore.py +1 -1
  55. {chad_code-0.1.0 → chad_code-1.0.0}/tests/test_intent.py +86 -1
  56. chad_code-1.0.0/tests/test_lever_bite.py +638 -0
  57. chad_code-1.0.0/tests/test_levers.py +121 -0
  58. {chad_code-0.1.0 → chad_code-1.0.0}/tests/test_mcp.py +1 -1
  59. {chad_code-0.1.0 → chad_code-1.0.0}/tests/test_mcp_oauth.py +2 -2
  60. chad_code-1.0.0/tests/test_mlx_fastpath.py +128 -0
  61. chad_code-1.0.0/tests/test_mlx_qsdpa.py +217 -0
  62. chad_code-1.0.0/tests/test_plan_review.py +95 -0
  63. chad_code-1.0.0/tests/test_prove.py +164 -0
  64. {chad_code-0.1.0 → chad_code-1.0.0}/tests/test_render.py +19 -2
  65. chad_code-1.0.0/tests/test_replace_lines.py +424 -0
  66. {chad_code-0.1.0 → chad_code-1.0.0}/tests/test_repomap.py +46 -1
  67. {chad_code-0.1.0 → chad_code-1.0.0}/tests/test_session.py +1 -1
  68. {chad_code-0.1.0 → chad_code-1.0.0}/tests/test_subagent.py +85 -5
  69. chad_code-1.0.0/tests/test_syntaxgate.py +166 -0
  70. chad_code-1.0.0/tests/test_toolcall_parse.py +230 -0
  71. {chad_code-0.1.0 → chad_code-1.0.0}/tests/test_tools.py +156 -6
  72. {chad_code-0.1.0 → chad_code-1.0.0}/tests/test_tui.py +113 -6
  73. {chad_code-0.1.0 → chad_code-1.0.0}/tests/test_validate.py +51 -0
  74. chad_code-0.1.0/PKG-INFO +0 -370
  75. chad_code-0.1.0/README.md +0 -334
  76. chad_code-0.1.0/src/chad/agent.py +0 -1093
  77. chad_code-0.1.0/src/chad/base_engine.py +0 -109
  78. chad_code-0.1.0/src/chad/compaction.py +0 -108
  79. chad_code-0.1.0/src/chad/guardrails.py +0 -373
  80. chad_code-0.1.0/src/chad/openai_engine.py +0 -252
  81. chad_code-0.1.0/src/chad/syntaxgate.py +0 -105
  82. chad_code-0.1.0/src/chad/toolcall_parse.py +0 -115
  83. chad_code-0.1.0/src/chad/tools.py +0 -962
  84. chad_code-0.1.0/src/chad_code.egg-info/PKG-INFO +0 -370
  85. chad_code-0.1.0/tests/test_agent_e2e.py +0 -184
  86. chad_code-0.1.0/tests/test_agent_guards.py +0 -478
  87. chad_code-0.1.0/tests/test_compaction.py +0 -189
  88. chad_code-0.1.0/tests/test_edit.py +0 -107
  89. chad_code-0.1.0/tests/test_openai_engine.py +0 -183
  90. chad_code-0.1.0/tests/test_syntaxgate.py +0 -98
  91. chad_code-0.1.0/tests/test_toolcall_parse.py +0 -127
  92. {chad_code-0.1.0 → chad_code-1.0.0}/LICENSE +0 -0
  93. {chad_code-0.1.0 → chad_code-1.0.0}/setup.cfg +0 -0
  94. {chad_code-0.1.0 → chad_code-1.0.0}/src/chad/diag.py +0 -0
  95. {chad_code-0.1.0 → chad_code-1.0.0}/src/chad/ignore.py +0 -0
  96. {chad_code-0.1.0 → chad_code-1.0.0}/src/chad/lsp.py +0 -0
  97. {chad_code-0.1.0 → chad_code-1.0.0}/src/chad_code.egg-info/dependency_links.txt +0 -0
  98. {chad_code-0.1.0 → chad_code-1.0.0}/src/chad_code.egg-info/entry_points.txt +0 -0
  99. {chad_code-0.1.0 → chad_code-1.0.0}/src/chad_code.egg-info/top_level.txt +0 -0
  100. {chad_code-0.1.0 → chad_code-1.0.0}/tests/test_confirm_preview.py +0 -0
  101. {chad_code-0.1.0 → chad_code-1.0.0}/tests/test_log_redaction.py +0 -0
  102. {chad_code-0.1.0 → chad_code-1.0.0}/tests/test_lsp.py +0 -0
  103. {chad_code-0.1.0 → chad_code-1.0.0}/tests/test_skills.py +0 -0
  104. {chad_code-0.1.0 → chad_code-1.0.0}/tests/test_symbols.py +0 -0
@@ -0,0 +1,223 @@
1
+ Metadata-Version: 2.4
2
+ Name: chad-code
3
+ Version: 1.0.0
4
+ Summary: Local MLX-backed, Claude-Code-style coding agent (Apple Silicon, Ornith 35B/9B)
5
+ License-Expression: MIT
6
+ Project-URL: Repository, https://github.com/nathansutton/chad
7
+ Project-URL: Issues, https://github.com/nathansutton/chad/issues
8
+ Keywords: mlx,coding-agent,apple-silicon,local-llm,tui
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Environment :: Console
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Operating System :: MacOS
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Topic :: Software Development :: Code Generators
17
+ Requires-Python: >=3.11
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Requires-Dist: mlx<0.33,>=0.32.0; sys_platform == "darwin"
21
+ Requires-Dist: mlx-lm<0.32,>=0.31.3; sys_platform == "darwin"
22
+ Requires-Dist: transformers<5.13,>=5.0
23
+ Requires-Dist: jinja2>=3.1
24
+ Requires-Dist: numpy<2,>=1.26
25
+ Requires-Dist: huggingface-hub>=1.22.0
26
+ Requires-Dist: jedi>=0.19.2
27
+ Requires-Dist: prompt_toolkit>=3.0.43
28
+ Requires-Dist: tree-sitter>=0.26.0
29
+ Requires-Dist: tree-sitter-language-pack>=1.12.2
30
+ Requires-Dist: rustworkx>=0.15
31
+ Requires-Dist: mcp>=1.27
32
+ Provides-Extra: highlight
33
+ Requires-Dist: pygments>=2.17; extra == "highlight"
34
+ Provides-Extra: lsp
35
+ Requires-Dist: serena-agent>=1.5; extra == "lsp"
36
+ Dynamic: license-file
37
+
38
+ # chad — a local, MLX-backed coding agent
39
+
40
+ [![tests](https://github.com/nathansutton/chad/actions/workflows/tests.yml/badge.svg)](https://github.com/nathansutton/chad/actions/workflows/tests.yml)
41
+
42
+ <img src="docs/tbench-size-vs-score.png" width="840" alt="Terminal-Bench 2.0: accuracy vs. model size. chad + Ornith (a 35B MoE) lands on the Claude Sonnet 4.5 line, matching open models many times its size and standing alone in the laptop-class ≤40B band.">
43
+
44
+ > Claude can do anything, for anyone, anywhere. chad does one thing. 🗿
45
+ > *Coding under supervision.*
46
+
47
+ A single-user coding agent that runs **entirely locally on Apple Silicon** via
48
+ [MLX](https://github.com/ml-explore/mlx). Claude-Code-style tool use (bash, read, write,
49
+ edit, glob, grep), plan mode, and a full-screen TUI — driven by a local model on your
50
+ laptop instead of a frontier model in a datacenter. No Docker, no API key, no model picker.
51
+
52
+ ## Quickstart
53
+
54
+ Apple Silicon Mac + [uv](https://docs.astral.sh/uv/). One command — no clone, no config:
55
+
56
+ ```bash
57
+ uvx chad-code # runs chad anywhere — the command is still `chad`
58
+ uvx chad-code prove # 2-min offline smoke test: 4 tiny fix-it tasks, verified, timed 🗿
59
+ ```
60
+
61
+ First run picks the right Ornith model for your RAM (9B under 32 GB, 35B at 32 GB+), asks,
62
+ and downloads it once (~5 GB / ~13 GB, resumable) into the shared Hugging Face cache. While
63
+ it downloads, `cd` into a project and think of a scoped first ask — *"fix the failing test
64
+ in `tests/test_x.py`"* lands; *"improve my codebase"* flails.
65
+
66
+ > The PyPI package is **`chad-code`**; bare `chad` is an unrelated squatted package. Other
67
+ > ways in (PATH install, bleeding-edge `main`, dev clone) are in
68
+ > [Installing & upgrading](#installing--upgrading).
69
+
70
+ ## chad is not a baby Claude
71
+
72
+ He has some of the same moves — tool use, plan mode, a real TUI — but he's a blunter
73
+ instrument:
74
+
75
+ | | **Claude** | **chad** 🗿 |
76
+ |-----------------|-------------------------------------------------|---------------------------------|
77
+ | **Range** | every workflow, every person, incredible nuance | one job: code, on your machine |
78
+ | **Runs** | anywhere — cloud, IDE, terminal, phone | your mac. that's it. |
79
+ | **Brain** | a frontier model in a datacenter | Ornith model |
80
+ | **Disposition** | understands what you *meant* | does what you *said* |
81
+ | **Harness** | open-ended, anything you can imagine | plan. execute. nothing else. |
82
+ | **When wrong** | reasons a way out | already shipped |
83
+
84
+ ![chad fixing a failing test end to end — reason, read, edit, rerun pytest, all on a local 35B](docs/demo.gif)
85
+
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
+
89
+ ## Sonnet on your laptop
90
+
91
+ The exam is [Terminal-Bench](https://www.tbench.ai/leaderboard), the standard benchmark for
92
+ CLI coding agents. chad won't top it — the A students are frontier models in datacenters.
93
+ The number worth looking at is **how much capability chad wrings out of 35B parameters**:
94
+ on Terminal-Bench 2.1, chad + Ornith lands around the **Claude Sonnet 4.5** line, matching
95
+ open models many times its size and beating every open model in its own weight class by a
96
+ wide margin. On a laptop, *capability per parameter* is the axis you actually compete on —
97
+ and that's where chad + Ornith is out on the frontier alone.
98
+
99
+ > **Placeholder number** — the full verified run is still in flight (`≈50%`, k=1). The whole
100
+ > benchmark is **publicly reproducible from a Mac**: the exact Harbor adapter, the runner,
101
+ > and the recipe live in [`benchmarks/tb2/`](benchmarks/tb2/README.md). Check it, don't
102
+ > trust it.
103
+
104
+ ## The bet: at this end of the report card, the harness beats the model
105
+
106
+ Every serious coding harness was built for a frontier model behind a datacenter API — which
107
+ bakes in two assumptions that are both false on a laptop: the model is an A student, and
108
+ prefill is somebody else's electricity. A C+ student emits tool calls with typos, quotes
109
+ edits it never applies, and rambles — and every token of transcript it drags around must be
110
+ re-read by *your* GPU at a few hundred tokens a second.
111
+
112
+ So chad's thesis isn't "run a model locally" — plenty of tools do that. It's that **for a
113
+ small model, harness quality is worth more than a model upgrade**, and the harness and
114
+ inference engine have to be designed *together*. The failure modes are all nameable: the
115
+ model pours its edit into the reasoning channel and the harness drops it; asks for a tool
116
+ the harness doesn't ship; balloons the context until cache reuse hits 0% and decode falls to
117
+ 2 tok/s. chad handles each *inside* the harness — tool calls parsed in four dialects and
118
+ repaired, arguments schema-coerced with a self-repair loop, edits run through a forgiveness
119
+ cascade, and above all the transcript kept a **strict token-prefix of the live KV cache** so
120
+ prefill never re-reads what it already read. That co-design is the whole moat. The full
121
+ story is in [Design & internals](docs/design.md).
122
+
123
+ ## Installing & upgrading
124
+
125
+ The one-line quickstart (`uvx chad-code`) is up top. The other ways in:
126
+
127
+ ```bash
128
+ uv tool install chad-code # install for good — then it's just `chad`
129
+ uvx --from git+https://github.com/nathansutton/chad chad # bleeding-edge main, no clone
130
+ ```
131
+
132
+ Or from a clone (the dev path):
133
+
134
+ ```bash
135
+ uv sync # install deps + the `chad` entrypoint (one time)
136
+ uv run chad # full-screen TUI
137
+ uv run chad "add a --json flag to main.py and update the tests" # one-shot, headless
138
+ uv run chad -c # resume this directory's last conversation
139
+ ```
140
+
141
+ **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.
144
+
145
+ | Your Mac | Model | Footprint |
146
+ |---|---|---|
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
152
+ [Unsloth's dynamic-quant convention](https://docs.unsloth.ai/) (`UD-…`).
153
+
154
+ **Upgrading** — depends on how you installed: `uv tool upgrade chad-code`; `uvx --refresh
155
+ chad-code`; or `git pull && uv sync` for a clone. What changed lands in
156
+ [`CHANGELOG.md`](CHANGELOG.md). Model weights are versioned separately — a code upgrade never
157
+ re-downloads the model.
158
+
159
+ **Development.** `uv sync` once, then `uv run pytest -q` — the fast unit gate loads **no
160
+ model weights**, runs in seconds, and is what CI runs. Throughput on your own machine:
161
+ `uv run chad-bench` (see [Throughput & performance](docs/benchmarks.md)). LSP-precise
162
+ find-references / rename need the `lsp` extra (`uv tool install 'chad-code[lsp]'`); without
163
+ it chad uses the tree-sitter fallback automatically.
164
+
165
+ ## Interactive UX
166
+
167
+ `uv run chad` launches a full-screen terminal UI (built on prompt_toolkit):
168
+
169
+ - **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.
171
+ - **type-ahead message queue** — keep typing while the agent works; messages run in order.
172
+ - **ctrl-c interrupts the running turn** without killing the session.
173
+ - **live status line** — model, mode, context %, a state glyph + verb, elapsed seconds, and
174
+ **↑prefilled / ↓generated** token counts (with an advancing **%** on an unavoidable full
175
+ re-prefill, so it's never silent).
176
+ - **slash commands** — `/init`, `/skills`, `/mcp`, `/accept`, `/resume`, `/compact`,
177
+ `/model`, `/mode`, `/help`, `/exit`. Same set in the `--repl` line interface.
178
+ - **`@file` / `@dir` mentions** and **`!command` shell passthrough** — pull a file into
179
+ context inline, or run a shell command without invoking the model.
180
+
181
+ **Usage.** `uv run chad --help` is the source of truth:
182
+
183
+ | Flag | What it does |
184
+ |---|---|
185
+ | `-c, --continue` | resume this directory's **most recent** session (non-destructive) |
186
+ | `--resume` | list recent sessions, pick one by number (interactive TTY only) |
187
+ | `--plan` | start in read-only plan mode (investigate + propose, edits blocked) |
188
+ | `--yolo` | auto-approve bash/write/edit (skip confirm prompts) |
189
+ | `--no-think` | skip Ornith's `<think>` blocks — faster on well-scoped work |
190
+ | `--repl` | plain line REPL instead of the TUI |
191
+
192
+ A headless task (positional, or piped with no TTY) auto-approves mutating tools; the model
193
+ runs greedy (temp 0). Every conversation is persisted under `~/.chad/sessions/`, and every
194
+ resume forks a new branch rather than overwriting — details in
195
+ [Configuration](docs/configuration.md#sessions). The rarely-touched tuning knobs
196
+ (`CHAD_MAX_CONTEXT`, `CHAD_KV_BITS`, turn-budget/think-cap, safety opt-outs) all live in
197
+ environment variables, fully documented there.
198
+
199
+ ## Extending chad
200
+
201
+ chad speaks the same two extension formats as Claude Code:
202
+
203
+ - **[Agent Skills](https://agentskills.io)** — drop a `SKILL.md` folder in `./.claude/skills/`
204
+ and chad discovers it, loading the full instructions only when a task matches.
205
+ - **[MCP servers](https://modelcontextprotocol.io)** — configure stdio or HTTP servers in
206
+ `./.mcp.json` to expose external tools (GitHub, Postgres, Linear, Slack, …) alongside
207
+ chad's builtins, with static-token and OAuth auth.
208
+
209
+ Both are covered in full in the [Configuration reference](docs/configuration.md).
210
+
211
+ ## Documentation
212
+
213
+ - **[Design & internals](docs/design.md)** — why prefill is the bill, the persistent prefix
214
+ cache, the trimmable/append-only trade, and the ideas borrowed from other agents.
215
+ - **[Throughput & performance](docs/benchmarks.md)** — prefill / decode / warm-step numbers
216
+ you can reproduce with `chad-bench`.
217
+ - **[Terminal-Bench 2.0 reproduction](benchmarks/tb2/README.md)** — the exact Harbor adapter
218
+ and runner behind the chart; serve Ornith yourself and check the number.
219
+ - **[Configuration reference](docs/configuration.md)** — Agent Skills, MCP servers, the
220
+ context window, every environment variable, and the safety opt-outs.
221
+ - **[Troubleshooting](docs/troubleshooting.md)** — when a session rambles, loops, or slows:
222
+ the symptom→knob map for a small local model.
223
+ - **[Contributing](CONTRIBUTING.md)** — what lands easily, and what needs a conversation first.
@@ -0,0 +1,186 @@
1
+ # chad — a local, MLX-backed coding agent
2
+
3
+ [![tests](https://github.com/nathansutton/chad/actions/workflows/tests.yml/badge.svg)](https://github.com/nathansutton/chad/actions/workflows/tests.yml)
4
+
5
+ <img src="docs/tbench-size-vs-score.png" width="840" alt="Terminal-Bench 2.0: accuracy vs. model size. chad + Ornith (a 35B MoE) lands on the Claude Sonnet 4.5 line, matching open models many times its size and standing alone in the laptop-class ≤40B band.">
6
+
7
+ > Claude can do anything, for anyone, anywhere. chad does one thing. 🗿
8
+ > *Coding under supervision.*
9
+
10
+ A single-user coding agent that runs **entirely locally on Apple Silicon** via
11
+ [MLX](https://github.com/ml-explore/mlx). Claude-Code-style tool use (bash, read, write,
12
+ edit, glob, grep), plan mode, and a full-screen TUI — driven by a local model on your
13
+ laptop instead of a frontier model in a datacenter. No Docker, no API key, no model picker.
14
+
15
+ ## Quickstart
16
+
17
+ Apple Silicon Mac + [uv](https://docs.astral.sh/uv/). One command — no clone, no config:
18
+
19
+ ```bash
20
+ uvx chad-code # runs chad anywhere — the command is still `chad`
21
+ uvx chad-code prove # 2-min offline smoke test: 4 tiny fix-it tasks, verified, timed 🗿
22
+ ```
23
+
24
+ First run picks the right Ornith model for your RAM (9B under 32 GB, 35B at 32 GB+), asks,
25
+ and downloads it once (~5 GB / ~13 GB, resumable) into the shared Hugging Face cache. While
26
+ it downloads, `cd` into a project and think of a scoped first ask — *"fix the failing test
27
+ in `tests/test_x.py`"* lands; *"improve my codebase"* flails.
28
+
29
+ > The PyPI package is **`chad-code`**; bare `chad` is an unrelated squatted package. Other
30
+ > ways in (PATH install, bleeding-edge `main`, dev clone) are in
31
+ > [Installing & upgrading](#installing--upgrading).
32
+
33
+ ## chad is not a baby Claude
34
+
35
+ He has some of the same moves — tool use, plan mode, a real TUI — but he's a blunter
36
+ instrument:
37
+
38
+ | | **Claude** | **chad** 🗿 |
39
+ |-----------------|-------------------------------------------------|---------------------------------|
40
+ | **Range** | every workflow, every person, incredible nuance | one job: code, on your machine |
41
+ | **Runs** | anywhere — cloud, IDE, terminal, phone | your mac. that's it. |
42
+ | **Brain** | a frontier model in a datacenter | Ornith model |
43
+ | **Disposition** | understands what you *meant* | does what you *said* |
44
+ | **Harness** | open-ended, anything you can imagine | plan. execute. nothing else. |
45
+ | **When wrong** | reasons a way out | already shipped |
46
+
47
+ ![chad fixing a failing test end to end — reason, read, edit, rerun pytest, all on a local 35B](docs/demo.gif)
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.
51
+
52
+ ## Sonnet on your laptop
53
+
54
+ The exam is [Terminal-Bench](https://www.tbench.ai/leaderboard), the standard benchmark for
55
+ CLI coding agents. chad won't top it — the A students are frontier models in datacenters.
56
+ The number worth looking at is **how much capability chad wrings out of 35B parameters**:
57
+ on Terminal-Bench 2.1, chad + Ornith lands around the **Claude Sonnet 4.5** line, matching
58
+ open models many times its size and beating every open model in its own weight class by a
59
+ wide margin. On a laptop, *capability per parameter* is the axis you actually compete on —
60
+ and that's where chad + Ornith is out on the frontier alone.
61
+
62
+ > **Placeholder number** — the full verified run is still in flight (`≈50%`, k=1). The whole
63
+ > benchmark is **publicly reproducible from a Mac**: the exact Harbor adapter, the runner,
64
+ > and the recipe live in [`benchmarks/tb2/`](benchmarks/tb2/README.md). Check it, don't
65
+ > trust it.
66
+
67
+ ## The bet: at this end of the report card, the harness beats the model
68
+
69
+ Every serious coding harness was built for a frontier model behind a datacenter API — which
70
+ bakes in two assumptions that are both false on a laptop: the model is an A student, and
71
+ prefill is somebody else's electricity. A C+ student emits tool calls with typos, quotes
72
+ edits it never applies, and rambles — and every token of transcript it drags around must be
73
+ re-read by *your* GPU at a few hundred tokens a second.
74
+
75
+ So chad's thesis isn't "run a model locally" — plenty of tools do that. It's that **for a
76
+ small model, harness quality is worth more than a model upgrade**, and the harness and
77
+ inference engine have to be designed *together*. The failure modes are all nameable: the
78
+ model pours its edit into the reasoning channel and the harness drops it; asks for a tool
79
+ the harness doesn't ship; balloons the context until cache reuse hits 0% and decode falls to
80
+ 2 tok/s. chad handles each *inside* the harness — tool calls parsed in four dialects and
81
+ repaired, arguments schema-coerced with a self-repair loop, edits run through a forgiveness
82
+ cascade, and above all the transcript kept a **strict token-prefix of the live KV cache** so
83
+ prefill never re-reads what it already read. That co-design is the whole moat. The full
84
+ story is in [Design & internals](docs/design.md).
85
+
86
+ ## Installing & upgrading
87
+
88
+ The one-line quickstart (`uvx chad-code`) is up top. The other ways in:
89
+
90
+ ```bash
91
+ uv tool install chad-code # install for good — then it's just `chad`
92
+ uvx --from git+https://github.com/nathansutton/chad chad # bleeding-edge main, no clone
93
+ ```
94
+
95
+ Or from a clone (the dev path):
96
+
97
+ ```bash
98
+ uv sync # install deps + the `chad` entrypoint (one time)
99
+ uv run chad # full-screen TUI
100
+ uv run chad "add a --json flag to main.py and update the tests" # one-shot, headless
101
+ uv run chad -c # resume this directory's last conversation
102
+ ```
103
+
104
+ **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
+
108
+ | Your Mac | Model | Footprint |
109
+ |---|---|---|
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
115
+ [Unsloth's dynamic-quant convention](https://docs.unsloth.ai/) (`UD-…`).
116
+
117
+ **Upgrading** — depends on how you installed: `uv tool upgrade chad-code`; `uvx --refresh
118
+ chad-code`; or `git pull && uv sync` for a clone. What changed lands in
119
+ [`CHANGELOG.md`](CHANGELOG.md). Model weights are versioned separately — a code upgrade never
120
+ re-downloads the model.
121
+
122
+ **Development.** `uv sync` once, then `uv run pytest -q` — the fast unit gate loads **no
123
+ model weights**, runs in seconds, and is what CI runs. Throughput on your own machine:
124
+ `uv run chad-bench` (see [Throughput & performance](docs/benchmarks.md)). LSP-precise
125
+ find-references / rename need the `lsp` extra (`uv tool install 'chad-code[lsp]'`); without
126
+ it chad uses the tree-sitter fallback automatically.
127
+
128
+ ## Interactive UX
129
+
130
+ `uv run chad` launches a full-screen terminal UI (built on prompt_toolkit):
131
+
132
+ - **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.
134
+ - **type-ahead message queue** — keep typing while the agent works; messages run in order.
135
+ - **ctrl-c interrupts the running turn** without killing the session.
136
+ - **live status line** — model, mode, context %, a state glyph + verb, elapsed seconds, and
137
+ **↑prefilled / ↓generated** token counts (with an advancing **%** on an unavoidable full
138
+ re-prefill, so it's never silent).
139
+ - **slash commands** — `/init`, `/skills`, `/mcp`, `/accept`, `/resume`, `/compact`,
140
+ `/model`, `/mode`, `/help`, `/exit`. Same set in the `--repl` line interface.
141
+ - **`@file` / `@dir` mentions** and **`!command` shell passthrough** — pull a file into
142
+ context inline, or run a shell command without invoking the model.
143
+
144
+ **Usage.** `uv run chad --help` is the source of truth:
145
+
146
+ | Flag | What it does |
147
+ |---|---|
148
+ | `-c, --continue` | resume this directory's **most recent** session (non-destructive) |
149
+ | `--resume` | list recent sessions, pick one by number (interactive TTY only) |
150
+ | `--plan` | start in read-only plan mode (investigate + propose, edits blocked) |
151
+ | `--yolo` | auto-approve bash/write/edit (skip confirm prompts) |
152
+ | `--no-think` | skip Ornith's `<think>` blocks — faster on well-scoped work |
153
+ | `--repl` | plain line REPL instead of the TUI |
154
+
155
+ A headless task (positional, or piped with no TTY) auto-approves mutating tools; the model
156
+ runs greedy (temp 0). Every conversation is persisted under `~/.chad/sessions/`, and every
157
+ resume forks a new branch rather than overwriting — details in
158
+ [Configuration](docs/configuration.md#sessions). The rarely-touched tuning knobs
159
+ (`CHAD_MAX_CONTEXT`, `CHAD_KV_BITS`, turn-budget/think-cap, safety opt-outs) all live in
160
+ environment variables, fully documented there.
161
+
162
+ ## Extending chad
163
+
164
+ chad speaks the same two extension formats as Claude Code:
165
+
166
+ - **[Agent Skills](https://agentskills.io)** — drop a `SKILL.md` folder in `./.claude/skills/`
167
+ and chad discovers it, loading the full instructions only when a task matches.
168
+ - **[MCP servers](https://modelcontextprotocol.io)** — configure stdio or HTTP servers in
169
+ `./.mcp.json` to expose external tools (GitHub, Postgres, Linear, Slack, …) alongside
170
+ chad's builtins, with static-token and OAuth auth.
171
+
172
+ Both are covered in full in the [Configuration reference](docs/configuration.md).
173
+
174
+ ## Documentation
175
+
176
+ - **[Design & internals](docs/design.md)** — why prefill is the bill, the persistent prefix
177
+ cache, the trimmable/append-only trade, and the ideas borrowed from other agents.
178
+ - **[Throughput & performance](docs/benchmarks.md)** — prefill / decode / warm-step numbers
179
+ you can reproduce with `chad-bench`.
180
+ - **[Terminal-Bench 2.0 reproduction](benchmarks/tb2/README.md)** — the exact Harbor adapter
181
+ and runner behind the chart; serve Ornith yourself and check the number.
182
+ - **[Configuration reference](docs/configuration.md)** — Agent Skills, MCP servers, the
183
+ context window, every environment variable, and the safety opt-outs.
184
+ - **[Troubleshooting](docs/troubleshooting.md)** — when a session rambles, loops, or slows:
185
+ the symptom→knob map for a small local model.
186
+ - **[Contributing](CONTRIBUTING.md)** — what lands easily, and what needs a conversation first.
@@ -2,9 +2,9 @@
2
2
  # Distribution name is `chad-code` (bare `chad` on PyPI is a squatted 2014 package).
3
3
  # The IMPORT package (src/chad/) and the `chad` command are unchanged — dist name,
4
4
  # import name, and command name are independent. `uvx chad-code` runs the alias
5
- # script added under [project.scripts]. See private/plans/063.
5
+ # script added under [project.scripts].
6
6
  name = "chad-code"
7
- version = "0.1.0"
7
+ version = "1.0.0"
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"
@@ -30,19 +30,31 @@ dependencies = [
30
30
  # loader (expert-weight stacking + vision-tower strip). A minor bump could refactor it
31
31
  # and silently break the `uvx --from git+…` install path, which resolves fresh from
32
32
  # PyPI and ignores uv.lock. Stay on the known-good 0.31 line; bump deliberately.
33
- "mlx>=0.31.2,<0.32",
34
- "mlx-lm>=0.31.3,<0.32",
33
+ # Apple-only: no CPU/CUDA build exists. Platform-gated so `pip install chad-code`
34
+ # succeeds on Linux (e.g. a benchmark container) for the remote `--backend llama`
35
+ # path, which loads no MLX. On macOS the default in-process engine installs it as before.
36
+ # mlx 0.32.0: Metal command-buffer failures (incl. OOM) become catchable Python
37
+ # exceptions instead of a SIGABRT (ml-explore/mlx#3523) — engine._prefill/generate
38
+ # lean on that for the 35B-on-24GB recovery path. Perf re-gated
39
+ # on the bump: prefill/decode within noise of 0.31.2 on both shipped models.
40
+ "mlx>=0.32.0,<0.33; sys_platform == 'darwin'",
41
+ "mlx-lm>=0.31.3,<0.32; sys_platform == 'darwin'",
35
42
  # mlx-lm requires transformers>=5.0, but 5.13.0 regressed AutoTokenizer.register:
36
43
  # it now does `key.__module__.startswith("transformers.")` with no hasattr guard, and
37
44
  # mlx-lm's tokenizer_utils passes the *string* "NewlineTokenizer" as config_class →
38
45
  # AttributeError at import. Cap below 5.13 until mlx-lm or transformers fixes it.
39
46
  "transformers>=5.0,<5.13",
47
+ # transformers needs jinja2 to render `apply_chat_template` (chad's `_render` on every
48
+ # backend). It's an OPTIONAL transformers dep — present transitively on a dev Mac but
49
+ # absent in a clean install (e.g. chad inside a Linux benchmark container), where its
50
+ # absence crashes the first turn. Declare it directly.
51
+ "jinja2>=3.1",
40
52
  "numpy>=1.26,<2",
41
- "huggingface-hub>=0.34", # first-run model download (cli.py/engine.py); imported directly, not just transitively
53
+ "huggingface-hub>=1.22.0", # first-run model download (cli.py/engine.py); imported directly, not just transitively
42
54
  "jedi>=0.19.2", # in-process symbolic code intelligence (read/search/edit)
43
55
  "prompt_toolkit>=3.0.43",
44
- "tree-sitter>=0.25.2",
45
- "tree-sitter-language-pack>=1.11.0",
56
+ "tree-sitter>=0.26.0",
57
+ "tree-sitter-language-pack>=1.12.2",
46
58
  # repomap's personalized PageRank. Native and battle-tested where the previous
47
59
  # hand-rolled power iteration was ours to maintain; single self-contained Rust
48
60
  # wheel, zero transitive deps. Benchmarked vs scipy/networkx/igraph on a real
@@ -54,7 +66,7 @@ dependencies = [
54
66
  "mcp>=1.27",
55
67
  ]
56
68
 
57
- # Optional syntax highlighting in diffs / confirm previews (plan 042 item 4). Pure-Python,
69
+ # Optional syntax highlighting in diffs / confirm previews. Pure-Python,
58
70
  # import-guarded in render.py: absent, output is byte-identical to the un-highlighted path.
59
71
  # Install with `uv sync --extra highlight`.
60
72
  # NOTE: no PyPI release exists; 'pip install chad' installs an unrelated squatted
@@ -86,7 +98,7 @@ Issues = "https://github.com/nathansutton/chad/issues"
86
98
  dev = ["pytest>=8", "ruff>=0.6", "mypy>=1.11", "types-pyyaml>=6"]
87
99
 
88
100
  [build-system]
89
- requires = ["setuptools>=61"]
101
+ requires = ["setuptools>=83.0.0"]
90
102
  build-backend = "setuptools.build_meta"
91
103
 
92
104
  # Standard src layout: the importable package lives at src/chad/. setuptools
@@ -97,8 +109,9 @@ where = ["src"]
97
109
 
98
110
  [tool.pytest.ini_options]
99
111
  testpaths = ["tests"]
100
- # The model-backed eval tiers self-skip without weights; the fast unit gate stays green.
101
- addopts = "-q"
112
+ # No "-q" here: CI/docs/agents all invoke `pytest -q` explicitly, and stacking the two
113
+ # (verbosity -2) suppresses the final "N passed" summary line entirely — an agent
114
+ # running the gate then gets output with no verdict in it.
102
115
 
103
116
  [tool.ruff]
104
117
  line-length = 100
@@ -128,3 +141,12 @@ implicit_optional = true # `x: T = None` defaults are idiomatic throughou
128
141
  disable_error_code = ["var-annotated"]
129
142
  # Tighten (disallow_untyped_defs, re-enable var-annotated, add B/UP/SIM in ruff) in a
130
143
  # follow-up once this baseline holds.
144
+
145
+ [[tool.mypy.overrides]]
146
+ # mlx_fastpath patches mlx_lm classes that only exist on macOS: with mlx installed
147
+ # (dev Macs, the macos CI jobs) its `type: ignore[method-assign]` comments are load-
148
+ # bearing; on the Linux lint runner mlx_lm is absent, the patched classes type as Any,
149
+ # and warn_unused_ignores flags those same comments — unfixable in the code for both
150
+ # platforms at once, so the unused-ignore warning alone is relaxed for this module.
151
+ module = "chad.mlx_fastpath"
152
+ warn_unused_ignores = false
@@ -4,4 +4,4 @@ A flat collection of cooperating modules behind one console script (``chad``):
4
4
  the inference engine, the tool layer, the agent loop, and the terminal UI.
5
5
  """
6
6
 
7
- __version__ = "0.1.0"
7
+ __version__ = "1.0.0"