locals 0.2.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 (121) hide show
  1. locals-0.2.0/LICENSE +21 -0
  2. locals-0.2.0/PKG-INFO +534 -0
  3. locals-0.2.0/README.md +496 -0
  4. locals-0.2.0/THIRD_PARTY_NOTICES.md +76 -0
  5. locals-0.2.0/locals/__init__.py +69 -0
  6. locals-0.2.0/locals/agents.py +485 -0
  7. locals-0.2.0/locals/api.py +333 -0
  8. locals-0.2.0/locals/apis.py +483 -0
  9. locals-0.2.0/locals/app.py +2505 -0
  10. locals-0.2.0/locals/attention.py +224 -0
  11. locals-0.2.0/locals/bench.py +112 -0
  12. locals-0.2.0/locals/blocks.py +485 -0
  13. locals-0.2.0/locals/budget.py +111 -0
  14. locals-0.2.0/locals/chat.py +227 -0
  15. locals-0.2.0/locals/cli.py +84 -0
  16. locals-0.2.0/locals/client.py +297 -0
  17. locals-0.2.0/locals/constraint.py +165 -0
  18. locals-0.2.0/locals/core.py +430 -0
  19. locals-0.2.0/locals/defaults.py +274 -0
  20. locals-0.2.0/locals/engine.py +1300 -0
  21. locals-0.2.0/locals/fields.py +48 -0
  22. locals-0.2.0/locals/forced.py +249 -0
  23. locals-0.2.0/locals/formats.py +969 -0
  24. locals-0.2.0/locals/fuse.py +339 -0
  25. locals-0.2.0/locals/gdn_kernel.py +205 -0
  26. locals-0.2.0/locals/grammar.py +594 -0
  27. locals-0.2.0/locals/harness.py +1239 -0
  28. locals-0.2.0/locals/hybrid_batch.py +1879 -0
  29. locals-0.2.0/locals/kernels.py +1441 -0
  30. locals-0.2.0/locals/lazy.py +224 -0
  31. locals-0.2.0/locals/llg.py +24 -0
  32. locals-0.2.0/locals/lm.py +75 -0
  33. locals-0.2.0/locals/lookup.py +167 -0
  34. locals-0.2.0/locals/menubar.py +100 -0
  35. locals-0.2.0/locals/mixed.py +69 -0
  36. locals-0.2.0/locals/mma_kernel.py +171 -0
  37. locals-0.2.0/locals/nax_kernel.py +471 -0
  38. locals-0.2.0/locals/norm_kernel.py +82 -0
  39. locals-0.2.0/locals/oai.py +811 -0
  40. locals-0.2.0/locals/packed.py +495 -0
  41. locals-0.2.0/locals/pda.py +558 -0
  42. locals-0.2.0/locals/pdactl.py +338 -0
  43. locals-0.2.0/locals/plan.py +1146 -0
  44. locals-0.2.0/locals/presets/tune_v6_applegpu_g14s.json +1 -0
  45. locals-0.2.0/locals/presets/tune_v6_applegpu_g17s.json +1 -0
  46. locals-0.2.0/locals/qmv_frag.py +344 -0
  47. locals-0.2.0/locals/qmv_multi.py +248 -0
  48. locals-0.2.0/locals/regex.py +585 -0
  49. locals-0.2.0/locals/regions.py +126 -0
  50. locals-0.2.0/locals/runtime.py +499 -0
  51. locals-0.2.0/locals/server.py +2300 -0
  52. locals-0.2.0/locals/service.py +680 -0
  53. locals-0.2.0/locals/siblings.py +208 -0
  54. locals-0.2.0/locals/solve.py +909 -0
  55. locals-0.2.0/locals/tree.py +211 -0
  56. locals-0.2.0/locals/treedec.py +133 -0
  57. locals-0.2.0/locals/vocab.py +172 -0
  58. locals-0.2.0/locals/walk.py +219 -0
  59. locals-0.2.0/locals.egg-info/PKG-INFO +534 -0
  60. locals-0.2.0/locals.egg-info/SOURCES.txt +119 -0
  61. locals-0.2.0/locals.egg-info/dependency_links.txt +1 -0
  62. locals-0.2.0/locals.egg-info/entry_points.txt +4 -0
  63. locals-0.2.0/locals.egg-info/requires.txt +14 -0
  64. locals-0.2.0/locals.egg-info/top_level.txt +1 -0
  65. locals-0.2.0/pyproject.toml +67 -0
  66. locals-0.2.0/setup.cfg +4 -0
  67. locals-0.2.0/tests/test_agent_requests.py +268 -0
  68. locals-0.2.0/tests/test_agents.py +49 -0
  69. locals-0.2.0/tests/test_api.py +254 -0
  70. locals-0.2.0/tests/test_apis.py +53 -0
  71. locals-0.2.0/tests/test_app.py +626 -0
  72. locals-0.2.0/tests/test_background_tune.py +166 -0
  73. locals-0.2.0/tests/test_batch_filter.py +49 -0
  74. locals-0.2.0/tests/test_blocks.py +154 -0
  75. locals-0.2.0/tests/test_budget.py +212 -0
  76. locals-0.2.0/tests/test_call_stream.py +219 -0
  77. locals-0.2.0/tests/test_chain_cache.py +53 -0
  78. locals-0.2.0/tests/test_chat.py +39 -0
  79. locals-0.2.0/tests/test_client.py +155 -0
  80. locals-0.2.0/tests/test_compute_dtype.py +57 -0
  81. locals-0.2.0/tests/test_connections.py +553 -0
  82. locals-0.2.0/tests/test_core.py +241 -0
  83. locals-0.2.0/tests/test_engine_model.py +72 -0
  84. locals-0.2.0/tests/test_forced.py +180 -0
  85. locals-0.2.0/tests/test_formats.py +430 -0
  86. locals-0.2.0/tests/test_gdn_fast_model.py +47 -0
  87. locals-0.2.0/tests/test_hangup.py +119 -0
  88. locals-0.2.0/tests/test_harness.py +610 -0
  89. locals-0.2.0/tests/test_json_safe.py +161 -0
  90. locals-0.2.0/tests/test_kernel_patching.py +151 -0
  91. locals-0.2.0/tests/test_lm.py +67 -0
  92. locals-0.2.0/tests/test_lookup.py +85 -0
  93. locals-0.2.0/tests/test_memory_guard.py +267 -0
  94. locals-0.2.0/tests/test_messages_api.py +306 -0
  95. locals-0.2.0/tests/test_mixed_prefill.py +106 -0
  96. locals-0.2.0/tests/test_model_size.py +98 -0
  97. locals-0.2.0/tests/test_nax_kernel.py +46 -0
  98. locals-0.2.0/tests/test_oai.py +657 -0
  99. locals-0.2.0/tests/test_pda.py +265 -0
  100. locals-0.2.0/tests/test_persistence.py +119 -0
  101. locals-0.2.0/tests/test_plan.py +546 -0
  102. locals-0.2.0/tests/test_prefix_cache.py +64 -0
  103. locals-0.2.0/tests/test_q35_kernels.py +199 -0
  104. locals-0.2.0/tests/test_regex.py +88 -0
  105. locals-0.2.0/tests/test_reply_parsing.py +63 -0
  106. locals-0.2.0/tests/test_request_temperature.py +62 -0
  107. locals-0.2.0/tests/test_sampling.py +57 -0
  108. locals-0.2.0/tests/test_server.py +175 -0
  109. locals-0.2.0/tests/test_server_attention.py +49 -0
  110. locals-0.2.0/tests/test_server_guards.py +259 -0
  111. locals-0.2.0/tests/test_service_idle.py +26 -0
  112. locals-0.2.0/tests/test_session_checkpoint.py +173 -0
  113. locals-0.2.0/tests/test_sliding_window_batch.py +70 -0
  114. locals-0.2.0/tests/test_snapshots_bounded.py +19 -0
  115. locals-0.2.0/tests/test_solo.py +129 -0
  116. locals-0.2.0/tests/test_solve.py +357 -0
  117. locals-0.2.0/tests/test_stock_engine_recovers.py +41 -0
  118. locals-0.2.0/tests/test_table_compaction.py +81 -0
  119. locals-0.2.0/tests/test_think_replay.py +56 -0
  120. locals-0.2.0/tests/test_tune_cache.py +163 -0
  121. locals-0.2.0/tests/test_walk_batch.py +86 -0
locals-0.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Arip Asadulaev
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.
locals-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,534 @@
1
+ Metadata-Version: 2.4
2
+ Name: locals
3
+ Version: 0.2.0
4
+ Summary: Run many AI agents at once on your Mac, up to 3x faster: an OpenAI- and Ollama-compatible MLX server with batched decoding, a prompt cache, and tool calls and JSON that always parse
5
+ Author: Arip Asadulaev
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/Generated-Computers/Locals
8
+ Project-URL: Documentation, https://github.com/Generated-Computers/Locals#readme
9
+ Project-URL: Issues, https://github.com/Generated-Computers/Locals/issues
10
+ Keywords: mlx,apple-silicon,llm,structured-output,constrained-decoding,json-schema,grammar,tool-calling,agents,inference
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Operating System :: MacOS
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
+ Requires-Python: >=3.11
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ License-File: THIRD_PARTY_NOTICES.md
25
+ Requires-Dist: mlx<0.34,>=0.32
26
+ Requires-Dist: mlx-lm<0.33,>=0.32
27
+ Requires-Dist: numpy>=1.26
28
+ Requires-Dist: huggingface_hub>=0.30
29
+ Requires-Dist: llguidance>=1.8
30
+ Requires-Dist: outlines-core<0.3,>=0.2
31
+ Requires-Dist: rich>=13
32
+ Provides-Extra: dev
33
+ Requires-Dist: pytest>=8; extra == "dev"
34
+ Requires-Dist: build>=1.2; extra == "dev"
35
+ Provides-Extra: menubar
36
+ Requires-Dist: rumps>=0.4; extra == "menubar"
37
+ Dynamic: license-file
38
+
39
+ <p align="center">
40
+ <img src="https://raw.githubusercontent.com/Generated-Computers/Locals/8404f6b4b32b8070facd0290d157e3ed97777623/docs/assets/logo.png#gh-light-mode-only" alt="Generated Computers" width="80%">
41
+ </p>
42
+
43
+ <h1 align="center">Locals</h1>
44
+
45
+ <p align="center">
46
+ <b>Run many AI agents at once on your Mac, up to 3x faster.</b><br>
47
+ A local server made for agents rather than plain chat: tool calls, long
48
+ conversations and many agents working at the same time. For OpenCode,
49
+ OpenHands, Cline, Aider, Claude Code and any OpenAI, Anthropic or Ollama app.
50
+ </p>
51
+
52
+ <p align="center">
53
+ <a href="https://github.com/Generated-Computers/Locals/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License: MIT"></a>
54
+ <a href="#getting-started"><img src="https://img.shields.io/badge/macOS-Apple%20silicon-lightgrey.svg" alt="macOS on Apple silicon"></a>
55
+ </p>
56
+
57
+ <p align="center">
58
+ <a href="#getting-started"><b>Getting started</b></a> ·
59
+ <a href="#works-with-your-agents"><b>Agents</b></a> ·
60
+ <a href="https://github.com/Generated-Computers/Locals/blob/main/docs/benchmarks/README.md"><b>Benchmarks</b></a> ·
61
+ <a href="#documentation"><b>Documentation</b></a> ·
62
+ <a href="https://arxiv.org/abs/2610.09139"><b>Paper</b></a>
63
+ </p>
64
+
65
+ ```bash
66
+ curl -LsSf https://raw.githubusercontent.com/Generated-Computers/Locals/main/install.sh | sh
67
+ ```
68
+
69
+ Then, in a new Terminal window:
70
+
71
+ ```bash
72
+ locals code ~/my-project
73
+ ```
74
+
75
+ That is all. The first time, Locals downloads a model that suits your Mac
76
+ (about 3 GB), starts it in the background and opens the OpenCode assistant in
77
+ your project. Nothing leaves your computer.
78
+
79
+ ## What it is
80
+
81
+ <img src="https://raw.githubusercontent.com/Generated-Computers/Locals/8404f6b4b32b8070facd0290d157e3ed97777623/docs/assets/emblem.png" alt="Generated Computers Co." width="35%" align="right">
82
+
83
+ Locals runs AI models on your own Mac for agents, not for chatting with a raw
84
+ model. An agent works differently from a person in a chat. It calls tools, and
85
+ every call has to be right. It sends a long prompt that grows a little every
86
+ turn. And it rarely works alone: coding assistants run helpers in parallel, and
87
+ teams of agents split one task between them. Locals is built for this work, from
88
+ the way it computes a batch of requests on your Mac's graphics chip to the way
89
+ it writes a tool call, so a team of agents gets its answers up to three times
90
+ faster than with the standard way of running models on a Mac.
91
+
92
+ It works with the coding agents you may already use, such as OpenCode, Cline,
93
+ Aider, OpenHands and Claude Code, and with any app or program that talks to
94
+ OpenAI, Anthropic or Ollama. Everything stays on your computer.
95
+
96
+ Locals is built on the paper
97
+ [Breaking the Space Barrier and its Application to Language Model Inference](https://arxiv.org/abs/2610.09139)
98
+ (Arip Asadulaev, 2026). A JSON format or a tool call can be described as a
99
+ graph, and checking a reply against it as finding a path in that graph. The
100
+ paper does this in less memory than Savitch's classical bound and turns it into
101
+ an inference engine: text the format already decides is written without running
102
+ the model, the checks run on the graphics chip, and a format needs about 3 MB of
103
+ memory instead of up to 1.5 GB. With it, sixteen tool-calling agents finish 2.5
104
+ times sooner than with mlx-lm and llguidance.
105
+
106
+ ## Made for agents
107
+
108
+ - **Many agents at once.** Requests from every agent are computed together, with
109
+ GPU kernels written for a few requests at a time, so eight agents working at
110
+ once finish in about the time two would need one after the other.
111
+ - **Tool calls that always parse.** Replies are written in each model's own
112
+ tool-call format under a grammar applied on the GPU, so an agent can call only
113
+ the tools it offered, every argument arrives in the type its schema asks for,
114
+ and a reply cut off by its length limit still closes its call. Requests for
115
+ JSON follow their schema the same way.
116
+ - **Each turn picks up where the last one ended.** Locals keeps every
117
+ conversation between turns, and the long system prompt an agent tool starts
118
+ with (3,000 to 16,000 tokens) on disk across restarts, so an agent's next turn
119
+ reads only what it added: the next turn of a 138,000-token conversation starts
120
+ after 2.4 seconds.
121
+ - **Guards made for agents.** A small model can repeat itself or call the same
122
+ tool forever; Locals notices and stops both. A memory guard keeps many agents
123
+ with long prompts from ending in an out-of-memory error, and an agent that
124
+ hangs up frees the server at once.
125
+ - **One command per agent tool.** `locals code` opens OpenCode in your project,
126
+ and `locals launch` connects Hermes Agent, OpenClaw, Claude Code, Kilo Code,
127
+ Cline, OpenHands and Aider.
128
+ - **A team of agents for bigger tasks.** `locals run` splits a task into parts,
129
+ gives each part to several agents at once, each in its own copy of your
130
+ project, and lets your tests decide.
131
+
132
+ ## Results at a glance
133
+
134
+ <picture>
135
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/Generated-Computers/Locals/main/docs/assets/charts/requests-narrow-dark.svg">
136
+ <img width="70%" alt="Qwen3.5-4B on an M2 Pro with 16 GB. mlx-lm: 61, 82, 87, 87, 157 tokens per second with 1, 2, 4, 8 and 16 requests at once; Locals: 64, 116, 160, 271, 341 (1.0x, 1.4x, 1.8x, 3.1x, 2.2x)." src="https://raw.githubusercontent.com/Generated-Computers/Locals/main/docs/assets/charts/requests-narrow.svg">
137
+ </picture>
138
+
139
+ mlx-lm, the standard way of running models on a Mac, answers several requests
140
+ together, but it gets no faster from four of them to eight: it writes 87 tokens
141
+ per second for four requests and the same 87 for eight. Locals keeps getting
142
+ faster as requests are added, up to three times mlx-lm's speed with eight at
143
+ once.
144
+
145
+ It is faster for a single agent too: when the reply repeats a file it is
146
+ rewriting, after a restart, and in long conversations. The table has these
147
+ cases, on a MacBook Pro with an M2 Pro and 16 GB and Qwen3.5-4B, the default
148
+ model.
149
+
150
+ <br clear="right">
151
+
152
+ | On a MacBook Pro with an M2 Pro and 16 GB, Qwen3.5-4B | Without Locals | With Locals | |
153
+ |---|---|---|---|
154
+ | 8 requests at once | 87 tokens/s (mlx-lm) | 271 tokens/s | 3.1x |
155
+ | 8 agents asking at once: time to the first word | 42 s (Ollama) | 1.6 s | 26x sooner |
156
+ | One agent rewriting a 100-line file | 43 tokens/s (mlx-lm) | 128 tokens/s | 3.0x |
157
+ | An agent's first request after a restart | 16 s (mlx-lm) | 1.7 s | 9.6x sooner |
158
+ | A follow-up question about a 48,000-token document | out of memory (mlx-lm) | 0.6 s | |
159
+ | 16 coding agents calling tools (Qwen3.5-2B, from the paper) | 75 s (mlx-lm) | 29 s | 2.5x |
160
+ | 40 programming problems from LiveCodeBench, 8 at a time (from the paper) | 20 min (mlx-lm) | 8 min | 2.5x |
161
+
162
+ <picture>
163
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/Generated-Computers/Locals/main/docs/assets/charts/macs-dark.svg">
164
+ <img alt="Qwen3.5-4B through the server, 1 to 16 requests at once. M2 Pro · 16 GB: mlx-lm [51, 79, 88, 75, 124], Locals [65, 116, 150, 244, 310]. M2 Max · 96 GB: mlx-lm [91, 121, 142, 152, 267], Locals [104, 177, 244, 403, 530]. M5 Pro · 24 GB: mlx-lm [86, 151, 232, 258, 333], Locals [90, 161, 253, 382, 508]." src="https://raw.githubusercontent.com/Generated-Computers/Locals/main/docs/assets/charts/macs.svg" width="100%">
165
+ </picture>
166
+
167
+ Bigger models gain more on the M2 Max: 3.0x for Qwen3.5-9B and 3.1x for a 27B
168
+ model with eight requests at once. On the M5 Pro the gain is smaller, because
169
+ mlx-lm is much faster there: MLX has its own kernels for the M5's neural
170
+ accelerators, and these numbers were measured before Locals had its own. M1, M3
171
+ and M4 chips have not been measured yet: results from them are welcome as
172
+ [issues](https://github.com/Generated-Computers/Locals/issues), with the output
173
+ of `locals bench` and `locals tune --report`.
174
+
175
+ ## Benchmarks
176
+
177
+ Every table, and how each was measured, is in
178
+ [Benchmarks](https://github.com/Generated-Computers/Locals/blob/main/docs/benchmarks/README.md). Unless a chart says otherwise, it was
179
+ measured on a MacBook Pro with an M2 Pro (19-core GPU) and 16 GB, with
180
+ Qwen3.5-4B (`mlx-community/Qwen3.5-4B-MLX-4bit`), MLX 0.32 and mlx-lm 0.32.
181
+
182
+ <picture>
183
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/Generated-Computers/Locals/main/docs/assets/charts/models-dark.svg">
184
+ <img alt="M2 Pro · 16 GB: Qwen3.5-2B 3.1x (188 to 576 tokens/s), MiniCPM5-2B 3.0x (160 to 478 tokens/s), LFM2.5-2.6B 2.8x (144 to 404 tokens/s), Qwen3.5-4B 3.1x (87 to 271 tokens/s), Gemma 4 E4B 2.8x (80 to 224 tokens/s). M2 Max · 96 GB: Qwen3.5-4B 2.66x (152 to 403 tokens/s), Qwen3.5-9B 3.03x (72 to 220 tokens/s), Qwen3.8-27B 3.13x (25 to 78 tokens/s). M5 Pro · 24 GB: Qwen3.5-4B 1.48x (258 to 382 tokens/s), Qwen3.5-9B 1.58x (145 to 229 tokens/s)." src="https://raw.githubusercontent.com/Generated-Computers/Locals/main/docs/assets/charts/models.svg" width="100%">
185
+ </picture>
186
+
187
+ Models quantized to 4 bits in the usual way (in groups of 64) gain 2.3x to 3.3x
188
+ with 8 requests at once; other formats run at mlx-lm's speed
189
+ ([below](#where-locals-is-not-faster)).
190
+
191
+ ### Against other servers
192
+
193
+ <picture>
194
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/Generated-Computers/Locals/main/docs/assets/charts/servers-dark.svg">
195
+ <img alt="Qwen3.5-4B, 1,000-token prompts, 8 requests at once on an M2 Pro. Time to the first token: Locals 1.6 s, llama.cpp 2.1 s, Magnitude 16.1 s, Ollama 41.8 s. Tokens per second: Locals 110, llama.cpp 71, Magnitude 42, Ollama 34." src="https://raw.githubusercontent.com/Generated-Computers/Locals/main/docs/assets/charts/servers.svg" width="100%">
196
+ </picture>
197
+
198
+ Ollama 0.40.5, Magnitude 0.2.9 and llama.cpp `b11724`, one at a time on the GPU,
199
+ each with its own 4-bit build of the model, measured with SemiAnalysis's
200
+ InferenceX client (temperature 0, replies of natural length). The tables for
201
+ 1,000- and 8,000-token prompts and for Gemma 4 are in
202
+ [Benchmarks](https://github.com/Generated-Computers/Locals/blob/main/docs/benchmarks/README.md#3-against-other-servers).
203
+
204
+ ### Long prompts
205
+
206
+ **No pause while a long prompt is read.** When an agent sends an 8,000-token
207
+ prompt while others are getting answers, Locals reads it in the same passes as
208
+ their next tokens, so their replies keep streaming: the longest gap in them went
209
+ from 12 s to 3 s, with the same throughput, against reading the prompt on its
210
+ own. A 3,000-token request that arrives during a 30,000-token one gets its first
211
+ token after 7 s instead of 41.
212
+
213
+ ### Where Locals is not faster
214
+
215
+ - **One request alone, with nothing to reuse**: about the same as mlx-lm (64
216
+ against 61 tokens per second on the M2 Pro). It is faster alone when the reply
217
+ repeats the prompt (file rewrites) or the prompt is cached.
218
+ - **Prompt-bound work**: reading a prompt is limited by the GPU's arithmetic.
219
+ With 8,000-token prompts and 8 requests at once the server writes 57 tokens
220
+ per second; most of the time goes into reading.
221
+ - **Formats outside the tuned kernels**: 4-bit affine quantization in groups of
222
+ 64 is covered; mxfp4 (a mixture-of-experts model, Mellum) ran at mlx-lm's
223
+ speed.
224
+ - **The M5's neural accelerators**: MLX's own kernels already use them, so the
225
+ gain there is 1.5x, not 3x (before Locals' own `nax` kernel, which is
226
+ experimental).
227
+
228
+ ## Works with your agents
229
+
230
+ <p align="center">
231
+ <img src="https://raw.githubusercontent.com/Generated-Computers/Locals/main/docs/assets/agents/hermes.png" width="12.4%" alt="Hermes Agent" title="Hermes Agent"><img src="https://raw.githubusercontent.com/Generated-Computers/Locals/main/docs/assets/agents/kilo.png" width="12.4%" alt="Kilo Code" title="Kilo Code"><img src="https://raw.githubusercontent.com/Generated-Computers/Locals/main/docs/assets/agents/opencode.png" width="12.4%" alt="OpenCode" title="OpenCode"><img src="https://raw.githubusercontent.com/Generated-Computers/Locals/main/docs/assets/agents/openhands.png" width="12.4%" alt="OpenHands" title="OpenHands"><img src="https://raw.githubusercontent.com/Generated-Computers/Locals/main/docs/assets/agents/cline.png" width="12.4%" alt="Cline" title="Cline"><img src="https://raw.githubusercontent.com/Generated-Computers/Locals/main/docs/assets/agents/aider.png" width="12.4%" alt="Aider" title="Aider"><img src="https://raw.githubusercontent.com/Generated-Computers/Locals/main/docs/assets/agents/roo.png" width="12.4%" alt="Roo Code" title="Roo Code"><img src="https://raw.githubusercontent.com/Generated-Computers/Locals/main/docs/assets/agents/openclaw.png" width="12.4%" alt="OpenClaw" title="OpenClaw">
232
+ </p>
233
+
234
+ Locals works with the coding agents and assistants people already use, on a
235
+ model running on your Mac. All of these but Roo Code were tested end to end with
236
+ Qwen3.5-4B on a 16 GB Mac (Cline and Kilo Code through their command-line
237
+ versions), on real tasks such as writing a program, running it and reporting
238
+ what it printed. One command starts Locals and connects the tool to it:
239
+
240
+ | Tool | Run |
241
+ |---|---|
242
+ | [Hermes Agent](https://github.com/NousResearch/hermes-agent) | `locals launch hermes` |
243
+ | [Kilo Code](https://github.com/Kilo-Org/kilocode) | `locals launch kilo` |
244
+ | [OpenCode](https://github.com/anomalyco/opencode) | `locals code ~/my-project` |
245
+ | [OpenHands](https://github.com/OpenHands/OpenHands) | `locals launch openhands` |
246
+ | [Cline](https://github.com/cline/cline) | `locals launch cline` |
247
+ | [Aider](https://github.com/Aider-AI/aider) | `locals launch aider` |
248
+ | [Roo Code](https://github.com/RooCodeInc/Roo-Code) | in VS Code, the settings from `locals launch editor` ([how](#use-it-in-apps-and-editors)) |
249
+ | [OpenClaw](https://github.com/openclaw/openclaw) | `locals launch openclaw` |
250
+ | [Claude Code](https://github.com/anthropics/claude-code) | `locals launch claude` (through Anthropic's Messages API, which Locals also answers) |
251
+
252
+ `locals launch list` shows every tool it can open. Locals keeps running in the
253
+ background after you close a tool: `locals status` shows what it is doing and
254
+ `locals stop` stops it.
255
+
256
+ <sub>The logos belong to their projects and are shown only to say that Locals
257
+ works with these tools.</sub>
258
+
259
+ ## Getting started
260
+
261
+ You need a Mac with Apple silicon (M1 or newer) and macOS 14 or newer. A Mac
262
+ with 16 GB of memory gives the best results; with 8 GB, use one of the smaller
263
+ models.
264
+
265
+ Open the Terminal app and run:
266
+
267
+ ```bash
268
+ curl -LsSf https://raw.githubusercontent.com/Generated-Computers/Locals/main/install.sh | sh
269
+ ```
270
+
271
+ Then open a new Terminal window (the installer adds Locals to your shell's
272
+ PATH, which only new windows read) and start a coding assistant on one of your
273
+ projects:
274
+
275
+ ```bash
276
+ locals code ~/my-project
277
+ ```
278
+
279
+ After the first start, which downloads the model, Locals starts in seconds.
280
+
281
+ - **OpenCode** uses Locals as its default model from then on, so plain
282
+ `opencode` uses it too; `locals disconnect opencode` gives OpenCode its own
283
+ settings back.
284
+ - **To update** Locals, run the install command again.
285
+ - **To remove** it, run `locals stop`, `locals disconnect opencode` and
286
+ `uv tool uninstall locals`.
287
+ - **With the uv package manager**, you can install with
288
+ `uv tool install --python 3.12 git+https://github.com/Generated-Computers/Locals`
289
+ instead.
290
+
291
+ ### Coming from Ollama, LM Studio, mlx-lm or llama.cpp
292
+
293
+ Locals installs next to them and changes nothing of theirs: it has its own port
294
+ (8321) and its own folders. Only the memory is shared, so quit the other one
295
+ while Locals runs; two models at once rarely fit. Locals remembers the model and
296
+ port you start it with for later commands.
297
+
298
+ **Ollama.** Quit Ollama, then let Locals answer on Ollama's port. Apps set up
299
+ for Ollama (Open WebUI, Raycast, Continue) and the `ollama` command itself keep
300
+ working unchanged, whatever model name they ask for:
301
+
302
+ ```bash
303
+ osascript -e 'quit app "Ollama"' # or: brew services stop ollama
304
+ locals launch --model qwen3.5:4b ollama
305
+ ```
306
+
307
+ Ollama's model names work in Locals, and for a model Locals does not know it
308
+ names the MLX version on Hugging Face to use instead. Ollama's own downloads
309
+ are in its own format (GGUF for most models), so a model is downloaded once
310
+ more, in MLX's. To
311
+ go back, run `locals stop` and start Ollama.
312
+
313
+ **LM Studio.** LM Studio's MLX models run in Locals where they are, with no
314
+ second download. Stop LM Studio's server and start Locals on its port, so apps
315
+ that use it keep working:
316
+
317
+ ```bash
318
+ locals start --model ~/.lmstudio/models/mlx-community/Qwen3.5-4B-MLX-4bit --port 1234
319
+ ```
320
+
321
+ **mlx-lm.** The same models and the same download folder, so nothing downloads
322
+ again. `locals serve` takes the place of `mlx_lm.server`, with the same API:
323
+
324
+ ```bash
325
+ locals serve --model mlx-community/Qwen3.5-4B-MLX-4bit --port 8080
326
+ ```
327
+
328
+ **llama.cpp.** Locals runs MLX models, not GGUF files; give it one and it names
329
+ the MLX version of the same model. Start it on `llama-server`'s port to keep
330
+ your clients:
331
+
332
+ ```bash
333
+ locals start --model qwen --port 8080
334
+ ```
335
+
336
+ **Any other server with the OpenAI API** (vLLM, LocalAI): point your client at
337
+ `http://127.0.0.1:8321/v1`, or start Locals on the port the client already uses
338
+ with `--port`.
339
+
340
+ ## Examples
341
+
342
+ **Work on a project with an assistant.** This opens OpenCode in your project, where
343
+ you can ask for changes in plain words and watch it read, edit and test your code:
344
+
345
+ ```bash
346
+ locals code ~/my-project
347
+ ```
348
+
349
+ **Give it one task and get the result.** The assistant does the task from start
350
+ to finish without opening a window, and prints what it did:
351
+
352
+ ```bash
353
+ locals code ~/my-project --run "add a --verbose flag to cli.py and run the tests"
354
+ ```
355
+
356
+ **Let a team of agents do a bigger task.** Several agents work on the parts of
357
+ the task at the same time, each in its own copy of your project, and your tests
358
+ decide when it is done. Your project is changed only when the tests pass:
359
+
360
+ ```bash
361
+ locals run "write wordcount.py with a function count_words(text) and tests in test_wordcount.py" \
362
+ --dir ~/my-project --check "python3 -m pytest -q"
363
+ ```
364
+
365
+ **Ask a question about your code.** An agent reads the project and prints the
366
+ answer:
367
+
368
+ ```bash
369
+ locals run "Which function parses dates, and which format does it expect?" --dir ~/my-project
370
+ ```
371
+
372
+ **Chat with the model** in the Terminal, like a private chatbot:
373
+
374
+ ```bash
375
+ locals chat
376
+ ```
377
+
378
+ **Turn text into structured data.** Describe the fields you want in a JSON schema,
379
+ for example in a file called `person.json`:
380
+
381
+ ```json
382
+ {"type": "object",
383
+ "properties": {"name": {"type": "string"}, "age": {"type": "integer"}, "email": {"type": "string"},
384
+ "status": {"enum": ["pending", "approved", "rejected"]}, "tags": {"type": "array", "items": {"type": "string"}}},
385
+ "required": ["name", "age", "email", "status", "tags"]}
386
+ ```
387
+
388
+ Then the answer always follows it, field by field:
389
+
390
+ ```bash
391
+ locals generate --prompt "Ana Silva, 29, ana@example.com, application approved, tags: vip, early" \
392
+ --schema person.json
393
+ ```
394
+
395
+ ```json
396
+ {"name":"Ana Silva","age":29,"email":"ana@example.com","status":"approved","tags":["vip","early"]}
397
+ ```
398
+
399
+ ## Use it in apps and editors
400
+
401
+ Start Locals once with the model you want; it keeps running in the background:
402
+
403
+ ```bash
404
+ locals start --model qwen
405
+ ```
406
+
407
+ **The OpenCode app.** Run `locals setup --model qwen` once, then choose Locals in
408
+ OpenCode's model list. This works in the desktop app, the editor extension and
409
+ the Terminal version alike.
410
+
411
+ **Kilo Code, Cline and Roo Code in VS Code**, and **Continue, Zed and JetBrains.**
412
+ Choose the provider called "OpenAI Compatible" and enter these values. Run
413
+ `locals launch editor` to print them for the model that is running.
414
+
415
+ | Setting | What to enter |
416
+ |---|---|
417
+ | Base URL | `http://127.0.0.1:8321/v1` |
418
+ | API key | any text, for example `local` |
419
+ | Model | the model's name from the table below, for example `locals/qwen3.5-4b` |
420
+ | Context window | the number `locals launch editor` prints, if the extension asks for it |
421
+
422
+ **Apps that work with Ollama**, such as Open WebUI or Raycast, need no settings:
423
+ run `locals launch ollama`.
424
+
425
+ ## Models
426
+
427
+ Locals picks a model that fits your Mac's memory, so most people never need to
428
+ change it. To use another one, start Locals with its name, for example
429
+ `locals start --model lfm`. Locals runs one model at a time. The last two
430
+ columns are speeds in tokens per second (tps) with 8 requests at once, on the
431
+ M2 Pro with 16 GB above.
432
+
433
+ | Model | Start it with | Name in your editor | Size | mlx-lm | Locals |
434
+ |---|---|---|---|---|---|
435
+ | Qwen3.5-4B (the default) | `--model qwen` | `locals/qwen3.5-4b` | 2.8 GB | 87 tps | 271 tps |
436
+ | LFM2.5-2.6B | `--model lfm` | `locals/lfm2.5-2.6b` | 1.5 GB | 144 tps | 404 tps |
437
+ | MiniCPM5-2B | `--model minicpm` | `locals/minicpm5-2b` | 1.3 GB | 160 tps | 478 tps |
438
+ | Gemma 4 E4B | `--model gemma` | `locals/gemma-4-e4b-it` | 4.8 GB | 80 tps | 224 tps |
439
+
440
+ On a Mac with less than 12 GB of memory, the default is Qwen3.5-2B instead
441
+ (`--model qwen3.5-2b`; `locals/qwen3.5-2b` in your editor).
442
+
443
+ Each model also has a thinking mode, in which it reasons before it answers: add
444
+ `-thinking` to the name, for example `locals/lfm2.5-2.6b-thinking`. The smaller
445
+ models are good choices for a Mac with 8 GB of memory, and other models made for
446
+ Apple silicon on [Hugging Face](https://huggingface.co/mlx-community) work too.
447
+
448
+ Conversations can be long: up to about 178,000 tokens with the default model
449
+ on a 16 GB Mac, a few hundred pages of text. On the M2 Pro, reading a
450
+ 170,000-token document takes about 12 minutes the first time, and follow-up
451
+ questions about it start in 2 seconds. OpenCode is set up for 32,000 tokens,
452
+ and OpenClaw, Hermes Agent and Kilo Code for 64,000, which keeps each of their
453
+ steps quick.
454
+
455
+ ## Using it from your own code
456
+
457
+ Locals understands the same requests as the OpenAI and Ollama services, so
458
+ programs written for them work with it unchanged. Start Locals with
459
+ `locals start`, then point your program at `http://127.0.0.1:8321/v1`:
460
+
461
+ ```python
462
+ from openai import OpenAI
463
+
464
+ client = OpenAI(base_url="http://127.0.0.1:8321/v1", api_key="local")
465
+ reply = client.chat.completions.create(
466
+ model="locals", # the model the server runs
467
+ messages=[{"role": "user", "content": "Write a haiku about the sea."}],
468
+ )
469
+ print(reply.choices[0].message.content)
470
+ ```
471
+
472
+ Send many requests at once, from threads or with an async client, and Locals
473
+ answers them together; that is where it is fastest. Streaming, answers in a
474
+ fixed JSON format, function calls, the Ollama library and plain `curl` all work
475
+ as well; the [examples](https://github.com/Generated-Computers/Locals/blob/main/examples/README.md) show each of them.
476
+
477
+ ## Privacy and safety
478
+
479
+ Everything runs on your Mac. Locals only accepts requests from apps on your own
480
+ computer, so a website you visit cannot use it. When a team of agents works on a
481
+ task (`locals run`, `locals solve`), the commands they run can change files only
482
+ in their own copy of your project, and in the temporary and cache folders that
483
+ tools write to. `locals code` runs OpenCode in your project itself, as OpenCode
484
+ always runs.
485
+
486
+ ## If something does not work
487
+
488
+ Run `locals status`, or open http://127.0.0.1:8321 in your browser, to see whether
489
+ Locals is running and what it is doing. On a chip other than the M2 Pro and
490
+ M2 Max, whose tuning ships with Locals, it tunes itself to your chip the first
491
+ time, in the background while it is idle: 10 to 20 minutes of idle time in all.
492
+ You can use it during that time, and it gets faster once it finishes.
493
+
494
+ Questions and problems are welcome as
495
+ [issues on GitHub](https://github.com/Generated-Computers/Locals/issues).
496
+
497
+ ## Documentation
498
+
499
+ | Topic | Page |
500
+ |---|---|
501
+ | How Locals works: the server, the batch engine, the prompt cache, the team of agents behind `locals run`, and every setting | [How Locals works](https://github.com/Generated-Computers/Locals/blob/main/docs/README.md) |
502
+ | Every benchmark, and how it was measured | [Benchmarks](https://github.com/Generated-Computers/Locals/blob/main/docs/benchmarks/README.md) |
503
+ | Every table with its date, commit and command; the M2 Max | [Measurements](https://github.com/Generated-Computers/Locals/blob/main/docs/measurements/README.md), [M2 Max](https://github.com/Generated-Computers/Locals/blob/main/docs/measurements/m2-max.md) |
504
+ | Why Locals is faster than mlx-lm, part by part | [Why Locals is faster](https://github.com/Generated-Computers/Locals/blob/main/docs/why-faster/README.md) |
505
+ | Streaming, JSON, function calls, the Ollama library and `curl` | [Examples](https://github.com/Generated-Computers/Locals/blob/main/examples/README.md) |
506
+ | The tests, and the end-to-end suite with real agent tools | [Tests](https://github.com/Generated-Computers/Locals/blob/main/tests/README.md), [End to end](https://github.com/Generated-Computers/Locals/blob/main/tests/e2e/README.md) |
507
+ | Working on Locals itself | [CONTRIBUTING.md](https://github.com/Generated-Computers/Locals/blob/main/CONTRIBUTING.md) |
508
+
509
+ To work on Locals:
510
+
511
+ ```bash
512
+ git clone https://github.com/Generated-Computers/Locals
513
+ cd Locals
514
+ uv sync --extra dev
515
+ uv run pytest tests -q -m "not model"
516
+ ```
517
+
518
+ ## Citation
519
+
520
+ If you use Locals in your research, please cite the paper:
521
+
522
+ ```bibtex
523
+ @article{asadulaev2026breaking,
524
+ title = {Breaking the Space Barrier and its Application to Language Model Inference},
525
+ author = {Asadulaev, Arip},
526
+ journal = {arXiv preprint arXiv:2610.09139},
527
+ year = {2026}
528
+ }
529
+ ```
530
+
531
+ ## License
532
+
533
+ Locals is released under the MIT license. It is made by
534
+ [Generated Computers](https://github.com/Generated-Computers).